Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 Mar 2011 18:44:49 +0000 (10:44 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 Mar 2011 18:44:49 +0000 (10:44 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6:
  ALSA: hda - Don't set to D3 in Cirrus errata init verbs
  ALSA: hda - add new Fermi 5xx codec IDs to snd-hda
  ASoC: WM8994: Ensure late enable events are processed for the ADCs
  ASoC: WM8994: Don't disable the AIF[1|2]CLK_ENA unconditionaly
  ASoC: Fix WM9081 platform data initialisation
  ALSA: hda - Fix unable to record issue on ASUS N82JV
  ALSA: HDA: Realtek: Fixup jack detection to input subsystem

2410 files changed:
.gitignore
.mailmap
Documentation/ABI/testing/sysfs-platform-at91 [new file with mode: 0644]
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/drm.tmpl
Documentation/DocBook/dvb/dvbapi.xml
Documentation/DocBook/filesystems.tmpl
Documentation/DocBook/media.tmpl
Documentation/DocBook/v4l/dev-rds.xml
Documentation/DocBook/v4l/v4l2.xml
Documentation/devicetree/bindings/ata/fsl-sata.txt [new file with mode: 0644]
Documentation/devicetree/bindings/eeprom.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/8xxx_gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/led.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/fsl-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/marvell.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/sja1000.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/mdio-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/83xx-512x-pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/cpm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/emac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/reboot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/board.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/diu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/ecm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/gtm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/guts.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/lbc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mcm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/pmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/sec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/ssi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/nintendo/wii.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/fsl-spi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-bus.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/fsl-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-ehci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/xilinx.txt [new file with mode: 0644]
Documentation/devicetree/booting-without-of.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ntfs.txt
Documentation/hwmon/jc42
Documentation/hwmon/k10temp
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/lguest/lguest.txt
Documentation/networking/00-INDEX
Documentation/networking/Makefile
Documentation/networking/bonding.txt
Documentation/networking/dns_resolver.txt
Documentation/networking/ip-sysctl.txt
Documentation/powerpc/booting-without-of.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/cpm.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/emac.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/ndfc.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/reboot.txt [deleted file]
Documentation/powerpc/dts-bindings/can/sja1000.txt [deleted file]
Documentation/powerpc/dts-bindings/ecm.txt [deleted file]
Documentation/powerpc/dts-bindings/eeprom.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/board.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/can.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/diu.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/dma.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/esdhc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/gtm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/guts.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/i2c.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/lbc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mcm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpc5200.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/msi-pic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/pmc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/sata.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/sec.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/spi.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/ssi.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/tsec.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/upm-nand.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/led.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/mdio.txt [deleted file]
Documentation/powerpc/dts-bindings/marvell.txt [deleted file]
Documentation/powerpc/dts-bindings/mmc-spi-slot.txt [deleted file]
Documentation/powerpc/dts-bindings/mtd-physmap.txt [deleted file]
Documentation/powerpc/dts-bindings/nintendo/gamecube.txt [deleted file]
Documentation/powerpc/dts-bindings/nintendo/wii.txt [deleted file]
Documentation/powerpc/dts-bindings/phy.txt [deleted file]
Documentation/powerpc/dts-bindings/spi-bus.txt [deleted file]
Documentation/powerpc/dts-bindings/usb-ehci.txt [deleted file]
Documentation/powerpc/dts-bindings/xilinx.txt [deleted file]
Documentation/scheduler/sched-stats.txt
Documentation/video4linux/v4l2-controls.txt
Documentation/workqueue.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_impl.h
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/irq_srm.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/.gitignore
arch/arm/configs/ag5evm_defconfig
arch/arm/configs/am200epdkit_defconfig
arch/arm/configs/at572d940hfek_defconfig
arch/arm/configs/badge4_defconfig
arch/arm/configs/bcmring_defconfig
arch/arm/configs/cm_x2xx_defconfig
arch/arm/configs/colibri_pxa270_defconfig
arch/arm/configs/collie_defconfig
arch/arm/configs/corgi_defconfig
arch/arm/configs/da8xx_omapl_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/dove_defconfig
arch/arm/configs/ebsa110_defconfig
arch/arm/configs/edb7211_defconfig
arch/arm/configs/em_x270_defconfig
arch/arm/configs/ep93xx_defconfig
arch/arm/configs/eseries_pxa_defconfig
arch/arm/configs/ezx_defconfig
arch/arm/configs/footbridge_defconfig
arch/arm/configs/fortunet_defconfig
arch/arm/configs/h5000_defconfig
arch/arm/configs/imote2_defconfig
arch/arm/configs/ixp2000_defconfig
arch/arm/configs/ixp23xx_defconfig
arch/arm/configs/ixp4xx_defconfig
arch/arm/configs/loki_defconfig
arch/arm/configs/lpd7a400_defconfig
arch/arm/configs/lpd7a404_defconfig
arch/arm/configs/magician_defconfig
arch/arm/configs/mv78xx0_defconfig
arch/arm/configs/mx1_defconfig
arch/arm/configs/mx21_defconfig
arch/arm/configs/mx27_defconfig
arch/arm/configs/mx3_defconfig
arch/arm/configs/mx51_defconfig
arch/arm/configs/nhk8815_defconfig
arch/arm/configs/omap1_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/orion5x_defconfig
arch/arm/configs/pcm027_defconfig
arch/arm/configs/pcontrol_g20_defconfig
arch/arm/configs/pleb_defconfig
arch/arm/configs/pnx4008_defconfig
arch/arm/configs/simpad_defconfig
arch/arm/configs/spitz_defconfig
arch/arm/configs/stmp378x_defconfig
arch/arm/configs/stmp37xx_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/trizeps4_defconfig
arch/arm/configs/u300_defconfig
arch/arm/configs/viper_defconfig
arch/arm/configs/xcep_defconfig
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/include/asm/hardware/sp810.h
arch/arm/include/asm/io.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/head.S
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/kprobes-decode.c
arch/arm/kernel/module.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/pmu.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp_twd.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/gpio.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-imx/mach-mx25_3ds.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/include/mach/timex.h
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-mxs/clock-mx23.c
arch/arm/mach-mxs/clock-mx28.c
arch/arm/mach-mxs/clock.c
arch/arm/mach-mxs/gpio.c
arch/arm/mach-mxs/include/mach/clock.h
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/include/mach/entry-macro.S
arch/arm/mach-omap1/irq.c
arch/arm/mach-omap1/lcd_dma.c
arch/arm/mach-omap1/time.c
arch/arm/mach-omap1/timer32k.c
arch/arm/mach-omap2/board-cm-t3517.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-rm680.c
arch/arm/mach-omap2/clkt_dpll.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/clockdomains44xx_data.c
arch/arm/mach-omap2/dma.c
arch/arm/mach-omap2/include/mach/entry-macro.S
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
arch/arm/mach-omap2/prcm_mpu44xx.h
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/voltage.c
arch/arm/mach-pxa/colibri-evalboard.c
arch/arm/mach-pxa/colibri-pxa300.c
arch/arm/mach-pxa/include/mach/colibri.h
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/pm.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/platsmp.c
arch/arm/mach-s5p6442/include/mach/map.h
arch/arm/mach-s5p64x0/include/mach/map.h
arch/arm/mach-s5pc100/include/mach/map.h
arch/arm/mach-s5pv210/include/mach/map.h
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-s5pv310/Kconfig
arch/arm/mach-s5pv310/include/mach/map.h
arch/arm/mach-s5pv310/include/mach/sysmmu.h
arch/arm/mach-sa1100/collie.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g3evm.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
arch/arm/mach-shmobile/include/mach/head-mackerel.txt
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh73a0.c
arch/arm/mach-spear3xx/include/mach/spear320.h
arch/arm/mach-tegra/gpio.c
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/clkdev.h
arch/arm/mach-tegra/include/mach/kbc.h [new file with mode: 0644]
arch/arm/mach-tegra/irq.c
arch/arm/mach-versatile/Kconfig
arch/arm/mach-vexpress/platsmp.c
arch/arm/mach-vexpress/v2m.c
arch/arm/mm/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/init.c
arch/arm/mm/proc-v7.S
arch/arm/oprofile/common.c
arch/arm/plat-mxc/include/mach/uncompress.h
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/counter_32k.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/include/plat/common.h
arch/arm/plat-omap/mailbox.c
arch/arm/plat-pxa/mfp.c
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/dev-uart.c
arch/arm/plat-s5p/include/plat/sysmmu.h [deleted file]
arch/arm/plat-s5p/sysmmu.c
arch/arm/plat-samsung/dev-ts.c
arch/arm/plat-samsung/include/plat/pm.h
arch/arm/plat-spear/include/plat/uncompress.h
arch/arm/plat-spear/include/plat/vmalloc.h
arch/arm/tools/mach-types
arch/avr32/Kconfig
arch/avr32/include/asm/pgalloc.h
arch/blackfin/Kconfig
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF527-TLL6527M_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-ACVILON_defconfig
arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/configs/BlackStamp_defconfig
arch/blackfin/configs/CM-BF527_defconfig
arch/blackfin/configs/CM-BF533_defconfig
arch/blackfin/configs/CM-BF537E_defconfig
arch/blackfin/configs/CM-BF537U_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/configs/CM-BF561_defconfig
arch/blackfin/configs/DNP5370_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/IP0X_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/SRV1_defconfig
arch/blackfin/configs/TCM-BF518_defconfig
arch/blackfin/configs/TCM-BF537_defconfig
arch/blackfin/include/asm/bfin_serial.h
arch/blackfin/lib/outs.S
arch/blackfin/mach-common/cache.S
arch/cris/Kconfig
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/configs/artpec_3_defconfig
arch/cris/configs/etrax-100lx_v2_defconfig
arch/cris/configs/etraxfs_defconfig
arch/cris/kernel/irq.c
arch/cris/kernel/vmlinux.lds.S
arch/frv/Kconfig
arch/frv/defconfig
arch/h8300/Kconfig
arch/h8300/defconfig
arch/h8300/kernel/irq.c
arch/ia64/Kconfig
arch/m32r/Kconfig
arch/m32r/configs/m32700ut.smp_defconfig
arch/m32r/configs/m32700ut.up_defconfig
arch/m32r/configs/mappi.nommu_defconfig
arch/m32r/configs/mappi.smp_defconfig
arch/m32r/configs/mappi.up_defconfig
arch/m32r/configs/mappi2.opsp_defconfig
arch/m32r/configs/mappi2.vdec2_defconfig
arch/m32r/configs/mappi3.smp_defconfig
arch/m32r/configs/oaks32r_defconfig
arch/m32r/configs/opsput_defconfig
arch/m32r/configs/usrv_defconfig
arch/m32r/kernel/irq.c
arch/m32r/platforms/m32104ut/setup.c
arch/m32r/platforms/m32700ut/setup.c
arch/m32r/platforms/mappi/setup.c
arch/m32r/platforms/mappi2/setup.c
arch/m32r/platforms/mappi3/setup.c
arch/m32r/platforms/oaks32r/setup.c
arch/m32r/platforms/opsput/setup.c
arch/m32r/platforms/usrv/setup.c
arch/m68k/amiga/config.c
arch/m68k/atari/ataints.c
arch/m68k/atari/config.c
arch/m68k/atari/debug.c
arch/m68k/include/asm/atarihw.h
arch/m68k/include/asm/string.h
arch/m68k/lib/string.c
arch/m68knommu/Kconfig
arch/m68knommu/configs/m5208evb_defconfig
arch/m68knommu/configs/m5249evb_defconfig
arch/m68knommu/configs/m5272c3_defconfig
arch/m68knommu/configs/m5275evb_defconfig
arch/m68knommu/configs/m5307c3_defconfig
arch/m68knommu/configs/m5407c3_defconfig
arch/m68knommu/defconfig
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/lib/Makefile
arch/m68knommu/lib/memmove.c [new file with mode: 0644]
arch/m68knommu/platform/5249/intc2.c
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68360/commproc.c
arch/m68knommu/platform/68360/config.c
arch/m68knommu/platform/68360/entry.S
arch/m68knommu/platform/68360/ints.c
arch/m68knommu/platform/coldfire/entry.S
arch/microblaze/Kconfig
arch/microblaze/configs/mmu_defconfig
arch/microblaze/configs/nommu_defconfig
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/kernel/cpu/pvr.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/setup.c
arch/microblaze/lib/fastcopy.S
arch/mips/Kconfig
arch/mips/Kconfig.debug
arch/mips/configs/ar7_defconfig
arch/mips/configs/bcm47xx_defconfig
arch/mips/configs/bcm63xx_defconfig
arch/mips/configs/bigsur_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/cavium-octeon_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/db1000_defconfig
arch/mips/configs/db1100_defconfig
arch/mips/configs/db1200_defconfig
arch/mips/configs/db1500_defconfig
arch/mips/configs/db1550_defconfig
arch/mips/configs/decstation_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/fuloong2e_defconfig
arch/mips/configs/gpr_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip28_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/jazz_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/markeins_defconfig
arch/mips/configs/mipssim_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/configs/msp71xx_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/configs/pb1100_defconfig
arch/mips/configs/pb1200_defconfig
arch/mips/configs/pb1500_defconfig
arch/mips/configs/pb1550_defconfig
arch/mips/configs/pnx8335-stb225_defconfig
arch/mips/configs/pnx8550-jbs_defconfig
arch/mips/configs/pnx8550-stb810_defconfig
arch/mips/configs/powertv_defconfig
arch/mips/configs/rb532_defconfig
arch/mips/configs/rbtx49xx_defconfig
arch/mips/configs/rm200_defconfig
arch/mips/configs/sb1250-swarm_defconfig
arch/mips/configs/tb0219_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0287_defconfig
arch/mips/configs/workpad_defconfig
arch/mips/configs/wrppmc_defconfig
arch/mips/configs/yosemite_defconfig
arch/mn10300/Kconfig
arch/mn10300/configs/asb2303_defconfig
arch/mn10300/configs/asb2364_defconfig
arch/parisc/Kconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/kernel/pdc_cons.c
arch/powerpc/Kconfig
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/mpc8308rdb.dts
arch/powerpc/boot/dts/p1022ds.dts
arch/powerpc/configs/40x/acadia_defconfig
arch/powerpc/configs/40x/ep405_defconfig
arch/powerpc/configs/40x/hcu4_defconfig
arch/powerpc/configs/40x/kilauea_defconfig
arch/powerpc/configs/40x/makalu_defconfig
arch/powerpc/configs/40x/walnut_defconfig
arch/powerpc/configs/44x/arches_defconfig
arch/powerpc/configs/44x/bamboo_defconfig
arch/powerpc/configs/44x/bluestone_defconfig
arch/powerpc/configs/44x/canyonlands_defconfig
arch/powerpc/configs/44x/ebony_defconfig
arch/powerpc/configs/44x/eiger_defconfig
arch/powerpc/configs/44x/icon_defconfig
arch/powerpc/configs/44x/iss476-smp_defconfig
arch/powerpc/configs/44x/katmai_defconfig
arch/powerpc/configs/44x/rainier_defconfig
arch/powerpc/configs/44x/redwood_defconfig
arch/powerpc/configs/44x/sam440ep_defconfig
arch/powerpc/configs/44x/sequoia_defconfig
arch/powerpc/configs/44x/taishan_defconfig
arch/powerpc/configs/44x/warp_defconfig
arch/powerpc/configs/52xx/cm5200_defconfig
arch/powerpc/configs/52xx/lite5200b_defconfig
arch/powerpc/configs/52xx/motionpro_defconfig
arch/powerpc/configs/52xx/pcm030_defconfig
arch/powerpc/configs/52xx/tqm5200_defconfig
arch/powerpc/configs/83xx/asp8347_defconfig
arch/powerpc/configs/83xx/kmeter1_defconfig
arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
arch/powerpc/configs/83xx/mpc832x_mds_defconfig
arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
arch/powerpc/configs/83xx/mpc834x_itx_defconfig
arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
arch/powerpc/configs/83xx/mpc834x_mds_defconfig
arch/powerpc/configs/83xx/mpc836x_mds_defconfig
arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
arch/powerpc/configs/83xx/mpc837x_mds_defconfig
arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
arch/powerpc/configs/83xx/sbc834x_defconfig
arch/powerpc/configs/85xx/ksi8560_defconfig
arch/powerpc/configs/85xx/mpc8540_ads_defconfig
arch/powerpc/configs/85xx/mpc8560_ads_defconfig
arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
arch/powerpc/configs/85xx/sbc8548_defconfig
arch/powerpc/configs/85xx/sbc8560_defconfig
arch/powerpc/configs/85xx/socrates_defconfig
arch/powerpc/configs/85xx/stx_gp3_defconfig
arch/powerpc/configs/85xx/tqm8540_defconfig
arch/powerpc/configs/85xx/tqm8541_defconfig
arch/powerpc/configs/85xx/tqm8548_defconfig
arch/powerpc/configs/85xx/tqm8555_defconfig
arch/powerpc/configs/85xx/tqm8560_defconfig
arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
arch/powerpc/configs/86xx/gef_ppc9a_defconfig
arch/powerpc/configs/86xx/gef_sbc310_defconfig
arch/powerpc/configs/86xx/gef_sbc610_defconfig
arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
arch/powerpc/configs/86xx/sbc8641d_defconfig
arch/powerpc/configs/adder875_defconfig
arch/powerpc/configs/e55xx_smp_defconfig
arch/powerpc/configs/ep8248e_defconfig
arch/powerpc/configs/ep88xc_defconfig
arch/powerpc/configs/gamecube_defconfig
arch/powerpc/configs/holly_defconfig
arch/powerpc/configs/mgcoge_defconfig
arch/powerpc/configs/mgsuvd_defconfig
arch/powerpc/configs/mpc7448_hpc2_defconfig
arch/powerpc/configs/mpc8272_ads_defconfig
arch/powerpc/configs/mpc83xx_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/mpc866_ads_defconfig
arch/powerpc/configs/mpc86xx_defconfig
arch/powerpc/configs/mpc885_ads_defconfig
arch/powerpc/configs/ppc40x_defconfig
arch/powerpc/configs/ppc44x_defconfig
arch/powerpc/configs/pq2fads_defconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/configs/storcenter_defconfig
arch/powerpc/configs/tqm8xx_defconfig
arch/powerpc/configs/wii_defconfig
arch/powerpc/include/asm/feature-fixups.h
arch/powerpc/include/asm/immap_qe.h
arch/powerpc/include/asm/irqflags.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/spu.h
arch/powerpc/kernel/cpu_setup_6xx.S
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/perf_event_fsl_emb.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/rtasd.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/lib/feature-fixups-test.S
arch/powerpc/mm/numa.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/platforms/83xx/mpc830x_rdb.c
arch/powerpc/platforms/83xx/mpc831x_rdb.c
arch/powerpc/platforms/83xx/mpc83xx.h
arch/powerpc/platforms/83xx/usb.c
arch/powerpc/platforms/cell/cpufreq_spudemand.c
arch/powerpc/platforms/cell/qpace_setup.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/embedded6xx/gamecube.c
arch/powerpc/platforms/embedded6xx/wii.c
arch/powerpc/platforms/iseries/Kconfig
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/kexec.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/mpic.c
arch/s390/Kconfig
arch/s390/boot/compressed/misc.c
arch/s390/crypto/sha_common.c
arch/s390/include/asm/atomic.h
arch/s390/include/asm/cache.h
arch/s390/include/asm/cacheflush.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/tlb.h
arch/s390/kernel/traps.c
arch/s390/lib/uaccess_std.c
arch/s390/mm/pgtable.c
arch/score/Kconfig
arch/score/configs/spct6600_defconfig
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boot/Makefile
arch/sh/boot/compressed/Makefile
arch/sh/boot/compressed/misc.c
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/sections.h
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/topology.c
arch/sh/lib/delay.c
arch/sh/mm/cache.c
arch/sparc/Kconfig
arch/sparc/include/asm/pcr.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/una_asm_32.S
arch/sparc/lib/bitext.c
arch/tile/Kconfig
arch/tile/Kconfig.debug
arch/tile/configs/tile_defconfig
arch/um/Kconfig.common
arch/um/Kconfig.um
arch/um/defconfig
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/include/asm/acpi.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/cacheflush.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/numa_32.h
arch/x86/include/asm/numa_64.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/perf_event_p4.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/smpboot_hooks.h
arch/x86/include/asm/system_64.h [deleted file]
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/alternative.c
arch/x86/kernel/apb_timer.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/head_32.S
arch/x86/kernel/irq.c
arch/x86/kernel/process.c
arch/x86/kernel/reboot.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/svm.c
arch/x86/lguest/Kconfig
arch/x86/lguest/boot.c
arch/x86/mm/numa.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr.c
arch/x86/mm/srat_32.c
arch/x86/platform/olpc/olpc_dt.c
arch/x86/xen/enlighten.c
arch/x86/xen/irq.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c
arch/xtensa/configs/common_defconfig
arch/xtensa/configs/iss_defconfig
arch/xtensa/configs/s6105_defconfig
block/Kconfig
block/blk-core.c
block/blk-flush.c
block/blk-lib.c
block/blk-throttle.c
block/cfq-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/acpica/accommon.h
drivers/acpi/acpica/acconfig.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/amlresrc.h
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswscope.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evgpeutil.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdebug.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exnames.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/exstorob.c
drivers/acpi/acpica/exsystem.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwpci.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwvalid.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsdumpdv.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psopcode.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psscope.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/pswalk.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rsaddr.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsinfo.c
drivers/acpi/acpica/rsio.c
drivers/acpi/acpica/rsirq.c
drivers/acpi/acpica/rslist.c
drivers/acpi/acpica/rsmemory.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/utalloc.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utlock.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utosi.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utstate.c
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/battery.c
drivers/acpi/debugfs.c
drivers/acpi/nvs.c
drivers/acpi/osl.c
drivers/acpi/sleep.c
drivers/acpi/video_detect.c
drivers/acpi/wakeup.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_mpc52xx.c
drivers/atm/idt77105.c
drivers/atm/solos-pci.c
drivers/base/Kconfig
drivers/base/power/runtime.c
drivers/block/Makefile
drivers/block/aoe/Makefile
drivers/block/cciss.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/cdrom/cdrom.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/Kconfig
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/bfin_jtag_comm.c
drivers/char/hvc_beat.c [deleted file]
drivers/char/hvc_console.c [deleted file]
drivers/char/hvc_console.h [deleted file]
drivers/char/hvc_dcc.c [deleted file]
drivers/char/hvc_irq.c [deleted file]
drivers/char/hvc_iseries.c [deleted file]
drivers/char/hvc_iucv.c [deleted file]
drivers/char/hvc_rtas.c [deleted file]
drivers/char/hvc_tile.c [deleted file]
drivers/char/hvc_udbg.c [deleted file]
drivers/char/hvc_vio.c [deleted file]
drivers/char/hvc_xen.c [deleted file]
drivers/char/hvcs.c [deleted file]
drivers/char/hvsi.c [deleted file]
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/ipwireless/main.c
drivers/char/tpm/tpm_tis.c
drivers/char/virtio_console.c
drivers/clocksource/acpi_pm.c
drivers/clocksource/tcb_clksrc.c
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq.c
drivers/dma/amba-pl08x.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/ipu/ipu_idmac.c
drivers/edac/amd64_edac.c
drivers/firewire/Kconfig
drivers/firewire/core-card.c
drivers/firewire/net.c
drivers/firmware/Kconfig
drivers/firmware/dmi_scan.c
drivers/gpio/langwell_gpio.c
drivers/gpio/pca953x.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_temp.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv50_evo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_blit_kms.c
drivers/gpu/drm/radeon/evergreen_blit_shaders.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/mkregtable.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r100_track.h
drivers/gpu/drm/radeon/r200.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_blit_shaders.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600_reg.h
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/reg_srcs/r300
drivers/gpu/drm/radeon/reg_srcs/r420
drivers/gpu/drm/radeon/reg_srcs/rs600
drivers/gpu/drm/radeon/reg_srcs/rv515
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/stub/Kconfig
drivers/gpu/vga/Kconfig
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/usbhid/Kconfig
drivers/hwmon/Kconfig
drivers/hwmon/ad7414.c
drivers/hwmon/adt7411.c
drivers/hwmon/applesmc.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/emc1403.c
drivers/hwmon/jc42.c
drivers/hwmon/k10temp.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lm63.c
drivers/hwmon/lm85.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-stu300.c
drivers/ide/Kconfig
drivers/idle/intel_idle.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/amso1100/c2_vq.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/mthca/Kconfig
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/ulp/ipoib/Kconfig
drivers/input/Kconfig
drivers/input/gameport/gameport.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/tegra-kbc.c [new file with mode: 0644]
drivers/input/keyboard/tnetv107x-keypad.c
drivers/input/misc/ixp4xx-beeper.c
drivers/input/misc/rotary_encoder.c
drivers/input/mouse/Kconfig
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/serio/Kconfig
drivers/input/serio/ct82c710.c
drivers/input/serio/serio.c
drivers/input/serio/serport.c
drivers/input/sparse-keymap.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/input/touchscreen/wacom_w8001.c
drivers/isdn/hardware/eicon/istream.c
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hysdn/hysdn_defs.h
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/hysdn/hysdn_net.c
drivers/isdn/hysdn/hysdn_procconf.c
drivers/isdn/icn/icn.c
drivers/leds/leds-pwm.c
drivers/leds/ledtrig-gpio.c
drivers/lguest/page_tables.c
drivers/lguest/x86/core.c
drivers/macintosh/therm_pm72.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/tda8290.c
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/firewire/firedtv-rc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/ix2505v.c
drivers/media/dvb/frontends/mb86a20s.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-gemtek-pci.c [deleted file]
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/imon.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/ir-raw.c
drivers/media/rc/keymaps/rc-dib0700-nec.c
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/rc-main.c
drivers/media/rc/streamzap.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7175.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/cafe_ccic.c
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-streams.h
drivers/media/video/cx231xx/cx231xx-dvb.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/davinci/vpif.c
drivers/media/video/davinci/vpif.h
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/davinci/vpif_capture.h
drivers/media/video/davinci/vpif_display.c
drivers/media/video/davinci/vpif_display.h
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/et61x251/et61x251.h
drivers/media/video/gspca/benq.c
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/jpeg.h
drivers/media/video/gspca/konica.c
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/ov534_9.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sn9c2028.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca1528.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/sq905c.c
drivers/media/video/gspca/sq930x.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv0680.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/xirlink_cit.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/Makefile
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-i2c.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/mt9v011.c
drivers/media/video/mt9v011.h [deleted file]
drivers/media/video/ov7670.c
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/sr030pc30.c
drivers/media/video/tda9875.c [deleted file]
drivers/media/video/tlg2300/pd-video.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/w9966.c
drivers/media/video/zoran/zoran_card.c
drivers/memstick/core/memstick.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptscsih.c
drivers/mfd/asic3.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/tps6586x.c
drivers/mfd/ucb1x00-ts.c
drivers/mfd/wm8994-core.c
drivers/misc/bmp085.c
drivers/misc/tifm_core.c
drivers/misc/vmw_balloon.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/ushc.c
drivers/mtd/nand/r852.c
drivers/mtd/sm_ftl.c
drivers/mtd/ubi/build.c
drivers/net/Kconfig
drivers/net/arm/ks8695net.c
drivers/net/atl1c/atl1c_main.c
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_cmn.h
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_init.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/bnx2x/bnx2x_stats.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/at91_can.c
drivers/net/can/janz-ican3.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/Kconfig
drivers/net/can/pch_can.c
drivers/net/can/softing/Kconfig [new file with mode: 0644]
drivers/net/can/softing/Makefile [new file with mode: 0644]
drivers/net/can/softing/softing.h [new file with mode: 0644]
drivers/net/can/softing/softing_cs.c [new file with mode: 0644]
drivers/net/can/softing/softing_fw.c [new file with mode: 0644]
drivers/net/can/softing/softing_main.c [new file with mode: 0644]
drivers/net/can/softing/softing_platform.h [new file with mode: 0644]
drivers/net/cnic.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/cxgb4vf/t4vf_hw.c
drivers/net/davinci_emac.c
drivers/net/depca.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/dnet.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_osdep.h
drivers/net/e1000e/netdev.c
drivers/net/enc28j60.c
drivers/net/fec.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/igbvf/vf.c
drivers/net/irda/sh_irda.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_fcoe.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_sriov.c
drivers/net/ixgbe/ixgbe_x540.c
drivers/net/macb.c
drivers/net/mlx4/main.c
drivers/net/niu.c
drivers/net/ns83820.c
drivers/net/pch_gbe/pch_gbe.h
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/r8169.c
drivers/net/sfc/ethtool.c
drivers/net/sis900.c
drivers/net/skge.c
drivers/net/stmmac/stmmac_main.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/usb/cdc_ncm.c
drivers/net/usb/dm9601.c
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vxge/vxge-config.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/carl9170/usb.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00firmware.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl12xx/spi.c
drivers/net/xen-netfront.c
drivers/nfc/Kconfig
drivers/nfc/pn544.c
drivers/of/pdt.c
drivers/parport/share.c
drivers/pci/pci-sysfs.c
drivers/pci/pcie/Kconfig
drivers/pcmcia/Kconfig
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_base.h
drivers/pcmcia/pxa2xx_lubbock.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/intel_scu_ipcutil.c
drivers/platform/x86/tc1100-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pps/clients/pps-ktimer.c
drivers/pps/clients/pps_parport.c
drivers/pps/generators/Kconfig
drivers/pps/generators/pps_gen_parport.c
drivers/pps/kapi.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio-sysfs.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/wm831x-dcdc.c
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-at32ap700x.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-msm6242.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-proc.c
drivers/rtc/rtc-rp5c01.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-test.c
drivers/rtc/rtc-vr41xx.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_eckd.c
drivers/s390/cio/qdio_main.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/smsgiucv.c
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_attr.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_fc.c
drivers/serial/21285.c [deleted file]
drivers/serial/68328serial.c [deleted file]
drivers/serial/68328serial.h [deleted file]
drivers/serial/68360serial.c [deleted file]
drivers/serial/8250.c [deleted file]
drivers/serial/8250.h [deleted file]
drivers/serial/8250_accent.c [deleted file]
drivers/serial/8250_acorn.c [deleted file]
drivers/serial/8250_boca.c [deleted file]
drivers/serial/8250_early.c [deleted file]
drivers/serial/8250_exar_st16c554.c [deleted file]
drivers/serial/8250_fourport.c [deleted file]
drivers/serial/8250_gsc.c [deleted file]
drivers/serial/8250_hp300.c [deleted file]
drivers/serial/8250_hub6.c [deleted file]
drivers/serial/8250_mca.c [deleted file]
drivers/serial/8250_pci.c [deleted file]
drivers/serial/8250_pnp.c [deleted file]
drivers/serial/Kconfig [deleted file]
drivers/serial/Makefile [deleted file]
drivers/serial/altera_jtaguart.c [deleted file]
drivers/serial/altera_uart.c [deleted file]
drivers/serial/amba-pl010.c [deleted file]
drivers/serial/amba-pl011.c [deleted file]
drivers/serial/apbuart.c [deleted file]
drivers/serial/apbuart.h [deleted file]
drivers/serial/atmel_serial.c [deleted file]
drivers/serial/bcm63xx_uart.c [deleted file]
drivers/serial/bfin_5xx.c [deleted file]
drivers/serial/bfin_sport_uart.c [deleted file]
drivers/serial/bfin_sport_uart.h [deleted file]
drivers/serial/clps711x.c [deleted file]
drivers/serial/cpm_uart/Makefile [deleted file]
drivers/serial/cpm_uart/cpm_uart.h [deleted file]
drivers/serial/cpm_uart/cpm_uart_core.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm1.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm1.h [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm2.c [deleted file]
drivers/serial/cpm_uart/cpm_uart_cpm2.h [deleted file]
drivers/serial/crisv10.c [deleted file]
drivers/serial/crisv10.h [deleted file]
drivers/serial/dz.c [deleted file]
drivers/serial/dz.h [deleted file]
drivers/serial/icom.c [deleted file]
drivers/serial/icom.h [deleted file]
drivers/serial/ifx6x60.c [deleted file]
drivers/serial/ifx6x60.h [deleted file]
drivers/serial/imx.c [deleted file]
drivers/serial/ioc3_serial.c [deleted file]
drivers/serial/ioc4_serial.c [deleted file]
drivers/serial/ip22zilog.c [deleted file]
drivers/serial/ip22zilog.h [deleted file]
drivers/serial/jsm/Makefile [deleted file]
drivers/serial/jsm/jsm.h [deleted file]
drivers/serial/jsm/jsm_driver.c [deleted file]
drivers/serial/jsm/jsm_neo.c [deleted file]
drivers/serial/jsm/jsm_tty.c [deleted file]
drivers/serial/kgdboc.c [deleted file]
drivers/serial/m32r_sio.c [deleted file]
drivers/serial/m32r_sio.h [deleted file]
drivers/serial/m32r_sio_reg.h [deleted file]
drivers/serial/max3100.c [deleted file]
drivers/serial/max3107-aava.c [deleted file]
drivers/serial/max3107.c [deleted file]
drivers/serial/max3107.h [deleted file]
drivers/serial/mcf.c [deleted file]
drivers/serial/mfd.c [deleted file]
drivers/serial/mpc52xx_uart.c [deleted file]
drivers/serial/mpsc.c [deleted file]
drivers/serial/mrst_max3110.c [deleted file]
drivers/serial/mrst_max3110.h [deleted file]
drivers/serial/msm_serial.c [deleted file]
drivers/serial/msm_serial.h [deleted file]
drivers/serial/mux.c [deleted file]
drivers/serial/netx-serial.c [deleted file]
drivers/serial/nwpserial.c [deleted file]
drivers/serial/of_serial.c [deleted file]
drivers/serial/omap-serial.c [deleted file]
drivers/serial/pch_uart.c [deleted file]
drivers/serial/pmac_zilog.c [deleted file]
drivers/serial/pmac_zilog.h [deleted file]
drivers/serial/pnx8xxx_uart.c [deleted file]
drivers/serial/pxa.c [deleted file]
drivers/serial/s3c2400.c [deleted file]
drivers/serial/s3c2410.c [deleted file]
drivers/serial/s3c2412.c [deleted file]
drivers/serial/s3c2440.c [deleted file]
drivers/serial/s3c24a0.c [deleted file]
drivers/serial/s3c6400.c [deleted file]
drivers/serial/s5pv210.c [deleted file]
drivers/serial/sa1100.c [deleted file]
drivers/serial/samsung.c [deleted file]
drivers/serial/samsung.h [deleted file]
drivers/serial/sb1250-duart.c [deleted file]
drivers/serial/sc26xx.c [deleted file]
drivers/serial/serial_core.c [deleted file]
drivers/serial/serial_cs.c [deleted file]
drivers/serial/serial_ks8695.c [deleted file]
drivers/serial/serial_lh7a40x.c [deleted file]
drivers/serial/serial_txx9.c [deleted file]
drivers/serial/sh-sci.c [deleted file]
drivers/serial/sh-sci.h [deleted file]
drivers/serial/sn_console.c [deleted file]
drivers/serial/suncore.c [deleted file]
drivers/serial/suncore.h [deleted file]
drivers/serial/sunhv.c [deleted file]
drivers/serial/sunsab.c [deleted file]
drivers/serial/sunsab.h [deleted file]
drivers/serial/sunsu.c [deleted file]
drivers/serial/sunzilog.c [deleted file]
drivers/serial/sunzilog.h [deleted file]
drivers/serial/timbuart.c [deleted file]
drivers/serial/timbuart.h [deleted file]
drivers/serial/uartlite.c [deleted file]
drivers/serial/ucc_uart.c [deleted file]
drivers/serial/vr41xx_siu.c [deleted file]
drivers/serial/vt8500_serial.c [deleted file]
drivers/serial/zs.c [deleted file]
drivers/serial/zs.h [deleted file]
drivers/sh/intc/chip.c
drivers/spi/pxa2xx_spi_pci.c
drivers/spi/spi_sh_msiof.c
drivers/ssb/Kconfig
drivers/ssb/pcmcia.c
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
drivers/staging/brcm80211/sys/wl_mac80211.c
drivers/staging/brcm80211/sys/wlc_mac80211.c
drivers/staging/brcm80211/sys/wlc_pub.h
drivers/staging/comedi/Kconfig
drivers/staging/comedi/drivers/mite.c
drivers/staging/comedi/drivers/ni_6527.c
drivers/staging/comedi/drivers/ni_65xx.c
drivers/staging/comedi/drivers/ni_660x.c
drivers/staging/comedi/drivers/ni_670x.c
drivers/staging/comedi/drivers/ni_labpc.c
drivers/staging/comedi/drivers/ni_pcidio.c
drivers/staging/comedi/drivers/ni_pcimio.c
drivers/staging/hv/blkvsc_drv.c
drivers/staging/hv/netvsc.c
drivers/staging/hv/netvsc_drv.c
drivers/staging/iio/adc/ad7476_core.c
drivers/staging/iio/adc/ad7887_core.c
drivers/staging/iio/adc/ad799x_core.c
drivers/staging/iio/dac/ad5446.c
drivers/staging/intel_sst/intelmid_v2_control.c
drivers/staging/lirc/TODO.lirc_zilog
drivers/staging/lirc/lirc_imon.c
drivers/staging/lirc/lirc_it87.c
drivers/staging/lirc/lirc_parallel.c
drivers/staging/lirc/lirc_sasem.c
drivers/staging/lirc/lirc_serial.c
drivers/staging/lirc/lirc_sir.c
drivers/staging/lirc/lirc_zilog.c
drivers/staging/msm/msm_fb.c
drivers/staging/olpc_dcon/olpc_dcon.c
drivers/staging/rt2860/rt_main_dev.c
drivers/staging/rt2860/usb_main_dev.c
drivers/staging/rtl8712/hal_init.c
drivers/staging/rtl8712/usb_intf.c
drivers/staging/sm7xx/smtcfb.c
drivers/staging/speakup/kobjects.c
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
drivers/staging/tidspbridge/core/io_sm.c
drivers/staging/tidspbridge/core/tiomap3430.c
drivers/staging/tidspbridge/include/dspbridge/io_sm.h
drivers/staging/tm6000/tm6000-video.c
drivers/staging/usbip/stub.h
drivers/staging/usbip/stub_dev.c
drivers/staging/usbip/stub_rx.c
drivers/staging/usbip/vhci.h
drivers/staging/usbip/vhci_hcd.c
drivers/staging/usbip/vhci_rx.c
drivers/staging/vme/bridges/Module.symvers [deleted file]
drivers/staging/xgifb/vb_setmode.c
drivers/staging/zram/zram_drv.c
drivers/target/Makefile
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_iblock.c
drivers/target/target_core_mib.c [deleted file]
drivers/target/target_core_mib.h [deleted file]
drivers/target/target_core_pscsi.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/thermal/Kconfig
drivers/thermal/thermal_sys.c
drivers/tty/Makefile
drivers/tty/hvc/Makefile [new file with mode: 0644]
drivers/tty/hvc/hvc_beat.c [new file with mode: 0644]
drivers/tty/hvc/hvc_console.c [new file with mode: 0644]
drivers/tty/hvc/hvc_console.h [new file with mode: 0644]
drivers/tty/hvc/hvc_dcc.c [new file with mode: 0644]
drivers/tty/hvc/hvc_irq.c [new file with mode: 0644]
drivers/tty/hvc/hvc_iseries.c [new file with mode: 0644]
drivers/tty/hvc/hvc_iucv.c [new file with mode: 0644]
drivers/tty/hvc/hvc_rtas.c [new file with mode: 0644]
drivers/tty/hvc/hvc_tile.c [new file with mode: 0644]
drivers/tty/hvc/hvc_udbg.c [new file with mode: 0644]
drivers/tty/hvc/hvc_vio.c [new file with mode: 0644]
drivers/tty/hvc/hvc_xen.c [new file with mode: 0644]
drivers/tty/hvc/hvcs.c [new file with mode: 0644]
drivers/tty/hvc/hvsi.c [new file with mode: 0644]
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/serial/21285.c [new file with mode: 0644]
drivers/tty/serial/68328serial.c [new file with mode: 0644]
drivers/tty/serial/68328serial.h [new file with mode: 0644]
drivers/tty/serial/68360serial.c [new file with mode: 0644]
drivers/tty/serial/8250.c [new file with mode: 0644]
drivers/tty/serial/8250.h [new file with mode: 0644]
drivers/tty/serial/8250_accent.c [new file with mode: 0644]
drivers/tty/serial/8250_acorn.c [new file with mode: 0644]
drivers/tty/serial/8250_boca.c [new file with mode: 0644]
drivers/tty/serial/8250_early.c [new file with mode: 0644]
drivers/tty/serial/8250_exar_st16c554.c [new file with mode: 0644]
drivers/tty/serial/8250_fourport.c [new file with mode: 0644]
drivers/tty/serial/8250_gsc.c [new file with mode: 0644]
drivers/tty/serial/8250_hp300.c [new file with mode: 0644]
drivers/tty/serial/8250_hub6.c [new file with mode: 0644]
drivers/tty/serial/8250_mca.c [new file with mode: 0644]
drivers/tty/serial/8250_pci.c [new file with mode: 0644]
drivers/tty/serial/8250_pnp.c [new file with mode: 0644]
drivers/tty/serial/Kconfig [new file with mode: 0644]
drivers/tty/serial/Makefile [new file with mode: 0644]
drivers/tty/serial/altera_jtaguart.c [new file with mode: 0644]
drivers/tty/serial/altera_uart.c [new file with mode: 0644]
drivers/tty/serial/amba-pl010.c [new file with mode: 0644]
drivers/tty/serial/amba-pl011.c [new file with mode: 0644]
drivers/tty/serial/apbuart.c [new file with mode: 0644]
drivers/tty/serial/apbuart.h [new file with mode: 0644]
drivers/tty/serial/atmel_serial.c [new file with mode: 0644]
drivers/tty/serial/bcm63xx_uart.c [new file with mode: 0644]
drivers/tty/serial/bfin_5xx.c [new file with mode: 0644]
drivers/tty/serial/bfin_sport_uart.c [new file with mode: 0644]
drivers/tty/serial/bfin_sport_uart.h [new file with mode: 0644]
drivers/tty/serial/clps711x.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/Makefile [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart.h [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_core.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c [new file with mode: 0644]
drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h [new file with mode: 0644]
drivers/tty/serial/crisv10.c [new file with mode: 0644]
drivers/tty/serial/crisv10.h [new file with mode: 0644]
drivers/tty/serial/dz.c [new file with mode: 0644]
drivers/tty/serial/dz.h [new file with mode: 0644]
drivers/tty/serial/icom.c [new file with mode: 0644]
drivers/tty/serial/icom.h [new file with mode: 0644]
drivers/tty/serial/ifx6x60.c [new file with mode: 0644]
drivers/tty/serial/ifx6x60.h [new file with mode: 0644]
drivers/tty/serial/imx.c [new file with mode: 0644]
drivers/tty/serial/ioc3_serial.c [new file with mode: 0644]
drivers/tty/serial/ioc4_serial.c [new file with mode: 0644]
drivers/tty/serial/ip22zilog.c [new file with mode: 0644]
drivers/tty/serial/ip22zilog.h [new file with mode: 0644]
drivers/tty/serial/jsm/Makefile [new file with mode: 0644]
drivers/tty/serial/jsm/jsm.h [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_driver.c [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_neo.c [new file with mode: 0644]
drivers/tty/serial/jsm/jsm_tty.c [new file with mode: 0644]
drivers/tty/serial/kgdboc.c [new file with mode: 0644]
drivers/tty/serial/m32r_sio.c [new file with mode: 0644]
drivers/tty/serial/m32r_sio.h [new file with mode: 0644]
drivers/tty/serial/m32r_sio_reg.h [new file with mode: 0644]
drivers/tty/serial/max3100.c [new file with mode: 0644]
drivers/tty/serial/max3107-aava.c [new file with mode: 0644]
drivers/tty/serial/max3107.c [new file with mode: 0644]
drivers/tty/serial/max3107.h [new file with mode: 0644]
drivers/tty/serial/mcf.c [new file with mode: 0644]
drivers/tty/serial/mfd.c [new file with mode: 0644]
drivers/tty/serial/mpc52xx_uart.c [new file with mode: 0644]
drivers/tty/serial/mpsc.c [new file with mode: 0644]
drivers/tty/serial/mrst_max3110.c [new file with mode: 0644]
drivers/tty/serial/mrst_max3110.h [new file with mode: 0644]
drivers/tty/serial/msm_serial.c [new file with mode: 0644]
drivers/tty/serial/msm_serial.h [new file with mode: 0644]
drivers/tty/serial/mux.c [new file with mode: 0644]
drivers/tty/serial/netx-serial.c [new file with mode: 0644]
drivers/tty/serial/nwpserial.c [new file with mode: 0644]
drivers/tty/serial/of_serial.c [new file with mode: 0644]
drivers/tty/serial/omap-serial.c [new file with mode: 0644]
drivers/tty/serial/pch_uart.c [new file with mode: 0644]
drivers/tty/serial/pmac_zilog.c [new file with mode: 0644]
drivers/tty/serial/pmac_zilog.h [new file with mode: 0644]
drivers/tty/serial/pnx8xxx_uart.c [new file with mode: 0644]
drivers/tty/serial/pxa.c [new file with mode: 0644]
drivers/tty/serial/s3c2400.c [new file with mode: 0644]
drivers/tty/serial/s3c2410.c [new file with mode: 0644]
drivers/tty/serial/s3c2412.c [new file with mode: 0644]
drivers/tty/serial/s3c2440.c [new file with mode: 0644]
drivers/tty/serial/s3c24a0.c [new file with mode: 0644]
drivers/tty/serial/s3c6400.c [new file with mode: 0644]
drivers/tty/serial/s5pv210.c [new file with mode: 0644]
drivers/tty/serial/sa1100.c [new file with mode: 0644]
drivers/tty/serial/samsung.c [new file with mode: 0644]
drivers/tty/serial/samsung.h [new file with mode: 0644]
drivers/tty/serial/sb1250-duart.c [new file with mode: 0644]
drivers/tty/serial/sc26xx.c [new file with mode: 0644]
drivers/tty/serial/serial_core.c [new file with mode: 0644]
drivers/tty/serial/serial_cs.c [new file with mode: 0644]
drivers/tty/serial/serial_ks8695.c [new file with mode: 0644]
drivers/tty/serial/serial_lh7a40x.c [new file with mode: 0644]
drivers/tty/serial/serial_txx9.c [new file with mode: 0644]
drivers/tty/serial/sh-sci.c [new file with mode: 0644]
drivers/tty/serial/sh-sci.h [new file with mode: 0644]
drivers/tty/serial/sn_console.c [new file with mode: 0644]
drivers/tty/serial/suncore.c [new file with mode: 0644]
drivers/tty/serial/suncore.h [new file with mode: 0644]
drivers/tty/serial/sunhv.c [new file with mode: 0644]
drivers/tty/serial/sunsab.c [new file with mode: 0644]
drivers/tty/serial/sunsab.h [new file with mode: 0644]
drivers/tty/serial/sunsu.c [new file with mode: 0644]
drivers/tty/serial/sunzilog.c [new file with mode: 0644]
drivers/tty/serial/sunzilog.h [new file with mode: 0644]
drivers/tty/serial/timbuart.c [new file with mode: 0644]
drivers/tty/serial/timbuart.h [new file with mode: 0644]
drivers/tty/serial/uartlite.c [new file with mode: 0644]
drivers/tty/serial/ucc_uart.c [new file with mode: 0644]
drivers/tty/serial/vr41xx_siu.c [new file with mode: 0644]
drivers/tty/serial/vt8500_serial.c [new file with mode: 0644]
drivers/tty/serial/zs.c [new file with mode: 0644]
drivers/tty/serial/zs.h [new file with mode: 0644]
drivers/tty/sysrq.c
drivers/tty/tty_io.c
drivers/tty/vt/selection.c
drivers/tty/vt/vc_screen.c
drivers/tty/vt/vt.c
drivers/tty/vt/vt_ioctl.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/Kconfig
drivers/usb/core/endpoint.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/ci13xxx_udc.h
drivers/usb/gadget/composite.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/usbled.c
drivers/usb/misc/uss720.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_dma.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget.h
drivers/usb/musb/musb_host.c
drivers/usb/musb/musbhsdma.h
drivers/usb/musb/omap2430.c
drivers/usb/otg/Kconfig
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/ulpi.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/moto_modem.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/qcaux.c
drivers/usb/serial/siemens_mpi.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/visor.c
drivers/usb/storage/unusual_cypress.h
drivers/usb/storage/unusual_devs.h
drivers/vhost/net.c
drivers/vhost/vhost.h
drivers/video/Kconfig
drivers/video/arkfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_pm.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/ltv350qv.c
drivers/video/bf537-lq035.c
drivers/video/chipsfb.c
drivers/video/console/Kconfig
drivers/video/console/fbcon.c
drivers/video/console/vgacon.c
drivers/video/da8xx-fb.c
drivers/video/fbmem.c
drivers/video/fbsysfs.c
drivers/video/geode/gxfb_core.c
drivers/video/geode/lxfb_core.c
drivers/video/i810/i810_main.c
drivers/video/jz4740_fb.c
drivers/video/mx3fb.c
drivers/video/nuc900fb.c
drivers/video/nvidia/nvidia.c
drivers/video/ps3fb.c
drivers/video/pxa168fb.c
drivers/video/pxa3xx-gcu.c
drivers/video/s3fb.c
drivers/video/savage/savagefb_driver.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sm501fb.c
drivers/video/tmiofb.c
drivers/video/via/viafbdev.c
drivers/video/vt8623fb.c
drivers/video/xen-fbfront.c
drivers/virtio/virtio_pci.c
drivers/w1/masters/omap_hdq.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/m548x_wdt.c [deleted file]
drivers/watchdog/m54xx_wdt.c [new file with mode: 0644]
drivers/xen/manage.c
drivers/xen/xenfs/xenbus.c
fs/Kconfig
fs/afs/write.c
fs/aio.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/ordered-data.c
fs/btrfs/print-tree.c
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/xattr.c
fs/cifs/Kconfig
fs/cifs/Makefile
fs/cifs/README
fs/cifs/cifs_debug.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_unicode.c
fs/cifs/cifsacl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsencrypt.h [deleted file]
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/md4.c [deleted file]
fs/cifs/md5.c [deleted file]
fs/cifs/md5.h [deleted file]
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smbdes.c
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/dcache.c
fs/direct-io.c
fs/dlm/lowcomms.c
fs/ecryptfs/dentry.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/ext2/namei.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/mballoc.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/fcntl.c
fs/file_table.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/gfs2/glock.c
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/main.c
fs/gfs2/super.c
fs/hfs/dir.c
fs/hfsplus/extents.c
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/wrapper.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/lockd/host.c
fs/minix/namei.c
fs/namei.c
fs/namespace.c
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3acl.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nfs_common/nfsacl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/btnode.c
fs/nilfs2/btnode.h
fs/nilfs2/mdt.c
fs/nilfs2/namei.c
fs/nilfs2/page.c
fs/nilfs2/page.h
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/ntfs/mft.c
fs/ocfs2/journal.h
fs/ocfs2/refcounttree.c
fs/ocfs2/super.c
fs/open.c
fs/partitions/ldm.c
fs/partitions/mac.c
fs/pipe.c
fs/posix_acl.c
fs/proc/Kconfig
fs/proc/array.c
fs/proc/consoles.c
fs/proc/proc_devtree.c
fs/quota/dquot.c
fs/quota/quota.c
fs/reiserfs/namei.c
fs/reiserfs/super.c
fs/squashfs/block.c
fs/squashfs/xz_wrapper.c
fs/squashfs/zlib_wrapper.c
fs/super.c
fs/sysfs/Kconfig
fs/sysv/namei.c
fs/udf/namei.c
fs/ufs/namei.c
fs/xfs/linux-2.6/xfs_discard.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/quota/xfs_qm.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_trans.c
include/acpi/acexcep.h
include/acpi/acnames.h
include/acpi/acoutput.h
include/acpi/acpi.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acrestyp.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h
include/acpi/actypes.h
include/acpi/platform/acenv.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/pgtable.h
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/keys/rxrpc-type.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/acpi_io.h [new file with mode: 0644]
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/caif/Kbuild [new file with mode: 0644]
include/linux/ceph/messenger.h
include/linux/console.h
include/linux/dcbnl.h
include/linux/freezer.h
include/linux/fs.h
include/linux/gfp.h
include/linux/huge_mm.h
include/linux/ieee80211.h
include/linux/input/bu21013.h
include/linux/input/matrix_keypad.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/kernel.h
include/linux/klist.h
include/linux/kmemcheck.h
include/linux/list.h
include/linux/lockdep.h
include/linux/memcontrol.h
include/linux/mfd/wm8994/core.h
include/linux/mm.h
include/linux/mmc/sh_mmcif.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/mroute.h
include/linux/mroute6.h
include/linux/nfsacl.h
include/linux/oprofile.h
include/linux/pm.h
include/linux/pm_wakeup.h
include/linux/posix_acl.h
include/linux/ptrace.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/res_counter.h
include/linux/rio_regs.h
include/linux/rtc.h
include/linux/sched.h
include/linux/security.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/svc_xprt.h
include/linux/syscalls.h
include/linux/sysrq.h
include/linux/thermal.h
include/linux/tracepoint.h
include/linux/usb/cdc.h
include/linux/usb/hcd.h
include/linux/usb/msm_hsusb_hw.h
include/linux/usb/serial.h
include/linux/virtio_config.h
include/linux/virtio_console.h
include/linux/workqueue.h
include/media/mt9v011.h [new file with mode: 0644]
include/media/rc-core.h
include/media/saa7146.h
include/media/v4l2-common.h
include/media/v4l2-ctrls.h
include/media/v4l2-subdev.h
include/net/bluetooth/hci_core.h
include/net/genetlink.h
include/net/ipv6.h
include/net/netfilter/nf_conntrack_ecache.h
include/net/netfilter/nf_tproxy_core.h
include/net/sch_generic.h
include/net/sctp/user.h
include/net/sock.h
include/pcmcia/ds.h
include/scsi/scsi.h
include/target/target_core_base.h
include/target/target_core_transport.h
include/trace/events/block.h
include/trace/ftrace.h
init/Kconfig
init/calibrate.c
init/main.c
kernel/capability.c
kernel/cpuset.c
kernel/cred.c
kernel/irq/Kconfig
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/resend.c
kernel/lockdep.c
kernel/module.c
kernel/params.c
kernel/perf_event.c
kernel/power/main.c
kernel/power/process.c
kernel/power/snapshot.c
kernel/printk.c
kernel/ptrace.c
kernel/sched.c
kernel/sched_autogroup.c
kernel/sched_autogroup.h
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_rt.c
kernel/smp.c
kernel/sys.c
kernel/sysctl.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-sched.c
kernel/time/timer_list.c
kernel/timer.c
kernel/trace/blktrace.c
kernel/trace/trace_events.c
kernel/trace/trace_export.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_syscalls.c
kernel/tracepoint.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig.debug
lib/list_debug.c
lib/nlattr.c
lib/radix-tree.c
lib/rbtree.c
lib/swiotlb.c
lib/textsearch.c
lib/xz/Kconfig
mm/Kconfig
mm/compaction.c
mm/huge_memory.c
mm/kmemleak-test.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/mremap.c
mm/page_alloc.c
mm/pgtable-generic.c
mm/swapfile.c
mm/truncate.c
mm/vmscan.c
net/batman-adv/main.h
net/batman-adv/packet.h
net/batman-adv/types.h
net/batman-adv/unicast.c
net/batman-adv/vis.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_fdb.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/caif/cfcnfg.c
net/caif/chnl_net.c
net/can/bcm.c
net/can/raw.c
net/ceph/messenger.c
net/ceph/pagevec.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/ethtool.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dcb/dcbnl.c
net/dccp/input.c
net/dns_resolver/dns_key.c
net/dsa/dsa.c
net/econet/af_econet.c
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/inet_diag.c
net/ipv4/inet_timewait_sock.c
net/ipv4/inetpeer.c
net/ipv4/ip_gre.c
net/ipv4/ipmr.c
net/ipv4/netfilter/arpt_mangle.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/ipv6/ip6mr.c
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/xfrm6_policy.c
net/mac80211/Kconfig
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_log.c
net/netfilter/nf_tproxy_core.c
net/netfilter/xt_TPROXY.c
net/netfilter/xt_iprange.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/rfkill/Kconfig
net/rxrpc/ar-input.c
net/rxrpc/ar-key.c
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fifo.c
net/sched/sch_generic.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_prio.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sched/sch_teql.c
net/sctp/sm_make_chunk.c
net/sctp/socket.c
net/sunrpc/svcsock.c
net/wireless/Kconfig
net/wireless/wext-compat.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/x25/x25_link.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
scripts/basic/fixdep.c
scripts/package/builddeb
security/keys/Makefile
security/keys/compat.c
security/keys/encrypted.c [new file with mode: 0644]
security/keys/encrypted.h [new file with mode: 0644]
security/keys/encrypted_defined.c [deleted file]
security/keys/encrypted_defined.h [deleted file]
security/keys/gc.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/permission.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c [new file with mode: 0644]
security/keys/trusted.h [new file with mode: 0644]
security/keys/trusted_defined.c [deleted file]
security/keys/trusted_defined.h [deleted file]
security/keys/user_defined.c
security/security.c
security/selinux/hooks.c
security/selinux/ss/conditional.c
security/selinux/ss/policydb.c
sound/arm/aaci.c
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-kmem.c
tools/perf/builtin-lock.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-test.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/include/linux/bitops.h
tools/perf/util/map.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/probe-event.c
tools/perf/util/session.c
tools/perf/util/svghelper.c
tools/perf/util/symbol.c
tools/perf/util/types.h
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/browsers/map.c
tools/perf/util/values.c
tools/power/x86/turbostat/turbostat.c
usr/Kconfig

index 8faa6c0..5d56a3f 100644 (file)
@@ -28,6 +28,7 @@ modules.builtin
 *.gz
 *.bz2
 *.lzma
+*.xz
 *.lzo
 *.patch
 *.gcno
index 581fd39..1eba28a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -23,6 +23,7 @@ Andy Adamson <andros@citi.umich.edu>
 Arnaud Patard <arnaud.patard@rtp-net.org>
 Arnd Bergmann <arnd@arndb.de>
 Axel Dyks <xl@xlsigned.net>
+Axel Lin <axel.lin@gmail.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
diff --git a/Documentation/ABI/testing/sysfs-platform-at91 b/Documentation/ABI/testing/sysfs-platform-at91
new file mode 100644 (file)
index 0000000..4cc6a86
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/devices/platform/at91_can/net/<iface>/mb0_id
+Date:          January 2011
+KernelVersion: 2.6.38
+Contact:       Marc Kleine-Budde <kernel@pengutronix.de>
+Description:
+               Value representing the can_id of mailbox 0.
+
+               Default: 0x7ff (standard frame)
+
+               Due to a chip bug (errata 50.2.6.3 & 50.3.5.3 in
+               "AT91SAM9263 Preliminary 6249H-ATARM-27-Jul-09") the
+               contents of mailbox 0 may be send under certain
+               conditions (even if disabled or in rx mode).
+
+               The workaround in the errata suggests not to use the
+               mailbox and load it with an unused identifier.
+
+               In order to use an extended can_id add the
+               CAN_EFF_FLAG (0x80000000U) to the can_id. Example:
+
+               - standard id 0x7ff:
+               echo 0x7ff      > /sys/class/net/can0/mb0_id
+
+               - extended id 0x1fffffff:
+               echo 0x9fffffff > /sys/class/net/can0/mb0_id
index 35447e0..36f63d4 100644 (file)
@@ -217,8 +217,8 @@ X!Isound/sound_firmware.c
   <chapter id="uart16x50">
      <title>16x50 UART Driver</title>
 !Iinclude/linux/serial_core.h
-!Edrivers/serial/serial_core.c
-!Edrivers/serial/8250.c
+!Edrivers/tty/serial/serial_core.c
+!Edrivers/tty/serial/8250.c
   </chapter>
 
   <chapter id="fbdev">
index 2861055..c279158 100644 (file)
@@ -73,8 +73,8 @@
       services.
     </para>
     <para>
-      The core of every DRM driver is struct drm_device.  Drivers
-      will typically statically initialize a drm_device structure,
+      The core of every DRM driver is struct drm_driver.  Drivers
+      will typically statically initialize a drm_driver structure,
       then pass it to drm_init() at load time.
     </para>
 
@@ -84,7 +84,7 @@
     <title>Driver initialization</title>
     <para>
       Before calling the DRM initialization routines, the driver must
-      first create and fill out a struct drm_device structure.
+      first create and fill out a struct drm_driver structure.
     </para>
     <programlisting>
       static struct drm_driver driver = {
index e3a97fd..ad8678d 100644 (file)
@@ -28,7 +28,7 @@
        <holder>Convergence GmbH</holder>
 </copyright>
 <copyright>
-       <year>2009-2010</year>
+       <year>2009-2011</year>
        <holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
index 5e87ad5..f51f285 100644 (file)
      </sect1>
   </chapter>
 
+  <chapter id="fs_events">
+     <title>Events based on file descriptors</title>
+!Efs/eventfd.c
+  </chapter>
+
   <chapter id="sysfs">
      <title>The Filesystem for Exporting Kernel Objects</title>
 !Efs/sysfs/file.c
index f11048d..a99088a 100644 (file)
@@ -28,7 +28,7 @@
 <title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 <copyright>
-       <year>2009-2010</year>
+       <year>2009-2011</year>
        <holder>LinuxTV Developers</holder>
 </copyright>
 
@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled
 </author>
 </authorgroup>
 <copyright>
-       <year>2009-2010</year>
+       <year>2009-2011</year>
        <holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
index 360d273..2427f54 100644 (file)
@@ -75,6 +75,7 @@ as follows:</para>
   </section>
 
   <section>
+    <title>RDS datastructures</title>
     <table frame="none" pgwide="1" id="v4l2-rds-data">
       <title>struct
 <structname>v4l2_rds_data</structname></title>
@@ -129,10 +130,11 @@ as follows:</para>
 
     <table frame="none" pgwide="1" id="v4l2-rds-block-codes">
       <title>Block defines</title>
-      <tgroup cols="3">
+      <tgroup cols="4">
        <colspec colname="c1" colwidth="1*" />
        <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="5*" />
+       <colspec colname="c3" colwidth="1*" />
+       <colspec colname="c4" colwidth="5*" />
        <tbody valign="top">
          <row>
            <entry>V4L2_RDS_BLOCK_MSK</entry>
index 839e93e..9288af9 100644 (file)
@@ -100,6 +100,7 @@ Remote Controller chapter.</contrib>
       <year>2008</year>
       <year>2009</year>
       <year>2010</year>
+      <year>2011</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
 Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
     </copyright>
@@ -381,7 +382,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.33</subtitle>
+ <subtitle>Revision 2.6.38</subtitle>
 
   <chapter id="common">
     &sub-common;
diff --git a/Documentation/devicetree/bindings/ata/fsl-sata.txt b/Documentation/devicetree/bindings/ata/fsl-sata.txt
new file mode 100644 (file)
index 0000000..b46bcf4
--- /dev/null
@@ -0,0 +1,29 @@
+* Freescale 8xxx/3.0 Gb/s SATA nodes
+
+SATA nodes are defined to describe on-chip Serial ATA controllers.
+Each SATA port should have its own node.
+
+Required properties:
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-sata", where CHIP is the processor
+                (mpc8315, mpc8379, etc.) and the second is
+                "fsl,pq-sata"
+- interrupts        : <interrupt mapping for SATA IRQ>
+- cell-index        : controller index.
+                          1 for controller @ 0x18000
+                          2 for controller @ 0x19000
+                          3 for controller @ 0x1a000
+                          4 for controller @ 0x1b000
+
+Optional properties:
+- interrupt-parent  : optional, if needed for interrupt mapping
+- reg               : <registers mapping>
+
+Example:
+       sata@18000 {
+               compatible = "fsl,mpc8379-sata", "fsl,pq-sata";
+               reg = <0x18000 0x1000>;
+               cell-index = <1>;
+               interrupts = <2c 8>;
+               interrupt-parent = < &ipic >;
+       };
diff --git a/Documentation/devicetree/bindings/eeprom.txt b/Documentation/devicetree/bindings/eeprom.txt
new file mode 100644 (file)
index 0000000..4342c10
--- /dev/null
@@ -0,0 +1,28 @@
+EEPROMs (I2C)
+
+Required properties:
+
+  - compatible : should be "<manufacturer>,<type>"
+                If there is no specific driver for <manufacturer>, a generic
+                driver based on <type> is selected. Possible types are:
+                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
+                24c128, 24c256, 24c512, 24c1024, spd
+
+  - reg : the I2C address of the EEPROM
+
+Optional properties:
+
+  - pagesize : the length of the pagesize for writing. Please consult the
+               manual of your device, that value varies a lot. A wrong value
+              may result in data loss! If not specified, a safety value of
+              '1' is used which will be very slow.
+
+  - read-only: this parameterless property disables writes to the eeprom
+
+Example:
+
+eeprom@52 {
+       compatible = "atmel,24c32";
+       reg = <0x52>;
+       pagesize = <32>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/8xxx_gpio.txt b/Documentation/devicetree/bindings/gpio/8xxx_gpio.txt
new file mode 100644 (file)
index 0000000..b0019eb
--- /dev/null
@@ -0,0 +1,60 @@
+GPIO controllers on MPC8xxx SoCs
+
+This is for the non-QE/CPM/GUTs GPIO controllers as found on
+8349, 8572, 8610 and compatible.
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Required properties:
+- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
+  83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+ - interrupts : Interrupt mapping for GPIO IRQ.
+ - interrupt-parent : Phandle for the interrupt controller that
+   services interrupts for this device.
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of gpio-controller nodes for a MPC8347 SoC:
+
+       gpio1: gpio-controller@c00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xc00 0x100>;
+               interrupts = <74 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+       gpio2: gpio-controller@d00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xd00 0x100>;
+               interrupts = <75 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+See booting-without-of.txt for details of how to specify GPIO
+information for devices.
+
+To use GPIO pins as interrupt sources for peripherals, specify the
+GPIO controller as the interrupt parent and define GPIO number +
+trigger mode using the interrupts property, which is defined like
+this:
+
+interrupts = <number trigger>, where:
+ - number: GPIO pin (0..31)
+ - trigger: trigger mode:
+       2 = trigger on falling edge
+       3 = trigger on both edges
+
+Example of device using this is:
+
+       funkyfpga@0 {
+               compatible = "funky-fpga";
+               ...
+               interrupts = <4 3>;
+               interrupt-parent = <&gpio1>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
new file mode 100644 (file)
index 0000000..edaa84d
--- /dev/null
@@ -0,0 +1,50 @@
+Specifying GPIO information for devices
+============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+                    &gpio-controller2-phandle gpio2-specifier
+                    0 /* holes are permitted, means no GPIO 3 */
+                    &gpio-controller4-phandle gpio4-specifier
+                    ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+
+Example of the node using GPIOs:
+
+       node {
+               gpios = <&qe_pio_e 18 0>;
+       };
+
+In this example gpio-specifier is "18 0" and encodes GPIO pin number,
+and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+       };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+       };
+
+
diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt
new file mode 100644 (file)
index 0000000..064db92
--- /dev/null
@@ -0,0 +1,58 @@
+LEDs connected to GPIO lines
+
+Required properties:
+- compatible : should be "gpio-leds".
+
+Each LED is represented as a sub-node of the gpio-leds device.  Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
+  for devices" in Documentation/powerpc/booting-without-of.txt.  Active
+  low LEDs should be indicated using flags in the GPIO specifier.
+- label :  (optional) The label for this LED.  If omitted, the label is
+  taken from the node name (excluding the unit address).
+- linux,default-trigger :  (optional) This parameter, if present, is a
+  string defining the trigger assigned to the LED.  Current triggers are:
+    "backlight" - LED will act as a back-light, controlled by the framebuffer
+                 system
+    "default-on" - LED will turn on, but see "default-state" below
+    "heartbeat" - LED "double" flashes at a load average based rate
+    "ide-disk" - LED indicates disk activity
+    "timer" - LED flashes at a fixed, configurable rate
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Examples:
+
+leds {
+       compatible = "gpio-leds";
+       hdd {
+               label = "IDE Activity";
+               gpios = <&mcu_pio 0 1>; /* Active low */
+               linux,default-trigger = "ide-disk";
+       };
+
+       fault {
+               gpios = <&mcu_pio 1 0>;
+               /* Keep LED on if BIOS detected hardware fault */
+               default-state = "keep";
+       };
+};
+
+run-control {
+       compatible = "gpio-leds";
+       red {
+               gpios = <&mpc8572 6 0>;
+               default-state = "off";
+       };
+       green {
+               gpios = <&mpc8572 7 0>;
+               default-state = "on";
+       };
+}
diff --git a/Documentation/devicetree/bindings/i2c/fsl-i2c.txt b/Documentation/devicetree/bindings/i2c/fsl-i2c.txt
new file mode 100644 (file)
index 0000000..1eacd6b
--- /dev/null
@@ -0,0 +1,64 @@
+* I2C
+
+Required properties :
+
+ - reg : Offset and length of the register set for the device
+ - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
+   compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
+   mpc5200 or mpc5200b. For the mpc5121, an additional node
+   "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
+
+Recommended properties :
+
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - fsl,preserve-clocking : boolean; if defined, the clock settings
+   from the bootloader are preserved (not touched).
+ - clock-frequency : desired I2C bus clock frequency in Hz.
+ - fsl,timeout : I2C bus timeout in microseconds.
+
+Examples :
+
+       /* MPC5121 based board */
+       i2c@1740 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+               reg = <0x1740 0x20>;
+               interrupts = <11 0x8>;
+               interrupt-parent = <&ipic>;
+               clock-frequency = <100000>;
+       };
+
+       i2ccontrol@1760 {
+               compatible = "fsl,mpc5121-i2c-ctrl";
+               reg = <0x1760 0x8>;
+       };
+
+       /* MPC5200B based board */
+       i2c@3d00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+               reg = <0x3d00 0x40>;
+               interrupts = <2 15 0>;
+               interrupt-parent = <&mpc5200_pic>;
+               fsl,preserve-clocking;
+       };
+
+       /* MPC8544 base board */
+       i2c@3100 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc8544-i2c", "fsl-i2c";
+               reg = <0x3100 0x100>;
+               interrupts = <43 2>;
+               interrupt-parent = <&mpic>;
+               clock-frequency = <400000>;
+               fsl,timeout = <10000>;
+       };
diff --git a/Documentation/devicetree/bindings/marvell.txt b/Documentation/devicetree/bindings/marvell.txt
new file mode 100644 (file)
index 0000000..f1533d9
--- /dev/null
@@ -0,0 +1,521 @@
+Marvell Discovery mv64[345]6x System Controller chips
+===========================================================
+
+The Marvell mv64[345]60 series of system controller chips contain
+many of the peripherals needed to implement a complete computer
+system.  In this section, we define device tree nodes to describe
+the system controller chip itself and each of the peripherals
+which it contains.  Compatible string values for each node are
+prefixed with the string "marvell,", for Marvell Technology Group Ltd.
+
+1) The /system-controller node
+
+  This node is used to represent the system-controller and must be
+  present when the system uses a system controller chip. The top-level
+  system-controller node contains information that is global to all
+  devices within the system controller chip. The node name begins
+  with "system-controller" followed by the unit address, which is
+  the base address of the memory-mapped register set for the system
+  controller chip.
+
+  Required properties:
+
+    - ranges : Describes the translation of system controller addresses
+      for memory mapped registers.
+    - clock-frequency: Contains the main clock frequency for the system
+      controller chip.
+    - reg : This property defines the address and size of the
+      memory-mapped registers contained within the system controller
+      chip.  The address specified in the "reg" property should match
+      the unit address of the system-controller node.
+    - #address-cells : Address representation for system controller
+      devices.  This field represents the number of cells needed to
+      represent the address of the memory-mapped registers of devices
+      within the system controller chip.
+    - #size-cells : Size representation for the memory-mapped
+      registers within the system controller chip.
+    - #interrupt-cells : Defines the width of cells used to represent
+      interrupts.
+
+  Optional properties:
+
+    - model : The specific model of the system controller chip.  Such
+      as, "mv64360", "mv64460", or "mv64560".
+    - compatible : A string identifying the compatibility identifiers
+      of the system controller chip.
+
+  The system-controller node contains child nodes for each system
+  controller device that the platform uses.  Nodes should not be created
+  for devices which exist on the system controller chip but are not used
+
+  Example Marvell Discovery mv64360 system-controller node:
+
+    system-controller@f1000000 { /* Marvell Discovery mv64360 */
+           #address-cells = <1>;
+           #size-cells = <1>;
+           model = "mv64360";                      /* Default */
+           compatible = "marvell,mv64360";
+           clock-frequency = <133333333>;
+           reg = <0xf1000000 0x10000>;
+           virtual-reg = <0xf1000000>;
+           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
+
+           [ child node definitions... ]
+    }
+
+2) Child nodes of /system-controller
+
+   a) Marvell Discovery MDIO bus
+
+   The MDIO is a bus to which the PHY devices are connected.  For each
+   device that exists on this bus, a child node should be created.  See
+   the definition of the PHY node below for an example of how to define
+   a PHY.
+
+   Required properties:
+     - #address-cells : Should be <1>
+     - #size-cells : Should be <0>
+     - device_type : Should be "mdio"
+     - compatible : Should be "marvell,mv64360-mdio"
+
+   Example:
+
+     mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            device_type = "mdio";
+            compatible = "marvell,mv64360-mdio";
+
+            ethernet-phy@0 {
+                    ......
+            };
+     };
+
+
+   b) Marvell Discovery ethernet controller
+
+   The Discover ethernet controller is described with two levels
+   of nodes.  The first level describes an ethernet silicon block
+   and the second level describes up to 3 ethernet nodes within
+   that block.  The reason for the multiple levels is that the
+   registers for the node are interleaved within a single set
+   of registers.  The "ethernet-block" level describes the
+   shared register set, and the "ethernet" nodes describe ethernet
+   port-specific properties.
+
+   Ethernet block node
+
+   Required properties:
+     - #address-cells : <1>
+     - #size-cells : <0>
+     - compatible : "marvell,mv64360-eth-block"
+     - reg : Offset and length of the register set for this block
+
+   Example Discovery Ethernet block node:
+     ethernet-block@2000 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "marvell,mv64360-eth-block";
+            reg = <0x2000 0x2000>;
+            ethernet@0 {
+                    .......
+            };
+     };
+
+   Ethernet port node
+
+   Required properties:
+     - device_type : Should be "network".
+     - compatible : Should be "marvell,mv64360-eth".
+     - reg : Should be <0>, <1>, or <2>, according to which registers
+       within the silicon block the device uses.
+     - interrupts : <a> where a is the interrupt number for the port.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     - phy : the phandle for the PHY connected to this ethernet
+       controller.
+     - local-mac-address : 6 bytes, MAC address
+
+   Example Discovery Ethernet port node:
+     ethernet@0 {
+            device_type = "network";
+            compatible = "marvell,mv64360-eth";
+            reg = <0>;
+            interrupts = <32>;
+            interrupt-parent = <&PIC>;
+            phy = <&PHY0>;
+            local-mac-address = [ 00 00 00 00 00 00 ];
+     };
+
+
+
+   c) Marvell Discovery PHY nodes
+
+   Required properties:
+     - device_type : Should be "ethernet-phy"
+     - interrupts : <a> where a is the interrupt number for this phy.
+     - interrupt-parent : the phandle for the interrupt controller that
+       services interrupts for this device.
+     - reg : The ID number for the phy, usually a small integer
+
+   Example Discovery PHY node:
+     ethernet-phy@1 {
+            device_type = "ethernet-phy";
+            compatible = "broadcom,bcm5421";
+            interrupts = <76>;      /* GPP 12 */
+            interrupt-parent = <&PIC>;
+            reg = <1>;
+     };
+
+
+   d) Marvell Discovery SDMA nodes
+
+   Represent DMA hardware associated with the MPSC (multiprotocol
+   serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-sdma"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the DMA
+       device.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SDMA node:
+     sdma@4000 {
+            compatible = "marvell,mv64360-sdma";
+            reg = <0x4000 0xc18>;
+            virtual-reg = <0xf1004000>;
+            interrupts = <36>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   e) Marvell Discovery BRG nodes
+
+   Represent baud rate generator hardware associated with the MPSC
+   (multiprotocol serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-brg"
+     - reg : Offset and length of the register set for this device
+     - clock-src : A value from 0 to 15 which selects the clock
+       source for the baud rate generator.  This value corresponds
+       to the CLKS value in the BRGx configuration register.  See
+       the mv64x60 User's Manual.
+     - clock-frequence : The frequency (in Hz) of the baud rate
+       generator's input clock.
+     - current-speed : The current speed setting (presumably by
+       firmware) of the baud rate generator.
+
+   Example Discovery BRG node:
+     brg@b200 {
+            compatible = "marvell,mv64360-brg";
+            reg = <0xb200 0x8>;
+            clock-src = <8>;
+            clock-frequency = <133333333>;
+            current-speed = <9600>;
+     };
+
+
+   f) Marvell Discovery CUNIT nodes
+
+   Represent the Serial Communications Unit device hardware.
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     cunit@f200 {
+            reg = <0xf200 0x200>;
+     };
+
+
+   g) Marvell Discovery MPSCROUTING nodes
+
+   Represent the Discovery's MPSC routing hardware
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     mpscrouting@b500 {
+            reg = <0xb400 0xc>;
+     };
+
+
+   h) Marvell Discovery MPSCINTR nodes
+
+   Represent the Discovery's MPSC DMA interrupt hardware registers
+   (SDMA cause and mask registers).
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPSCINTR node:
+     mpsintr@b800 {
+            reg = <0xb800 0x100>;
+     };
+
+
+   i) Marvell Discovery MPSC nodes
+
+   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
+   serial port.
+
+   Required properties:
+     - device_type : "serial"
+     - compatible : "marvell,mv64360-mpsc"
+     - reg : Offset and length of the register set for this device
+     - sdma : the phandle for the SDMA node used by this port
+     - brg : the phandle for the BRG node used by this port
+     - cunit : the phandle for the CUNIT node used by this port
+     - mpscrouting : the phandle for the MPSCROUTING node used by this port
+     - mpscintr : the phandle for the MPSCINTR node used by this port
+     - cell-index : the hardware index of this cell in the MPSC core
+     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
+       register
+     - interrupts : <a> where a is the interrupt number for the MPSC.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery MPSCINTR node:
+     mpsc@8000 {
+            device_type = "serial";
+            compatible = "marvell,mv64360-mpsc";
+            reg = <0x8000 0x38>;
+            virtual-reg = <0xf1008000>;
+            sdma = <&SDMA0>;
+            brg = <&BRG0>;
+            cunit = <&CUNIT>;
+            mpscrouting = <&MPSCROUTING>;
+            mpscintr = <&MPSCINTR>;
+            cell-index = <0>;
+            max_idle = <40>;
+            interrupts = <40>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   j) Marvell Discovery Watch Dog Timer nodes
+
+   Represent the Discovery's watchdog timer hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-wdt"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery Watch Dog Timer node:
+     wdt@b410 {
+            compatible = "marvell,mv64360-wdt";
+            reg = <0xb410 0x8>;
+     };
+
+
+   k) Marvell Discovery I2C nodes
+
+   Represent the Discovery's I2C hardware
+
+   Required properties:
+     - device_type : "i2c"
+     - compatible : "marvell,mv64360-i2c"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the I2C.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery I2C node:
+            compatible = "marvell,mv64360-i2c";
+            reg = <0xc000 0x20>;
+            virtual-reg = <0xf100c000>;
+            interrupts = <37>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+
+   Represent the Discovery's PIC hardware
+
+   Required properties:
+     - #interrupt-cells : <1>
+     - #address-cells : <0>
+     - compatible : "marvell,mv64360-pic"
+     - reg : Offset and length of the register set for this device
+     - interrupt-controller
+
+   Example Discovery PIC node:
+     pic {
+            #interrupt-cells = <1>;
+            #address-cells = <0>;
+            compatible = "marvell,mv64360-pic";
+            reg = <0x0 0x88>;
+            interrupt-controller;
+     };
+
+
+   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+
+   Represent the Discovery's MPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-mpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPP node:
+     mpp@f000 {
+            compatible = "marvell,mv64360-mpp";
+            reg = <0xf000 0x10>;
+     };
+
+
+   n) Marvell Discovery GPP (General Purpose Pins) nodes
+
+   Represent the Discovery's GPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-gpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery GPP node:
+     gpp@f000 {
+            compatible = "marvell,mv64360-gpp";
+            reg = <0xf100 0x20>;
+     };
+
+
+   o) Marvell Discovery PCI host bridge node
+
+   Represents the Discovery's PCI host bridge device.  The properties
+   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
+   1275-1994.  A typical value for the compatible property is
+   "marvell,mv64360-pci".
+
+   Example Discovery PCI host bridge node
+     pci@80000000 {
+            #address-cells = <3>;
+            #size-cells = <2>;
+            #interrupt-cells = <1>;
+            device_type = "pci";
+            compatible = "marvell,mv64360-pci";
+            reg = <0xcf8 0x8>;
+            ranges = <0x01000000 0x0        0x0
+                            0x88000000 0x0 0x01000000
+                      0x02000000 0x0 0x80000000
+                            0x80000000 0x0 0x08000000>;
+            bus-range = <0 255>;
+            clock-frequency = <66000000>;
+            interrupt-parent = <&PIC>;
+            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+            interrupt-map = <
+                    /* IDSEL 0x0a */
+                    0x5000 0 0 1 &PIC 80
+                    0x5000 0 0 2 &PIC 81
+                    0x5000 0 0 3 &PIC 91
+                    0x5000 0 0 4 &PIC 93
+
+                    /* IDSEL 0x0b */
+                    0x5800 0 0 1 &PIC 91
+                    0x5800 0 0 2 &PIC 93
+                    0x5800 0 0 3 &PIC 80
+                    0x5800 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0c */
+                    0x6000 0 0 1 &PIC 91
+                    0x6000 0 0 2 &PIC 93
+                    0x6000 0 0 3 &PIC 80
+                    0x6000 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0d */
+                    0x6800 0 0 1 &PIC 93
+                    0x6800 0 0 2 &PIC 80
+                    0x6800 0 0 3 &PIC 81
+                    0x6800 0 0 4 &PIC 91
+            >;
+     };
+
+
+   p) Marvell Discovery CPU Error nodes
+
+   Represent the Discovery's CPU error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-cpu-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery CPU Error node:
+     cpu-error@0070 {
+            compatible = "marvell,mv64360-cpu-error";
+            reg = <0x70 0x10 0x128 0x28>;
+            interrupts = <3>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   q) Marvell Discovery SRAM Controller nodes
+
+   Represent the Discovery's SRAM controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-sram-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SRAM Controller node:
+     sram-ctrl@0380 {
+            compatible = "marvell,mv64360-sram-ctrl";
+            reg = <0x380 0x80>;
+            interrupts = <13>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   r) Marvell Discovery PCI Error Handler nodes
+
+   Represent the Discovery's PCI error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-pci-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery PCI Error Handler node:
+     pci-error@1d40 {
+            compatible = "marvell,mv64360-pci-error";
+            reg = <0x1d40 0x40 0xc28 0x4>;
+            interrupts = <12>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   s) Marvell Discovery Memory Controller nodes
+
+   Represent the Discovery's memory controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-mem-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery Memory Controller node:
+     mem-ctrl@1400 {
+            compatible = "marvell,mv64360-mem-ctrl";
+            reg = <0x1400 0x60>;
+            interrupts = <17>;
+            interrupt-parent = <&PIC>;
+     };
+
+
diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
new file mode 100644 (file)
index 0000000..64bcb8b
--- /dev/null
@@ -0,0 +1,29 @@
+* Freescale Enhanced Secure Digital Host Controller (eSDHC)
+
+The Enhanced Secure Digital Host Controller provides an interface
+for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+  - compatible : should be
+    "fsl,<chip>-esdhc", "fsl,esdhc"
+  - reg : should contain eSDHC registers location and length.
+  - interrupts : should contain eSDHC interrupt.
+  - interrupt-parent : interrupt source phandle.
+  - clock-frequency : specifies eSDHC base clock frequency.
+  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
+    reports inverted write-protect state;
+  - sdhci,1-bit-only : (optional) specifies that a controller can
+    only handle 1-bit data transfers.
+  - sdhci,auto-cmd12: (optional) specifies that a controller can
+    only handle auto CMD12.
+
+Example:
+
+sdhci@2e000 {
+       compatible = "fsl,mpc8378-esdhc", "fsl,esdhc";
+       reg = <0x2e000 0x1000>;
+       interrupts = <42 0x8>;
+       interrupt-parent = <&ipic>;
+       /* Filled in by U-Boot */
+       clock-frequency = <0>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
new file mode 100644 (file)
index 0000000..c39ac28
--- /dev/null
@@ -0,0 +1,23 @@
+MMC/SD/SDIO slot directly connected to a SPI bus
+
+Required properties:
+- compatible : should be "mmc-spi-slot".
+- reg : should specify SPI address (chip-select number).
+- spi-max-frequency : maximum frequency for this device (Hz).
+- voltage-ranges : two cells are required, first cell specifies minimum
+  slot voltage (mV), second cell specifies maximum slot voltage (mV).
+  Several ranges could be specified.
+- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
+  Write-Protect GPIO.
+
+Example:
+
+       mmc-slot@0 {
+               compatible = "fsl,mpc8323rdb-mmc-slot",
+                            "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&qe_pio_d 14 1
+                        &qe_pio_d 15 0>;
+               voltage-ranges = <3300 3300>;
+               spi-max-frequency = <50000000>;
+       };
diff --git a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt
new file mode 100644 (file)
index 0000000..a48b2ca
--- /dev/null
@@ -0,0 +1,63 @@
+Freescale Localbus UPM programmed to work with NAND flash
+
+Required properties:
+- compatible : "fsl,upm-nand".
+- reg : should specify localbus chip select and size used for the chip.
+- fsl,upm-addr-offset : UPM pattern offset for the address latch.
+- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
+
+Optional properties:
+- fsl,upm-wait-flags : add chip-dependent short delays after running the
+       UPM pattern (0x1), after writing a data byte (0x2) or after
+       writing out a buffer (0x4).
+- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
+       The corresponding address lines are used to select the chip.
+- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
+       (R/B#). For multi-chip devices, "n" GPIO definitions are required
+       according to the number of chips.
+- chip-delay : chip dependent delay for transfering data from array to
+       read registers (tR). Required if property "gpios" is not used
+       (R/B# pins not connected).
+
+Examples:
+
+upm@1,0 {
+       compatible = "fsl,upm-nand";
+       reg = <1 0 1>;
+       fsl,upm-addr-offset = <16>;
+       fsl,upm-cmd-offset = <8>;
+       gpios = <&qe_pio_e 18 0>;
+
+       flash {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "...";
+
+               partition@0 {
+                       ...
+               };
+       };
+};
+
+upm@3,0 {
+       #address-cells = <0>;
+       #size-cells = <0>;
+       compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
+       reg = <3 0x0 0x800>;
+       fsl,upm-addr-offset = <0x10>;
+       fsl,upm-cmd-offset = <0x08>;
+       /* Multi-chip NAND device */
+       fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
+       fsl,upm-wait-flags = <0x5>;
+       chip-delay = <25>; // in micro-seconds
+
+       nand@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                           label = "fs";
+                           reg = <0x00000000 0x10000000>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
new file mode 100644 (file)
index 0000000..80152cb
--- /dev/null
@@ -0,0 +1,90 @@
+CFI or JEDEC memory-mapped NOR flash, MTD-RAM (NVRAM...)
+
+Flash chips (Memory Technology Devices) are often used for solid state
+file systems on embedded devices.
+
+ - compatible : should contain the specific model of mtd chip(s)
+   used, if known, followed by either "cfi-flash", "jedec-flash"
+   or "mtd-ram".
+ - reg : Address range(s) of the mtd chip(s)
+   It's possible to (optionally) define multiple "reg" tuples so that
+   non-identical chips can be described in one node.
+ - bank-width : Width (in bytes) of the bank.  Equal to the
+   device width times the number of interleaved chips.
+ - device-width : (optional) Width of a single mtd chip.  If
+   omitted, assumed to be equal to 'bank-width'.
+ - #address-cells, #size-cells : Must be present if the device has
+   sub-nodes representing partitions (see below).  In this case
+   both #address-cells and #size-cells must be equal to 1.
+
+For JEDEC compatible devices, the following additional properties
+are defined:
+
+ - vendor-id : Contains the flash chip's vendor id (1 byte).
+ - device-id : Contains the flash chip's device id (1 byte).
+
+In addition to the information on the mtd bank itself, the
+device tree may optionally contain additional information
+describing partitions of the address space.  This can be
+used on platforms which have strong conventions about which
+portions of a flash are used for what purposes, but which don't
+use an on-flash partition table such as RedBoot.
+
+Each partition is represented as a sub-node of the mtd device.
+Each node's name represents the name of the corresponding
+partition of the mtd device.
+
+Flash partitions
+ - reg : The partition's offset and size within the mtd bank.
+ - label : (optional) The label / name for this partition.
+   If omitted, the label is taken from the node name (excluding
+   the unit address).
+ - read-only : (optional) This parameter, if present, is a hint to
+   Linux that this partition should only be mounted
+   read-only.  This is usually used for flash partitions
+   containing early-boot firmware images or data which should not
+   be clobbered.
+
+Example:
+
+       flash@ff000000 {
+               compatible = "amd,am29lv128ml", "cfi-flash";
+               reg = <ff000000 01000000>;
+               bank-width = <4>;
+               device-width = <1>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               fs@0 {
+                       label = "fs";
+                       reg = <0 f80000>;
+               };
+               firmware@f80000 {
+                       label ="firmware";
+                       reg = <f80000 80000>;
+                       read-only;
+               };
+       };
+
+Here an example with multiple "reg" tuples:
+
+       flash@f0000000,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "intel,PC48F4400P0VB", "cfi-flash";
+               reg = <0 0x00000000 0x02000000
+                      0 0x02000000 0x02000000>;
+               bank-width = <2>;
+               partition@0 {
+                       label = "test-part1";
+                       reg = <0 0x04000000>;
+               };
+       };
+
+An example using SRAM:
+
+       sram@2,0 {
+               compatible = "samsung,k6f1616u6a", "mtd-ram";
+               reg = <2 0 0x00200000>;
+               bank-width = <2>;
+       };
+
diff --git a/Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt b/Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt
new file mode 100644 (file)
index 0000000..2fa4fcd
--- /dev/null
@@ -0,0 +1,53 @@
+CAN Device Tree Bindings
+------------------------
+
+(c) 2006-2009 Secret Lab Technologies Ltd
+Grant Likely <grant.likely@secretlab.ca>
+
+fsl,mpc5200-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                                "ref" for reference clock (XTAL)
+                          "ref" is default in case this property is not
+                          present.
+
+fsl,mpc5121-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source and divider shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                               "ref" for reference clock
+                               "sys" for system clock
+                          If this property is not present, an optimal CAN
+                          clock source and frequency based on the system
+                          clock will be selected. If this is not possible,
+                          the reference clock will be used.
+
+- fsl,mscan-clock-divider: for the reference and system clock, an additional
+                          clock divider can be specified. By default, a
+                          value of 1 is used.
+
+Note that the MPC5121 Rev. 1 processor is not supported.
+
+Examples:
+       can@1300 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <12 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1300 0x80>;
+       };
+
+       can@1380 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <13 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1380 0x80>;
+               fsl,mscan-clock-source = "ref";
+               fsl,mscan-clock-divider = <3>;
+       };
diff --git a/Documentation/devicetree/bindings/net/can/sja1000.txt b/Documentation/devicetree/bindings/net/can/sja1000.txt
new file mode 100644 (file)
index 0000000..d6d209d
--- /dev/null
@@ -0,0 +1,53 @@
+Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
+
+Required properties:
+
+- compatible : should be "nxp,sja1000".
+
+- reg : should specify the chip select, address offset and size required
+       to map the registers of the SJA1000. The size is usually 0x80.
+
+- interrupts: property with a value describing the interrupt source
+       (number and sensitivity) required for the SJA1000.
+
+Optional properties:
+
+- nxp,external-clock-frequency : Frequency of the external oscillator
+       clock in Hz. Note that the internal clock frequency used by the
+       SJA1000 is half of that value. If not specified, a default value
+       of 16000000 (16 MHz) is used.
+
+- nxp,tx-output-mode : operation mode of the TX output control logic:
+       <0x0> : bi-phase output mode
+       <0x1> : normal output mode (default)
+       <0x2> : test output mode
+       <0x3> : clock output mode
+
+- nxp,tx-output-config : TX output pin configuration:
+       <0x01> : TX0 invert
+       <0x02> : TX0 pull-down (default)
+       <0x04> : TX0 pull-up
+       <0x06> : TX0 push-pull
+       <0x08> : TX1 invert
+       <0x10> : TX1 pull-down
+       <0x20> : TX1 pull-up
+       <0x30> : TX1 push-pull
+
+- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin.
+       If not specified or if the specified value is 0, the CLKOUT pin
+       will be disabled.
+
+- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
+
+For futher information, please have a look to the SJA1000 data sheet.
+
+Examples:
+
+can@3,100 {
+       compatible = "nxp,sja1000";
+       reg = <3 0x100 0x80>;
+       interrupts = <2 0>;
+       interrupt-parent = <&mpic>;
+       nxp,external-clock-frequency = <16000000>;
+};
+
diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
new file mode 100644 (file)
index 0000000..edb7ae1
--- /dev/null
@@ -0,0 +1,76 @@
+* MDIO IO device
+
+The MDIO is a bus to which the PHY devices are connected.  For each
+device that exists on this bus, a child node should be created.  See
+the definition of the PHY node in booting-without-of.txt for an example
+of how to define a PHY.
+
+Required properties:
+  - reg : Offset and length of the register set for the device
+  - compatible : Should define the compatible device type for the
+    mdio.  Currently, this is most likely to be "fsl,gianfar-mdio"
+
+Example:
+
+       mdio@24520 {
+               reg = <24520 20>;
+               compatible = "fsl,gianfar-mdio";
+
+               ethernet-phy@0 {
+                       ......
+               };
+       };
+
+* TBI Internal MDIO bus
+
+As of this writing, every tsec is associated with an internal TBI PHY.
+This PHY is accessed through the local MDIO bus.  These buses are defined
+similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi".
+The TBI PHYs underneath them are similar to normal PHYs, but the reg property
+is considered instructive, rather than descriptive.  The reg property should
+be chosen so it doesn't interfere with other PHYs on the bus.
+
+* Gianfar-compatible ethernet nodes
+
+Properties:
+
+  - device_type : Should be "network"
+  - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
+  - compatible : Should be "gianfar"
+  - reg : Offset and length of the register set for the device
+  - local-mac-address : List of bytes representing the ethernet address of
+    this controller
+  - interrupts : For FEC devices, the first interrupt is the device's
+    interrupt.  For TSEC and eTSEC devices, the first interrupt is
+    transmit, the second is receive, and the third is error.
+  - phy-handle : The phandle for the PHY connected to this ethernet
+    controller.
+  - fixed-link : <a b c d e> where a is emulated phy id - choose any,
+    but unique to the all specified fixed-links, b is duplex - 0 half,
+    1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
+    pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
+  - phy-connection-type : a string naming the controller/PHY interface type,
+    i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
+    "tbi", or "rtbi".  This property is only really needed if the connection
+    is of type "rgmii-id", as all other connection types are detected by
+    hardware.
+  - fsl,magic-packet : If present, indicates that the hardware supports
+    waking up via magic packet.
+  - bd-stash : If present, indicates that the hardware supports stashing
+    buffer descriptors in the L2.
+  - rx-stash-len : Denotes the number of bytes of a received buffer to stash
+    in the L2.
+  - rx-stash-idx : Denotes the index of the first byte from the received
+    buffer to stash in the L2.
+
+Example:
+       ethernet@24000 {
+               device_type = "network";
+               model = "TSEC";
+               compatible = "gianfar";
+               reg = <0x24000 0x1000>;
+               local-mac-address = [ 00 E0 0C 00 73 00 ];
+               interrupts = <29 2 30 2 34 2>;
+               interrupt-parent = <&mpic>;
+               phy-handle = <&phy0>
+       };
diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt
new file mode 100644 (file)
index 0000000..bc95495
--- /dev/null
@@ -0,0 +1,19 @@
+MDIO on GPIOs
+
+Currently defined compatibles:
+- virtual,gpio-mdio
+
+MDC and MDIO lines connected to GPIO controllers are listed in the
+gpios property as described in section VIII.1 in the following order:
+
+MDC, MDIO.
+
+Example:
+
+mdio {
+       compatible = "virtual,mdio-gpio";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       gpios = <&qe_pio_a 11
+                &qe_pio_c 6>;
+};
diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
new file mode 100644 (file)
index 0000000..bb8c742
--- /dev/null
@@ -0,0 +1,25 @@
+PHY nodes
+
+Required properties:
+
+ - device_type : Should be "ethernet-phy"
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - reg : The ID number for the phy, usually a small integer
+ - linux,phandle :  phandle for this node; likely referenced by an
+   ethernet controller node.
+
+Example:
+
+ethernet-phy@0 {
+       linux,phandle = <2452000>
+       interrupt-parent = <40000>;
+       interrupts = <35 1>;
+       reg = <0>;
+       device_type = "ethernet-phy";
+};
diff --git a/Documentation/devicetree/bindings/pci/83xx-512x-pci.txt b/Documentation/devicetree/bindings/pci/83xx-512x-pci.txt
new file mode 100644 (file)
index 0000000..35a4653
--- /dev/null
@@ -0,0 +1,40 @@
+* Freescale 83xx and 512x PCI bridges
+
+Freescale 83xx and 512x SOCs include the same pci bridge core.
+
+83xx/512x specific notes:
+- reg: should contain two address length tuples
+    The first is for the internal pci bridge registers
+    The second is for the pci config space access registers
+
+Example (MPC8313ERDB)
+       pci0: pci@e0008500 {
+               cell-index = <1>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                               /* IDSEL 0x0E -mini PCI */
+                                0x7000 0x0 0x0 0x1 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x3 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x4 &ipic 18 0x8
+
+                               /* IDSEL 0x0F - PCI slot */
+                                0x7800 0x0 0x0 0x1 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7800 0x0 0x0 0x3 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
+               interrupt-parent = <&ipic>;
+               interrupts = <66 0x8>;
+               bus-range = <0x0 0x0>;
+               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
+                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               clock-frequency = <66666666>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
+               compatible = "fsl,mpc8349-pci";
+               device_type = "pci";
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/cpm.txt b/Documentation/devicetree/bindings/powerpc/4xx/cpm.txt
new file mode 100644 (file)
index 0000000..ee45980
--- /dev/null
@@ -0,0 +1,52 @@
+PPC4xx Clock Power Management (CPM) node
+
+Required properties:
+       - compatible            : compatible list, currently only "ibm,cpm"
+       - dcr-access-method     : "native"
+       - dcr-reg               : < DCR register range >
+
+Optional properties:
+       - er-offset             : All 4xx SoCs with a CPM controller have
+                                 one of two different order for the CPM
+                                 registers. Some have the CPM registers
+                                 in the following order (ER,FR,SR). The
+                                 others have them in the following order
+                                 (SR,ER,FR). For the second case set
+                                 er-offset = <1>.
+       - unused-units          : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set to turn off unused
+                                 devices.
+       - idle-doze             : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set to turn off unused
+                                 devices. This is usually just CPM[CPU].
+       - standby               : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set on standby and
+                                 restored on resume.
+       - suspend               : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set on suspend (mem) and
+                                 restored on resume. Note, for standby
+                                 and suspend the corresponding bits can
+                                 be different or the same. Usually for
+                                 standby only class 2 and 3 units are set.
+                                 However, the interface does not care.
+                                 If they are the same, the additional
+                                 power saving will be seeing if support
+                                 is available to put the DDR in self
+                                 refresh mode and any additional power
+                                 saving techniques for the specific SoC.
+
+Example:
+       CPM0: cpm {
+               compatible = "ibm,cpm";
+               dcr-access-method = "native";
+               dcr-reg = <0x160 0x003>;
+               er-offset = <0>;
+               unused-units = <0x00000100>;
+               idle-doze = <0x02000000>;
+               standby = <0xfeff0000>;
+               suspend = <0xfeff791d>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
new file mode 100644 (file)
index 0000000..2161334
--- /dev/null
@@ -0,0 +1,148 @@
+    4xx/Axon EMAC ethernet nodes
+
+    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
+    the Axon bridge.  To operate this needs to interact with a ths
+    special McMAL DMA controller, and sometimes an RGMII or ZMII
+    interface.  In addition to the nodes and properties described
+    below, the node for the OPB bus on which the EMAC sits must have a
+    correct clock-frequency property.
+
+      i) The EMAC node itself
+
+    Required properties:
+    - device_type       : "network"
+
+    - compatible        : compatible list, contains 2 entries, first is
+                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
+                         405gp, Axon) and second is either "ibm,emac" or
+                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
+                         "ibm,emac4"
+    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
+    - interrupt-parent  : optional, if needed for interrupt mapping
+    - reg               : <registers mapping>
+    - local-mac-address : 6 bytes, MAC address
+    - mal-device        : phandle of the associated McMAL node
+    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
+                         with this EMAC
+    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
+                         with this EMAC
+    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
+                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
+                         each Axon chip)
+    - max-frame-size    : 1 cell, maximum frame size supported in bytes
+    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048
+    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048.
+    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
+                         thresholds).
+                         For Axon, 0x00000010
+    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
+                         in bytes.
+                         For Axon, 0x00000100 (I think ...)
+    - phy-mode          : string, mode of operations of the PHY interface.
+                         Supported values are: "mii", "rmii", "smii", "rgmii",
+                         "tbi", "gmii", rtbi", "sgmii".
+                         For Axon on CAB, it is "rgmii"
+    - mdio-device       : 1 cell, required iff using shared MDIO registers
+                         (440EP).  phandle of the EMAC to use to drive the
+                         MDIO lines for the PHY used by this EMAC.
+    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
+                         the ZMII device node
+    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
+                         channel or 0xffffffff if ZMII is only used for MDIO.
+    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
+                         of the RGMII device node.
+                         For Axon: phandle of plb5/plb4/opb/rgmii
+    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
+                         RGMII channel is used by this EMAC.
+                         Fox Axon: present, whatever value is appropriate for each
+                         EMAC, that is the content of the current (bogus) "phy-port"
+                         property.
+
+    Optional properties:
+    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
+                         a search is performed.
+    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
+                         for, used if phy-address is absent. bit 0x00000001 is
+                         MDIO address 0.
+                         For Axon it can be absent, though my current driver
+                         doesn't handle phy-address yet so for now, keep
+                         0x00ffffff in it.
+    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         rx-fifo-size).  For Axon, either absent or 2048.
+    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         tx-fifo-size). For Axon, either absent or 2048.
+    - tah-device        : 1 cell, optional. If connected to a TAH engine for
+                         offload, phandle of the TAH device node.
+    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
+                         TAH engine.
+
+    Example:
+
+       EMAC0: ethernet@40000800 {
+               device_type = "network";
+               compatible = "ibm,emac-440gp", "ibm,emac";
+               interrupt-parent = <&UIC1>;
+               interrupts = <1c 4 1d 4>;
+               reg = <40000800 70>;
+               local-mac-address = [00 04 AC E3 1B 1E];
+               mal-device = <&MAL0>;
+               mal-tx-channel = <0 1>;
+               mal-rx-channel = <0>;
+               cell-index = <0>;
+               max-frame-size = <5dc>;
+               rx-fifo-size = <1000>;
+               tx-fifo-size = <800>;
+               phy-mode = "rmii";
+               phy-map = <00000001>;
+               zmii-device = <&ZMII0>;
+               zmii-channel = <0>;
+       };
+
+      ii) McMAL node
+
+    Required properties:
+    - device_type        : "dma-controller"
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
+                          emac) and the second is either "ibm,mcmal" or
+                          "ibm,mcmal2".
+                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
+    - interrupts         : <interrupt mapping for the MAL interrupts sources:
+                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
+                           For Axon: This is _different_ from the current
+                          firmware.  We use the "delayed" interrupts for txeob
+                          and rxeob. Thus we end up with mapping those 5 MPIC
+                          interrupts, all level positive sensitive: 10, 11, 32,
+                          33, 34 (in decimal)
+    - dcr-reg            : < DCR registers range >
+    - dcr-parent         : if needed for dcr-reg
+    - num-tx-chans       : 1 cell, number of Tx channels
+    - num-rx-chans       : 1 cell, number of Rx channels
+
+      iii) ZMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,zmii".
+                          For Axon, there is no ZMII node.
+    - reg                : <registers mapping>
+
+      iv) RGMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,rgmii".
+                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
+    - reg                : <registers mapping>
+    - revision           : as provided by the RGMII new version register if
+                          available.
+                          For Axon: 0x0000012a
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt b/Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt
new file mode 100644 (file)
index 0000000..869f0b5
--- /dev/null
@@ -0,0 +1,39 @@
+AMCC NDFC (NanD Flash Controller)
+
+Required properties:
+- compatible : "ibm,ndfc".
+- reg : should specify chip select and size used for the chip (0x2000).
+
+Optional properties:
+- ccr : NDFC config and control register value (default 0).
+- bank-settings : NDFC bank configuration register value (default 0).
+
+Notes:
+- partition(s) - follows the OF MTD standard for partitions
+
+Example:
+
+ndfc@1,0 {
+       compatible = "ibm,ndfc";
+       reg = <0x00000001 0x00000000 0x00002000>;
+       ccr = <0x00001000>;
+       bank-settings = <0x80002222>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       nand {
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "kernel";
+                       reg = <0x00000000 0x00200000>;
+               };
+               partition@200000 {
+                       label = "root";
+                       reg = <0x00200000 0x03E00000>;
+               };
+       };
+};
+
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt b/Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt
new file mode 100644 (file)
index 0000000..515ebcf
--- /dev/null
@@ -0,0 +1,93 @@
+PPC440SPe DMA/XOR (DMA Controller and XOR Accelerator)
+
+Device nodes needed for operation of the ppc440spe-adma driver
+are specified hereby. These are I2O/DMA, DMA and XOR nodes
+for DMA engines and Memory Queue Module node. The latter is used
+by ADMA driver for configuration of RAID-6 H/W capabilities of
+the PPC440SPe. In addition to the nodes and properties described
+below, the ranges property of PLB node must specify ranges for
+DMA devices.
+
+ i) The I2O node
+
+ Required properties:
+
+ - compatible          : "ibm,i2o-440spe";
+ - reg                 : <registers mapping>
+ - dcr-reg             : <DCR registers range>
+
+ Example:
+
+       I2O: i2o@400100000 {
+               compatible = "ibm,i2o-440spe";
+               reg = <0x00000004 0x00100000 0x100>;
+               dcr-reg = <0x060 0x020>;
+       };
+
+
+ ii) The DMA node
+
+ Required properties:
+
+ - compatible          : "ibm,dma-440spe";
+ - cell-index          : 1 cell, hardware index of the DMA engine
+                         (typically 0x0 and 0x1 for DMA0 and DMA1)
+ - reg                 : <registers mapping>
+ - dcr-reg             : <DCR registers range>
+ - interrupts          : <interrupt mapping for DMA0/1 interrupts sources:
+                          2 sources: DMAx CS FIFO Needs Service IRQ (on UIC0)
+                          and DMA Error IRQ (on UIC1). The latter is common
+                          for both DMA engines>.
+ - interrupt-parent    : needed for interrupt mapping
+
+ Example:
+
+       DMA0: dma0@400100100 {
+               compatible = "ibm,dma-440spe";
+               cell-index = <0>;
+               reg = <0x00000004 0x00100100 0x100>;
+               dcr-reg = <0x060 0x020>;
+               interrupt-parent = <&DMA0>;
+               interrupts = <0 1>;
+               #interrupt-cells = <1>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               interrupt-map = <
+                       0 &UIC0 0x14 4
+                       1 &UIC1 0x16 4>;
+       };
+
+
+ iii) XOR Accelerator node
+
+ Required properties:
+
+ - compatible          : "amcc,xor-accelerator";
+ - reg                 : <registers mapping>
+ - interrupts          : <interrupt mapping for XOR interrupt source>
+ - interrupt-parent    : for interrupt mapping
+
+ Example:
+
+       xor-accel@400200000 {
+               compatible = "amcc,xor-accelerator";
+               reg = <0x00000004 0x00200000 0x400>;
+               interrupt-parent = <&UIC1>;
+               interrupts = <0x1f 4>;
+       };
+
+
+ iv) Memory Queue Module node
+
+ Required properties:
+
+ - compatible          : "ibm,mq-440spe";
+ - dcr-reg             : <DCR registers range>
+
+ Example:
+
+       MQ0: mq {
+               compatible = "ibm,mq-440spe";
+               dcr-reg = <0x040 0x020>;
+       };
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt b/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt
new file mode 100644 (file)
index 0000000..d721726
--- /dev/null
@@ -0,0 +1,18 @@
+Reboot property to control system reboot on PPC4xx systems:
+
+By setting "reset_type" to one of the following values, the default
+software reset mechanism may be overidden. Here the possible values of
+"reset_type":
+
+      1 - PPC4xx core reset
+      2 - PPC4xx chip reset
+      3 - PPC4xx system reset (default)
+
+Example:
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,440SPe";
+                       ...
+                       reset-type = <2>;       /* Use chip-reset */
+               };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/board.txt b/Documentation/devicetree/bindings/powerpc/fsl/board.txt
new file mode 100644 (file)
index 0000000..39e9415
--- /dev/null
@@ -0,0 +1,63 @@
+* Board Control and Status (BCSR)
+
+Required properties:
+
+ - compatible : Should be "fsl,<board>-bcsr"
+ - reg : Offset and length of the register set for the device
+
+Example:
+
+       bcsr@f8000000 {
+               compatible = "fsl,mpc8360mds-bcsr";
+               reg = <f8000000 8000>;
+       };
+
+* Freescale on board FPGA
+
+This is the memory-mapped registers for on board FPGA.
+
+Required properities:
+- compatible : should be "fsl,fpga-pixis".
+- reg : should contain the address and the length of the FPPGA register
+  set.
+- interrupt-parent: should specify phandle for the interrupt controller.
+- interrupts : should specify event (wakeup) IRQ.
+
+Example (MPC8610HPCD):
+
+       board-control@e8000000 {
+               compatible = "fsl,fpga-pixis";
+               reg = <0xe8000000 32>;
+               interrupt-parent = <&mpic>;
+               interrupts = <8 8>;
+       };
+
+* Freescale BCSR GPIO banks
+
+Some BCSR registers act as simple GPIO controllers, each such
+register can be represented by the gpio-controller node.
+
+Required properities:
+- compatible : Should be "fsl,<board>-bcsr-gpio".
+- reg : Should contain the address and the length of the GPIO bank
+  register.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the port as GPIO controller.
+
+Example:
+
+       bcsr@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8360mds-bcsr";
+               reg = <1 0 0x8000>;
+               ranges = <0 1 0 0x8000>;
+
+               bcsr13: gpio-controller@d {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8360mds-bcsr-gpio";
+                       reg = <0xd 1>;
+                       gpio-controller;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt
new file mode 100644 (file)
index 0000000..160c752
--- /dev/null
@@ -0,0 +1,67 @@
+* Freescale Communications Processor Module
+
+NOTE: This is an interim binding, and will likely change slightly,
+as more devices are supported.  The QE bindings especially are
+incomplete.
+
+* Root CPM node
+
+Properties:
+- compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe".
+- reg : A 48-byte region beginning with CPCR.
+
+Example:
+     cpm@119c0 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       #interrupt-cells = <2>;
+       compatible = "fsl,mpc8272-cpm", "fsl,cpm2";
+       reg = <119c0 30>;
+     }
+
+* Properties common to multiple CPM/QE devices
+
+- fsl,cpm-command : This value is ORed with the opcode and command flag
+                    to specify the device on which a CPM command operates.
+
+- fsl,cpm-brg : Indicates which baud rate generator the device
+                is associated with.  If absent, an unused BRG
+                should be dynamically allocated.  If zero, the
+                device uses an external clock rather than a BRG.
+
+- reg : Unless otherwise specified, the first resource represents the
+        scc/fcc/ucc registers, and the second represents the device's
+        parameter RAM region (if it has one).
+
+* Multi-User RAM (MURAM)
+
+The multi-user/dual-ported RAM is expressed as a bus under the CPM node.
+
+Ranges must be set up subject to the following restrictions:
+
+- Children's reg nodes must be offsets from the start of all muram, even
+  if the user-data area does not begin at zero.
+- If multiple range entries are used, the difference between the parent
+  address and the child address must be the same in all, so that a single
+  mapping can cover them all while maintaining the ability to determine
+  CPM-side offsets with pointer subtraction.  It is recommended that
+  multiple range entries not be used.
+- A child address of zero must be translatable, even if no reg resources
+  contain it.
+
+A child "data" node must exist, compatible with "fsl,cpm-muram-data", to
+indicate the portion of muram that is usable by the OS for arbitrary
+purposes.  The data node may have an arbitrary number of reg resources,
+all of which contribute to the allocatable muram pool.
+
+Example, based on mpc8272:
+       muram@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0 10000>;
+
+               data@0 {
+                       compatible = "fsl,cpm-muram-data";
+                       reg = <0 2000 9800 800>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt
new file mode 100644 (file)
index 0000000..4c7d45e
--- /dev/null
@@ -0,0 +1,21 @@
+* Baud Rate Generators
+
+Currently defined compatibles:
+fsl,cpm-brg
+fsl,cpm1-brg
+fsl,cpm2-brg
+
+Properties:
+- reg : There may be an arbitrary number of reg resources; BRG
+  numbers are assigned to these in order.
+- clock-frequency : Specifies the base frequency driving
+  the BRG.
+
+Example:
+       brg@119f0 {
+               compatible = "fsl,mpc8272-brg",
+                            "fsl,cpm2-brg",
+                            "fsl,cpm-brg";
+               reg = <119f0 10 115f0 10>;
+               clock-frequency = <d#25000000>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt
new file mode 100644 (file)
index 0000000..87bc604
--- /dev/null
@@ -0,0 +1,41 @@
+* I2C
+
+The I2C controller is expressed as a bus under the CPM node.
+
+Properties:
+- compatible : "fsl,cpm1-i2c", "fsl,cpm2-i2c"
+- reg : On CPM2 devices, the second resource doesn't specify the I2C
+  Parameter RAM itself, but the I2C_BASE field of the CPM2 Parameter RAM
+  (typically 0x8afc 0x2).
+- #address-cells : Should be one. The cell is the i2c device address with
+  the r/w bit set to zero.
+- #size-cells : Should be zero.
+- clock-frequency : Can be used to set the i2c clock frequency. If
+  unspecified, a default frequency of 60kHz is being used.
+The following two properties are deprecated. They are only used by legacy
+i2c drivers to find the bus to probe:
+- linux,i2c-index : Can be used to hard code an i2c bus number. By default,
+  the bus number is dynamically assigned by the i2c core.
+- linux,i2c-class : Can be used to override the i2c class. The class is used
+  by legacy i2c device drivers to find a bus in a specific context like
+  system management, video or sound. By default, I2C_CLASS_HWMON (1) is
+  being used. The definition of the classes can be found in
+  include/i2c/i2c.h
+
+Example, based on mpc823:
+
+       i2c@860 {
+               compatible = "fsl,mpc823-i2c",
+                            "fsl,cpm1-i2c";
+               reg = <0x860 0x20 0x3c80 0x30>;
+               interrupts = <16>;
+               interrupt-parent = <&CPM_PIC>;
+               fsl,cpm-command = <0x10>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtc@68 {
+                       compatible = "dallas,ds1307";
+                       reg = <0x68>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt
new file mode 100644 (file)
index 0000000..8e3ee16
--- /dev/null
@@ -0,0 +1,18 @@
+* Interrupt Controllers
+
+Currently defined compatibles:
+- fsl,cpm1-pic
+  - only one interrupt cell
+- fsl,pq1-pic
+- fsl,cpm2-pic
+  - second interrupt cell is level/sense:
+    - 2 is falling edge
+    - 8 is active low
+
+Example:
+       interrupt-controller@10c00 {
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               reg = <10c00 80>;
+               compatible = "mpc8272-pic", "fsl,cpm2-pic";
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt
new file mode 100644 (file)
index 0000000..74bfda4
--- /dev/null
@@ -0,0 +1,15 @@
+* USB (Universal Serial Bus Controller)
+
+Properties:
+- compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb"
+
+Example:
+       usb@11bc0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,cpm2-usb";
+               reg = <11b60 18 8b00 100>;
+               interrupts = <b 8>;
+               interrupt-parent = <&PIC>;
+               fsl,cpm-command = <2e600000>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt
new file mode 100644 (file)
index 0000000..349f79f
--- /dev/null
@@ -0,0 +1,38 @@
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+On CPM1 devices, all ports are using slightly different register layouts.
+Ports A, C and D are 16bit ports and Ports B and E are 32bit ports.
+
+On CPM2 devices, all ports are 32bit ports and use a common register layout.
+
+Required properties:
+- compatible : "fsl,cpm1-pario-bank-a", "fsl,cpm1-pario-bank-b",
+  "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d",
+  "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank"
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of three SOC GPIO banks defined as gpio-controller nodes:
+
+       CPM1_PIO_A: gpio-controller@950 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-a";
+               reg = <0x950 0x10>;
+               gpio-controller;
+       };
+
+       CPM1_PIO_B: gpio-controller@ab8 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-b";
+               reg = <0xab8 0x10>;
+               gpio-controller;
+       };
+
+       CPM1_PIO_E: gpio-controller@ac8 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-e";
+               reg = <0xac8 0x18>;
+               gpio-controller;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt
new file mode 100644 (file)
index 0000000..0e42694
--- /dev/null
@@ -0,0 +1,45 @@
+* Network
+
+Currently defined compatibles:
+- fsl,cpm1-scc-enet
+- fsl,cpm2-scc-enet
+- fsl,cpm1-fec-enet
+- fsl,cpm2-fcc-enet (third resource is GFEMR)
+- fsl,qe-enet
+
+Example:
+
+       ethernet@11300 {
+               device_type = "network";
+               compatible = "fsl,mpc8272-fcc-enet",
+                            "fsl,cpm2-fcc-enet";
+               reg = <11300 20 8400 100 11390 1>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               interrupts = <20 8>;
+               interrupt-parent = <&PIC>;
+               phy-handle = <&PHY0>;
+               fsl,cpm-command = <12000300>;
+       };
+
+* MDIO
+
+Currently defined compatibles:
+fsl,pq1-fec-mdio (reg is same as first resource of FEC device)
+fsl,cpm2-mdio-bitbang (reg is port C registers)
+
+Properties for fsl,cpm2-mdio-bitbang:
+fsl,mdio-pin : pin of port C controlling mdio data
+fsl,mdc-pin : pin of port C controlling mdio clock
+
+Example:
+       mdio@10d40 {
+               device_type = "mdio";
+               compatible = "fsl,mpc8272ads-mdio-bitbang",
+                            "fsl,mpc8272-mdio-bitbang",
+                            "fsl,cpm2-mdio-bitbang";
+               reg = <10d40 14>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               fsl,mdio-pin = <12>;
+               fsl,mdc-pin = <13>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt
new file mode 100644 (file)
index 0000000..4f89302
--- /dev/null
@@ -0,0 +1,115 @@
+* Freescale QUICC Engine module (QE)
+This represents qe module that is installed on PowerQUICC II Pro.
+
+NOTE:  This is an interim binding; it should be updated to fit
+in with the CPM binding later in this document.
+
+Basically, it is a bus of devices, that could act more or less
+as a complete entity (UCC, USB etc ). All of them should be siblings on
+the "root" qe node, using the common properties from there.
+The description below applies to the qe of MPC8360 and
+more nodes and properties would be extended in the future.
+
+i) Root QE device
+
+Required properties:
+- compatible : should be "fsl,qe";
+- model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
+- reg : offset and length of the device registers.
+- bus-frequency : the clock frequency for QUICC Engine.
+- fsl,qe-num-riscs: define how many RISC engines the QE has.
+- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the
+  threads.
+
+Optional properties:
+- fsl,firmware-phandle:
+    Usage: required only if there is no fsl,qe-firmware child node
+    Value type: <phandle>
+    Definition: Points to a firmware node (see "QE Firmware Node" below)
+        that contains the firmware that should be uploaded for this QE.
+        The compatible property for the firmware node should say,
+        "fsl,qe-firmware".
+
+Recommended properties
+- brg-frequency : the internal clock source frequency for baud-rate
+  generators in Hz.
+
+Example:
+     qe@e0100000 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       #interrupt-cells = <2>;
+       compatible = "fsl,qe";
+       ranges = <0 e0100000 00100000>;
+       reg = <e0100000 480>;
+       brg-frequency = <0>;
+       bus-frequency = <179A7B00>;
+     }
+
+* Multi-User RAM (MURAM)
+
+Required properties:
+- compatible : should be "fsl,qe-muram", "fsl,cpm-muram".
+- mode : the could be "host" or "slave".
+- ranges : Should be defined as specified in 1) to describe the
+   translation of MURAM addresses.
+- data-only : sub-node which defines the address area under MURAM
+   bus that can be allocated as data/parameter
+
+Example:
+
+     muram@10000 {
+       compatible = "fsl,qe-muram", "fsl,cpm-muram";
+       ranges = <0 00010000 0000c000>;
+
+       data-only@0{
+               compatible = "fsl,qe-muram-data",
+                            "fsl,cpm-muram-data";
+               reg = <0 c000>;
+       };
+     };
+
+* QE Firmware Node
+
+This node defines a firmware binary that is embedded in the device tree, for
+the purpose of passing the firmware from bootloader to the kernel, or from
+the hypervisor to the guest.
+
+The firmware node itself contains the firmware binary contents, a compatible
+property, and any firmware-specific properties.  The node should be placed
+inside a QE node that needs it.  Doing so eliminates the need for a
+fsl,firmware-phandle property.  Other QE nodes that need the same firmware
+should define an fsl,firmware-phandle property that points to the firmware node
+in the first QE node.
+
+The fsl,firmware property can be specified in the DTS (possibly using incbin)
+or can be inserted by the boot loader at boot time.
+
+Required properties:
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: A standard property.  Specify a string that indicates what
+          kind of firmware it is.  For QE, this should be "fsl,qe-firmware".
+
+   - fsl,firmware
+      Usage: required
+      Value type: <prop-encoded-array>, encoded as an array of bytes
+      Definition: A standard property.  This property contains the firmware
+          binary "blob".
+
+Example:
+       qe1@e0080000 {
+               compatible = "fsl,qe";
+               qe_firmware:qe-firmware {
+                       compatible = "fsl,qe-firmware";
+                       fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...];
+               };
+               ...
+       };
+
+       qe2@e0090000 {
+               compatible = "fsl,qe";
+               fsl,firmware-phandle = <&qe_firmware>;
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt
new file mode 100644 (file)
index 0000000..249db3a
--- /dev/null
@@ -0,0 +1,24 @@
+* Uploaded QE firmware
+
+      If a new firmware has been uploaded to the QE (usually by the
+      boot loader), then a 'firmware' child node should be added to the QE
+      node.  This node provides information on the uploaded firmware that
+      device drivers may need.
+
+      Required properties:
+      - id: The string name of the firmware.  This is taken from the 'id'
+            member of the qe_firmware structure of the uploaded firmware.
+            Device drivers can search this string to determine if the
+            firmware they want is already present.
+      - extended-modes: The Extended Modes bitfield, taken from the
+                  firmware binary.  It is a 64-bit number represented
+                  as an array of two 32-bit numbers.
+      - virtual-traps: The virtual traps, taken from the firmware binary.
+                 It is an array of 8 32-bit numbers.
+
+Example:
+       firmware {
+               id = "Soft-UART";
+               extended-modes = <0 0>;
+               virtual-traps = <0 0 0 0 0 0 0 0>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt
new file mode 100644 (file)
index 0000000..6098426
--- /dev/null
@@ -0,0 +1,51 @@
+* Parallel I/O Ports
+
+This node configures Parallel I/O ports for CPUs with QE support.
+The node should reside in the "soc" node of the tree.  For each
+device that using parallel I/O ports, a child node should be created.
+See the definition of the Pin configuration nodes below for more
+information.
+
+Required properties:
+- device_type : should be "par_io".
+- reg : offset to the register set and its length.
+- num-ports : number of Parallel I/O ports
+
+Example:
+par_io@1400 {
+       reg = <1400 100>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       device_type = "par_io";
+       num-ports = <7>;
+       ucc_pin@01 {
+               ......
+       };
+
+Note that "par_io" nodes are obsolete, and should not be used for
+the new device trees. Instead, each Par I/O bank should be represented
+via its own gpio-controller node:
+
+Required properties:
+- #gpio-cells : should be "2".
+- compatible : should be "fsl,<chip>-qe-pario-bank",
+  "fsl,mpc8323-qe-pario-bank".
+- reg : offset to the register set and its length.
+- gpio-controller : node to identify gpio controllers.
+
+Example:
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8360-qe-pario-bank",
+               "fsl,mpc8323-qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+         };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8360-qe-pario-bank",
+                            "fsl,mpc8323-qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+         };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt
new file mode 100644 (file)
index 0000000..c5b4306
--- /dev/null
@@ -0,0 +1,60 @@
+* Pin configuration nodes
+
+Required properties:
+- linux,phandle : phandle of this node; likely referenced by a QE
+  device.
+- pio-map : array of pin configurations.  Each pin is defined by 6
+  integers.  The six numbers are respectively: port, pin, dir,
+  open_drain, assignment, has_irq.
+  - port : port number of the pin; 0-6 represent port A-G in UM.
+  - pin : pin number in the port.
+  - dir : direction of the pin, should encode as follows:
+
+     0 = The pin is disabled
+     1 = The pin is an output
+     2 = The pin is an input
+     3 = The pin is I/O
+
+  - open_drain : indicates the pin is normal or wired-OR:
+
+     0 = The pin is actively driven as an output
+     1 = The pin is an open-drain driver. As an output, the pin is
+         driven active-low, otherwise it is three-stated.
+
+  - assignment : function number of the pin according to the Pin Assignment
+    tables in User Manual.  Each pin can have up to 4 possible functions in
+    QE and two options for CPM.
+  - has_irq : indicates if the pin is used as source of external
+    interrupts.
+
+Example:
+     ucc_pin@01 {
+       linux,phandle = <140001>;
+       pio-map = <
+       /* port  pin  dir  open_drain  assignment  has_irq */
+               0  3  1  0  1  0        /* TxD0 */
+               0  4  1  0  1  0        /* TxD1 */
+               0  5  1  0  1  0        /* TxD2 */
+               0  6  1  0  1  0        /* TxD3 */
+               1  6  1  0  3  0        /* TxD4 */
+               1  7  1  0  1  0        /* TxD5 */
+               1  9  1  0  2  0        /* TxD6 */
+               1  a  1  0  2  0        /* TxD7 */
+               0  9  2  0  1  0        /* RxD0 */
+               0  a  2  0  1  0        /* RxD1 */
+               0  b  2  0  1  0        /* RxD2 */
+               0  c  2  0  1  0        /* RxD3 */
+               0  d  2  0  1  0        /* RxD4 */
+               1  1  2  0  2  0        /* RxD5 */
+               1  0  2  0  2  0        /* RxD6 */
+               1  4  2  0  2  0        /* RxD7 */
+               0  7  1  0  1  0        /* TX_EN */
+               0  8  1  0  1  0        /* TX_ER */
+               0  f  2  0  1  0        /* RX_DV */
+               0  10 2  0  1  0        /* RX_ER */
+               0  0  2  0  1  0        /* RX_CLK */
+               2  9  1  0  3  0        /* GTX_CLK - CLK10 */
+               2  8  2  0  1  0>;      /* GTX125 - CLK9 */
+     };
+
+
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt
new file mode 100644 (file)
index 0000000..e47734b
--- /dev/null
@@ -0,0 +1,70 @@
+* UCC (Unified Communications Controllers)
+
+Required properties:
+- device_type : should be "network", "hldc", "uart", "transparent"
+  "bisync", "atm", or "serial".
+- compatible : could be "ucc_geth" or "fsl_atm" and so on.
+- cell-index : the ucc number(1-8), corresponding to UCCx in UM.
+- reg : Offset and length of the register set for the device
+- interrupts : <a b> where a is the interrupt number and b is a
+  field that represents an encoding of the sense and level
+  information for the interrupt.  This should be encoded based on
+  the information in section 2) depending on the type of interrupt
+  controller you have.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+- pio-handle : The phandle for the Parallel I/O port configuration.
+- port-number : for UART drivers, the port number to use, between 0 and 3.
+  This usually corresponds to the /dev/ttyQE device, e.g. <0> = /dev/ttyQE0.
+  The port number is added to the minor number of the device.  Unlike the
+  CPM UART driver, the port-number is required for the QE UART driver.
+- soft-uart : for UART drivers, if specified this means the QE UART device
+  driver should use "Soft-UART" mode, which is needed on some SOCs that have
+  broken UART hardware.  Soft-UART is provided via a microcode upload.
+- rx-clock-name: the UCC receive clock source
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- tx-clock-name: the UCC transmit clock source
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+The following two properties are deprecated.  rx-clock has been replaced
+with rx-clock-name, and tx-clock has been replaced with tx-clock-name.
+Drivers that currently use the deprecated properties should continue to
+do so, in order to support older device trees, but they should be updated
+to check for the new properties first.
+- rx-clock : represents the UCC receive clock source.
+  0x00 : clock source is disabled;
+  0x1~0x10 : clock source is BRG1~BRG16 respectively;
+  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+- tx-clock: represents the UCC transmit clock source;
+  0x00 : clock source is disabled;
+  0x1~0x10 : clock source is BRG1~BRG16 respectively;
+  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+
+Required properties for network device_type:
+- mac-address : list of bytes representing the ethernet address.
+- phy-handle : The phandle for the PHY connected to this controller.
+
+Recommended properties:
+- phy-connection-type : a string naming the controller/PHY interface type,
+  i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal
+  Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only),
+  "tbi", or "rtbi".
+
+Example:
+       ucc@2000 {
+               device_type = "network";
+               compatible = "ucc_geth";
+               cell-index = <1>;
+               reg = <2000 200>;
+               interrupts = <a0 0>;
+               interrupt-parent = <700>;
+               mac-address = [ 00 04 9f 00 23 23 ];
+               rx-clock = "none";
+               tx-clock = "clk9";
+               phy-handle = <212000>;
+               phy-connection-type = "gmii";
+               pio-handle = <140001>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt
new file mode 100644 (file)
index 0000000..9ccd5f3
--- /dev/null
@@ -0,0 +1,37 @@
+Freescale QUICC Engine USB Controller
+
+Required properties:
+- compatible : should be "fsl,<chip>-qe-usb", "fsl,mpc8323-qe-usb".
+- reg : the first two cells should contain usb registers location and
+  length, the next two two cells should contain PRAM location and
+  length.
+- interrupts : should contain USB interrupt.
+- interrupt-parent : interrupt source phandle.
+- fsl,fullspeed-clock : specifies the full speed USB clock source:
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- fsl,lowspeed-clock : specifies the low speed USB clock source:
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- hub-power-budget : USB power budget for the root hub, in mA.
+- gpios : should specify GPIOs in this order: USBOE, USBTP, USBTN, USBRP,
+  USBRN, SPEED (optional), and POWER (optional).
+
+Example:
+
+usb@6c0 {
+       compatible = "fsl,mpc8360-qe-usb", "fsl,mpc8323-qe-usb";
+       reg = <0x6c0 0x40 0x8b00 0x100>;
+       interrupts = <11>;
+       interrupt-parent = <&qeic>;
+       fsl,fullspeed-clock = "clk21";
+       gpios = <&qe_pio_b  2 0 /* USBOE */
+                &qe_pio_b  3 0 /* USBTP */
+                &qe_pio_b  8 0 /* USBTN */
+                &qe_pio_b  9 0 /* USBRP */
+                &qe_pio_b 11 0 /* USBRN */
+                &qe_pio_e 20 0 /* SPEED */
+                &qe_pio_e 21 0 /* POWER */>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt
new file mode 100644 (file)
index 0000000..2ea76d9
--- /dev/null
@@ -0,0 +1,32 @@
+* Serial
+
+Currently defined compatibles:
+- fsl,cpm1-smc-uart
+- fsl,cpm2-smc-uart
+- fsl,cpm1-scc-uart
+- fsl,cpm2-scc-uart
+- fsl,qe-uart
+
+Modem control lines connected to GPIO controllers are listed in the gpios
+property as described in booting-without-of.txt, section IX.1 in the following
+order:
+
+CTS, RTS, DCD, DSR, DTR, and RI.
+
+The gpios property is optional and can be left out when control lines are
+not used.
+
+Example:
+
+       serial@11a00 {
+               device_type = "serial";
+               compatible = "fsl,mpc8272-scc-uart",
+                            "fsl,cpm2-scc-uart";
+               reg = <11a00 20 8000 100>;
+               interrupts = <28 8>;
+               interrupt-parent = <&PIC>;
+               fsl,cpm-brg = <1>;
+               fsl,cpm-command = <00800000>;
+               gpios = <&gpio_c 15 0
+                        &gpio_d 29 0>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/diu.txt b/Documentation/devicetree/bindings/powerpc/fsl/diu.txt
new file mode 100644 (file)
index 0000000..b66cb6d
--- /dev/null
@@ -0,0 +1,34 @@
+* Freescale Display Interface Unit
+
+The Freescale DIU is a LCD controller, with proper hardware, it can also
+drive DVI monitors.
+
+Required properties:
+- compatible : should be "fsl,diu" or "fsl,mpc5121-diu".
+- reg : should contain at least address and length of the DIU register
+  set.
+- interrupts : one DIU interrupt should be described here.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- edid : verbatim EDID data block describing attached display.
+  Data from the detailed timing descriptor will be used to
+  program the display controller.
+
+Example (MPC8610HPCD):
+       display@2c000 {
+               compatible = "fsl,diu";
+               reg = <0x2c000 100>;
+               interrupts = <72 2>;
+               interrupt-parent = <&mpic>;
+       };
+
+Example for MPC5121:
+       display@2100 {
+               compatible = "fsl,mpc5121-diu";
+               reg = <0x2100 0x100>;
+               interrupts = <64 0x8>;
+               interrupt-parent = <&ipic>;
+               edid = [edid-data];
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
new file mode 100644 (file)
index 0000000..2a4b4bc
--- /dev/null
@@ -0,0 +1,144 @@
+* Freescale 83xx DMA Controller
+
+Freescale PowerPC 83xx have on chip general purpose DMA controllers.
+
+Required properties:
+
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-dma", where CHIP is the processor
+                (mpc8349, mpc8360, etc.) and the second is
+                "fsl,elo-dma"
+- reg               : <registers mapping for DMA general status reg>
+- ranges               : Should be defined as specified in 1) to describe the
+                 DMA controller channels.
+- cell-index        : controller index.  0 for controller @ 0x8100
+- interrupts        : <interrupt mapping for DMA IRQ>
+- interrupt-parent  : optional, if needed for interrupt mapping
+
+
+- DMA channel nodes:
+        - compatible        : compatible list, contains 2 entries, first is
+                        "fsl,CHIP-dma-channel", where CHIP is the processor
+                        (mpc8349, mpc8350, etc.) and the second is
+                        "fsl,elo-dma-channel". However, see note below.
+        - reg               : <registers mapping for channel>
+        - cell-index        : dma channel index starts at 0.
+
+Optional properties:
+        - interrupts        : <interrupt mapping for DMA channel IRQ>
+                         (on 83xx this is expected to be identical to
+                          the interrupts property of the parent node)
+        - interrupt-parent  : optional, if needed for interrupt mapping
+
+Example:
+       dma@82a8 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8349-dma", "fsl,elo-dma";
+               reg = <0x82a8 4>;
+               ranges = <0 0x8100 0x1a4>;
+               interrupt-parent = <&ipic>;
+               interrupts = <71 8>;
+               cell-index = <0>;
+               dma-channel@0 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <0>;
+                       reg = <0 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@80 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <1>;
+                       reg = <0x80 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@100 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <2>;
+                       reg = <0x100 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@180 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <3>;
+                       reg = <0x180 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+       };
+
+* Freescale 85xx/86xx DMA Controller
+
+Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
+
+Required properties:
+
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-dma", where CHIP is the processor
+                (mpc8540, mpc8540, etc.) and the second is
+                "fsl,eloplus-dma"
+- reg               : <registers mapping for DMA general status reg>
+- cell-index        : controller index.  0 for controller @ 0x21000,
+                                         1 for controller @ 0xc000
+- ranges               : Should be defined as specified in 1) to describe the
+                 DMA controller channels.
+
+- DMA channel nodes:
+        - compatible        : compatible list, contains 2 entries, first is
+                        "fsl,CHIP-dma-channel", where CHIP is the processor
+                        (mpc8540, mpc8560, etc.) and the second is
+                        "fsl,eloplus-dma-channel". However, see note below.
+        - cell-index        : dma channel index starts at 0.
+        - reg               : <registers mapping for channel>
+        - interrupts        : <interrupt mapping for DMA channel IRQ>
+        - interrupt-parent  : optional, if needed for interrupt mapping
+
+Example:
+       dma@21300 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
+               reg = <0x21300 4>;
+               ranges = <0 0x21100 0x200>;
+               cell-index = <0>;
+               dma-channel@0 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0 0x80>;
+                       cell-index = <0>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <20 2>;
+               };
+               dma-channel@80 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x80 0x80>;
+                       cell-index = <1>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <21 2>;
+               };
+               dma-channel@100 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x100 0x80>;
+                       cell-index = <2>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <22 2>;
+               };
+               dma-channel@180 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x180 0x80>;
+                       cell-index = <3>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <23 2>;
+               };
+       };
+
+Note on DMA channel compatible properties: The compatible property must say
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
+driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
+DMA driver, such as the SSI sound drivers for the MPC8610.  Therefore, any DMA
+channel that should be used for another driver should not use
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel".  For the SSI drivers, for
+example, the compatible property should be "fsl,ssi-dma-channel".  See ssi.txt
+for more information.
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ecm.txt b/Documentation/devicetree/bindings/powerpc/fsl/ecm.txt
new file mode 100644 (file)
index 0000000..f514f29
--- /dev/null
@@ -0,0 +1,64 @@
+=====================================================================
+E500 LAW & Coherency Module Device Tree Binding
+Copyright (C) 2009 Freescale Semiconductor Inc.
+=====================================================================
+
+Local Access Window (LAW) Node
+
+The LAW node represents the region of CCSR space where local access
+windows are configured.  For ECM based devices this is the first 4k
+of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
+number of local access windows as specified by fsl,num-laws.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,ecm-law"
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+  - fsl,num-laws
+      Usage: required
+      Value type: <u32>
+      Definition: The value specifies the number of local access
+          windows for this device.
+
+=====================================================================
+
+E500 Coherency Module Node
+
+The E500 LAW node represents the region of CCSR space where ECM config
+and error reporting registers exist, this is the second 4k (0x1000)
+of CCSR space.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,CHIP-ecm", "fsl,ecm" where
+      CHIP is the processor (mpc8572, mpc8544, etc.)
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+   - interrupts
+      Usage: required
+      Value type: <prop-encoded-array>
+
+   - interrupt-parent
+      Usage: required
+      Value type: <phandle>
+
+=====================================================================
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/gtm.txt b/Documentation/devicetree/bindings/powerpc/fsl/gtm.txt
new file mode 100644 (file)
index 0000000..9a33efd
--- /dev/null
@@ -0,0 +1,31 @@
+* Freescale General-purpose Timers Module
+
+Required properties:
+  - compatible : should be
+    "fsl,<chip>-gtm", "fsl,gtm" for SOC GTMs
+    "fsl,<chip>-qe-gtm", "fsl,qe-gtm", "fsl,gtm" for QE GTMs
+    "fsl,<chip>-cpm2-gtm", "fsl,cpm2-gtm", "fsl,gtm" for CPM2 GTMs
+  - reg : should contain gtm registers location and length (0x40).
+  - interrupts : should contain four interrupts.
+  - interrupt-parent : interrupt source phandle.
+  - clock-frequency : specifies the frequency driving the timer.
+
+Example:
+
+timer@500 {
+       compatible = "fsl,mpc8360-gtm", "fsl,gtm";
+       reg = <0x500 0x40>;
+       interrupts = <90 8 78 8 84 8 72 8>;
+       interrupt-parent = <&ipic>;
+       /* filled by u-boot */
+       clock-frequency = <0>;
+};
+
+timer@440 {
+       compatible = "fsl,mpc8360-qe-gtm", "fsl,qe-gtm", "fsl,gtm";
+       reg = <0x440 0x40>;
+       interrupts = <12 13 14 15>;
+       interrupt-parent = <&qeic>;
+       /* filled by u-boot */
+       clock-frequency = <0>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
new file mode 100644 (file)
index 0000000..9e7a241
--- /dev/null
@@ -0,0 +1,25 @@
+* Global Utilities Block
+
+The global utilities block controls power management, I/O device
+enabling, power-on-reset configuration monitoring, general-purpose
+I/O signal configuration, alternate function selection for multiplexed
+signals, and clock control.
+
+Required properties:
+
+ - compatible : Should define the compatible device type for
+   global-utilities.
+ - reg : Offset and length of the register set for the device.
+
+Recommended properties:
+
+ - fsl,has-rstcr : Indicates that the global utilities register set
+   contains a functioning "reset control register" (i.e. the board
+   is wired to reset upon setting the HRESET_REQ bit in this register).
+
+Example:
+       global-utilities@e0000 {        /* global utilities block */
+               compatible = "fsl,mpc8548-guts";
+               reg = <e0000 1000>;
+               fsl,has-rstcr;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
new file mode 100644 (file)
index 0000000..3300fec
--- /dev/null
@@ -0,0 +1,35 @@
+* Chipselect/Local Bus
+
+Properties:
+- name : Should be localbus
+- #address-cells : Should be either two or three.  The first cell is the
+                   chipselect number, and the remaining cells are the
+                   offset into the chipselect.
+- #size-cells : Either one or two, depending on how large each chipselect
+                can be.
+- ranges : Each range corresponds to a single chipselect, and cover
+           the entire access window as configured.
+
+Example:
+       localbus@f0010100 {
+               compatible = "fsl,mpc8272-localbus",
+                          "fsl,pq2-localbus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <f0010100 40>;
+
+               ranges = <0 0 fe000000 02000000
+                         1 0 f4500000 00008000>;
+
+               flash@0,0 {
+                       compatible = "jedec-flash";
+                       reg = <0 0 2000000>;
+                       bank-width = <4>;
+                       device-width = <1>;
+               };
+
+               board-control@1,0 {
+                       reg = <1 0 20>;
+                       compatible = "fsl,mpc8272ads-bcsr";
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mcm.txt b/Documentation/devicetree/bindings/powerpc/fsl/mcm.txt
new file mode 100644 (file)
index 0000000..4ceda9b
--- /dev/null
@@ -0,0 +1,64 @@
+=====================================================================
+MPX LAW & Coherency Module Device Tree Binding
+Copyright (C) 2009 Freescale Semiconductor Inc.
+=====================================================================
+
+Local Access Window (LAW) Node
+
+The LAW node represents the region of CCSR space where local access
+windows are configured.  For MCM based devices this is the first 4k
+of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
+number of local access windows as specified by fsl,num-laws.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,mcm-law"
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+  - fsl,num-laws
+      Usage: required
+      Value type: <u32>
+      Definition: The value specifies the number of local access
+          windows for this device.
+
+=====================================================================
+
+MPX Coherency Module Node
+
+The MPX LAW node represents the region of CCSR space where MCM config
+and error reporting registers exist, this is the second 4k (0x1000)
+of CCSR space.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,CHIP-mcm", "fsl,mcm" where
+      CHIP is the processor (mpc8641, mpc8610, etc.)
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+   - interrupts
+      Usage: required
+      Value type: <prop-encoded-array>
+
+   - interrupt-parent
+      Usage: required
+      Value type: <phandle>
+
+=====================================================================
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt b/Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt
new file mode 100644 (file)
index 0000000..0f76633
--- /dev/null
@@ -0,0 +1,17 @@
+Freescale MPC8349E-mITX-compatible Power Management Micro Controller Unit (MCU)
+
+Required properties:
+- compatible : "fsl,<mcu-chip>-<board>", "fsl,mcu-mpc8349emitx".
+- reg : should specify I2C address (0x0a).
+- #gpio-cells : should be 2.
+- gpio-controller : should be present.
+
+Example:
+
+mcu@0a {
+       #gpio-cells = <2>;
+       compatible = "fsl,mc9s08qg8-mpc8349emitx",
+                    "fsl,mcu-mpc8349emitx";
+       reg = <0x0a>;
+       gpio-controller;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt
new file mode 100644 (file)
index 0000000..8832e87
--- /dev/null
@@ -0,0 +1,70 @@
+MPC5121 PSC Device Tree Bindings
+
+PSC in UART mode
+----------------
+
+For PSC in UART mode the needed PSC serial devices
+are specified by fsl,mpc5121-psc-uart nodes in the
+fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
+Controller node fsl,mpc5121-psc-fifo is requered there:
+
+fsl,mpc5121-psc-uart nodes
+--------------------------
+
+Required properties :
+ - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
+ - cell-index : Index of the PSC in hardware
+ - reg : Offset and length of the register set for the PSC device
+ - interrupts : <a b> where a is the interrupt number of the
+   PSC FIFO Controller and b is a field that represents an
+   encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Recommended properties :
+ - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
+ - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
+
+
+fsl,mpc5121-psc-fifo node
+-------------------------
+
+Required properties :
+ - compatible : Should be "fsl,mpc5121-psc-fifo"
+ - reg : Offset and length of the register set for the PSC
+         FIFO Controller
+ - interrupts : <a b> where a is the interrupt number of the
+   PSC FIFO Controller and b is a field that represents an
+   encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+
+Example for a board using PSC0 and PSC1 devices in serial mode:
+
+serial@11000 {
+       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+       cell-index = <0>;
+       reg = <0x11000 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+       fsl,rx-fifo-size = <16>;
+       fsl,tx-fifo-size = <16>;
+};
+
+serial@11100 {
+       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+       cell-index = <1>;
+       reg = <0x11100 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+       fsl,rx-fifo-size = <16>;
+       fsl,tx-fifo-size = <16>;
+};
+
+pscfifo@11f00 {
+       compatible = "fsl,mpc5121-psc-fifo";
+       reg = <0x11f00 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt
new file mode 100644 (file)
index 0000000..4ccb2cd
--- /dev/null
@@ -0,0 +1,198 @@
+MPC5200 Device Tree Bindings
+----------------------------
+
+(c) 2006-2009 Secret Lab Technologies Ltd
+Grant Likely <grant.likely@secretlab.ca>
+
+Naming conventions
+------------------
+For mpc5200 on-chip devices, the format for each compatible value is
+<chip>-<device>[-<mode>].  The OS should be able to match a device driver
+to the device based solely on the compatible value.  If two drivers
+match on the compatible list; the 'most compatible' driver should be
+selected.
+
+The split between the MPC5200 and the MPC5200B leaves a bit of a
+conundrum.  How should the compatible property be set up to provide
+maximum compatibility information; but still accurately describe the
+chip?  For the MPC5200; the answer is easy.  Most of the SoC devices
+originally appeared on the MPC5200.  Since they didn't exist anywhere
+else; the 5200 compatible properties will contain only one item;
+"fsl,mpc5200-<device>".
+
+The 5200B is almost the same as the 5200, but not quite.  It fixes
+silicon bugs and it adds a small number of enhancements.  Most of the
+devices either provide exactly the same interface as on the 5200.  A few
+devices have extra functions but still have a backwards compatible mode.
+To express this information as completely as possible, 5200B device trees
+should have two items in the compatible list:
+       compatible = "fsl,mpc5200b-<device>","fsl,mpc5200-<device>";
+
+It is *strongly* recommended that 5200B device trees follow this convention
+(instead of only listing the base mpc5200 item).
+
+ie. ethernet on mpc5200: compatible = "fsl,mpc5200-fec";
+    ethernet on mpc5200b: compatible = "fsl,mpc5200b-fec", "fsl,mpc5200-fec";
+
+Modal devices, like PSCs, also append the configured function to the
+end of the compatible field.  ie. A PSC in i2s mode would specify
+"fsl,mpc5200-psc-i2s", not "fsl,mpc5200-i2s".  This convention is chosen to
+avoid naming conflicts with non-psc devices providing the same
+function.  For example, "fsl,mpc5200-spi" and "fsl,mpc5200-psc-spi" describe
+the mpc5200 simple spi device and a PSC spi mode respectively.
+
+At the time of writing, exact chip may be either 'fsl,mpc5200' or
+'fsl,mpc5200b'.
+
+The soc node
+------------
+This node describes the on chip SOC peripherals.  Every mpc5200 based
+board will have this node, and as such there is a common naming
+convention for SOC devices.
+
+Required properties:
+name                   description
+----                   -----------
+ranges                 Memory range of the internal memory mapped registers.
+                       Should be <0 [baseaddr] 0xc000>
+reg                    Should be <[baseaddr] 0x100>
+compatible             mpc5200: "fsl,mpc5200-immr"
+                       mpc5200b: "fsl,mpc5200b-immr"
+system-frequency       'fsystem' frequency in Hz; XLB, IPB, USB and PCI
+                       clocks are derived from the fsystem clock.
+bus-frequency          IPB bus frequency in Hz.  Clock rate
+                       used by most of the soc devices.
+
+soc child nodes
+---------------
+Any on chip SOC devices available to Linux must appear as soc5200 child nodes.
+
+Note: The tables below show the value for the mpc5200.  A mpc5200b device
+tree should use the "fsl,mpc5200b-<device>","fsl,mpc5200-<device>" form.
+
+Required soc5200 child nodes:
+name                           compatible              Description
+----                           ----------              -----------
+cdm@<addr>                     fsl,mpc5200-cdm         Clock Distribution
+interrupt-controller@<addr>    fsl,mpc5200-pic         need an interrupt
+                                                       controller to boot
+bestcomm@<addr>                        fsl,mpc5200-bestcomm    Bestcomm DMA controller
+
+Recommended soc5200 child nodes; populate as needed for your board
+name           compatible              Description
+----           ----------              -----------
+timer@<addr>   fsl,mpc5200-gpt          General purpose timers
+gpio@<addr>    fsl,mpc5200-gpio         MPC5200 simple gpio controller
+gpio@<addr>    fsl,mpc5200-gpio-wkup    MPC5200 wakeup gpio controller
+rtc@<addr>     fsl,mpc5200-rtc          Real time clock
+mscan@<addr>   fsl,mpc5200-mscan        CAN bus controller
+pci@<addr>     fsl,mpc5200-pci          PCI bridge
+serial@<addr>  fsl,mpc5200-psc-uart     PSC in serial mode
+i2s@<addr>     fsl,mpc5200-psc-i2s      PSC in i2s mode
+ac97@<addr>    fsl,mpc5200-psc-ac97     PSC in ac97 mode
+spi@<addr>     fsl,mpc5200-psc-spi      PSC in spi mode
+irda@<addr>    fsl,mpc5200-psc-irda     PSC in IrDA mode
+spi@<addr>     fsl,mpc5200-spi          MPC5200 spi device
+ethernet@<addr>        fsl,mpc5200-fec          MPC5200 ethernet device
+ata@<addr>     fsl,mpc5200-ata          IDE ATA interface
+i2c@<addr>     fsl,mpc5200-i2c          I2C controller
+usb@<addr>     fsl,mpc5200-ohci,ohci-be USB controller
+xlb@<addr>     fsl,mpc5200-xlb          XLB arbitrator
+
+fsl,mpc5200-gpt nodes
+---------------------
+On the mpc5200 and 5200b, GPT0 has a watchdog timer function.  If the board
+design supports the internal wdt, then the device node for GPT0 should
+include the empty property 'fsl,has-wdt'.  Note that this does not activate
+the watchdog.  The timer will function as a GPT if the timer api is used, and
+it will function as watchdog if the watchdog device is used.  The watchdog
+mode has priority over the gpt mode, i.e. if the watchdog is activated, any
+gpt api call to this timer will fail with -EBUSY.
+
+If you add the property
+       fsl,wdt-on-boot = <n>;
+GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it.
+If n>0, the watchdog is started with a timeout of n seconds.  If n=0, the
+configuration of the watchdog is not touched.  This is useful in two cases:
+- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later;
+- do not touch a configuration assigned by the boot loader which supervises
+  the boot process itself.
+
+The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option.
+
+An mpc5200-gpt can be used as a single line GPIO controller.  To do so,
+add the following properties to the gpt node:
+       gpio-controller;
+       #gpio-cells = <2>;
+When referencing the GPIO line from another node, the first cell must always
+be zero and the second cell represents the gpio flags and described in the
+gpio device tree binding.
+
+An mpc5200-gpt can be used as a single line edge sensitive interrupt
+controller.  To do so, add the following properties to the gpt node:
+       interrupt-controller;
+       #interrupt-cells = <1>;
+When referencing the IRQ line from another node, the cell represents the
+sense mode; 1 for edge rising, 2 for edge falling.
+
+fsl,mpc5200-psc nodes
+---------------------
+The PSCs should include a cell-index which is the index of the PSC in
+hardware.  cell-index is used to determine which shared SoC registers to
+use when setting up PSC clocking.  cell-index number starts at '0'.  ie:
+       PSC1 has 'cell-index = <0>'
+       PSC4 has 'cell-index = <3>'
+
+PSC in i2s mode:  The mpc5200 and mpc5200b PSCs are not compatible when in
+i2s mode.  An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the
+compatible field.
+
+
+fsl,mpc5200-gpio and fsl,mpc5200-gpio-wkup nodes
+------------------------------------------------
+Each GPIO controller node should have the empty property gpio-controller and
+#gpio-cells set to 2. First cell is the GPIO number which is interpreted
+according to the bit numbers in the GPIO control registers. The second cell
+is for flags which is currently unused.
+
+fsl,mpc5200-fec nodes
+---------------------
+The FEC node can specify one of the following properties to configure
+the MII link:
+- fsl,7-wire-mode - An empty property that specifies the link uses 7-wire
+                    mode instead of MII
+- current-speed   - Specifies that the MII should be configured for a fixed
+                    speed.  This property should contain two cells.  The
+                    first cell specifies the speed in Mbps and the second
+                    should be '0' for half duplex and '1' for full duplex
+- phy-handle      - Contains a phandle to an Ethernet PHY.
+
+Interrupt controller (fsl,mpc5200-pic) node
+-------------------------------------------
+The mpc5200 pic binding splits hardware IRQ numbers into two levels.  The
+split reflects the layout of the PIC hardware itself, which groups
+interrupts into one of three groups; CRIT, MAIN or PERP.  Also, the
+Bestcomm dma engine has it's own set of interrupt sources which are
+cascaded off of peripheral interrupt 0, which the driver interprets as a
+fourth group, SDMA.
+
+The interrupts property for device nodes using the mpc5200 pic consists
+of three cells; <L1 L2 level>
+
+    L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3]
+    L2 := interrupt number; directly mapped from the value in the
+          "ICTL PerStat, MainStat, CritStat Encoded Register"
+    level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3]
+
+For external IRQs, use the following interrupt property values (how to
+specify external interrupts is a frequently asked question):
+External interrupts:
+       external irq0:  interrupts = <0 0 n>;
+       external irq1:  interrupts = <1 1 n>;
+       external irq2:  interrupts = <1 2 n>;
+       external irq3:  interrupts = <1 3 n>;
+'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
+
+fsl,mpc5200-mscan nodes
+-----------------------
+See file can.txt in this directory.
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
new file mode 100644 (file)
index 0000000..71e39cf
--- /dev/null
@@ -0,0 +1,42 @@
+* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
+
+The OpenPIC specification does not specify which interrupt source has to
+become which interrupt number. This is up to the software implementation
+of the interrupt controller. The only requirement is that every
+interrupt source has to have an unique interrupt number / vector number.
+To accomplish this the current implementation assigns the number zero to
+the first source, the number one to the second source and so on until
+all interrupt sources have their unique number.
+Usually the assigned vector number equals the interrupt number mentioned
+in the documentation for a given core / CPU. This is however not true
+for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
+between internal and external interrupt sources and starts counting at
+zero for both of them.
+
+So what to write for external interrupt source X or internal interrupt
+source Y into the device tree? Here is an example:
+
+The memory map for the interrupt controller in the MPC8544[0] shows,
+that the first interrupt source starts at 0x5_0000 (PIC Register Address
+Map-Interrupt Source Configuration Registers). This source becomes the
+number zero therefore:
+ External interrupt 0 = interrupt number 0
+ External interrupt 1 = interrupt number 1
+ External interrupt 2 = interrupt number 2
+ ...
+Every interrupt number allocates 0x20 bytes register space. So to get
+its number it is sufficient to shift the lower 16bits to right by five.
+So for the external interrupt 10 we have:
+  0x0140 >> 5 = 10
+
+After the external sources, the internal sources follow. The in core I2C
+controller on the MPC8544 for instance has the internal source number
+27. Oo obtain its interrupt number we take the lower 16bits of its memory
+address (0x5_0560) and shift it right:
+ 0x0560 >> 5 = 43
+
+Therefore the I2C device node for the MPC8544 CPU has to have the
+interrupt number 43 specified in the device tree.
+
+[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
+    MPC8544ERM Rev. 1 10/2007
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
new file mode 100644 (file)
index 0000000..bcc30ba
--- /dev/null
@@ -0,0 +1,36 @@
+* Freescale MSI interrupt controller
+
+Required properties:
+- compatible : compatible list, contains 2 entries,
+  first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
+  etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
+  the parent type.
+- reg : should contain the address and the length of the shared message
+  interrupt register set.
+- msi-available-ranges: use <start count> style section to define which
+  msi interrupt can be used in the 256 msi interrupts. This property is
+  optional, without this, all the 256 MSI interrupts can be used.
+- interrupts : each one of the interrupts here is one entry per 32 MSIs,
+  and routed to the host interrupt controller. the interrupts should
+  be set as edge sensitive.
+- interrupt-parent: the phandle for the interrupt controller
+  that services interrupts for this device. for 83xx cpu, the interrupts
+  are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed
+  to MPIC.
+
+Example:
+       msi@41600 {
+               compatible = "fsl,mpc8610-msi", "fsl,mpic-msi";
+               reg = <0x41600 0x80>;
+               msi-available-ranges = <0 0x100>;
+               interrupts = <
+                       0xe0 0
+                       0xe1 0
+                       0xe2 0
+                       0xe3 0
+                       0xe4 0
+                       0xe5 0
+                       0xe6 0
+                       0xe7 0>;
+               interrupt-parent = <&mpic>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
new file mode 100644 (file)
index 0000000..07256b7
--- /dev/null
@@ -0,0 +1,63 @@
+* Power Management Controller
+
+Properties:
+- compatible: "fsl,<chip>-pmc".
+
+  "fsl,mpc8349-pmc" should be listed for any chip whose PMC is
+  compatible.  "fsl,mpc8313-pmc" should also be listed for any chip
+  whose PMC is compatible, and implies deep-sleep capability.
+
+  "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
+  compatible.  "fsl,mpc8536-pmc" should also be listed for any chip
+  whose PMC is compatible, and implies deep-sleep capability.
+
+  "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
+  compatible; all statements below that apply to "fsl,mpc8548-pmc" also
+  apply to "fsl,mpc8641d-pmc".
+
+  Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
+  bit assignments are indicated via the sleep specifier in each device's
+  sleep property.
+
+- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
+  is the PMC block, and the second resource is the Clock Configuration
+  block.
+
+  For devices compatible with "fsl,mpc8548-pmc", the first resource
+  is a 32-byte block beginning with DEVDISR.
+
+- interrupts: For "fsl,mpc8349-pmc"-compatible devices, the first
+  resource is the PMC block interrupt.
+
+- fsl,mpc8313-wakeup-timer: For "fsl,mpc8313-pmc"-compatible devices,
+  this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
+  a wakeup source from deep sleep.
+
+Sleep specifiers:
+
+  fsl,mpc8349-pmc: Sleep specifiers consist of one cell.  For each bit
+  that is set in the cell, the corresponding bit in SCCR will be saved
+  and cleared on suspend, and restored on resume.  This sleep controller
+  supports disabling and resuming devices at any time.
+
+  fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
+  which will be ORed into PMCDR upon suspend, and cleared from PMCDR
+  upon resume.  The first two cells are as described for fsl,mpc8578-pmc.
+  This sleep controller only supports disabling devices during system
+  sleep, or permanently.
+
+  fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
+  first of which will be ORed into DEVDISR (and the second into
+  DEVDISR2, if present -- this cell should be zero or absent if the
+  hardware does not have DEVDISR2) upon a request for permanent device
+  disabling.  This sleep controller does not support configuring devices
+  to disable during system sleep (unless supported by another compatible
+  match), or dynamically.
+
+Example:
+
+       power@b00 {
+               compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
+               reg = <0xb00 0x100 0xa00 0x100>;
+               interrupts = <80 8>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt b/Documentation/devicetree/bindings/powerpc/fsl/sec.txt
new file mode 100644 (file)
index 0000000..2b6f2d4
--- /dev/null
@@ -0,0 +1,68 @@
+Freescale SoC SEC Security Engines
+
+Required properties:
+
+- compatible : Should contain entries for this and backward compatible
+  SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0"
+- reg : Offset and length of the register set for the device
+- interrupts : the SEC's interrupt number
+- fsl,num-channels : An integer representing the number of channels
+  available.
+- fsl,channel-fifo-len : An integer representing the number of
+  descriptor pointers each channel fetch fifo can hold.
+- fsl,exec-units-mask : The bitmask representing what execution units
+  (EUs) are available. It's a single 32-bit cell. EU information
+  should be encoded following the SEC's Descriptor Header Dword
+  EU_SEL0 field documentation, i.e. as follows:
+
+       bit 0  = reserved - should be 0
+       bit 1  = set if SEC has the ARC4 EU (AFEU)
+       bit 2  = set if SEC has the DES/3DES EU (DEU)
+       bit 3  = set if SEC has the message digest EU (MDEU/MDEU-A)
+       bit 4  = set if SEC has the random number generator EU (RNG)
+       bit 5  = set if SEC has the public key EU (PKEU)
+       bit 6  = set if SEC has the AES EU (AESU)
+       bit 7  = set if SEC has the Kasumi EU (KEU)
+       bit 8  = set if SEC has the CRC EU (CRCU)
+       bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B)
+
+remaining bits are reserved for future SEC EUs.
+
+- fsl,descriptor-types-mask : The bitmask representing what descriptors
+  are available. It's a single 32-bit cell. Descriptor type information
+  should be encoded following the SEC's Descriptor Header Dword DESC_TYPE
+  field documentation, i.e. as follows:
+
+       bit 0  = set if SEC supports the aesu_ctr_nonsnoop desc. type
+       bit 1  = set if SEC supports the ipsec_esp descriptor type
+       bit 2  = set if SEC supports the common_nonsnoop desc. type
+       bit 3  = set if SEC supports the 802.11i AES ccmp desc. type
+       bit 4  = set if SEC supports the hmac_snoop_no_afeu desc. type
+       bit 5  = set if SEC supports the srtp descriptor type
+       bit 6  = set if SEC supports the non_hmac_snoop_no_afeu desc.type
+       bit 7  = set if SEC supports the pkeu_assemble descriptor type
+       bit 8  = set if SEC supports the aesu_key_expand_output desc.type
+       bit 9  = set if SEC supports the pkeu_ptmul descriptor type
+       bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
+       bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
+
+  ..and so on and so forth.
+
+Optional properties:
+
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Example:
+
+       /* MPC8548E */
+       crypto@30000 {
+               compatible = "fsl,sec2.1", "fsl,sec2.0";
+               reg = <0x30000 0x10000>;
+               interrupts = <29 2>;
+               interrupt-parent = <&mpic>;
+               fsl,num-channels = <4>;
+               fsl,channel-fifo-len = <24>;
+               fsl,exec-units-mask = <0xfe>;
+               fsl,descriptor-types-mask = <0x12b0ebf>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt b/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt
new file mode 100644 (file)
index 0000000..5ff76c9
--- /dev/null
@@ -0,0 +1,73 @@
+Freescale Synchronous Serial Interface
+
+The SSI is a serial device that communicates with audio codecs.  It can
+be programmed in AC97, I2S, left-justified, or right-justified modes.
+
+Required properties:
+- compatible:       Compatible list, contains "fsl,ssi".
+- cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
+- reg:              Offset and length of the register set for the device.
+- interrupts:       <a b> where a is the interrupt number and b is a
+                    field that represents an encoding of the sense and
+                    level information for the interrupt.  This should be
+                    encoded based on the information in section 2)
+                    depending on the type of interrupt controller you
+                    have.
+- interrupt-parent: The phandle for the interrupt controller that
+                    services interrupts for this device.
+- fsl,mode:         The operating mode for the SSI interface.
+                    "i2s-slave" - I2S mode, SSI is clock slave
+                    "i2s-master" - I2S mode, SSI is clock master
+                    "lj-slave" - left-justified mode, SSI is clock slave
+                    "lj-master" - l.j. mode, SSI is clock master
+                    "rj-slave" - right-justified mode, SSI is clock slave
+                    "rj-master" - r.j., SSI is clock master
+                    "ac97-slave" - AC97 mode, SSI is clock slave
+                    "ac97-master" - AC97 mode, SSI is clock master
+- fsl,playback-dma: Phandle to a node for the DMA channel to use for
+                    playback of audio.  This is typically dictated by SOC
+                    design.  See the notes below.
+- fsl,capture-dma:  Phandle to a node for the DMA channel to use for
+                    capture (recording) of audio.  This is typically dictated
+                    by SOC design.  See the notes below.
+- fsl,fifo-depth:   The number of elements in the transmit and receive FIFOs.
+                    This number is the maximum allowed value for SFCSR[TFWM0].
+- fsl,ssi-asynchronous:
+                    If specified, the SSI is to be programmed in asynchronous
+                    mode.  In this mode, pins SRCK, STCK, SRFS, and STFS must
+                    all be connected to valid signals.  In synchronous mode,
+                    SRCK and SRFS are ignored.  Asynchronous mode allows
+                    playback and capture to use different sample sizes and
+                    sample rates.  Some drivers may require that SRCK and STCK
+                    be connected together, and SRFS and STFS be connected
+                    together.  This would still allow different sample sizes,
+                    but not different sample rates.
+
+Optional properties:
+- codec-handle:     Phandle to a 'codec' node that defines an audio
+                    codec connected to this SSI.  This node is typically
+                    a child of an I2C or other control node.
+
+Child 'codec' node required properties:
+- compatible:       Compatible list, contains the name of the codec
+
+Child 'codec' node optional properties:
+- clock-frequency:  The frequency of the input clock, which typically comes
+                    from an on-board dedicated oscillator.
+
+Notes on fsl,playback-dma and fsl,capture-dma:
+
+On SOCs that have an SSI, specific DMA channels are hard-wired for playback
+and capture.  On the MPC8610, for example, SSI1 must use DMA channel 0 for
+playback and DMA channel 1 for capture.  SSI2 must use DMA channel 2 for
+playback and DMA channel 3 for capture.  The developer can choose which
+DMA controller to use, but the channels themselves are hard-wired.  The
+purpose of these two properties is to represent this hardware design.
+
+The device tree nodes for the DMA channels that are referenced by
+"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
+"fsl,ssi-dma-channel".  The SOC-specific compatible string (e.g.
+"fsl,mpc8610-dma-channel") can remain.  If these nodes are left as
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
+drivers (fsldma) will attempt to use them, and it will conflict with the
+sound drivers.
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt b/Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt
new file mode 100644 (file)
index 0000000..b558585
--- /dev/null
@@ -0,0 +1,109 @@
+
+Nintendo GameCube device tree
+=============================
+
+1) The "flipper" node
+
+  This node represents the multi-function "Flipper" chip, which packages
+  many of the devices found in the Nintendo GameCube.
+
+  Required properties:
+
+   - compatible : Should be "nintendo,flipper"
+
+1.a) The Video Interface (VI) node
+
+  Represents the interface between the graphics processor and a external
+  video encoder.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-vi"
+   - reg : should contain the VI registers location and length
+   - interrupts : should contain the VI interrupt
+
+1.b) The Processor Interface (PI) node
+
+  Represents the data and control interface between the main processor
+  and graphics and audio processor.
+
+  Required properties:
+
+  - compatible : should be "nintendo,flipper-pi"
+  - reg : should contain the PI registers location and length
+
+1.b.i) The "Flipper" interrupt controller node
+
+  Represents the interrupt controller within the "Flipper" chip.
+  The node for the "Flipper" interrupt controller must be placed under
+  the PI node.
+
+  Required properties:
+
+  - compatible : should be "nintendo,flipper-pic"
+
+1.c) The Digital Signal Procesor (DSP) node
+
+  Represents the digital signal processor interface, designed to offload
+  audio related tasks.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-dsp"
+   - reg : should contain the DSP registers location and length
+   - interrupts : should contain the DSP interrupt
+
+1.c.i) The Auxiliary RAM (ARAM) node
+
+  Represents the non cpu-addressable ram designed mainly to store audio
+  related information.
+  The ARAM node must be placed under the DSP node.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-aram"
+   - reg : should contain the ARAM start (zero-based) and length
+
+1.d) The Disk Interface (DI) node
+
+  Represents the interface used to communicate with mass storage devices.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-di"
+   - reg : should contain the DI registers location and length
+   - interrupts : should contain the DI interrupt
+
+1.e) The Audio Interface (AI) node
+
+  Represents the interface to the external 16-bit stereo digital-to-analog
+  converter.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-ai"
+   - reg : should contain the AI registers location and length
+   - interrupts : should contain the AI interrupt
+
+1.f) The Serial Interface (SI) node
+
+  Represents the interface to the four single bit serial interfaces.
+  The SI is a proprietary serial interface used normally to control gamepads.
+  It's NOT a RS232-type interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-si"
+   - reg : should contain the SI registers location and length
+   - interrupts : should contain the SI interrupt
+
+1.g) The External Interface (EXI) node
+
+  Represents the multi-channel SPI-like interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-exi"
+   - reg : should contain the EXI registers location and length
+   - interrupts : should contain the EXI interrupt
+
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
new file mode 100644 (file)
index 0000000..a7e155a
--- /dev/null
@@ -0,0 +1,184 @@
+
+Nintendo Wii device tree
+========================
+
+0) The root node
+
+  This node represents the Nintendo Wii video game console.
+
+  Required properties:
+
+   - model : Should be "nintendo,wii"
+   - compatible : Should be "nintendo,wii"
+
+1) The "hollywood" node
+
+  This node represents the multi-function "Hollywood" chip, which packages
+  many of the devices found in the Nintendo Wii.
+
+  Required properties:
+
+   - compatible : Should be "nintendo,hollywood"
+
+1.a) The Video Interface (VI) node
+
+  Represents the interface between the graphics processor and a external
+  video encoder.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-vi","nintendo,flipper-vi"
+   - reg : should contain the VI registers location and length
+   - interrupts : should contain the VI interrupt
+
+1.b) The Processor Interface (PI) node
+
+  Represents the data and control interface between the main processor
+  and graphics and audio processor.
+
+  Required properties:
+
+  - compatible : should be "nintendo,hollywood-pi","nintendo,flipper-pi"
+  - reg : should contain the PI registers location and length
+
+1.b.i) The "Flipper" interrupt controller node
+
+  Represents the "Flipper" interrupt controller within the "Hollywood" chip.
+  The node for the "Flipper" interrupt controller must be placed under
+  the PI node.
+
+  Required properties:
+
+  - #interrupt-cells : <1>
+  - compatible : should be "nintendo,flipper-pic"
+  - interrupt-controller
+
+1.c) The Digital Signal Procesor (DSP) node
+
+  Represents the digital signal processor interface, designed to offload
+  audio related tasks.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-dsp","nintendo,flipper-dsp"
+   - reg : should contain the DSP registers location and length
+   - interrupts : should contain the DSP interrupt
+
+1.d) The Serial Interface (SI) node
+
+  Represents the interface to the four single bit serial interfaces.
+  The SI is a proprietary serial interface used normally to control gamepads.
+  It's NOT a RS232-type interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-si","nintendo,flipper-si"
+   - reg : should contain the SI registers location and length
+   - interrupts : should contain the SI interrupt
+
+1.e) The Audio Interface (AI) node
+
+  Represents the interface to the external 16-bit stereo digital-to-analog
+  converter.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-ai","nintendo,flipper-ai"
+   - reg : should contain the AI registers location and length
+   - interrupts : should contain the AI interrupt
+
+1.f) The External Interface (EXI) node
+
+  Represents the multi-channel SPI-like interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-exi","nintendo,flipper-exi"
+   - reg : should contain the EXI registers location and length
+   - interrupts : should contain the EXI interrupt
+
+1.g) The Open Host Controller Interface (OHCI) nodes
+
+  Represent the USB 1.x Open Host Controller Interfaces.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-usb-ohci","usb-ohci"
+   - reg : should contain the OHCI registers location and length
+   - interrupts : should contain the OHCI interrupt
+
+1.h) The Enhanced Host Controller Interface (EHCI) node
+
+  Represents the USB 2.0 Enhanced Host Controller Interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-usb-ehci","usb-ehci"
+   - reg : should contain the EHCI registers location and length
+   - interrupts : should contain the EHCI interrupt
+
+1.i) The Secure Digital Host Controller Interface (SDHCI) nodes
+
+  Represent the Secure Digital Host Controller Interfaces.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-sdhci","sdhci"
+   - reg : should contain the SDHCI registers location and length
+   - interrupts : should contain the SDHCI interrupt
+
+1.j) The Inter-Processsor Communication (IPC) node
+
+  Represent the Inter-Processor Communication interface. This interface
+  enables communications between the Broadway and the Starlet processors.
+
+   - compatible : should be "nintendo,hollywood-ipc"
+   - reg : should contain the IPC registers location and length
+   - interrupts : should contain the IPC interrupt
+
+1.k) The "Hollywood" interrupt controller node
+
+  Represents the "Hollywood" interrupt controller within the
+  "Hollywood" chip.
+
+  Required properties:
+
+  - #interrupt-cells : <1>
+  - compatible : should be "nintendo,hollywood-pic"
+  - reg : should contain the controller registers location and length
+  - interrupt-controller
+  - interrupts : should contain the cascade interrupt of the "flipper" pic
+  - interrupt-parent: should contain the phandle of the "flipper" pic
+
+1.l) The General Purpose I/O (GPIO) controller node
+
+  Represents the dual access 32 GPIO controller interface.
+
+  Required properties:
+
+  - #gpio-cells : <2>
+  - compatible : should be "nintendo,hollywood-gpio"
+  - reg : should contain the IPC registers location and length
+  - gpio-controller
+
+1.m) The control node
+
+  Represents the control interface used to setup several miscellaneous
+  settings of the "Hollywood" chip like boot memory mappings, resets,
+  disk interface mode, etc.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-control"
+   - reg : should contain the control registers location and length
+
+1.n) The Disk Interface (DI) node
+
+  Represents the interface used to communicate with mass storage devices.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-di"
+   - reg : should contain the DI registers location and length
+   - interrupts : should contain the DI interrupt
+
diff --git a/Documentation/devicetree/bindings/spi/fsl-spi.txt b/Documentation/devicetree/bindings/spi/fsl-spi.txt
new file mode 100644 (file)
index 0000000..777abd7
--- /dev/null
@@ -0,0 +1,53 @@
+* SPI (Serial Peripheral Interface)
+
+Required properties:
+- cell-index : QE SPI subblock index.
+               0: QE subblock SPI1
+               1: QE subblock SPI2
+- compatible : should be "fsl,spi".
+- mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
+- reg : Offset and length of the register set for the device
+- interrupts : <a b> where a is the interrupt number and b is a
+  field that represents an encoding of the sense and level
+  information for the interrupt.  This should be encoded based on
+  the information in section 2) depending on the type of interrupt
+  controller you have.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- gpios : specifies the gpio pins to be used for chipselects.
+  The gpios will be referred to as reg = <index> in the SPI child nodes.
+  If unspecified, a single SPI device without a chip select can be used.
+
+Example:
+       spi@4c0 {
+               cell-index = <0>;
+               compatible = "fsl,spi";
+               reg = <4c0 40>;
+               interrupts = <82 0>;
+               interrupt-parent = <700>;
+               mode = "cpu";
+               gpios = <&gpio 18 1     // device reg=<0>
+                        &gpio 19 1>;   // device reg=<1>
+       };
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+       spi@110000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc8536-espi";
+               reg = <0x110000 0x1000>;
+               interrupts = <53 0x2>;
+               interrupt-parent = <&mpic>;
+               fsl,espi-num-chipselects = <4>;
+       };
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
new file mode 100644 (file)
index 0000000..e782add
--- /dev/null
@@ -0,0 +1,57 @@
+SPI (Serial Peripheral Interface) busses
+
+SPI busses can be described with a node for the SPI master device
+and a set of child nodes for each SPI slave on the bus.  For this
+discussion, it is assumed that the system's SPI controller is in
+SPI master mode.  This binding does not describe SPI controllers
+in slave mode.
+
+The SPI master node requires the following properties:
+- #address-cells  - number of cells required to define a chip select
+               address on the SPI bus.
+- #size-cells     - should be zero.
+- compatible      - name of SPI bus controller following generic names
+               recommended practice.
+No other properties are required in the SPI bus node.  It is assumed
+that a driver for an SPI bus device will understand that it is an SPI bus.
+However, the binding does not attempt to define the specific method for
+assigning chip select numbers.  Since SPI chip select configuration is
+flexible and non-standardized, it is left out of this binding with the
+assumption that board specific platform code will be used to manage
+chip selects.  Individual drivers can define additional properties to
+support describing the chip select layout.
+
+SPI slave nodes must be children of the SPI master node and can
+contain the following properties.
+- reg             - (required) chip select address of device.
+- compatible      - (required) name of SPI device following generic names
+               recommended practice
+- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
+- spi-cpol        - (optional) Empty property indicating device requires
+               inverse clock polarity (CPOL) mode
+- spi-cpha        - (optional) Empty property indicating device requires
+               shifted clock phase (CPHA) mode
+- spi-cs-high     - (optional) Empty property indicating device requires
+               chip select active high
+
+SPI example for an MPC5200 SPI bus:
+       spi@f00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+               reg = <0xf00 0x20>;
+               interrupts = <2 13 0 2 14 0>;
+               interrupt-parent = <&mpc5200_pic>;
+
+               ethernet-switch@0 {
+                       compatible = "micrel,ks8995m";
+                       spi-max-frequency = <1000000>;
+                       reg = <0>;
+               };
+
+               codec@1 {
+                       compatible = "ti,tlv320aic26";
+                       spi-max-frequency = <100000>;
+                       reg = <1>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/usb/fsl-usb.txt b/Documentation/devicetree/bindings/usb/fsl-usb.txt
new file mode 100644 (file)
index 0000000..bd5723f
--- /dev/null
@@ -0,0 +1,81 @@
+Freescale SOC USB controllers
+
+The device node for a USB controller that is part of a Freescale
+SOC is as described in the document "Open Firmware Recommended
+Practice : Universal Serial Bus" with the following modifications
+and additions :
+
+Required properties :
+ - compatible : Should be "fsl-usb2-mph" for multi port host USB
+   controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
+ - phy_type : For multi port host USB controllers, should be one of
+   "ulpi", or "serial". For dual role USB controllers, should be
+   one of "ulpi", "utmi", "utmi_wide", or "serial".
+ - reg : Offset and length of the register set for the device
+ - port0 : boolean; if defined, indicates port0 is connected for
+   fsl-usb2-mph compatible controllers.  Either this property or
+   "port1" (or both) must be defined for "fsl-usb2-mph" compatible
+   controllers.
+ - port1 : boolean; if defined, indicates port1 is connected for
+   fsl-usb2-mph compatible controllers.  Either this property or
+   "port0" (or both) must be defined for "fsl-usb2-mph" compatible
+   controllers.
+ - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible
+   controllers.  Can be "host", "peripheral", or "otg".  Default to
+   "host" if not defined for backward compatibility.
+
+Recommended properties :
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
+   port power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
+   the PWR_FAULT signal polarity is inverted.
+
+Example multi port host USB controller device node :
+       usb@22000 {
+               compatible = "fsl-usb2-mph";
+               reg = <22000 1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = <700>;
+               interrupts = <27 1>;
+               phy_type = "ulpi";
+               port0;
+               port1;
+       };
+
+Example dual role USB controller device node :
+       usb@23000 {
+               compatible = "fsl-usb2-dr";
+               reg = <23000 1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = <700>;
+               interrupts = <26 1>;
+               dr_mode = "otg";
+               phy = "ulpi";
+       };
+
+Example dual role USB controller device node for MPC5121ADS:
+
+       usb@4000 {
+               compatible = "fsl,mpc5121-usb2-dr";
+               reg = <0x4000 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = < &ipic >;
+               interrupts = <44 0x8>;
+               dr_mode = "otg";
+               phy_type = "utmi_wide";
+               fsl,invert-drvvbus;
+               fsl,invert-pwr-fault;
+       };
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
new file mode 100644 (file)
index 0000000..fa18612
--- /dev/null
@@ -0,0 +1,25 @@
+USB EHCI controllers
+
+Required properties:
+  - compatible : should be "usb-ehci".
+  - reg : should contain at least address and length of the standard EHCI
+    register set for the device. Optional platform-dependent registers
+    (debug-port or other) can be also specified here, but only after
+    definition of standard EHCI registers.
+  - interrupts : one EHCI interrupt should be described here.
+If device registers are implemented in big endian mode, the device
+node should have "big-endian-regs" property.
+If controller implementation operates with big endian descriptors,
+"big-endian-desc" property should be specified.
+If both big endian registers and descriptors are used by the controller
+implementation, "big-endian" property can be specified instead of having
+both "big-endian-regs" and "big-endian-desc".
+
+Example (Sequoia 440EPx):
+    ehci@e0000300 {
+          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+          interrupt-parent = <&UIC0>;
+          interrupts = <1a 4>;
+          reg = <0 e0000300 90 0 e0000390 70>;
+          big-endian;
+   };
diff --git a/Documentation/devicetree/bindings/xilinx.txt b/Documentation/devicetree/bindings/xilinx.txt
new file mode 100644 (file)
index 0000000..299d092
--- /dev/null
@@ -0,0 +1,306 @@
+   d) Xilinx IP cores
+
+   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
+   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
+   of standard device types (network, serial, etc.) and miscellaneous
+   devices (gpio, LCD, spi, etc).  Also, since these devices are
+   implemented within the fpga fabric every instance of the device can be
+   synthesised with different options that change the behaviour.
+
+   Each IP-core has a set of parameters which the FPGA designer can use to
+   control how the core is synthesized.  Historically, the EDK tool would
+   extract the device parameters relevant to device drivers and copy them
+   into an 'xparameters.h' in the form of #define symbols.  This tells the
+   device drivers how the IP cores are configured, but it requires the kernel
+   to be recompiled every time the FPGA bitstream is resynthesized.
+
+   The new approach is to export the parameters into the device tree and
+   generate a new device tree each time the FPGA bitstream changes.  The
+   parameters which used to be exported as #defines will now become
+   properties of the device node.  In general, device nodes for IP-cores
+   will take the following form:
+
+       (name): (generic-name)@(base-address) {
+               compatible = "xlnx,(ip-core-name)-(HW_VER)"
+                            [, (list of compatible devices), ...];
+               reg = <(baseaddr) (size)>;
+               interrupt-parent = <&interrupt-controller-phandle>;
+               interrupts = < ... >;
+               xlnx,(parameter1) = "(string-value)";
+               xlnx,(parameter2) = <(int-value)>;
+       };
+
+       (generic-name):   an open firmware-style name that describes the
+                       generic class of device.  Preferably, this is one word, such
+                       as 'serial' or 'ethernet'.
+       (ip-core-name): the name of the ip block (given after the BEGIN
+                       directive in system.mhs).  Should be in lowercase
+                       and all underscores '_' converted to dashes '-'.
+       (name):         is derived from the "PARAMETER INSTANCE" value.
+       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
+                       dropped from the parameter name, the name is converted
+                       to lowercase and all underscore '_' characters are
+                       converted to dashes '-'.
+       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
+       (HW_VER):       from the HW_VER parameter.
+       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
+
+   Typically, the compatible list will include the exact IP core version
+   followed by an older IP core version which implements the same
+   interface or any other device with the same interface.
+
+   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
+
+   For example, the following block from system.mhs:
+
+       BEGIN opb_uartlite
+               PARAMETER INSTANCE = opb_uartlite_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BAUDRATE = 115200
+               PARAMETER C_DATA_BITS = 8
+               PARAMETER C_ODD_PARITY = 0
+               PARAMETER C_USE_PARITY = 0
+               PARAMETER C_CLK_FREQ = 50000000
+               PARAMETER C_BASEADDR = 0xEC100000
+               PARAMETER C_HIGHADDR = 0xEC10FFFF
+               BUS_INTERFACE SOPB = opb_7
+               PORT OPB_Clk = CLK_50MHz
+               PORT Interrupt = opb_uartlite_0_Interrupt
+               PORT RX = opb_uartlite_0_RX
+               PORT TX = opb_uartlite_0_TX
+               PORT OPB_Rst = sys_bus_reset_0
+       END
+
+   becomes the following device tree node:
+
+       opb_uartlite_0: serial@ec100000 {
+               device_type = "serial";
+               compatible = "xlnx,opb-uartlite-1.00.b";
+               reg = <ec100000 10000>;
+               interrupt-parent = <&opb_intc_0>;
+               interrupts = <1 0>; // got this from the opb_intc parameters
+               current-speed = <d#115200>;     // standard serial device prop
+               clock-frequency = <d#50000000>; // standard serial device prop
+               xlnx,data-bits = <8>;
+               xlnx,odd-parity = <0>;
+               xlnx,use-parity = <0>;
+       };
+
+   Some IP cores actually implement 2 or more logical devices.  In
+   this case, the device should still describe the whole IP core with
+   a single node and add a child node for each logical device.  The
+   ranges property can be used to translate from parent IP-core to the
+   registers of each device.  In addition, the parent node should be
+   compatible with the bus type 'xlnx,compound', and should contain
+   #address-cells and #size-cells, as with any other bus.  (Note: this
+   makes the assumption that both logical devices have the same bus
+   binding.  If this is not true, then separate nodes should be used
+   for each logical device).  The 'cell-index' property can be used to
+   enumerate logical devices within an IP core.  For example, the
+   following is the system.mhs entry for the dual ps2 controller found
+   on the ml403 reference design.
+
+       BEGIN opb_ps2_dual_ref
+               PARAMETER INSTANCE = opb_ps2_dual_ref_0
+               PARAMETER HW_VER = 1.00.a
+               PARAMETER C_BASEADDR = 0xA9000000
+               PARAMETER C_HIGHADDR = 0xA9001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+               PORT Sys_Intr1 = ps2_1_intr
+               PORT Sys_Intr2 = ps2_2_intr
+               PORT Clkin1 = ps2_clk_rx_1
+               PORT Clkin2 = ps2_clk_rx_2
+               PORT Clkpd1 = ps2_clk_tx_1
+               PORT Clkpd2 = ps2_clk_tx_2
+               PORT Rx1 = ps2_d_rx_1
+               PORT Rx2 = ps2_d_rx_2
+               PORT Txpd1 = ps2_d_tx_1
+               PORT Txpd2 = ps2_d_tx_2
+       END
+
+   It would result in the following device tree nodes:
+
+       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,compound";
+               ranges = <0 a9000000 2000>;
+               // If this device had extra parameters, then they would
+               // go here.
+               ps2@0 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <0 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+               ps2@1000 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <1000 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+       };
+
+   Also, the system.mhs file defines bus attachments from the processor
+   to the devices.  The device tree structure should reflect the bus
+   attachments.  Again an example; this system.mhs fragment:
+
+       BEGIN ppc405_virtex4
+               PARAMETER INSTANCE = ppc405_0
+               PARAMETER HW_VER = 1.01.a
+               BUS_INTERFACE DPLB = plb_v34_0
+               BUS_INTERFACE IPLB = plb_v34_0
+       END
+
+       BEGIN opb_intc
+               PARAMETER INSTANCE = opb_intc_0
+               PARAMETER HW_VER = 1.00.c
+               PARAMETER C_BASEADDR = 0xD1000FC0
+               PARAMETER C_HIGHADDR = 0xD1000FDF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN opb_uart16550
+               PARAMETER INSTANCE = opb_uart16550_0
+               PARAMETER HW_VER = 1.00.d
+               PARAMETER C_BASEADDR = 0xa0000000
+               PARAMETER C_HIGHADDR = 0xa0001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN plb_v34
+               PARAMETER INSTANCE = plb_v34_0
+               PARAMETER HW_VER = 1.02.a
+       END
+
+       BEGIN plb_bram_if_cntlr
+               PARAMETER INSTANCE = plb_bram_if_cntlr_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BASEADDR = 0xFFFF0000
+               PARAMETER C_HIGHADDR = 0xFFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+       END
+
+       BEGIN plb2opb_bridge
+               PARAMETER INSTANCE = plb2opb_bridge_0
+               PARAMETER HW_VER = 1.01.a
+               PARAMETER C_RNG0_BASEADDR = 0x20000000
+               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
+               PARAMETER C_RNG1_BASEADDR = 0x60000000
+               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
+               PARAMETER C_RNG2_BASEADDR = 0x80000000
+               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
+               PARAMETER C_RNG3_BASEADDR = 0xC0000000
+               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+               BUS_INTERFACE MOPB = opb_v20_0
+       END
+
+   Gives this device tree (some properties removed for clarity):
+
+       plb@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,plb-v34-1.02.a";
+               device_type = "ibm,plb";
+               ranges; // 1:1 translation
+
+               plb_bram_if_cntrl_0: bram@ffff0000 {
+                       reg = <ffff0000 10000>;
+               }
+
+               opb@20000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <20000000 20000000 20000000
+                                 60000000 60000000 20000000
+                                 80000000 80000000 40000000
+                                 c0000000 c0000000 20000000>;
+
+                       opb_uart16550_0: serial@a0000000 {
+                               reg = <a00000000 2000>;
+                       };
+
+                       opb_intc_0: interrupt-controller@d1000fc0 {
+                               reg = <d1000fc0 20>;
+                       };
+               };
+       };
+
+   That covers the general approach to binding xilinx IP cores into the
+   device tree.  The following are bindings for specific devices:
+
+      i) Xilinx ML300 Framebuffer
+
+      Simple framebuffer device from the ML300 reference design (also on the
+      ML403 reference design as well as others).
+
+      Optional properties:
+       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
+                                    implementations use a different resolution.
+                                    Default is <d#640 d#480>
+       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
+                                           Default is <d#1024 d#480>.
+       - rotate-display (empty) : rotate display 180 degrees.
+
+      ii) Xilinx SystemACE
+
+      The Xilinx SystemACE device is used to program FPGAs from an FPGA
+      bitstream stored on a CF card.  It can also be used as a generic CF
+      interface device.
+
+      Optional properties:
+       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
+
+      iii) Xilinx EMAC and Xilinx TEMAC
+
+      Xilinx Ethernet devices.  In addition to general xilinx properties
+      listed above, nodes for these devices should include a phy-handle
+      property, and may include other common network device properties
+      like local-mac-address.
+
+      iv) Xilinx Uartlite
+
+      Xilinx uartlite devices are simple fixed speed serial ports.
+
+      Required properties:
+       - current-speed : Baud rate of uartlite
+
+      v) Xilinx hwicap
+
+               Xilinx hwicap devices provide access to the configuration logic
+               of the FPGA through the Internal Configuration Access Port
+               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
+               readback of the configuration information, and some control over
+               'warm boots' of the FPGA fabric.
+
+               Required properties:
+               - xlnx,family : The family of the FPGA, necessary since the
+                      capabilities of the underlying ICAP hardware
+                      differ between different families.  May be
+                      'virtex2p', 'virtex4', or 'virtex5'.
+
+      vi) Xilinx Uart 16550
+
+      Xilinx UART 16550 devices are very similar to the NS16550 but with
+      different register spacing and an offset from the base address.
+
+      Required properties:
+       - clock-frequency : Frequency of the clock input
+       - reg-offset : A value of 3 is required
+       - reg-shift : A value of 2 is required
+
+      vii) Xilinx USB Host controller
+
+      The Xilinx USB host controller is EHCI compatible but with a different
+      base address for the EHCI registers, and it is always a big-endian
+      USB Host controller. The hardware can be configured as high speed only,
+      or high speed/full speed hybrid.
+
+      Required properties:
+      - xlnx,support-usb-fs: A value 0 means the core is built as high speed
+                             only. A value 1 means the core also supports
+                             full speed devices.
+
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt
new file mode 100644 (file)
index 0000000..28b1c9d
--- /dev/null
@@ -0,0 +1,1390 @@
+           Booting the Linux/ppc kernel without Open Firmware
+           --------------------------------------------------
+
+(c) 2005 Benjamin Herrenschmidt <benh at kernel.crashing.org>,
+    IBM Corp.
+(c) 2005 Becky Bruce <becky.bruce at freescale.com>,
+    Freescale Semiconductor, FSL SOC and 32-bit additions
+(c) 2006 MontaVista Software, Inc.
+    Flash chip node definition
+
+Table of Contents
+=================
+
+  I - Introduction
+    1) Entry point for arch/powerpc
+
+  II - The DT block format
+    1) Header
+    2) Device tree generalities
+    3) Device tree "structure" block
+    4) Device tree "strings" block
+
+  III - Required content of the device tree
+    1) Note about cells and address representation
+    2) Note about "compatible" properties
+    3) Note about "name" properties
+    4) Note about node and property names and character set
+    5) Required nodes and properties
+      a) The root node
+      b) The /cpus node
+      c) The /cpus/* nodes
+      d) the /memory node(s)
+      e) The /chosen node
+      f) the /soc<SOCname> node
+
+  IV - "dtc", the device tree compiler
+
+  V - Recommendations for a bootloader
+
+  VI - System-on-a-chip devices and nodes
+    1) Defining child nodes of an SOC
+    2) Representing devices without a current OF specification
+
+  VII - Specifying interrupt information for devices
+    1) interrupts property
+    2) interrupt-parent property
+    3) OpenPIC Interrupt Controllers
+    4) ISA Interrupt Controllers
+
+  VIII - Specifying device power management information (sleep property)
+
+  Appendix A - Sample SOC node for MPC8540
+
+
+Revision Information
+====================
+
+   May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet.
+
+   May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or
+                           clarifies the fact that a lot of things are
+                           optional, the kernel only requires a very
+                           small device tree, though it is encouraged
+                           to provide an as complete one as possible.
+
+   May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM
+                        - Misc fixes
+                        - Define version 3 and new format version 16
+                          for the DT block (version 16 needs kernel
+                          patches, will be fwd separately).
+                          String block now has a size, and full path
+                          is replaced by unit name for more
+                          compactness.
+                          linux,phandle is made optional, only nodes
+                          that are referenced by other nodes need it.
+                          "name" property is now automatically
+                          deduced from the unit name
+
+   June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and
+                           OF_DT_END_NODE in structure definition.
+                         - Change version 16 format to always align
+                           property data to 4 bytes. Since tokens are
+                           already aligned, that means no specific
+                           required alignment between property size
+                           and property data. The old style variable
+                           alignment would make it impossible to do
+                           "simple" insertion of properties using
+                           memmove (thanks Milton for
+                           noticing). Updated kernel patch as well
+                        - Correct a few more alignment constraints
+                        - Add a chapter about the device-tree
+                           compiler and the textural representation of
+                           the tree that can be "compiled" by dtc.
+
+   November 21, 2005: Rev 0.5
+                        - Additions/generalizations for 32-bit
+                        - Changed to reflect the new arch/powerpc
+                          structure
+                        - Added chapter VI
+
+
+ ToDo:
+       - Add some definitions of interrupt tree (simple/complex)
+       - Add some definitions for PCI host bridges
+       - Add some common address format examples
+       - Add definitions for standard properties and "compatible"
+         names for cells that are not already defined by the existing
+         OF spec.
+       - Compare FSL SOC use of PCI to standard and make sure no new
+         node definition required.
+       - Add more information about node definitions for SOC devices
+         that currently have no standard, like the FSL CPM.
+
+
+I - Introduction
+================
+
+During the development of the Linux/ppc64 kernel, and more
+specifically, the addition of new platform types outside of the old
+IBM pSeries/iSeries pair, it was decided to enforce some strict rules
+regarding the kernel entry and bootloader <-> kernel interfaces, in
+order to avoid the degeneration that had become the ppc32 kernel entry
+point and the way a new platform should be added to the kernel. The
+legacy iSeries platform breaks those rules as it predates this scheme,
+but no new board support will be accepted in the main tree that
+doesn't follow them properly.  In addition, since the advent of the
+arch/powerpc merged architecture for ppc32 and ppc64, new 32-bit
+platforms and 32-bit platforms which move into arch/powerpc will be
+required to use these rules as well.
+
+The main requirement that will be defined in more detail below is
+the presence of a device-tree whose format is defined after Open
+Firmware specification. However, in order to make life easier
+to embedded board vendors, the kernel doesn't require the device-tree
+to represent every device in the system and only requires some nodes
+and properties to be present. This will be described in detail in
+section III, but, for example, the kernel does not require you to
+create a node for every PCI device in the system. It is a requirement
+to have a node for PCI host bridges in order to provide interrupt
+routing informations and memory/IO ranges, among others. It is also
+recommended to define nodes for on chip devices and other buses that
+don't specifically fit in an existing OF specification. This creates a
+great flexibility in the way the kernel can then probe those and match
+drivers to device, without having to hard code all sorts of tables. It
+also makes it more flexible for board vendors to do minor hardware
+upgrades without significantly impacting the kernel code or cluttering
+it with special cases.
+
+
+1) Entry point for arch/powerpc
+-------------------------------
+
+   There is one single entry point to the kernel, at the start
+   of the kernel image. That entry point supports two calling
+   conventions:
+
+        a) Boot from Open Firmware. If your firmware is compatible
+        with Open Firmware (IEEE 1275) or provides an OF compatible
+        client interface API (support for "interpret" callback of
+        forth words isn't required), you can enter the kernel with:
+
+              r5 : OF callback pointer as defined by IEEE 1275
+              bindings to powerpc. Only the 32-bit client interface
+              is currently supported
+
+              r3, r4 : address & length of an initrd if any or 0
+
+              The MMU is either on or off; the kernel will run the
+              trampoline located in arch/powerpc/kernel/prom_init.c to
+              extract the device-tree and other information from open
+              firmware and build a flattened device-tree as described
+              in b). prom_init() will then re-enter the kernel using
+              the second method. This trampoline code runs in the
+              context of the firmware, which is supposed to handle all
+              exceptions during that time.
+
+        b) Direct entry with a flattened device-tree block. This entry
+        point is called by a) after the OF trampoline and can also be
+        called directly by a bootloader that does not support the Open
+        Firmware client interface. It is also used by "kexec" to
+        implement "hot" booting of a new kernel from a previous
+        running one. This method is what I will describe in more
+        details in this document, as method a) is simply standard Open
+        Firmware, and thus should be implemented according to the
+        various standard documents defining it and its binding to the
+        PowerPC platform. The entry point definition then becomes:
+
+                r3 : physical pointer to the device-tree block
+                (defined in chapter II) in RAM
+
+                r4 : physical pointer to the kernel itself. This is
+                used by the assembly code to properly disable the MMU
+                in case you are entering the kernel with MMU enabled
+                and a non-1:1 mapping.
+
+                r5 : NULL (as to differentiate with method a)
+
+        Note about SMP entry: Either your firmware puts your other
+        CPUs in some sleep loop or spin loop in ROM where you can get
+        them out via a soft reset or some other means, in which case
+        you don't need to care, or you'll have to enter the kernel
+        with all CPUs. The way to do that with method b) will be
+        described in a later revision of this document.
+
+   Board supports (platforms) are not exclusive config options. An
+   arbitrary set of board supports can be built in a single kernel
+   image. The kernel will "know" what set of functions to use for a
+   given platform based on the content of the device-tree. Thus, you
+   should:
+
+        a) add your platform support as a _boolean_ option in
+        arch/powerpc/Kconfig, following the example of PPC_PSERIES,
+        PPC_PMAC and PPC_MAPLE. The later is probably a good
+        example of a board support to start from.
+
+        b) create your main platform file as
+        "arch/powerpc/platforms/myplatform/myboard_setup.c" and add it
+        to the Makefile under the condition of your CONFIG_
+        option. This file will define a structure of type "ppc_md"
+        containing the various callbacks that the generic code will
+        use to get to your platform specific code
+
+  A kernel image may support multiple platforms, but only if the
+  platforms feature the same core architecture.  A single kernel build
+  cannot support both configurations with Book E and configurations
+  with classic Powerpc architectures.
+
+
+II - The DT block format
+========================
+
+
+This chapter defines the actual format of the flattened device-tree
+passed to the kernel. The actual content of it and kernel requirements
+are described later. You can find example of code manipulating that
+format in various places, including arch/powerpc/kernel/prom_init.c
+which will generate a flattened device-tree from the Open Firmware
+representation, or the fs2dt utility which is part of the kexec tools
+which will generate one from a filesystem representation. It is
+expected that a bootloader like uboot provides a bit more support,
+that will be discussed later as well.
+
+Note: The block has to be in main memory. It has to be accessible in
+both real mode and virtual mode with no mapping other than main
+memory. If you are writing a simple flash bootloader, it should copy
+the block to RAM before passing it to the kernel.
+
+
+1) Header
+---------
+
+   The kernel is passed the physical address pointing to an area of memory
+   that is roughly described in include/linux/of_fdt.h by the structure
+   boot_param_header:
+
+struct boot_param_header {
+        u32     magic;                  /* magic word OF_DT_HEADER */
+        u32     totalsize;              /* total size of DT block */
+        u32     off_dt_struct;          /* offset to structure */
+        u32     off_dt_strings;         /* offset to strings */
+        u32     off_mem_rsvmap;         /* offset to memory reserve map
+                                           */
+        u32     version;                /* format version */
+        u32     last_comp_version;      /* last compatible version */
+
+        /* version 2 fields below */
+        u32     boot_cpuid_phys;        /* Which physical CPU id we're
+                                           booting on */
+        /* version 3 fields below */
+        u32     size_dt_strings;        /* size of the strings block */
+
+        /* version 17 fields below */
+        u32    size_dt_struct;         /* size of the DT structure block */
+};
+
+   Along with the constants:
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER            0xd00dfeed      /* 4: version,
+                                                  4: total size */
+#define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
+                                                  */
+#define OF_DT_END_NODE          0x2             /* End node */
+#define OF_DT_PROP              0x3             /* Property: name off,
+                                                   size, content */
+#define OF_DT_END               0x9
+
+   All values in this header are in big endian format, the various
+   fields in this header are defined more precisely below. All
+   "offset" values are in bytes from the start of the header; that is
+   from the physical base address of the device tree block.
+
+   - magic
+
+     This is a magic value that "marks" the beginning of the
+     device-tree block header. It contains the value 0xd00dfeed and is
+     defined by the constant OF_DT_HEADER
+
+   - totalsize
+
+     This is the total size of the DT block including the header. The
+     "DT" block should enclose all data structures defined in this
+     chapter (who are pointed to by offsets in this header). That is,
+     the device-tree structure, strings, and the memory reserve map.
+
+   - off_dt_struct
+
+     This is an offset from the beginning of the header to the start
+     of the "structure" part the device tree. (see 2) device tree)
+
+   - off_dt_strings
+
+     This is an offset from the beginning of the header to the start
+     of the "strings" part of the device-tree
+
+   - off_mem_rsvmap
+
+     This is an offset from the beginning of the header to the start
+     of the reserved memory map. This map is a list of pairs of 64-
+     bit integers. Each pair is a physical address and a size. The
+     list is terminated by an entry of size 0. This map provides the
+     kernel with a list of physical memory areas that are "reserved"
+     and thus not to be used for memory allocations, especially during
+     early initialization. The kernel needs to allocate memory during
+     boot for things like un-flattening the device-tree, allocating an
+     MMU hash table, etc... Those allocations must be done in such a
+     way to avoid overriding critical things like, on Open Firmware
+     capable machines, the RTAS instance, or on some pSeries, the TCE
+     tables used for the iommu. Typically, the reserve map should
+     contain _at least_ this DT block itself (header,total_size). If
+     you are passing an initrd to the kernel, you should reserve it as
+     well. You do not need to reserve the kernel image itself. The map
+     should be 64-bit aligned.
+
+   - version
+
+     This is the version of this structure. Version 1 stops
+     here. Version 2 adds an additional field boot_cpuid_phys.
+     Version 3 adds the size of the strings block, allowing the kernel
+     to reallocate it easily at boot and free up the unused flattened
+     structure after expansion. Version 16 introduces a new more
+     "compact" format for the tree itself that is however not backward
+     compatible. Version 17 adds an additional field, size_dt_struct,
+     allowing it to be reallocated or moved more easily (this is
+     particularly useful for bootloaders which need to make
+     adjustments to a device tree based on probed information). You
+     should always generate a structure of the highest version defined
+     at the time of your implementation. Currently that is version 17,
+     unless you explicitly aim at being backward compatible.
+
+   - last_comp_version
+
+     Last compatible version. This indicates down to what version of
+     the DT block you are backward compatible. For example, version 2
+     is backward compatible with version 1 (that is, a kernel build
+     for version 1 will be able to boot with a version 2 format). You
+     should put a 1 in this field if you generate a device tree of
+     version 1 to 3, or 16 if you generate a tree of version 16 or 17
+     using the new unit name format.
+
+   - boot_cpuid_phys
+
+     This field only exist on version 2 headers. It indicate which
+     physical CPU ID is calling the kernel entry point. This is used,
+     among others, by kexec. If you are on an SMP system, this value
+     should match the content of the "reg" property of the CPU node in
+     the device-tree corresponding to the CPU calling the kernel entry
+     point (see further chapters for more informations on the required
+     device-tree contents)
+
+   - size_dt_strings
+
+     This field only exists on version 3 and later headers.  It
+     gives the size of the "strings" section of the device tree (which
+     starts at the offset given by off_dt_strings).
+
+   - size_dt_struct
+
+     This field only exists on version 17 and later headers.  It gives
+     the size of the "structure" section of the device tree (which
+     starts at the offset given by off_dt_struct).
+
+   So the typical layout of a DT block (though the various parts don't
+   need to be in that order) looks like this (addresses go from top to
+   bottom):
+
+
+             ------------------------------
+     base -> |  struct boot_param_header  |
+             ------------------------------
+             |      (alignment gap) (*)   |
+             ------------------------------
+             |      memory reserve map    |
+             ------------------------------
+             |      (alignment gap)       |
+             ------------------------------
+             |                            |
+             |    device-tree structure   |
+             |                            |
+             ------------------------------
+             |      (alignment gap)       |
+             ------------------------------
+             |                            |
+             |     device-tree strings    |
+             |                            |
+      -----> ------------------------------
+      |
+      |
+      --- (base + totalsize)
+
+  (*) The alignment gaps are not necessarily present; their presence
+      and size are dependent on the various alignment requirements of
+      the individual data blocks.
+
+
+2) Device tree generalities
+---------------------------
+
+This device-tree itself is separated in two different blocks, a
+structure block and a strings block. Both need to be aligned to a 4
+byte boundary.
+
+First, let's quickly describe the device-tree concept before detailing
+the storage format. This chapter does _not_ describe the detail of the
+required types of nodes & properties for the kernel, this is done
+later in chapter III.
+
+The device-tree layout is strongly inherited from the definition of
+the Open Firmware IEEE 1275 device-tree. It's basically a tree of
+nodes, each node having two or more named properties. A property can
+have a value or not.
+
+It is a tree, so each node has one and only one parent except for the
+root node who has no parent.
+
+A node has 2 names. The actual node name is generally contained in a
+property of type "name" in the node property list whose value is a
+zero terminated string and is mandatory for version 1 to 3 of the
+format definition (as it is in Open Firmware). Version 16 makes it
+optional as it can generate it from the unit name defined below.
+
+There is also a "unit name" that is used to differentiate nodes with
+the same name at the same level, it is usually made of the node
+names, the "@" sign, and a "unit address", which definition is
+specific to the bus type the node sits on.
+
+The unit name doesn't exist as a property per-se but is included in
+the device-tree structure. It is typically used to represent "path" in
+the device-tree. More details about the actual format of these will be
+below.
+
+The kernel generic code does not make any formal use of the
+unit address (though some board support code may do) so the only real
+requirement here for the unit address is to ensure uniqueness of
+the node unit name at a given level of the tree. Nodes with no notion
+of address and no possible sibling of the same name (like /memory or
+/cpus) may omit the unit address in the context of this specification,
+or use the "@0" default unit address. The unit name is used to define
+a node "full path", which is the concatenation of all parent node
+unit names separated with "/".
+
+The root node doesn't have a defined name, and isn't required to have
+a name property either if you are using version 3 or earlier of the
+format. It also has no unit address (no @ symbol followed by a unit
+address). The root node unit name is thus an empty string. The full
+path to the root node is "/".
+
+Every node which actually represents an actual device (that is, a node
+which isn't only a virtual "container" for more nodes, like "/cpus"
+is) is also required to have a "compatible" property indicating the
+specific hardware and an optional list of devices it is fully
+backwards compatible with.
+
+Finally, every node that can be referenced from a property in another
+node is required to have either a "phandle" or a "linux,phandle"
+property. Real Open Firmware implementations provide a unique
+"phandle" value for every node that the "prom_init()" trampoline code
+turns into "linux,phandle" properties. However, this is made optional
+if the flattened device tree is used directly. An example of a node
+referencing another node via "phandle" is when laying out the
+interrupt tree which will be described in a further version of this
+document.
+
+The "phandle" property is a 32-bit value that uniquely
+identifies a node. You are free to use whatever values or system of
+values, internal pointers, or whatever to generate these, the only
+requirement is that every node for which you provide that property has
+a unique value for it.
+
+Here is an example of a simple device-tree. In this example, an "o"
+designates a node followed by the node unit name. Properties are
+presented with their name followed by their content. "content"
+represents an ASCII string (zero terminated) value, while <content>
+represents a 32-bit hexadecimal value. The various nodes in this
+example will be discussed in a later chapter. At this point, it is
+only meant to give you a idea of what a device-tree looks like. I have
+purposefully kept the "name" and "linux,phandle" properties which
+aren't necessary in order to give you a better idea of what the tree
+looks like in practice.
+
+  / o device-tree
+      |- name = "device-tree"
+      |- model = "MyBoardName"
+      |- compatible = "MyBoardFamilyName"
+      |- #address-cells = <2>
+      |- #size-cells = <2>
+      |- linux,phandle = <0>
+      |
+      o cpus
+      | | - name = "cpus"
+      | | - linux,phandle = <1>
+      | | - #address-cells = <1>
+      | | - #size-cells = <0>
+      | |
+      | o PowerPC,970@0
+      |   |- name = "PowerPC,970"
+      |   |- device_type = "cpu"
+      |   |- reg = <0>
+      |   |- clock-frequency = <5f5e1000>
+      |   |- 64-bit
+      |   |- linux,phandle = <2>
+      |
+      o memory@0
+      | |- name = "memory"
+      | |- device_type = "memory"
+      | |- reg = <00000000 00000000 00000000 20000000>
+      | |- linux,phandle = <3>
+      |
+      o chosen
+        |- name = "chosen"
+        |- bootargs = "root=/dev/sda2"
+        |- linux,phandle = <4>
+
+This tree is almost a minimal tree. It pretty much contains the
+minimal set of required nodes and properties to boot a linux kernel;
+that is, some basic model informations at the root, the CPUs, and the
+physical memory layout.  It also includes misc information passed
+through /chosen, like in this example, the platform type (mandatory)
+and the kernel command line arguments (optional).
+
+The /cpus/PowerPC,970@0/64-bit property is an example of a
+property without a value. All other properties have a value. The
+significance of the #address-cells and #size-cells properties will be
+explained in chapter IV which defines precisely the required nodes and
+properties and their content.
+
+
+3) Device tree "structure" block
+
+The structure of the device tree is a linearized tree structure. The
+"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
+ends that node definition. Child nodes are simply defined before
+"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
+bit value. The tree has to be "finished" with a OF_DT_END token
+
+Here's the basic structure of a single node:
+
+     * token OF_DT_BEGIN_NODE (that is 0x00000001)
+     * for version 1 to 3, this is the node full path as a zero
+       terminated string, starting with "/". For version 16 and later,
+       this is the node unit name only (or an empty string for the
+       root node)
+     * [align gap to next 4 bytes boundary]
+     * for each property:
+        * token OF_DT_PROP (that is 0x00000003)
+        * 32-bit value of property value size in bytes (or 0 if no
+          value)
+        * 32-bit value of offset in string block of property name
+        * property value data if any
+        * [align gap to next 4 bytes boundary]
+     * [child nodes if any]
+     * token OF_DT_END_NODE (that is 0x00000002)
+
+So the node content can be summarized as a start token, a full path,
+a list of properties, a list of child nodes, and an end token. Every
+child node is a full node structure itself as defined above.
+
+NOTE: The above definition requires that all property definitions for
+a particular node MUST precede any subnode definitions for that node.
+Although the structure would not be ambiguous if properties and
+subnodes were intermingled, the kernel parser requires that the
+properties come first (up until at least 2.6.22).  Any tools
+manipulating a flattened tree must take care to preserve this
+constraint.
+
+4) Device tree "strings" block
+
+In order to save space, property names, which are generally redundant,
+are stored separately in the "strings" block. This block is simply the
+whole bunch of zero terminated strings for all property names
+concatenated together. The device-tree property definitions in the
+structure block will contain offset values from the beginning of the
+strings block.
+
+
+III - Required content of the device tree
+=========================================
+
+WARNING: All "linux,*" properties defined in this document apply only
+to a flattened device-tree. If your platform uses a real
+implementation of Open Firmware or an implementation compatible with
+the Open Firmware client interface, those properties will be created
+by the trampoline code in the kernel's prom_init() file. For example,
+that's where you'll have to add code to detect your board model and
+set the platform number. However, when using the flattened device-tree
+entry point, there is no prom_init() pass, and thus you have to
+provide those properties yourself.
+
+
+1) Note about cells and address representation
+----------------------------------------------
+
+The general rule is documented in the various Open Firmware
+documentations. If you choose to describe a bus with the device-tree
+and there exist an OF bus binding, then you should follow the
+specification. However, the kernel does not require every single
+device or bus to be described by the device tree.
+
+In general, the format of an address for a device is defined by the
+parent bus type, based on the #address-cells and #size-cells
+properties.  Note that the parent's parent definitions of #address-cells
+and #size-cells are not inherited so every node with children must specify
+them.  The kernel requires the root node to have those properties defining
+addresses format for devices directly mapped on the processor bus.
+
+Those 2 properties define 'cells' for representing an address and a
+size. A "cell" is a 32-bit number. For example, if both contain 2
+like the example tree given above, then an address and a size are both
+composed of 2 cells, and each is a 64-bit number (cells are
+concatenated and expected to be in big endian format). Another example
+is the way Apple firmware defines them, with 2 cells for an address
+and one cell for a size.  Most 32-bit implementations should define
+#address-cells and #size-cells to 1, which represents a 32-bit value.
+Some 32-bit processors allow for physical addresses greater than 32
+bits; these processors should define #address-cells as 2.
+
+"reg" properties are always a tuple of the type "address size" where
+the number of cells of address and size is specified by the bus
+#address-cells and #size-cells. When a bus supports various address
+spaces and other flags relative to a given address allocation (like
+prefetchable, etc...) those flags are usually added to the top level
+bits of the physical address. For example, a PCI physical address is
+made of 3 cells, the bottom two containing the actual address itself
+while the top cell contains address space indication, flags, and pci
+bus & device numbers.
+
+For buses that support dynamic allocation, it's the accepted practice
+to then not provide the address in "reg" (keep it 0) though while
+providing a flag indicating the address is dynamically allocated, and
+then, to provide a separate "assigned-addresses" property that
+contains the fully allocated addresses. See the PCI OF bindings for
+details.
+
+In general, a simple bus with no address space bits and no dynamic
+allocation is preferred if it reflects your hardware, as the existing
+kernel address parsing functions will work out of the box. If you
+define a bus type with a more complex address format, including things
+like address space bits, you'll have to add a bus translator to the
+prom_parse.c file of the recent kernels for your bus type.
+
+The "reg" property only defines addresses and sizes (if #size-cells is
+non-0) within a given bus. In order to translate addresses upward
+(that is into parent bus addresses, and possibly into CPU physical
+addresses), all buses must contain a "ranges" property. If the
+"ranges" property is missing at a given level, it's assumed that
+translation isn't possible, i.e., the registers are not visible on the
+parent bus.  The format of the "ranges" property for a bus is a list
+of:
+
+       bus address, parent bus address, size
+
+"bus address" is in the format of the bus this bus node is defining,
+that is, for a PCI bridge, it would be a PCI address. Thus, (bus
+address, size) defines a range of addresses for child devices. "parent
+bus address" is in the format of the parent bus of this bus. For
+example, for a PCI host controller, that would be a CPU address. For a
+PCI<->ISA bridge, that would be a PCI address. It defines the base
+address in the parent bus where the beginning of that range is mapped.
+
+For new 64-bit board support, I recommend either the 2/2 format or
+Apple's 2/1 format which is slightly more compact since sizes usually
+fit in a single 32-bit word.   New 32-bit board support should use a
+1/1 format, unless the processor supports physical addresses greater
+than 32-bits, in which case a 2/1 format is recommended.
+
+Alternatively, the "ranges" property may be empty, indicating that the
+registers are visible on the parent bus using an identity mapping
+translation.  In other words, the parent bus address space is the same
+as the child bus address space.
+
+2) Note about "compatible" properties
+-------------------------------------
+
+These properties are optional, but recommended in devices and the root
+node. The format of a "compatible" property is a list of concatenated
+zero terminated strings. They allow a device to express its
+compatibility with a family of similar devices, in some cases,
+allowing a single driver to match against several devices regardless
+of their actual names.
+
+3) Note about "name" properties
+-------------------------------
+
+While earlier users of Open Firmware like OldWorld macintoshes tended
+to use the actual device name for the "name" property, it's nowadays
+considered a good practice to use a name that is closer to the device
+class (often equal to device_type). For example, nowadays, Ethernet
+controllers are named "ethernet", an additional "model" property
+defining precisely the chip type/model, and "compatible" property
+defining the family in case a single driver can driver more than one
+of these chips. However, the kernel doesn't generally put any
+restriction on the "name" property; it is simply considered good
+practice to follow the standard and its evolutions as closely as
+possible.
+
+Note also that the new format version 16 makes the "name" property
+optional. If it's absent for a node, then the node's unit name is then
+used to reconstruct the name. That is, the part of the unit name
+before the "@" sign is used (or the entire unit name if no "@" sign
+is present).
+
+4) Note about node and property names and character set
+-------------------------------------------------------
+
+While Open Firmware provides more flexible usage of 8859-1, this
+specification enforces more strict rules. Nodes and properties should
+be comprised only of ASCII characters 'a' to 'z', '0' to
+'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
+allow uppercase characters 'A' to 'Z' (property names should be
+lowercase. The fact that vendors like Apple don't respect this rule is
+irrelevant here). Additionally, node and property names should always
+begin with a character in the range 'a' to 'z' (or 'A' to 'Z' for node
+names).
+
+The maximum number of characters for both nodes and property names
+is 31. In the case of node names, this is only the leftmost part of
+a unit name (the pure "name" property), it doesn't include the unit
+address which can extend beyond that limit.
+
+
+5) Required nodes and properties
+--------------------------------
+  These are all that are currently required. However, it is strongly
+  recommended that you expose PCI host bridges as documented in the
+  PCI binding to Open Firmware, and your interrupt tree as documented
+  in OF interrupt tree specification.
+
+  a) The root node
+
+  The root node requires some properties to be present:
+
+    - model : this is your board name/model
+    - #address-cells : address representation for "root" devices
+    - #size-cells: the size representation for "root" devices
+    - compatible : the board "family" generally finds its way here,
+      for example, if you have 2 board models with a similar layout,
+      that typically get driven by the same platform code in the
+      kernel, you would specify the exact board model in the
+      compatible property followed by an entry that represents the SoC
+      model.
+
+  The root node is also generally where you add additional properties
+  specific to your board like the serial number if any, that sort of
+  thing. It is recommended that if you add any "custom" property whose
+  name may clash with standard defined ones, you prefix them with your
+  vendor name and a comma.
+
+  b) The /cpus node
+
+  This node is the parent of all individual CPU nodes. It doesn't
+  have any specific requirements, though it's generally good practice
+  to have at least:
+
+               #address-cells = <00000001>
+               #size-cells    = <00000000>
+
+  This defines that the "address" for a CPU is a single cell, and has
+  no meaningful size. This is not necessary but the kernel will assume
+  that format when reading the "reg" properties of a CPU node, see
+  below
+
+  c) The /cpus/* nodes
+
+  So under /cpus, you are supposed to create a node for every CPU on
+  the machine. There is no specific restriction on the name of the
+  CPU, though it's common to call it <architecture>,<core>. For
+  example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX.
+  However, the Generic Names convention suggests that it would be
+  better to simply use 'cpu' for each cpu node and use the compatible
+  property to identify the specific cpu core.
+
+  Required properties:
+
+    - device_type : has to be "cpu"
+    - reg : This is the physical CPU number, it's a single 32-bit cell
+      and is also used as-is as the unit number for constructing the
+      unit name in the full path. For example, with 2 CPUs, you would
+      have the full path:
+        /cpus/PowerPC,970FX@0
+        /cpus/PowerPC,970FX@1
+      (unit addresses do not require leading zeroes)
+    - d-cache-block-size : one cell, L1 data cache block size in bytes (*)
+    - i-cache-block-size : one cell, L1 instruction cache block size in
+      bytes
+    - d-cache-size : one cell, size of L1 data cache in bytes
+    - i-cache-size : one cell, size of L1 instruction cache in bytes
+
+(*) The cache "block" size is the size on which the cache management
+instructions operate. Historically, this document used the cache
+"line" size here which is incorrect. The kernel will prefer the cache
+block size and will fallback to cache line size for backward
+compatibility.
+
+  Recommended properties:
+
+    - timebase-frequency : a cell indicating the frequency of the
+      timebase in Hz. This is not directly used by the generic code,
+      but you are welcome to copy/paste the pSeries code for setting
+      the kernel timebase/decrementer calibration based on this
+      value.
+    - clock-frequency : a cell indicating the CPU core clock frequency
+      in Hz. A new property will be defined for 64-bit values, but if
+      your frequency is < 4Ghz, one cell is enough. Here as well as
+      for the above, the common code doesn't use that property, but
+      you are welcome to re-use the pSeries or Maple one. A future
+      kernel version might provide a common function for this.
+    - d-cache-line-size : one cell, L1 data cache line size in bytes
+      if different from the block size
+    - i-cache-line-size : one cell, L1 instruction cache line size in
+      bytes if different from the block size
+
+  You are welcome to add any property you find relevant to your board,
+  like some information about the mechanism used to soft-reset the
+  CPUs. For example, Apple puts the GPIO number for CPU soft reset
+  lines in there as a "soft-reset" property since they start secondary
+  CPUs by soft-resetting them.
+
+
+  d) the /memory node(s)
+
+  To define the physical memory layout of your board, you should
+  create one or more memory node(s). You can either create a single
+  node with all memory ranges in its reg property, or you can create
+  several nodes, as you wish. The unit address (@ part) used for the
+  full path is the address of the first range of memory defined by a
+  given node. If you use a single memory node, this will typically be
+  @0.
+
+  Required properties:
+
+    - device_type : has to be "memory"
+    - reg : This property contains all the physical memory ranges of
+      your board. It's a list of addresses/sizes concatenated
+      together, with the number of cells of each defined by the
+      #address-cells and #size-cells of the root node. For example,
+      with both of these properties being 2 like in the example given
+      earlier, a 970 based machine with 6Gb of RAM could typically
+      have a "reg" property here that looks like:
+
+      00000000 00000000 00000000 80000000
+      00000001 00000000 00000001 00000000
+
+      That is a range starting at 0 of 0x80000000 bytes and a range
+      starting at 0x100000000 and of 0x100000000 bytes. You can see
+      that there is no memory covering the IO hole between 2Gb and
+      4Gb. Some vendors prefer splitting those ranges into smaller
+      segments, but the kernel doesn't care.
+
+  e) The /chosen node
+
+  This node is a bit "special". Normally, that's where Open Firmware
+  puts some variable environment information, like the arguments, or
+  the default input/output devices.
+
+  This specification makes a few of these mandatory, but also defines
+  some linux-specific properties that would be normally constructed by
+  the prom_init() trampoline when booting with an OF client interface,
+  but that you have to provide yourself when using the flattened format.
+
+  Recommended properties:
+
+    - bootargs : This zero-terminated string is passed as the kernel
+      command line
+    - linux,stdout-path : This is the full path to your standard
+      console device if any. Typically, if you have serial devices on
+      your board, you may want to put the full path to the one set as
+      the default console in the firmware here, for the kernel to pick
+      it up as its own default console.
+
+  Note that u-boot creates and fills in the chosen node for platforms
+  that use it.
+
+  (Note: a practice that is now obsolete was to include a property
+  under /chosen called interrupt-controller which had a phandle value
+  that pointed to the main interrupt controller)
+
+  f) the /soc<SOCname> node
+
+  This node is used to represent a system-on-a-chip (SoC) and must be
+  present if the processor is a SoC. The top-level soc node contains
+  information that is global to all devices on the SoC. The node name
+  should contain a unit address for the SoC, which is the base address
+  of the memory-mapped register set for the SoC. The name of an SoC
+  node should start with "soc", and the remainder of the name should
+  represent the part number for the soc.  For example, the MPC8540's
+  soc node would be called "soc8540".
+
+  Required properties:
+
+    - ranges : Should be defined as specified in 1) to describe the
+      translation of SoC addresses for memory mapped SoC registers.
+    - bus-frequency: Contains the bus frequency for the SoC node.
+      Typically, the value of this field is filled in by the boot
+      loader.
+    - compatible : Exact model of the SoC
+
+
+  Recommended properties:
+
+    - reg : This property defines the address and size of the
+      memory-mapped registers that are used for the SOC node itself.
+      It does not include the child device registers - these will be
+      defined inside each child node.  The address specified in the
+      "reg" property should match the unit address of the SOC node.
+    - #address-cells : Address representation for "soc" devices.  The
+      format of this field may vary depending on whether or not the
+      device registers are memory mapped.  For memory mapped
+      registers, this field represents the number of cells needed to
+      represent the address of the registers.  For SOCs that do not
+      use MMIO, a special address format should be defined that
+      contains enough cells to represent the required information.
+      See 1) above for more details on defining #address-cells.
+    - #size-cells : Size representation for "soc" devices
+    - #interrupt-cells : Defines the width of cells used to represent
+       interrupts.  Typically this value is <2>, which includes a
+       32-bit number that represents the interrupt number, and a
+       32-bit number that represents the interrupt sense and level.
+       This field is only needed if the SOC contains an interrupt
+       controller.
+
+  The SOC node may contain child nodes for each SOC device that the
+  platform uses.  Nodes should not be created for devices which exist
+  on the SOC but are not used by a particular platform. See chapter VI
+  for more information on how to specify devices that are part of a SOC.
+
+  Example SOC node for the MPC8540:
+
+       soc8540@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               ranges = <00000000 e0000000 00100000>
+               reg = <e0000000 00003000>;
+               bus-frequency = <0>;
+       }
+
+
+
+IV - "dtc", the device tree compiler
+====================================
+
+
+dtc source code can be found at
+<http://git.jdl.com/gitweb/?p=dtc.git>
+
+WARNING: This version is still in early development stage; the
+resulting device-tree "blobs" have not yet been validated with the
+kernel. The current generated block lacks a useful reserve map (it will
+be fixed to generate an empty one, it's up to the bootloader to fill
+it up) among others. The error handling needs work, bugs are lurking,
+etc...
+
+dtc basically takes a device-tree in a given format and outputs a
+device-tree in another format. The currently supported formats are:
+
+  Input formats:
+  -------------
+
+     - "dtb": "blob" format, that is a flattened device-tree block
+       with
+        header all in a binary blob.
+     - "dts": "source" format. This is a text file containing a
+       "source" for a device-tree. The format is defined later in this
+        chapter.
+     - "fs" format. This is a representation equivalent to the
+        output of /proc/device-tree, that is nodes are directories and
+       properties are files
+
+ Output formats:
+ ---------------
+
+     - "dtb": "blob" format
+     - "dts": "source" format
+     - "asm": assembly language file. This is a file that can be
+       sourced by gas to generate a device-tree "blob". That file can
+       then simply be added to your Makefile. Additionally, the
+       assembly file exports some symbols that can be used.
+
+
+The syntax of the dtc tool is
+
+    dtc [-I <input-format>] [-O <output-format>]
+        [-o output-filename] [-V output_version] input_filename
+
+
+The "output_version" defines what version of the "blob" format will be
+generated. Supported versions are 1,2,3 and 16. The default is
+currently version 3 but that may change in the future to version 16.
+
+Additionally, dtc performs various sanity checks on the tree, like the
+uniqueness of linux, phandle properties, validity of strings, etc...
+
+The format of the .dts "source" file is "C" like, supports C and C++
+style comments.
+
+/ {
+}
+
+The above is the "device-tree" definition. It's the only statement
+supported currently at the toplevel.
+
+/ {
+  property1 = "string_value";  /* define a property containing a 0
+                                 * terminated string
+                                */
+
+  property2 = <1234abcd>;      /* define a property containing a
+                                 * numerical 32-bit value (hexadecimal)
+                                */
+
+  property3 = <12345678 12345678 deadbeef>;
+                                /* define a property containing 3
+                                 * numerical 32-bit values (cells) in
+                                 * hexadecimal
+                                */
+  property4 = [0a 0b 0c 0d de ea ad be ef];
+                                /* define a property whose content is
+                                 * an arbitrary array of bytes
+                                 */
+
+  childnode@address {  /* define a child node named "childnode"
+                                 * whose unit name is "childnode at
+                                * address"
+                                 */
+
+    childprop = "hello\n";      /* define a property "childprop" of
+                                 * childnode (in this case, a string)
+                                 */
+  };
+};
+
+Nodes can contain other nodes etc... thus defining the hierarchical
+structure of the tree.
+
+Strings support common escape sequences from C: "\n", "\t", "\r",
+"\(octal value)", "\x(hex value)".
+
+It is also suggested that you pipe your source file through cpp (gcc
+preprocessor) so you can use #include's, #define for constants, etc...
+
+Finally, various options are planned but not yet implemented, like
+automatic generation of phandles, labels (exported to the asm file so
+you can point to a property content and change it easily from whatever
+you link the device-tree with), label or path instead of numeric value
+in some cells to "point" to a node (replaced by a phandle at compile
+time), export of reserve map address to the asm file, ability to
+specify reserve map content at compile time, etc...
+
+We may provide a .h include file with common definitions of that
+proves useful for some properties (like building PCI properties or
+interrupt maps) though it may be better to add a notion of struct
+definitions to the compiler...
+
+
+V - Recommendations for a bootloader
+====================================
+
+
+Here are some various ideas/recommendations that have been proposed
+while all this has been defined and implemented.
+
+  - The bootloader may want to be able to use the device-tree itself
+    and may want to manipulate it (to add/edit some properties,
+    like physical memory size or kernel arguments). At this point, 2
+    choices can be made. Either the bootloader works directly on the
+    flattened format, or the bootloader has its own internal tree
+    representation with pointers (similar to the kernel one) and
+    re-flattens the tree when booting the kernel. The former is a bit
+    more difficult to edit/modify, the later requires probably a bit
+    more code to handle the tree structure. Note that the structure
+    format has been designed so it's relatively easy to "insert"
+    properties or nodes or delete them by just memmoving things
+    around. It contains no internal offsets or pointers for this
+    purpose.
+
+  - An example of code for iterating nodes & retrieving properties
+    directly from the flattened tree format can be found in the kernel
+    file drivers/of/fdt.c.  Look at the of_scan_flat_dt() function,
+    its usage in early_init_devtree(), and the corresponding various
+    early_init_dt_scan_*() callbacks. That code can be re-used in a
+    GPL bootloader, and as the author of that code, I would be happy
+    to discuss possible free licensing to any vendor who wishes to
+    integrate all or part of this code into a non-GPL bootloader.
+    (reference needed; who is 'I' here? ---gcl Jan 31, 2011)
+
+
+
+VI - System-on-a-chip devices and nodes
+=======================================
+
+Many companies are now starting to develop system-on-a-chip
+processors, where the processor core (CPU) and many peripheral devices
+exist on a single piece of silicon.  For these SOCs, an SOC node
+should be used that defines child nodes for the devices that make
+up the SOC. While platforms are not required to use this model in
+order to boot the kernel, it is highly encouraged that all SOC
+implementations define as complete a flat-device-tree as possible to
+describe the devices on the SOC.  This will allow for the
+genericization of much of the kernel code.
+
+
+1) Defining child nodes of an SOC
+---------------------------------
+
+Each device that is part of an SOC may have its own node entry inside
+the SOC node.  For each device that is included in the SOC, the unit
+address property represents the address offset for this device's
+memory-mapped registers in the parent's address space.  The parent's
+address space is defined by the "ranges" property in the top-level soc
+node. The "reg" property for each node that exists directly under the
+SOC node should contain the address mapping from the child address space
+to the parent SOC address space and the size of the device's
+memory-mapped register file.
+
+For many devices that may exist inside an SOC, there are predefined
+specifications for the format of the device tree node.  All SOC child
+nodes should follow these specifications, except where noted in this
+document.
+
+See appendix A for an example partial SOC node definition for the
+MPC8540.
+
+
+2) Representing devices without a current OF specification
+----------------------------------------------------------
+
+Currently, there are many devices on SoCs that do not have a standard
+representation defined as part of the Open Firmware specifications,
+mainly because the boards that contain these SoCs are not currently
+booted using Open Firmware.  Binding documentation for new devices
+should be added to the Documentation/devicetree/bindings directory.
+That directory will expand as device tree support is added to more and
+more SoCs.
+
+
+VII - Specifying interrupt information for devices
+===================================================
+
+The device tree represents the buses and devices of a hardware
+system in a form similar to the physical bus topology of the
+hardware.
+
+In addition, a logical 'interrupt tree' exists which represents the
+hierarchy and routing of interrupts in the hardware.
+
+The interrupt tree model is fully described in the
+document "Open Firmware Recommended Practice: Interrupt
+Mapping Version 0.9".  The document is available at:
+<http://playground.sun.com/1275/practice>.
+
+1) interrupts property
+----------------------
+
+Devices that generate interrupts to a single interrupt controller
+should use the conventional OF representation described in the
+OF interrupt mapping documentation.
+
+Each device which generates interrupts must have an 'interrupt'
+property.  The interrupt property value is an arbitrary number of
+of 'interrupt specifier' values which describe the interrupt or
+interrupts for the device.
+
+The encoding of an interrupt specifier is determined by the
+interrupt domain in which the device is located in the
+interrupt tree.  The root of an interrupt domain specifies in
+its #interrupt-cells property the number of 32-bit cells
+required to encode an interrupt specifier.  See the OF interrupt
+mapping documentation for a detailed description of domains.
+
+For example, the binding for the OpenPIC interrupt controller
+specifies  an #interrupt-cells value of 2 to encode the interrupt
+number and level/sense information. All interrupt children in an
+OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
+property.
+
+The PCI bus binding specifies a #interrupt-cell value of 1 to encode
+which interrupt pin (INTA,INTB,INTC,INTD) is used.
+
+2) interrupt-parent property
+----------------------------
+
+The interrupt-parent property is specified to define an explicit
+link between a device node and its interrupt parent in
+the interrupt tree.  The value of interrupt-parent is the
+phandle of the parent node.
+
+If the interrupt-parent property is not defined for a node, its
+interrupt parent is assumed to be an ancestor in the node's
+_device tree_ hierarchy.
+
+3) OpenPIC Interrupt Controllers
+--------------------------------
+
+OpenPIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+Sense and level information should be encoded as follows:
+
+       0 = low to high edge sensitive type enabled
+       1 = active low level sensitive type enabled
+       2 = active high level sensitive type enabled
+       3 = high to low edge sensitive type enabled
+
+4) ISA Interrupt Controllers
+----------------------------
+
+ISA PIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+ISA PIC interrupt controllers should adhere to the ISA PIC
+encodings listed below:
+
+       0 =  active low level sensitive type enabled
+       1 =  active high level sensitive type enabled
+       2 =  high to low edge sensitive type enabled
+       3 =  low to high edge sensitive type enabled
+
+VIII - Specifying Device Power Management Information (sleep property)
+===================================================================
+
+Devices on SOCs often have mechanisms for placing devices into low-power
+states that are decoupled from the devices' own register blocks.  Sometimes,
+this information is more complicated than a cell-index property can
+reasonably describe.  Thus, each device controlled in such a manner
+may contain a "sleep" property which describes these connections.
+
+The sleep property consists of one or more sleep resources, each of
+which consists of a phandle to a sleep controller, followed by a
+controller-specific sleep specifier of zero or more cells.
+
+The semantics of what type of low power modes are possible are defined
+by the sleep controller.  Some examples of the types of low power modes
+that may be supported are:
+
+ - Dynamic: The device may be disabled or enabled at any time.
+ - System Suspend: The device may request to be disabled or remain
+   awake during system suspend, but will not be disabled until then.
+ - Permanent: The device is disabled permanently (until the next hard
+   reset).
+
+Some devices may share a clock domain with each other, such that they should
+only be suspended when none of the devices are in use.  Where reasonable,
+such nodes should be placed on a virtual bus, where the bus has the sleep
+property.  If the clock domain is shared among devices that cannot be
+reasonably grouped in this manner, then create a virtual sleep controller
+(similar to an interrupt nexus, except that defining a standardized
+sleep-map should wait until its necessity is demonstrated).
+
+Appendix A - Sample SOC node for MPC8540
+========================================
+
+       soc@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8540-ccsr", "simple-bus";
+               device_type = "soc";
+               ranges = <0x00000000 0xe0000000 0x00100000>
+               bus-frequency = <0>;
+               interrupt-parent = <&pic>;
+
+               ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar", "simple-bus";
+                       reg = <0x24000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 00 ];
+                       interrupts = <29 2 30 2 34 2>;
+                       phy-handle = <&phy0>;
+                       sleep = <&pmc 00000080>;
+                       ranges;
+
+                       mdio@24520 {
+                               reg = <0x24520 0x20>;
+                               compatible = "fsl,gianfar-mdio";
+
+                               phy0: ethernet-phy@0 {
+                                       interrupts = <5 1>;
+                                       reg = <0>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       interrupts = <5 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy3: ethernet-phy@3 {
+                                       interrupts = <7 1>;
+                                       reg = <3>;
+                                       device_type = "ethernet-phy";
+                               };
+                       };
+               };
+
+               ethernet@25000 {
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar";
+                       reg = <0x25000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 01 ];
+                       interrupts = <13 2 14 2 18 2>;
+                       phy-handle = <&phy1>;
+                       sleep = <&pmc 00000040>;
+               };
+
+               ethernet@26000 {
+                       device_type = "network";
+                       model = "FEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 02 ];
+                       interrupts = <41 2>;
+                       phy-handle = <&phy3>;
+                       sleep = <&pmc 00000020>;
+               };
+
+               serial@4500 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8540-duart", "simple-bus";
+                       sleep = <&pmc 00000002>;
+                       ranges;
+
+                       serial@4500 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0x4500 0x100>;
+                               clock-frequency = <0>;
+                               interrupts = <42 2>;
+                       };
+
+                       serial@4600 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0x4600 0x100>;
+                               clock-frequency = <0>;
+                               interrupts = <42 2>;
+                       };
+               };
+
+               pic: pic@40000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+
+               i2c@3000 {
+                       interrupts = <43 2>;
+                       reg = <0x3000 0x100>;
+                       compatible  = "fsl-i2c";
+                       dfsrr;
+                       sleep = <&pmc 00000004>;
+               };
+
+               pmc: power@e0070 {
+                       compatible = "fsl,mpc8540-pmc", "fsl,mpc8548-pmc";
+                       reg = <0xe0070 0x20>;
+               };
+       };
index 8c594c4..b3f35e5 100644 (file)
@@ -357,14 +357,6 @@ Who:       Dave Jones <davej@redhat.com>, Matthew Garrett <mjg@redhat.com>
 
 -----------------------------
 
-What:  __do_IRQ all in one fits nothing interrupt handler
-When:  2.6.32
-Why:   __do_IRQ was kept for easy migration to the type flow handlers.
-       More than two years of migration time is enough.
-Who:   Thomas Gleixner <tglx@linutronix.de>
-
------------------------------
-
 What:  fakephp and associated sysfs files in /sys/bus/pci/slots/
 When:  2011
 Why:   In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
@@ -611,3 +603,19 @@ Why:       The adm9240, w83792d and w83793 hardware monitoring drivers have
 Who:   Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
+
+What:  noswapaccount kernel command line parameter
+When:  2.6.40
+Why:   The original implementation of memsw feature enabled by
+       CONFIG_CGROUP_MEM_RES_CTLR_SWAP could be disabled by the noswapaccount
+       kernel parameter (introduced in 2.6.29-rc1). Later on, this decision
+       turned out to be not ideal because we cannot have the feature compiled
+       in and disabled by default and let only interested to enable it
+       (e.g. general distribution kernels might need it). Therefore we have
+       added swapaccount[=0|1] parameter (introduced in 2.6.37) which provides
+       the both possibilities. If we remove noswapaccount we will have
+       less command line parameters with the same functionality and we
+       can also cleanup the parameter handling a bit ().
+Who:   Michal Hocko <mhocko@suse.cz>
+
+----------------------------
index 6ef8cf3..933bc66 100644 (file)
@@ -460,6 +460,8 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 2.1.30:
        - Fix writev() (it kept writing the first segment over and over again
          instead of moving onto subsequent segments).
+       - Fix crash in ntfs_mft_record_alloc() when mapping the new extent mft
+         record failed.
 2.1.29:
        - Fix a deadlock when mounting read-write.
 2.1.28:
index 0e76ef1..a22ecf4 100644 (file)
@@ -51,7 +51,8 @@ Supported chips:
   * JEDEC JC 42.4 compliant temperature sensor chips
     Prefix: 'jc42'
     Addresses scanned: I2C 0x18 - 0x1f
-    Datasheet: -
+    Datasheet:
+       http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf
 
 Author:
        Guenter Roeck <guenter.roeck@ericsson.com>
@@ -60,7 +61,11 @@ Author:
 Description
 -----------
 
-This driver implements support for JEDEC JC 42.4 compliant temperature sensors.
+This driver implements support for JEDEC JC 42.4 compliant temperature sensors,
+which are used on many DDR3 memory modules for mobile devices and servers. Some
+systems use the sensor to prevent memory overheating by automatically throttling
+the memory controller.
+
 The driver auto-detects the chips listed above, but can be manually instantiated
 to support other JC 42.4 compliant chips.
 
@@ -81,15 +86,19 @@ limits. The chip supports only a single register to configure the hysteresis,
 which applies to all limits. This register can be written by writing into
 temp1_crit_hyst. Other hysteresis attributes are read-only.
 
+If the BIOS has configured the sensor for automatic temperature management, it
+is likely that it has locked the registers, i.e., that the temperature limits
+cannot be changed.
+
 Sysfs entries
 -------------
 
 temp1_input            Temperature (RO)
-temp1_min              Minimum temperature (RW)
-temp1_max              Maximum temperature (RW)
-temp1_crit             Critical high temperature (RW)
+temp1_min              Minimum temperature (RO or RW)
+temp1_max              Maximum temperature (RO or RW)
+temp1_crit             Critical high temperature (RO or RW)
 
-temp1_crit_hyst                Critical hysteresis temperature (RW)
+temp1_crit_hyst                Critical hysteresis temperature (RO or RW)
 temp1_max_hyst         Maximum hysteresis temperature (RO)
 
 temp1_min_alarm                Temperature low alarm
index 6526eee..d2b56a4 100644 (file)
@@ -9,6 +9,8 @@ Supported chips:
   Socket S1G3: Athlon II, Sempron, Turion II
 * AMD Family 11h processors:
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
+* AMD Family 12h processors: "Llano"
+* AMD Family 14h processors: "Brazos" (C/E/G-Series)
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
@@ -17,10 +19,14 @@ Supported chips:
     http://support.amd.com/us/Processor_TechDocs/31116.pdf
   BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors:
     http://support.amd.com/us/Processor_TechDocs/41256.pdf
+  BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors:
+    http://support.amd.com/us/Processor_TechDocs/43170.pdf
   Revision Guide for AMD Family 10h Processors:
     http://support.amd.com/us/Processor_TechDocs/41322.pdf
   Revision Guide for AMD Family 11h Processors:
     http://support.amd.com/us/Processor_TechDocs/41788.pdf
+  Revision Guide for AMD Family 14h Models 00h-0Fh Processors:
+    http://support.amd.com/us/Processor_TechDocs/47534.pdf
   AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks:
     http://support.amd.com/us/Processor_TechDocs/43373.pdf
   AMD Family 10h Server and Workstation Processor Power and Thermal Data Sheet:
@@ -34,7 +40,7 @@ Description
 -----------
 
 This driver permits reading of the internal temperature sensor of AMD
-Family 10h and 11h processors.
+Family 10h/11h/12h/14h processors.
 
 All these processors have a sensor, but on those for Socket F or AM2+,
 the sensor may return inconsistent values (erratum 319).  The driver
index b72e071..f4a04c0 100644 (file)
@@ -43,11 +43,11 @@ parameter is applicable:
        AVR32   AVR32 architecture is enabled.
        AX25    Appropriate AX.25 support is enabled.
        BLACKFIN Blackfin architecture is enabled.
+       DRM     Direct Rendering Management support is enabled.
+       DYNAMIC_DEBUG Build in debug messages and enable them at runtime
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
        EFI     EFI Partitioning (GPT) is enabled
        EIDE    EIDE/ATAPI support is enabled.
-       DRM     Direct Rendering Management support is enabled.
-       DYNAMIC_DEBUG Build in debug messages and enable them at runtime
        FB      The frame buffer device is enabled.
        GCOV    GCOV profiling is enabled.
        HW      Appropriate hardware is enabled.
@@ -144,6 +144,11 @@ a fixed number of characters. This limit depends on the architecture
 and is between 256 and 4096 characters. It is defined in the file
 ./include/asm/setup.h as COMMAND_LINE_SIZE.
 
+Finally, the [KMG] suffix is commonly described after a number of kernel
+parameter values. These 'K', 'M', and 'G' letters represent the _binary_
+multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30
+bytes respectively. Such letter suffixes can also be entirely omitted.
+
 
        acpi=           [HW,ACPI,X86]
                        Advanced Configuration and Power Interface
@@ -545,16 +550,20 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format:
                        <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
 
-       crashkernel=nn[KMG]@ss[KMG]
-                       [KNL] Reserve a chunk of physical memory to
-                       hold a kernel to switch to with kexec on panic.
+       crashkernel=size[KMG][@offset[KMG]]
+                       [KNL] Using kexec, Linux can switch to a 'crash kernel'
+                       upon panic. This parameter reserves the physical
+                       memory region [offset, offset + size] for that kernel
+                       image. If '@offset' is omitted, then a suitable offset
+                       is selected automatically. Check
+                       Documentation/kdump/kdump.txt for further details.
 
        crashkernel=range1:size1[,range2:size2,...][@offset]
                        [KNL] Same as above, but depends on the memory
                        in the running system. The syntax of range is
                        start-[end] where start and end are both
                        a memory unit (amount[KMG]). See also
-                       Documentation/kdump/kdump.txt for a example.
+                       Documentation/kdump/kdump.txt for an example.
 
        cs89x0_dma=     [HW,NET]
                        Format: <dma>
@@ -1262,10 +1271,9 @@ and is between 256 and 4096 characters. It is defined in the file
                        6 (KERN_INFO)           informational
                        7 (KERN_DEBUG)          debug-level messages
 
-       log_buf_len=n   Sets the size of the printk ring buffer, in bytes.
-                       Format: { n | nk | nM }
-                       n must be a power of two.  The default size
-                       is set in the kernel config file.
+       log_buf_len=n[KMG]      Sets the size of the printk ring buffer,
+                       in bytes.  n must be a power of two.  The default
+                       size is set in the kernel config file.
 
        logo.nologo     [FB] Disables display of the built-in Linux logo.
                        This may be used to provide more screen space for
index dc73bc5..d9da7e1 100644 (file)
@@ -39,6 +39,9 @@
 #include <limits.h>
 #include <stddef.h>
 #include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+
 #include <linux/virtio_config.h>
 #include <linux/virtio_net.h>
 #include <linux/virtio_blk.h>
@@ -298,20 +301,27 @@ static void *map_zeroed_pages(unsigned int num)
 
        /*
         * We use a private mapping (ie. if we write to the page, it will be
-        * copied).
+        * copied). We allocate an extra two pages PROT_NONE to act as guard
+        * pages against read/write attempts that exceed allocated space.
         */
-       addr = mmap(NULL, getpagesize() * num,
-                   PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+       addr = mmap(NULL, getpagesize() * (num+2),
+                   PROT_NONE, MAP_PRIVATE, fd, 0);
+
        if (addr == MAP_FAILED)
                err(1, "Mmapping %u pages of /dev/zero", num);
 
+       if (mprotect(addr + getpagesize(), getpagesize() * num,
+                    PROT_READ|PROT_WRITE) == -1)
+               err(1, "mprotect rw %u pages failed", num);
+
        /*
         * One neat mmap feature is that you can close the fd, and it
         * stays mapped.
         */
        close(fd);
 
-       return addr;
+       /* Return address after PROT_NONE page */
+       return addr + getpagesize();
 }
 
 /* Get some more pages for a device. */
@@ -343,7 +353,7 @@ static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
         * done to it.  This allows us to share untouched memory between
         * Guests.
         */
-       if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC,
+       if (mmap(addr, len, PROT_READ|PROT_WRITE,
                 MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
                return;
 
@@ -573,10 +583,10 @@ static void *_check_pointer(unsigned long addr, unsigned int size,
                            unsigned int line)
 {
        /*
-        * We have to separately check addr and addr+size, because size could
-        * be huge and addr + size might wrap around.
+        * Check if the requested address and size exceeds the allocated memory,
+        * or addr + size wraps around.
         */
-       if (addr >= guest_limit || addr + size >= guest_limit)
+       if ((addr + size) > guest_limit || (addr + size) < addr)
                errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
        /*
         * We return a pointer for the caller's convenience, now we know it's
@@ -1872,6 +1882,8 @@ static struct option opts[] = {
        { "block", 1, NULL, 'b' },
        { "rng", 0, NULL, 'r' },
        { "initrd", 1, NULL, 'i' },
+       { "username", 1, NULL, 'u' },
+       { "chroot", 1, NULL, 'c' },
        { NULL },
 };
 static void usage(void)
@@ -1894,6 +1906,12 @@ int main(int argc, char *argv[])
        /* If they specify an initrd file to load. */
        const char *initrd_name = NULL;
 
+       /* Password structure for initgroups/setres[gu]id */
+       struct passwd *user_details = NULL;
+
+       /* Directory to chroot to */
+       char *chroot_path = NULL;
+
        /* Save the args: we "reboot" by execing ourselves again. */
        main_args = argv;
 
@@ -1950,6 +1968,14 @@ int main(int argc, char *argv[])
                case 'i':
                        initrd_name = optarg;
                        break;
+               case 'u':
+                       user_details = getpwnam(optarg);
+                       if (!user_details)
+                               err(1, "getpwnam failed, incorrect username?");
+                       break;
+               case 'c':
+                       chroot_path = optarg;
+                       break;
                default:
                        warnx("Unknown argument %s", argv[optind]);
                        usage();
@@ -2021,6 +2047,37 @@ int main(int argc, char *argv[])
        /* If we exit via err(), this kills all the threads, restores tty. */
        atexit(cleanup_devices);
 
+       /* If requested, chroot to a directory */
+       if (chroot_path) {
+               if (chroot(chroot_path) != 0)
+                       err(1, "chroot(\"%s\") failed", chroot_path);
+
+               if (chdir("/") != 0)
+                       err(1, "chdir(\"/\") failed");
+
+               verbose("chroot done\n");
+       }
+
+       /* If requested, drop privileges */
+       if (user_details) {
+               uid_t u;
+               gid_t g;
+
+               u = user_details->pw_uid;
+               g = user_details->pw_gid;
+
+               if (initgroups(user_details->pw_name, g) != 0)
+                       err(1, "initgroups failed");
+
+               if (setresgid(g, g, g) != 0)
+                       err(1, "setresgid failed");
+
+               if (setresuid(u, u, u) != 0)
+                       err(1, "setresuid failed");
+
+               verbose("Dropping privileges completed\n");
+       }
+
        /* Finally, run the Guest.  This doesn't return. */
        run_guest();
 }
index 6ccaf8e..dad9997 100644 (file)
@@ -117,6 +117,11 @@ Running Lguest:
     
   for general information on how to get bridging to work.
 
+- Random number generation. Using the --rng option will provide a
+  /dev/hwrng in the guest that will read from the host's /dev/random.
+  Use this option in conjunction with rng-tools (see ../hw_random.txt)
+  to provide entropy to the guest kernel's /dev/random.
+
 There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
 
 Good luck!
index fe5c099..4edd78d 100644 (file)
@@ -40,8 +40,6 @@ decnet.txt
        - info on using the DECnet networking layer in Linux.
 depca.txt
        - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
-dgrs.txt
-       - the Digi International RightSwitch SE-X Ethernet driver
 dmfe.txt
        - info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
 e100.txt
@@ -50,8 +48,6 @@ e1000.txt
        - info on Intel's E1000 line of gigabit ethernet boards
 eql.txt
        - serial IP load balancing
-ethertap.txt
-       - the Ethertap user space packet reception and transmission driver
 ewrk3.txt
        - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
 filter.txt
@@ -104,8 +100,6 @@ tuntap.txt
        - TUN/TAP device driver, allowing user space Rx/Tx of packets.
 vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
-wavelan.txt
-       - AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver
 x25.txt
        - general info on X.25 development.
 x25-iface.txt
index 5aba7a3..24c308d 100644 (file)
@@ -4,6 +4,8 @@ obj- := dummy.o
 # List of programs to build
 hostprogs-y := ifenslave
 
+HOSTCFLAGS_ifenslave.o += -I$(objtree)/usr/include
+
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
index 5dc6387..25d2f41 100644 (file)
@@ -49,7 +49,8 @@ Table of Contents
 3.3    Configuring Bonding Manually with Ifenslave
 3.3.1          Configuring Multiple Bonds Manually
 3.4    Configuring Bonding Manually via Sysfs
-3.5    Overriding Configuration for Special Cases
+3.5    Configuration with Interfaces Support
+3.6    Overriding Configuration for Special Cases
 
 4. Querying Bonding Configuration
 4.1    Bonding Configuration
@@ -161,8 +162,8 @@ onwards) do not have /usr/include/linux symbolically linked to the
 default kernel source include directory.
 
 SECOND IMPORTANT NOTE:
-       If you plan to configure bonding using sysfs, you do not need
-to use ifenslave.
+       If you plan to configure bonding using sysfs or using the
+/etc/network/interfaces file, you do not need to use ifenslave.
 
 2. Bonding Driver Options
 =========================
@@ -779,22 +780,26 @@ resend_igmp
 
        You can configure bonding using either your distro's network
 initialization scripts, or manually using either ifenslave or the
-sysfs interface.  Distros generally use one of two packages for the
-network initialization scripts: initscripts or sysconfig.  Recent
-versions of these packages have support for bonding, while older
+sysfs interface.  Distros generally use one of three packages for the
+network initialization scripts: initscripts, sysconfig or interfaces.
+Recent versions of these packages have support for bonding, while older
 versions do not.
 
        We will first describe the options for configuring bonding for
-distros using versions of initscripts and sysconfig with full or
-partial support for bonding, then provide information on enabling
+distros using versions of initscripts, sysconfig and interfaces with full
+or partial support for bonding, then provide information on enabling
 bonding without support from the network initialization scripts (i.e.,
 older versions of initscripts or sysconfig).
 
-       If you're unsure whether your distro uses sysconfig or
-initscripts, or don't know if it's new enough, have no fear.
+       If you're unsure whether your distro uses sysconfig,
+initscripts or interfaces, or don't know if it's new enough, have no fear.
 Determining this is fairly straightforward.
 
-       First, issue the command:
+       First, look for a file called interfaces in /etc/network directory.
+If this file is present in your system, then your system use interfaces. See
+Configuration with Interfaces Support.
+
+       Else, issue the command:
 
 $ rpm -qf /sbin/ifup
 
@@ -1327,8 +1332,62 @@ echo 2000 > /sys/class/net/bond1/bonding/arp_interval
 echo +eth2 > /sys/class/net/bond1/bonding/slaves
 echo +eth3 > /sys/class/net/bond1/bonding/slaves
 
-3.5 Overriding Configuration for Special Cases
+3.5 Configuration with Interfaces Support
+-----------------------------------------
+
+        This section applies to distros which use /etc/network/interfaces file
+to describe network interface configuration, most notably Debian and it's
+derivatives.
+
+       The ifup and ifdown commands on Debian don't support bonding out of
+the box. The ifenslave-2.6 package should be installed to provide bonding
+support.  Once installed, this package will provide bond-* options to be used
+into /etc/network/interfaces.
+
+       Note that ifenslave-2.6 package will load the bonding module and use
+the ifenslave command when appropriate.
+
+Example Configurations
+----------------------
+
+In /etc/network/interfaces, the following stanza will configure bond0, in
+active-backup mode, with eth0 and eth1 as slaves.
+
+auto bond0
+iface bond0 inet dhcp
+       bond-slaves eth0 eth1
+       bond-mode active-backup
+       bond-miimon 100
+       bond-primary eth0 eth1
+
+If the above configuration doesn't work, you might have a system using
+upstart for system startup. This is most notably true for recent
+Ubuntu versions. The following stanza in /etc/network/interfaces will
+produce the same result on those systems.
+
+auto bond0
+iface bond0 inet dhcp
+       bond-slaves none
+       bond-mode active-backup
+       bond-miimon 100
+
+auto eth0
+iface eth0 inet manual
+       bond-master bond0
+       bond-primary eth0 eth1
+
+auto eth1
+iface eth1 inet manual
+       bond-master bond0
+       bond-primary eth0 eth1
+
+For a full list of bond-* supported options in /etc/network/interfaces and some
+more advanced examples tailored to you particular distros, see the files in
+/usr/share/doc/ifenslave-2.6.
+
+3.6 Overriding Configuration for Special Cases
 ----------------------------------------------
+
 When using the bonding driver, the physical port which transmits a frame is
 typically selected by the bonding driver, and is not relevant to the user or
 system administrator.  The output port is simply selected using the policies of
index aefd1e6..04ca063 100644 (file)
@@ -61,7 +61,6 @@ before the more general line given above as the first match is the one taken.
        create  dns_resolver    foo:*   *       /usr/sbin/dns.foo %k
 
 
-
 =====
 USAGE
 =====
@@ -104,6 +103,14 @@ implemented in the module can be called after doing:
      returned also.
 
 
+===============================
+READING DNS KEYS FROM USERSPACE
+===============================
+
+Keys of dns_resolver type can be read from userspace using keyctl_read() or
+"keyctl read/print/pipe".
+
+
 =========
 MECHANISM
 =========
index d99940d..ac3b4a7 100644 (file)
@@ -187,7 +187,7 @@ tcp_cookie_size - INTEGER
 tcp_dsack - BOOLEAN
        Allows TCP to send "duplicate" SACKs.
 
-tcp_ecn - BOOLEAN
+tcp_ecn - INTEGER
        Enable Explicit Congestion Notification (ECN) in TCP. ECN is only
        used when both ends of the TCP flow support it. It is useful to
        avoid losses due to congestion (when the bottleneck router supports
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
deleted file mode 100644 (file)
index 7400d75..0000000
+++ /dev/null
@@ -1,1447 +0,0 @@
-           Booting the Linux/ppc kernel without Open Firmware
-           --------------------------------------------------
-
-(c) 2005 Benjamin Herrenschmidt <benh at kernel.crashing.org>,
-    IBM Corp.
-(c) 2005 Becky Bruce <becky.bruce at freescale.com>,
-    Freescale Semiconductor, FSL SOC and 32-bit additions
-(c) 2006 MontaVista Software, Inc.
-    Flash chip node definition
-
-Table of Contents
-=================
-
-  I - Introduction
-    1) Entry point for arch/powerpc
-    2) Board support
-
-  II - The DT block format
-    1) Header
-    2) Device tree generalities
-    3) Device tree "structure" block
-    4) Device tree "strings" block
-
-  III - Required content of the device tree
-    1) Note about cells and address representation
-    2) Note about "compatible" properties
-    3) Note about "name" properties
-    4) Note about node and property names and character set
-    5) Required nodes and properties
-      a) The root node
-      b) The /cpus node
-      c) The /cpus/* nodes
-      d) the /memory node(s)
-      e) The /chosen node
-      f) the /soc<SOCname> node
-
-  IV - "dtc", the device tree compiler
-
-  V - Recommendations for a bootloader
-
-  VI - System-on-a-chip devices and nodes
-    1) Defining child nodes of an SOC
-    2) Representing devices without a current OF specification
-      a) PHY nodes
-      b) Interrupt controllers
-      c) 4xx/Axon EMAC ethernet nodes
-      d) Xilinx IP cores
-      e) USB EHCI controllers
-      f) MDIO on GPIOs
-      g) SPI busses
-
-  VII - Specifying interrupt information for devices
-    1) interrupts property
-    2) interrupt-parent property
-    3) OpenPIC Interrupt Controllers
-    4) ISA Interrupt Controllers
-
-  VIII - Specifying device power management information (sleep property)
-
-  Appendix A - Sample SOC node for MPC8540
-
-
-Revision Information
-====================
-
-   May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet.
-
-   May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or
-                           clarifies the fact that a lot of things are
-                           optional, the kernel only requires a very
-                           small device tree, though it is encouraged
-                           to provide an as complete one as possible.
-
-   May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM
-                        - Misc fixes
-                        - Define version 3 and new format version 16
-                          for the DT block (version 16 needs kernel
-                          patches, will be fwd separately).
-                          String block now has a size, and full path
-                          is replaced by unit name for more
-                          compactness.
-                          linux,phandle is made optional, only nodes
-                          that are referenced by other nodes need it.
-                          "name" property is now automatically
-                          deduced from the unit name
-
-   June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and
-                           OF_DT_END_NODE in structure definition.
-                         - Change version 16 format to always align
-                           property data to 4 bytes. Since tokens are
-                           already aligned, that means no specific
-                           required alignment between property size
-                           and property data. The old style variable
-                           alignment would make it impossible to do
-                           "simple" insertion of properties using
-                           memmove (thanks Milton for
-                           noticing). Updated kernel patch as well
-                        - Correct a few more alignment constraints
-                        - Add a chapter about the device-tree
-                           compiler and the textural representation of
-                           the tree that can be "compiled" by dtc.
-
-   November 21, 2005: Rev 0.5
-                        - Additions/generalizations for 32-bit
-                        - Changed to reflect the new arch/powerpc
-                          structure
-                        - Added chapter VI
-
-
- ToDo:
-       - Add some definitions of interrupt tree (simple/complex)
-       - Add some definitions for PCI host bridges
-       - Add some common address format examples
-       - Add definitions for standard properties and "compatible"
-         names for cells that are not already defined by the existing
-         OF spec.
-       - Compare FSL SOC use of PCI to standard and make sure no new
-         node definition required.
-       - Add more information about node definitions for SOC devices
-         that currently have no standard, like the FSL CPM.
-
-
-I - Introduction
-================
-
-During the recent development of the Linux/ppc64 kernel, and more
-specifically, the addition of new platform types outside of the old
-IBM pSeries/iSeries pair, it was decided to enforce some strict rules
-regarding the kernel entry and bootloader <-> kernel interfaces, in
-order to avoid the degeneration that had become the ppc32 kernel entry
-point and the way a new platform should be added to the kernel. The
-legacy iSeries platform breaks those rules as it predates this scheme,
-but no new board support will be accepted in the main tree that
-doesn't follow them properly.  In addition, since the advent of the
-arch/powerpc merged architecture for ppc32 and ppc64, new 32-bit
-platforms and 32-bit platforms which move into arch/powerpc will be
-required to use these rules as well.
-
-The main requirement that will be defined in more detail below is
-the presence of a device-tree whose format is defined after Open
-Firmware specification. However, in order to make life easier
-to embedded board vendors, the kernel doesn't require the device-tree
-to represent every device in the system and only requires some nodes
-and properties to be present. This will be described in detail in
-section III, but, for example, the kernel does not require you to
-create a node for every PCI device in the system. It is a requirement
-to have a node for PCI host bridges in order to provide interrupt
-routing informations and memory/IO ranges, among others. It is also
-recommended to define nodes for on chip devices and other busses that
-don't specifically fit in an existing OF specification. This creates a
-great flexibility in the way the kernel can then probe those and match
-drivers to device, without having to hard code all sorts of tables. It
-also makes it more flexible for board vendors to do minor hardware
-upgrades without significantly impacting the kernel code or cluttering
-it with special cases.
-
-
-1) Entry point for arch/powerpc
--------------------------------
-
-   There is one and one single entry point to the kernel, at the start
-   of the kernel image. That entry point supports two calling
-   conventions:
-
-        a) Boot from Open Firmware. If your firmware is compatible
-        with Open Firmware (IEEE 1275) or provides an OF compatible
-        client interface API (support for "interpret" callback of
-        forth words isn't required), you can enter the kernel with:
-
-              r5 : OF callback pointer as defined by IEEE 1275
-              bindings to powerpc. Only the 32-bit client interface
-              is currently supported
-
-              r3, r4 : address & length of an initrd if any or 0
-
-              The MMU is either on or off; the kernel will run the
-              trampoline located in arch/powerpc/kernel/prom_init.c to
-              extract the device-tree and other information from open
-              firmware and build a flattened device-tree as described
-              in b). prom_init() will then re-enter the kernel using
-              the second method. This trampoline code runs in the
-              context of the firmware, which is supposed to handle all
-              exceptions during that time.
-
-        b) Direct entry with a flattened device-tree block. This entry
-        point is called by a) after the OF trampoline and can also be
-        called directly by a bootloader that does not support the Open
-        Firmware client interface. It is also used by "kexec" to
-        implement "hot" booting of a new kernel from a previous
-        running one. This method is what I will describe in more
-        details in this document, as method a) is simply standard Open
-        Firmware, and thus should be implemented according to the
-        various standard documents defining it and its binding to the
-        PowerPC platform. The entry point definition then becomes:
-
-                r3 : physical pointer to the device-tree block
-                (defined in chapter II) in RAM
-
-                r4 : physical pointer to the kernel itself. This is
-                used by the assembly code to properly disable the MMU
-                in case you are entering the kernel with MMU enabled
-                and a non-1:1 mapping.
-
-                r5 : NULL (as to differentiate with method a)
-
-        Note about SMP entry: Either your firmware puts your other
-        CPUs in some sleep loop or spin loop in ROM where you can get
-        them out via a soft reset or some other means, in which case
-        you don't need to care, or you'll have to enter the kernel
-        with all CPUs. The way to do that with method b) will be
-        described in a later revision of this document.
-
-
-2) Board support
-----------------
-
-64-bit kernels:
-
-   Board supports (platforms) are not exclusive config options. An
-   arbitrary set of board supports can be built in a single kernel
-   image. The kernel will "know" what set of functions to use for a
-   given platform based on the content of the device-tree. Thus, you
-   should:
-
-        a) add your platform support as a _boolean_ option in
-        arch/powerpc/Kconfig, following the example of PPC_PSERIES,
-        PPC_PMAC and PPC_MAPLE. The later is probably a good
-        example of a board support to start from.
-
-        b) create your main platform file as
-        "arch/powerpc/platforms/myplatform/myboard_setup.c" and add it
-        to the Makefile under the condition of your CONFIG_
-        option. This file will define a structure of type "ppc_md"
-        containing the various callbacks that the generic code will
-        use to get to your platform specific code
-
-        c) Add a reference to your "ppc_md" structure in the
-        "machines" table in arch/powerpc/kernel/setup_64.c if you are
-        a 64-bit platform.
-
-        d) request and get assigned a platform number (see PLATFORM_*
-        constants in arch/powerpc/include/asm/processor.h
-
-32-bit embedded kernels:
-
-  Currently, board support is essentially an exclusive config option.
-  The kernel is configured for a single platform.  Part of the reason
-  for this is to keep kernels on embedded systems small and efficient;
-  part of this is due to the fact the code is already that way. In the
-  future, a kernel may support multiple platforms, but only if the
-  platforms feature the same core architecture.  A single kernel build
-  cannot support both configurations with Book E and configurations
-  with classic Powerpc architectures.
-
-  32-bit embedded platforms that are moved into arch/powerpc using a
-  flattened device tree should adopt the merged tree practice of
-  setting ppc_md up dynamically, even though the kernel is currently
-  built with support for only a single platform at a time.  This allows
-  unification of the setup code, and will make it easier to go to a
-  multiple-platform-support model in the future.
-
-NOTE: I believe the above will be true once Ben's done with the merge
-of the boot sequences.... someone speak up if this is wrong!
-
-  To add a 32-bit embedded platform support, follow the instructions
-  for 64-bit platforms above, with the exception that the Kconfig
-  option should be set up such that the kernel builds exclusively for
-  the platform selected.  The processor type for the platform should
-  enable another config option to select the specific board
-  supported.
-
-NOTE: If Ben doesn't merge the setup files, may need to change this to
-point to setup_32.c
-
-
-   I will describe later the boot process and various callbacks that
-   your platform should implement.
-
-
-II - The DT block format
-========================
-
-
-This chapter defines the actual format of the flattened device-tree
-passed to the kernel. The actual content of it and kernel requirements
-are described later. You can find example of code manipulating that
-format in various places, including arch/powerpc/kernel/prom_init.c
-which will generate a flattened device-tree from the Open Firmware
-representation, or the fs2dt utility which is part of the kexec tools
-which will generate one from a filesystem representation. It is
-expected that a bootloader like uboot provides a bit more support,
-that will be discussed later as well.
-
-Note: The block has to be in main memory. It has to be accessible in
-both real mode and virtual mode with no mapping other than main
-memory. If you are writing a simple flash bootloader, it should copy
-the block to RAM before passing it to the kernel.
-
-
-1) Header
----------
-
-   The kernel is entered with r3 pointing to an area of memory that is
-   roughly described in arch/powerpc/include/asm/prom.h by the structure
-   boot_param_header:
-
-struct boot_param_header {
-        u32     magic;                  /* magic word OF_DT_HEADER */
-        u32     totalsize;              /* total size of DT block */
-        u32     off_dt_struct;          /* offset to structure */
-        u32     off_dt_strings;         /* offset to strings */
-        u32     off_mem_rsvmap;         /* offset to memory reserve map
-                                           */
-        u32     version;                /* format version */
-        u32     last_comp_version;      /* last compatible version */
-
-        /* version 2 fields below */
-        u32     boot_cpuid_phys;        /* Which physical CPU id we're
-                                           booting on */
-        /* version 3 fields below */
-        u32     size_dt_strings;        /* size of the strings block */
-
-        /* version 17 fields below */
-        u32    size_dt_struct;         /* size of the DT structure block */
-};
-
-   Along with the constants:
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER            0xd00dfeed      /* 4: version,
-                                                  4: total size */
-#define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
-                                                  */
-#define OF_DT_END_NODE          0x2             /* End node */
-#define OF_DT_PROP              0x3             /* Property: name off,
-                                                   size, content */
-#define OF_DT_END               0x9
-
-   All values in this header are in big endian format, the various
-   fields in this header are defined more precisely below. All
-   "offset" values are in bytes from the start of the header; that is
-   from the value of r3.
-
-   - magic
-
-     This is a magic value that "marks" the beginning of the
-     device-tree block header. It contains the value 0xd00dfeed and is
-     defined by the constant OF_DT_HEADER
-
-   - totalsize
-
-     This is the total size of the DT block including the header. The
-     "DT" block should enclose all data structures defined in this
-     chapter (who are pointed to by offsets in this header). That is,
-     the device-tree structure, strings, and the memory reserve map.
-
-   - off_dt_struct
-
-     This is an offset from the beginning of the header to the start
-     of the "structure" part the device tree. (see 2) device tree)
-
-   - off_dt_strings
-
-     This is an offset from the beginning of the header to the start
-     of the "strings" part of the device-tree
-
-   - off_mem_rsvmap
-
-     This is an offset from the beginning of the header to the start
-     of the reserved memory map. This map is a list of pairs of 64-
-     bit integers. Each pair is a physical address and a size. The
-     list is terminated by an entry of size 0. This map provides the
-     kernel with a list of physical memory areas that are "reserved"
-     and thus not to be used for memory allocations, especially during
-     early initialization. The kernel needs to allocate memory during
-     boot for things like un-flattening the device-tree, allocating an
-     MMU hash table, etc... Those allocations must be done in such a
-     way to avoid overriding critical things like, on Open Firmware
-     capable machines, the RTAS instance, or on some pSeries, the TCE
-     tables used for the iommu. Typically, the reserve map should
-     contain _at least_ this DT block itself (header,total_size). If
-     you are passing an initrd to the kernel, you should reserve it as
-     well. You do not need to reserve the kernel image itself. The map
-     should be 64-bit aligned.
-
-   - version
-
-     This is the version of this structure. Version 1 stops
-     here. Version 2 adds an additional field boot_cpuid_phys.
-     Version 3 adds the size of the strings block, allowing the kernel
-     to reallocate it easily at boot and free up the unused flattened
-     structure after expansion. Version 16 introduces a new more
-     "compact" format for the tree itself that is however not backward
-     compatible. Version 17 adds an additional field, size_dt_struct,
-     allowing it to be reallocated or moved more easily (this is
-     particularly useful for bootloaders which need to make
-     adjustments to a device tree based on probed information). You
-     should always generate a structure of the highest version defined
-     at the time of your implementation. Currently that is version 17,
-     unless you explicitly aim at being backward compatible.
-
-   - last_comp_version
-
-     Last compatible version. This indicates down to what version of
-     the DT block you are backward compatible. For example, version 2
-     is backward compatible with version 1 (that is, a kernel build
-     for version 1 will be able to boot with a version 2 format). You
-     should put a 1 in this field if you generate a device tree of
-     version 1 to 3, or 16 if you generate a tree of version 16 or 17
-     using the new unit name format.
-
-   - boot_cpuid_phys
-
-     This field only exist on version 2 headers. It indicate which
-     physical CPU ID is calling the kernel entry point. This is used,
-     among others, by kexec. If you are on an SMP system, this value
-     should match the content of the "reg" property of the CPU node in
-     the device-tree corresponding to the CPU calling the kernel entry
-     point (see further chapters for more informations on the required
-     device-tree contents)
-
-   - size_dt_strings
-
-     This field only exists on version 3 and later headers.  It
-     gives the size of the "strings" section of the device tree (which
-     starts at the offset given by off_dt_strings).
-
-   - size_dt_struct
-
-     This field only exists on version 17 and later headers.  It gives
-     the size of the "structure" section of the device tree (which
-     starts at the offset given by off_dt_struct).
-
-   So the typical layout of a DT block (though the various parts don't
-   need to be in that order) looks like this (addresses go from top to
-   bottom):
-
-
-             ------------------------------
-       r3 -> |  struct boot_param_header  |
-             ------------------------------
-             |      (alignment gap) (*)   |
-             ------------------------------
-             |      memory reserve map    |
-             ------------------------------
-             |      (alignment gap)       |
-             ------------------------------
-             |                            |
-             |    device-tree structure   |
-             |                            |
-             ------------------------------
-             |      (alignment gap)       |
-             ------------------------------
-             |                            |
-             |     device-tree strings    |
-             |                            |
-      -----> ------------------------------
-      |
-      |
-      --- (r3 + totalsize)
-
-  (*) The alignment gaps are not necessarily present; their presence
-      and size are dependent on the various alignment requirements of
-      the individual data blocks.
-
-
-2) Device tree generalities
----------------------------
-
-This device-tree itself is separated in two different blocks, a
-structure block and a strings block. Both need to be aligned to a 4
-byte boundary.
-
-First, let's quickly describe the device-tree concept before detailing
-the storage format. This chapter does _not_ describe the detail of the
-required types of nodes & properties for the kernel, this is done
-later in chapter III.
-
-The device-tree layout is strongly inherited from the definition of
-the Open Firmware IEEE 1275 device-tree. It's basically a tree of
-nodes, each node having two or more named properties. A property can
-have a value or not.
-
-It is a tree, so each node has one and only one parent except for the
-root node who has no parent.
-
-A node has 2 names. The actual node name is generally contained in a
-property of type "name" in the node property list whose value is a
-zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 16 makes it
-optional as it can generate it from the unit name defined below.
-
-There is also a "unit name" that is used to differentiate nodes with
-the same name at the same level, it is usually made of the node
-names, the "@" sign, and a "unit address", which definition is
-specific to the bus type the node sits on.
-
-The unit name doesn't exist as a property per-se but is included in
-the device-tree structure. It is typically used to represent "path" in
-the device-tree. More details about the actual format of these will be
-below.
-
-The kernel powerpc generic code does not make any formal use of the
-unit address (though some board support code may do) so the only real
-requirement here for the unit address is to ensure uniqueness of
-the node unit name at a given level of the tree. Nodes with no notion
-of address and no possible sibling of the same name (like /memory or
-/cpus) may omit the unit address in the context of this specification,
-or use the "@0" default unit address. The unit name is used to define
-a node "full path", which is the concatenation of all parent node
-unit names separated with "/".
-
-The root node doesn't have a defined name, and isn't required to have
-a name property either if you are using version 3 or earlier of the
-format. It also has no unit address (no @ symbol followed by a unit
-address). The root node unit name is thus an empty string. The full
-path to the root node is "/".
-
-Every node which actually represents an actual device (that is, a node
-which isn't only a virtual "container" for more nodes, like "/cpus"
-is) is also required to have a "device_type" property indicating the
-type of node .
-
-Finally, every node that can be referenced from a property in another
-node is required to have a "linux,phandle" property. Real open
-firmware implementations provide a unique "phandle" value for every
-node that the "prom_init()" trampoline code turns into
-"linux,phandle" properties. However, this is made optional if the
-flattened device tree is used directly. An example of a node
-referencing another node via "phandle" is when laying out the
-interrupt tree which will be described in a further version of this
-document.
-
-This "linux, phandle" property is a 32-bit value that uniquely
-identifies a node. You are free to use whatever values or system of
-values, internal pointers, or whatever to generate these, the only
-requirement is that every node for which you provide that property has
-a unique value for it.
-
-Here is an example of a simple device-tree. In this example, an "o"
-designates a node followed by the node unit name. Properties are
-presented with their name followed by their content. "content"
-represents an ASCII string (zero terminated) value, while <content>
-represents a 32-bit hexadecimal value. The various nodes in this
-example will be discussed in a later chapter. At this point, it is
-only meant to give you a idea of what a device-tree looks like. I have
-purposefully kept the "name" and "linux,phandle" properties which
-aren't necessary in order to give you a better idea of what the tree
-looks like in practice.
-
-  / o device-tree
-      |- name = "device-tree"
-      |- model = "MyBoardName"
-      |- compatible = "MyBoardFamilyName"
-      |- #address-cells = <2>
-      |- #size-cells = <2>
-      |- linux,phandle = <0>
-      |
-      o cpus
-      | | - name = "cpus"
-      | | - linux,phandle = <1>
-      | | - #address-cells = <1>
-      | | - #size-cells = <0>
-      | |
-      | o PowerPC,970@0
-      |   |- name = "PowerPC,970"
-      |   |- device_type = "cpu"
-      |   |- reg = <0>
-      |   |- clock-frequency = <5f5e1000>
-      |   |- 64-bit
-      |   |- linux,phandle = <2>
-      |
-      o memory@0
-      | |- name = "memory"
-      | |- device_type = "memory"
-      | |- reg = <00000000 00000000 00000000 20000000>
-      | |- linux,phandle = <3>
-      |
-      o chosen
-        |- name = "chosen"
-        |- bootargs = "root=/dev/sda2"
-        |- linux,phandle = <4>
-
-This tree is almost a minimal tree. It pretty much contains the
-minimal set of required nodes and properties to boot a linux kernel;
-that is, some basic model informations at the root, the CPUs, and the
-physical memory layout.  It also includes misc information passed
-through /chosen, like in this example, the platform type (mandatory)
-and the kernel command line arguments (optional).
-
-The /cpus/PowerPC,970@0/64-bit property is an example of a
-property without a value. All other properties have a value. The
-significance of the #address-cells and #size-cells properties will be
-explained in chapter IV which defines precisely the required nodes and
-properties and their content.
-
-
-3) Device tree "structure" block
-
-The structure of the device tree is a linearized tree structure. The
-"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
-ends that node definition. Child nodes are simply defined before
-"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
-bit value. The tree has to be "finished" with a OF_DT_END token
-
-Here's the basic structure of a single node:
-
-     * token OF_DT_BEGIN_NODE (that is 0x00000001)
-     * for version 1 to 3, this is the node full path as a zero
-       terminated string, starting with "/". For version 16 and later,
-       this is the node unit name only (or an empty string for the
-       root node)
-     * [align gap to next 4 bytes boundary]
-     * for each property:
-        * token OF_DT_PROP (that is 0x00000003)
-        * 32-bit value of property value size in bytes (or 0 if no
-          value)
-        * 32-bit value of offset in string block of property name
-        * property value data if any
-        * [align gap to next 4 bytes boundary]
-     * [child nodes if any]
-     * token OF_DT_END_NODE (that is 0x00000002)
-
-So the node content can be summarized as a start token, a full path,
-a list of properties, a list of child nodes, and an end token. Every
-child node is a full node structure itself as defined above.
-
-NOTE: The above definition requires that all property definitions for
-a particular node MUST precede any subnode definitions for that node.
-Although the structure would not be ambiguous if properties and
-subnodes were intermingled, the kernel parser requires that the
-properties come first (up until at least 2.6.22).  Any tools
-manipulating a flattened tree must take care to preserve this
-constraint.
-
-4) Device tree "strings" block
-
-In order to save space, property names, which are generally redundant,
-are stored separately in the "strings" block. This block is simply the
-whole bunch of zero terminated strings for all property names
-concatenated together. The device-tree property definitions in the
-structure block will contain offset values from the beginning of the
-strings block.
-
-
-III - Required content of the device tree
-=========================================
-
-WARNING: All "linux,*" properties defined in this document apply only
-to a flattened device-tree. If your platform uses a real
-implementation of Open Firmware or an implementation compatible with
-the Open Firmware client interface, those properties will be created
-by the trampoline code in the kernel's prom_init() file. For example,
-that's where you'll have to add code to detect your board model and
-set the platform number. However, when using the flattened device-tree
-entry point, there is no prom_init() pass, and thus you have to
-provide those properties yourself.
-
-
-1) Note about cells and address representation
-----------------------------------------------
-
-The general rule is documented in the various Open Firmware
-documentations. If you choose to describe a bus with the device-tree
-and there exist an OF bus binding, then you should follow the
-specification. However, the kernel does not require every single
-device or bus to be described by the device tree.
-
-In general, the format of an address for a device is defined by the
-parent bus type, based on the #address-cells and #size-cells
-properties.  Note that the parent's parent definitions of #address-cells
-and #size-cells are not inherited so every node with children must specify
-them.  The kernel requires the root node to have those properties defining
-addresses format for devices directly mapped on the processor bus.
-
-Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32-bit number. For example, if both contain 2
-like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64-bit number (cells are
-concatenated and expected to be in big endian format). Another example
-is the way Apple firmware defines them, with 2 cells for an address
-and one cell for a size.  Most 32-bit implementations should define
-#address-cells and #size-cells to 1, which represents a 32-bit value.
-Some 32-bit processors allow for physical addresses greater than 32
-bits; these processors should define #address-cells as 2.
-
-"reg" properties are always a tuple of the type "address size" where
-the number of cells of address and size is specified by the bus
-#address-cells and #size-cells. When a bus supports various address
-spaces and other flags relative to a given address allocation (like
-prefetchable, etc...) those flags are usually added to the top level
-bits of the physical address. For example, a PCI physical address is
-made of 3 cells, the bottom two containing the actual address itself
-while the top cell contains address space indication, flags, and pci
-bus & device numbers.
-
-For busses that support dynamic allocation, it's the accepted practice
-to then not provide the address in "reg" (keep it 0) though while
-providing a flag indicating the address is dynamically allocated, and
-then, to provide a separate "assigned-addresses" property that
-contains the fully allocated addresses. See the PCI OF bindings for
-details.
-
-In general, a simple bus with no address space bits and no dynamic
-allocation is preferred if it reflects your hardware, as the existing
-kernel address parsing functions will work out of the box. If you
-define a bus type with a more complex address format, including things
-like address space bits, you'll have to add a bus translator to the
-prom_parse.c file of the recent kernels for your bus type.
-
-The "reg" property only defines addresses and sizes (if #size-cells is
-non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into CPU physical
-addresses), all busses must contain a "ranges" property. If the
-"ranges" property is missing at a given level, it's assumed that
-translation isn't possible, i.e., the registers are not visible on the
-parent bus.  The format of the "ranges" property for a bus is a list
-of:
-
-       bus address, parent bus address, size
-
-"bus address" is in the format of the bus this bus node is defining,
-that is, for a PCI bridge, it would be a PCI address. Thus, (bus
-address, size) defines a range of addresses for child devices. "parent
-bus address" is in the format of the parent bus of this bus. For
-example, for a PCI host controller, that would be a CPU address. For a
-PCI<->ISA bridge, that would be a PCI address. It defines the base
-address in the parent bus where the beginning of that range is mapped.
-
-For a new 64-bit powerpc board, I recommend either the 2/2 format or
-Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32-bit word.   New 32-bit powerpc boards should use a
-1/1 format, unless the processor supports physical addresses greater
-than 32-bits, in which case a 2/1 format is recommended.
-
-Alternatively, the "ranges" property may be empty, indicating that the
-registers are visible on the parent bus using an identity mapping
-translation.  In other words, the parent bus address space is the same
-as the child bus address space.
-
-2) Note about "compatible" properties
--------------------------------------
-
-These properties are optional, but recommended in devices and the root
-node. The format of a "compatible" property is a list of concatenated
-zero terminated strings. They allow a device to express its
-compatibility with a family of similar devices, in some cases,
-allowing a single driver to match against several devices regardless
-of their actual names.
-
-3) Note about "name" properties
--------------------------------
-
-While earlier users of Open Firmware like OldWorld macintoshes tended
-to use the actual device name for the "name" property, it's nowadays
-considered a good practice to use a name that is closer to the device
-class (often equal to device_type). For example, nowadays, ethernet
-controllers are named "ethernet", an additional "model" property
-defining precisely the chip type/model, and "compatible" property
-defining the family in case a single driver can driver more than one
-of these chips. However, the kernel doesn't generally put any
-restriction on the "name" property; it is simply considered good
-practice to follow the standard and its evolutions as closely as
-possible.
-
-Note also that the new format version 16 makes the "name" property
-optional. If it's absent for a node, then the node's unit name is then
-used to reconstruct the name. That is, the part of the unit name
-before the "@" sign is used (or the entire unit name if no "@" sign
-is present).
-
-4) Note about node and property names and character set
--------------------------------------------------------
-
-While open firmware provides more flexible usage of 8859-1, this
-specification enforces more strict rules. Nodes and properties should
-be comprised only of ASCII characters 'a' to 'z', '0' to
-'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
-allow uppercase characters 'A' to 'Z' (property names should be
-lowercase. The fact that vendors like Apple don't respect this rule is
-irrelevant here). Additionally, node and property names should always
-begin with a character in the range 'a' to 'z' (or 'A' to 'Z' for node
-names).
-
-The maximum number of characters for both nodes and property names
-is 31. In the case of node names, this is only the leftmost part of
-a unit name (the pure "name" property), it doesn't include the unit
-address which can extend beyond that limit.
-
-
-5) Required nodes and properties
---------------------------------
-  These are all that are currently required. However, it is strongly
-  recommended that you expose PCI host bridges as documented in the
-  PCI binding to open firmware, and your interrupt tree as documented
-  in OF interrupt tree specification.
-
-  a) The root node
-
-  The root node requires some properties to be present:
-
-    - model : this is your board name/model
-    - #address-cells : address representation for "root" devices
-    - #size-cells: the size representation for "root" devices
-    - device_type : This property shouldn't be necessary. However, if
-      you decide to create a device_type for your root node, make sure it
-      is _not_ "chrp" unless your platform is a pSeries or PAPR compliant
-      one for 64-bit, or a CHRP-type machine for 32-bit as this will
-      matched by the kernel this way.
-
-  Additionally, some recommended properties are:
-
-    - compatible : the board "family" generally finds its way here,
-      for example, if you have 2 board models with a similar layout,
-      that typically get driven by the same platform code in the
-      kernel, you would use a different "model" property but put a
-      value in "compatible". The kernel doesn't directly use that
-      value but it is generally useful.
-
-  The root node is also generally where you add additional properties
-  specific to your board like the serial number if any, that sort of
-  thing. It is recommended that if you add any "custom" property whose
-  name may clash with standard defined ones, you prefix them with your
-  vendor name and a comma.
-
-  b) The /cpus node
-
-  This node is the parent of all individual CPU nodes. It doesn't
-  have any specific requirements, though it's generally good practice
-  to have at least:
-
-               #address-cells = <00000001>
-               #size-cells    = <00000000>
-
-  This defines that the "address" for a CPU is a single cell, and has
-  no meaningful size. This is not necessary but the kernel will assume
-  that format when reading the "reg" properties of a CPU node, see
-  below
-
-  c) The /cpus/* nodes
-
-  So under /cpus, you are supposed to create a node for every CPU on
-  the machine. There is no specific restriction on the name of the
-  CPU, though It's common practice to call it PowerPC,<name>. For
-  example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX.
-
-  Required properties:
-
-    - device_type : has to be "cpu"
-    - reg : This is the physical CPU number, it's a single 32-bit cell
-      and is also used as-is as the unit number for constructing the
-      unit name in the full path. For example, with 2 CPUs, you would
-      have the full path:
-        /cpus/PowerPC,970FX@0
-        /cpus/PowerPC,970FX@1
-      (unit addresses do not require leading zeroes)
-    - d-cache-block-size : one cell, L1 data cache block size in bytes (*)
-    - i-cache-block-size : one cell, L1 instruction cache block size in
-      bytes
-    - d-cache-size : one cell, size of L1 data cache in bytes
-    - i-cache-size : one cell, size of L1 instruction cache in bytes
-
-(*) The cache "block" size is the size on which the cache management
-instructions operate. Historically, this document used the cache
-"line" size here which is incorrect. The kernel will prefer the cache
-block size and will fallback to cache line size for backward
-compatibility.
-
-  Recommended properties:
-
-    - timebase-frequency : a cell indicating the frequency of the
-      timebase in Hz. This is not directly used by the generic code,
-      but you are welcome to copy/paste the pSeries code for setting
-      the kernel timebase/decrementer calibration based on this
-      value.
-    - clock-frequency : a cell indicating the CPU core clock frequency
-      in Hz. A new property will be defined for 64-bit values, but if
-      your frequency is < 4Ghz, one cell is enough. Here as well as
-      for the above, the common code doesn't use that property, but
-      you are welcome to re-use the pSeries or Maple one. A future
-      kernel version might provide a common function for this.
-    - d-cache-line-size : one cell, L1 data cache line size in bytes
-      if different from the block size
-    - i-cache-line-size : one cell, L1 instruction cache line size in
-      bytes if different from the block size
-
-  You are welcome to add any property you find relevant to your board,
-  like some information about the mechanism used to soft-reset the
-  CPUs. For example, Apple puts the GPIO number for CPU soft reset
-  lines in there as a "soft-reset" property since they start secondary
-  CPUs by soft-resetting them.
-
-
-  d) the /memory node(s)
-
-  To define the physical memory layout of your board, you should
-  create one or more memory node(s). You can either create a single
-  node with all memory ranges in its reg property, or you can create
-  several nodes, as you wish. The unit address (@ part) used for the
-  full path is the address of the first range of memory defined by a
-  given node. If you use a single memory node, this will typically be
-  @0.
-
-  Required properties:
-
-    - device_type : has to be "memory"
-    - reg : This property contains all the physical memory ranges of
-      your board. It's a list of addresses/sizes concatenated
-      together, with the number of cells of each defined by the
-      #address-cells and #size-cells of the root node. For example,
-      with both of these properties being 2 like in the example given
-      earlier, a 970 based machine with 6Gb of RAM could typically
-      have a "reg" property here that looks like:
-
-      00000000 00000000 00000000 80000000
-      00000001 00000000 00000001 00000000
-
-      That is a range starting at 0 of 0x80000000 bytes and a range
-      starting at 0x100000000 and of 0x100000000 bytes. You can see
-      that there is no memory covering the IO hole between 2Gb and
-      4Gb. Some vendors prefer splitting those ranges into smaller
-      segments, but the kernel doesn't care.
-
-  e) The /chosen node
-
-  This node is a bit "special". Normally, that's where open firmware
-  puts some variable environment information, like the arguments, or
-  the default input/output devices.
-
-  This specification makes a few of these mandatory, but also defines
-  some linux-specific properties that would be normally constructed by
-  the prom_init() trampoline when booting with an OF client interface,
-  but that you have to provide yourself when using the flattened format.
-
-  Recommended properties:
-
-    - bootargs : This zero-terminated string is passed as the kernel
-      command line
-    - linux,stdout-path : This is the full path to your standard
-      console device if any. Typically, if you have serial devices on
-      your board, you may want to put the full path to the one set as
-      the default console in the firmware here, for the kernel to pick
-      it up as its own default console. If you look at the function
-      set_preferred_console() in arch/ppc64/kernel/setup.c, you'll see
-      that the kernel tries to find out the default console and has
-      knowledge of various types like 8250 serial ports. You may want
-      to extend this function to add your own.
-
-  Note that u-boot creates and fills in the chosen node for platforms
-  that use it.
-
-  (Note: a practice that is now obsolete was to include a property
-  under /chosen called interrupt-controller which had a phandle value
-  that pointed to the main interrupt controller)
-
-  f) the /soc<SOCname> node
-
-  This node is used to represent a system-on-a-chip (SOC) and must be
-  present if the processor is a SOC. The top-level soc node contains
-  information that is global to all devices on the SOC. The node name
-  should contain a unit address for the SOC, which is the base address
-  of the memory-mapped register set for the SOC. The name of an soc
-  node should start with "soc", and the remainder of the name should
-  represent the part number for the soc.  For example, the MPC8540's
-  soc node would be called "soc8540".
-
-  Required properties:
-
-    - device_type : Should be "soc"
-    - ranges : Should be defined as specified in 1) to describe the
-      translation of SOC addresses for memory mapped SOC registers.
-    - bus-frequency: Contains the bus frequency for the SOC node.
-      Typically, the value of this field is filled in by the boot
-      loader.
-
-
-  Recommended properties:
-
-    - reg : This property defines the address and size of the
-      memory-mapped registers that are used for the SOC node itself.
-      It does not include the child device registers - these will be
-      defined inside each child node.  The address specified in the
-      "reg" property should match the unit address of the SOC node.
-    - #address-cells : Address representation for "soc" devices.  The
-      format of this field may vary depending on whether or not the
-      device registers are memory mapped.  For memory mapped
-      registers, this field represents the number of cells needed to
-      represent the address of the registers.  For SOCs that do not
-      use MMIO, a special address format should be defined that
-      contains enough cells to represent the required information.
-      See 1) above for more details on defining #address-cells.
-    - #size-cells : Size representation for "soc" devices
-    - #interrupt-cells : Defines the width of cells used to represent
-       interrupts.  Typically this value is <2>, which includes a
-       32-bit number that represents the interrupt number, and a
-       32-bit number that represents the interrupt sense and level.
-       This field is only needed if the SOC contains an interrupt
-       controller.
-
-  The SOC node may contain child nodes for each SOC device that the
-  platform uses.  Nodes should not be created for devices which exist
-  on the SOC but are not used by a particular platform. See chapter VI
-  for more information on how to specify devices that are part of a SOC.
-
-  Example SOC node for the MPC8540:
-
-       soc8540@e0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               #interrupt-cells = <2>;
-               device_type = "soc";
-               ranges = <00000000 e0000000 00100000>
-               reg = <e0000000 00003000>;
-               bus-frequency = <0>;
-       }
-
-
-
-IV - "dtc", the device tree compiler
-====================================
-
-
-dtc source code can be found at
-<http://git.jdl.com/gitweb/?p=dtc.git>
-
-WARNING: This version is still in early development stage; the
-resulting device-tree "blobs" have not yet been validated with the
-kernel. The current generated block lacks a useful reserve map (it will
-be fixed to generate an empty one, it's up to the bootloader to fill
-it up) among others. The error handling needs work, bugs are lurking,
-etc...
-
-dtc basically takes a device-tree in a given format and outputs a
-device-tree in another format. The currently supported formats are:
-
-  Input formats:
-  -------------
-
-     - "dtb": "blob" format, that is a flattened device-tree block
-       with
-        header all in a binary blob.
-     - "dts": "source" format. This is a text file containing a
-       "source" for a device-tree. The format is defined later in this
-        chapter.
-     - "fs" format. This is a representation equivalent to the
-        output of /proc/device-tree, that is nodes are directories and
-       properties are files
-
- Output formats:
- ---------------
-
-     - "dtb": "blob" format
-     - "dts": "source" format
-     - "asm": assembly language file. This is a file that can be
-       sourced by gas to generate a device-tree "blob". That file can
-       then simply be added to your Makefile. Additionally, the
-       assembly file exports some symbols that can be used.
-
-
-The syntax of the dtc tool is
-
-    dtc [-I <input-format>] [-O <output-format>]
-        [-o output-filename] [-V output_version] input_filename
-
-
-The "output_version" defines what version of the "blob" format will be
-generated. Supported versions are 1,2,3 and 16. The default is
-currently version 3 but that may change in the future to version 16.
-
-Additionally, dtc performs various sanity checks on the tree, like the
-uniqueness of linux, phandle properties, validity of strings, etc...
-
-The format of the .dts "source" file is "C" like, supports C and C++
-style comments.
-
-/ {
-}
-
-The above is the "device-tree" definition. It's the only statement
-supported currently at the toplevel.
-
-/ {
-  property1 = "string_value";  /* define a property containing a 0
-                                 * terminated string
-                                */
-
-  property2 = <1234abcd>;      /* define a property containing a
-                                 * numerical 32-bit value (hexadecimal)
-                                */
-
-  property3 = <12345678 12345678 deadbeef>;
-                                /* define a property containing 3
-                                 * numerical 32-bit values (cells) in
-                                 * hexadecimal
-                                */
-  property4 = [0a 0b 0c 0d de ea ad be ef];
-                                /* define a property whose content is
-                                 * an arbitrary array of bytes
-                                 */
-
-  childnode@address {  /* define a child node named "childnode"
-                                 * whose unit name is "childnode at
-                                * address"
-                                 */
-
-    childprop = "hello\n";      /* define a property "childprop" of
-                                 * childnode (in this case, a string)
-                                 */
-  };
-};
-
-Nodes can contain other nodes etc... thus defining the hierarchical
-structure of the tree.
-
-Strings support common escape sequences from C: "\n", "\t", "\r",
-"\(octal value)", "\x(hex value)".
-
-It is also suggested that you pipe your source file through cpp (gcc
-preprocessor) so you can use #include's, #define for constants, etc...
-
-Finally, various options are planned but not yet implemented, like
-automatic generation of phandles, labels (exported to the asm file so
-you can point to a property content and change it easily from whatever
-you link the device-tree with), label or path instead of numeric value
-in some cells to "point" to a node (replaced by a phandle at compile
-time), export of reserve map address to the asm file, ability to
-specify reserve map content at compile time, etc...
-
-We may provide a .h include file with common definitions of that
-proves useful for some properties (like building PCI properties or
-interrupt maps) though it may be better to add a notion of struct
-definitions to the compiler...
-
-
-V - Recommendations for a bootloader
-====================================
-
-
-Here are some various ideas/recommendations that have been proposed
-while all this has been defined and implemented.
-
-  - The bootloader may want to be able to use the device-tree itself
-    and may want to manipulate it (to add/edit some properties,
-    like physical memory size or kernel arguments). At this point, 2
-    choices can be made. Either the bootloader works directly on the
-    flattened format, or the bootloader has its own internal tree
-    representation with pointers (similar to the kernel one) and
-    re-flattens the tree when booting the kernel. The former is a bit
-    more difficult to edit/modify, the later requires probably a bit
-    more code to handle the tree structure. Note that the structure
-    format has been designed so it's relatively easy to "insert"
-    properties or nodes or delete them by just memmoving things
-    around. It contains no internal offsets or pointers for this
-    purpose.
-
-  - An example of code for iterating nodes & retrieving properties
-    directly from the flattened tree format can be found in the kernel
-    file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function,
-    its usage in early_init_devtree(), and the corresponding various
-    early_init_dt_scan_*() callbacks. That code can be re-used in a
-    GPL bootloader, and as the author of that code, I would be happy
-    to discuss possible free licensing to any vendor who wishes to
-    integrate all or part of this code into a non-GPL bootloader.
-
-
-
-VI - System-on-a-chip devices and nodes
-=======================================
-
-Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (CPU) and many peripheral devices
-exist on a single piece of silicon.  For these SOCs, an SOC node
-should be used that defines child nodes for the devices that make
-up the SOC. While platforms are not required to use this model in
-order to boot the kernel, it is highly encouraged that all SOC
-implementations define as complete a flat-device-tree as possible to
-describe the devices on the SOC.  This will allow for the
-genericization of much of the kernel code.
-
-
-1) Defining child nodes of an SOC
----------------------------------
-
-Each device that is part of an SOC may have its own node entry inside
-the SOC node.  For each device that is included in the SOC, the unit
-address property represents the address offset for this device's
-memory-mapped registers in the parent's address space.  The parent's
-address space is defined by the "ranges" property in the top-level soc
-node. The "reg" property for each node that exists directly under the
-SOC node should contain the address mapping from the child address space
-to the parent SOC address space and the size of the device's
-memory-mapped register file.
-
-For many devices that may exist inside an SOC, there are predefined
-specifications for the format of the device tree node.  All SOC child
-nodes should follow these specifications, except where noted in this
-document.
-
-See appendix A for an example partial SOC node definition for the
-MPC8540.
-
-
-2) Representing devices without a current OF specification
-----------------------------------------------------------
-
-Currently, there are many devices on SOCs that do not have a standard
-representation pre-defined as part of the open firmware
-specifications, mainly because the boards that contain these SOCs are
-not currently booted using open firmware.   This section contains
-descriptions for the SOC devices for which new nodes have been
-defined; this list will expand as more and more SOC-containing
-platforms are moved over to use the flattened-device-tree model.
-
-VII - Specifying interrupt information for devices
-===================================================
-
-The device tree represents the busses and devices of a hardware
-system in a form similar to the physical bus topology of the
-hardware.
-
-In addition, a logical 'interrupt tree' exists which represents the
-hierarchy and routing of interrupts in the hardware.
-
-The interrupt tree model is fully described in the
-document "Open Firmware Recommended Practice: Interrupt
-Mapping Version 0.9".  The document is available at:
-<http://playground.sun.com/1275/practice>.
-
-1) interrupts property
-----------------------
-
-Devices that generate interrupts to a single interrupt controller
-should use the conventional OF representation described in the
-OF interrupt mapping documentation.
-
-Each device which generates interrupts must have an 'interrupt'
-property.  The interrupt property value is an arbitrary number of
-of 'interrupt specifier' values which describe the interrupt or
-interrupts for the device.
-
-The encoding of an interrupt specifier is determined by the
-interrupt domain in which the device is located in the
-interrupt tree.  The root of an interrupt domain specifies in
-its #interrupt-cells property the number of 32-bit cells
-required to encode an interrupt specifier.  See the OF interrupt
-mapping documentation for a detailed description of domains.
-
-For example, the binding for the OpenPIC interrupt controller
-specifies  an #interrupt-cells value of 2 to encode the interrupt
-number and level/sense information. All interrupt children in an
-OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
-property.
-
-The PCI bus binding specifies a #interrupt-cell value of 1 to encode
-which interrupt pin (INTA,INTB,INTC,INTD) is used.
-
-2) interrupt-parent property
-----------------------------
-
-The interrupt-parent property is specified to define an explicit
-link between a device node and its interrupt parent in
-the interrupt tree.  The value of interrupt-parent is the
-phandle of the parent node.
-
-If the interrupt-parent property is not defined for a node, its
-interrupt parent is assumed to be an ancestor in the node's
-_device tree_ hierarchy.
-
-3) OpenPIC Interrupt Controllers
---------------------------------
-
-OpenPIC interrupt controllers require 2 cells to encode
-interrupt information.  The first cell defines the interrupt
-number.  The second cell defines the sense and level
-information.
-
-Sense and level information should be encoded as follows:
-
-       0 = low to high edge sensitive type enabled
-       1 = active low level sensitive type enabled
-       2 = active high level sensitive type enabled
-       3 = high to low edge sensitive type enabled
-
-4) ISA Interrupt Controllers
-----------------------------
-
-ISA PIC interrupt controllers require 2 cells to encode
-interrupt information.  The first cell defines the interrupt
-number.  The second cell defines the sense and level
-information.
-
-ISA PIC interrupt controllers should adhere to the ISA PIC
-encodings listed below:
-
-       0 =  active low level sensitive type enabled
-       1 =  active high level sensitive type enabled
-       2 =  high to low edge sensitive type enabled
-       3 =  low to high edge sensitive type enabled
-
-VIII - Specifying Device Power Management Information (sleep property)
-===================================================================
-
-Devices on SOCs often have mechanisms for placing devices into low-power
-states that are decoupled from the devices' own register blocks.  Sometimes,
-this information is more complicated than a cell-index property can
-reasonably describe.  Thus, each device controlled in such a manner
-may contain a "sleep" property which describes these connections.
-
-The sleep property consists of one or more sleep resources, each of
-which consists of a phandle to a sleep controller, followed by a
-controller-specific sleep specifier of zero or more cells.
-
-The semantics of what type of low power modes are possible are defined
-by the sleep controller.  Some examples of the types of low power modes
-that may be supported are:
-
- - Dynamic: The device may be disabled or enabled at any time.
- - System Suspend: The device may request to be disabled or remain
-   awake during system suspend, but will not be disabled until then.
- - Permanent: The device is disabled permanently (until the next hard
-   reset).
-
-Some devices may share a clock domain with each other, such that they should
-only be suspended when none of the devices are in use.  Where reasonable,
-such nodes should be placed on a virtual bus, where the bus has the sleep
-property.  If the clock domain is shared among devices that cannot be
-reasonably grouped in this manner, then create a virtual sleep controller
-(similar to an interrupt nexus, except that defining a standardized
-sleep-map should wait until its necessity is demonstrated).
-
-Appendix A - Sample SOC node for MPC8540
-========================================
-
-       soc@e0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8540-ccsr", "simple-bus";
-               device_type = "soc";
-               ranges = <0x00000000 0xe0000000 0x00100000>
-               bus-frequency = <0>;
-               interrupt-parent = <&pic>;
-
-               ethernet@24000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       device_type = "network";
-                       model = "TSEC";
-                       compatible = "gianfar", "simple-bus";
-                       reg = <0x24000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 00 ];
-                       interrupts = <29 2 30 2 34 2>;
-                       phy-handle = <&phy0>;
-                       sleep = <&pmc 00000080>;
-                       ranges;
-
-                       mdio@24520 {
-                               reg = <0x24520 0x20>;
-                               compatible = "fsl,gianfar-mdio";
-
-                               phy0: ethernet-phy@0 {
-                                       interrupts = <5 1>;
-                                       reg = <0>;
-                                       device_type = "ethernet-phy";
-                               };
-
-                               phy1: ethernet-phy@1 {
-                                       interrupts = <5 1>;
-                                       reg = <1>;
-                                       device_type = "ethernet-phy";
-                               };
-
-                               phy3: ethernet-phy@3 {
-                                       interrupts = <7 1>;
-                                       reg = <3>;
-                                       device_type = "ethernet-phy";
-                               };
-                       };
-               };
-
-               ethernet@25000 {
-                       device_type = "network";
-                       model = "TSEC";
-                       compatible = "gianfar";
-                       reg = <0x25000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 01 ];
-                       interrupts = <13 2 14 2 18 2>;
-                       phy-handle = <&phy1>;
-                       sleep = <&pmc 00000040>;
-               };
-
-               ethernet@26000 {
-                       device_type = "network";
-                       model = "FEC";
-                       compatible = "gianfar";
-                       reg = <0x26000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 02 ];
-                       interrupts = <41 2>;
-                       phy-handle = <&phy3>;
-                       sleep = <&pmc 00000020>;
-               };
-
-               serial@4500 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "fsl,mpc8540-duart", "simple-bus";
-                       sleep = <&pmc 00000002>;
-                       ranges;
-
-                       serial@4500 {
-                               device_type = "serial";
-                               compatible = "ns16550";
-                               reg = <0x4500 0x100>;
-                               clock-frequency = <0>;
-                               interrupts = <42 2>;
-                       };
-
-                       serial@4600 {
-                               device_type = "serial";
-                               compatible = "ns16550";
-                               reg = <0x4600 0x100>;
-                               clock-frequency = <0>;
-                               interrupts = <42 2>;
-                       };
-               };
-
-               pic: pic@40000 {
-                       interrupt-controller;
-                       #address-cells = <0>;
-                       #interrupt-cells = <2>;
-                       reg = <0x40000 0x40000>;
-                       compatible = "chrp,open-pic";
-                       device_type = "open-pic";
-               };
-
-               i2c@3000 {
-                       interrupts = <43 2>;
-                       reg = <0x3000 0x100>;
-                       compatible  = "fsl-i2c";
-                       dfsrr;
-                       sleep = <&pmc 00000004>;
-               };
-
-               pmc: power@e0070 {
-                       compatible = "fsl,mpc8540-pmc", "fsl,mpc8548-pmc";
-                       reg = <0xe0070 0x20>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/4xx/cpm.txt b/Documentation/powerpc/dts-bindings/4xx/cpm.txt
deleted file mode 100644 (file)
index ee45980..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-PPC4xx Clock Power Management (CPM) node
-
-Required properties:
-       - compatible            : compatible list, currently only "ibm,cpm"
-       - dcr-access-method     : "native"
-       - dcr-reg               : < DCR register range >
-
-Optional properties:
-       - er-offset             : All 4xx SoCs with a CPM controller have
-                                 one of two different order for the CPM
-                                 registers. Some have the CPM registers
-                                 in the following order (ER,FR,SR). The
-                                 others have them in the following order
-                                 (SR,ER,FR). For the second case set
-                                 er-offset = <1>.
-       - unused-units          : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set to turn off unused
-                                 devices.
-       - idle-doze             : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set to turn off unused
-                                 devices. This is usually just CPM[CPU].
-       - standby               : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set on standby and
-                                 restored on resume.
-       - suspend               : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set on suspend (mem) and
-                                 restored on resume. Note, for standby
-                                 and suspend the corresponding bits can
-                                 be different or the same. Usually for
-                                 standby only class 2 and 3 units are set.
-                                 However, the interface does not care.
-                                 If they are the same, the additional
-                                 power saving will be seeing if support
-                                 is available to put the DDR in self
-                                 refresh mode and any additional power
-                                 saving techniques for the specific SoC.
-
-Example:
-       CPM0: cpm {
-               compatible = "ibm,cpm";
-               dcr-access-method = "native";
-               dcr-reg = <0x160 0x003>;
-               er-offset = <0>;
-               unused-units = <0x00000100>;
-               idle-doze = <0x02000000>;
-               standby = <0xfeff0000>;
-               suspend = <0xfeff791d>;
-};
diff --git a/Documentation/powerpc/dts-bindings/4xx/emac.txt b/Documentation/powerpc/dts-bindings/4xx/emac.txt
deleted file mode 100644 (file)
index 2161334..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-    4xx/Axon EMAC ethernet nodes
-
-    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
-    the Axon bridge.  To operate this needs to interact with a ths
-    special McMAL DMA controller, and sometimes an RGMII or ZMII
-    interface.  In addition to the nodes and properties described
-    below, the node for the OPB bus on which the EMAC sits must have a
-    correct clock-frequency property.
-
-      i) The EMAC node itself
-
-    Required properties:
-    - device_type       : "network"
-
-    - compatible        : compatible list, contains 2 entries, first is
-                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
-                         405gp, Axon) and second is either "ibm,emac" or
-                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
-                         "ibm,emac4"
-    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
-    - interrupt-parent  : optional, if needed for interrupt mapping
-    - reg               : <registers mapping>
-    - local-mac-address : 6 bytes, MAC address
-    - mal-device        : phandle of the associated McMAL node
-    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
-                         with this EMAC
-    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
-                         with this EMAC
-    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
-                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
-                         each Axon chip)
-    - max-frame-size    : 1 cell, maximum frame size supported in bytes
-    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048
-    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048.
-    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
-                         thresholds).
-                         For Axon, 0x00000010
-    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
-                         in bytes.
-                         For Axon, 0x00000100 (I think ...)
-    - phy-mode          : string, mode of operations of the PHY interface.
-                         Supported values are: "mii", "rmii", "smii", "rgmii",
-                         "tbi", "gmii", rtbi", "sgmii".
-                         For Axon on CAB, it is "rgmii"
-    - mdio-device       : 1 cell, required iff using shared MDIO registers
-                         (440EP).  phandle of the EMAC to use to drive the
-                         MDIO lines for the PHY used by this EMAC.
-    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
-                         the ZMII device node
-    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
-                         channel or 0xffffffff if ZMII is only used for MDIO.
-    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
-                         of the RGMII device node.
-                         For Axon: phandle of plb5/plb4/opb/rgmii
-    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
-                         RGMII channel is used by this EMAC.
-                         Fox Axon: present, whatever value is appropriate for each
-                         EMAC, that is the content of the current (bogus) "phy-port"
-                         property.
-
-    Optional properties:
-    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
-                         a search is performed.
-    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
-                         for, used if phy-address is absent. bit 0x00000001 is
-                         MDIO address 0.
-                         For Axon it can be absent, though my current driver
-                         doesn't handle phy-address yet so for now, keep
-                         0x00ffffff in it.
-    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         rx-fifo-size).  For Axon, either absent or 2048.
-    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         tx-fifo-size). For Axon, either absent or 2048.
-    - tah-device        : 1 cell, optional. If connected to a TAH engine for
-                         offload, phandle of the TAH device node.
-    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
-                         TAH engine.
-
-    Example:
-
-       EMAC0: ethernet@40000800 {
-               device_type = "network";
-               compatible = "ibm,emac-440gp", "ibm,emac";
-               interrupt-parent = <&UIC1>;
-               interrupts = <1c 4 1d 4>;
-               reg = <40000800 70>;
-               local-mac-address = [00 04 AC E3 1B 1E];
-               mal-device = <&MAL0>;
-               mal-tx-channel = <0 1>;
-               mal-rx-channel = <0>;
-               cell-index = <0>;
-               max-frame-size = <5dc>;
-               rx-fifo-size = <1000>;
-               tx-fifo-size = <800>;
-               phy-mode = "rmii";
-               phy-map = <00000001>;
-               zmii-device = <&ZMII0>;
-               zmii-channel = <0>;
-       };
-
-      ii) McMAL node
-
-    Required properties:
-    - device_type        : "dma-controller"
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
-                          emac) and the second is either "ibm,mcmal" or
-                          "ibm,mcmal2".
-                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
-    - interrupts         : <interrupt mapping for the MAL interrupts sources:
-                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
-                           For Axon: This is _different_ from the current
-                          firmware.  We use the "delayed" interrupts for txeob
-                          and rxeob. Thus we end up with mapping those 5 MPIC
-                          interrupts, all level positive sensitive: 10, 11, 32,
-                          33, 34 (in decimal)
-    - dcr-reg            : < DCR registers range >
-    - dcr-parent         : if needed for dcr-reg
-    - num-tx-chans       : 1 cell, number of Tx channels
-    - num-rx-chans       : 1 cell, number of Rx channels
-
-      iii) ZMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,zmii".
-                          For Axon, there is no ZMII node.
-    - reg                : <registers mapping>
-
-      iv) RGMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,rgmii".
-                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
-    - reg                : <registers mapping>
-    - revision           : as provided by the RGMII new version register if
-                          available.
-                          For Axon: 0x0000012a
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/ndfc.txt b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt
deleted file mode 100644 (file)
index 869f0b5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-AMCC NDFC (NanD Flash Controller)
-
-Required properties:
-- compatible : "ibm,ndfc".
-- reg : should specify chip select and size used for the chip (0x2000).
-
-Optional properties:
-- ccr : NDFC config and control register value (default 0).
-- bank-settings : NDFC bank configuration register value (default 0).
-
-Notes:
-- partition(s) - follows the OF MTD standard for partitions
-
-Example:
-
-ndfc@1,0 {
-       compatible = "ibm,ndfc";
-       reg = <0x00000001 0x00000000 0x00002000>;
-       ccr = <0x00001000>;
-       bank-settings = <0x80002222>;
-       #address-cells = <1>;
-       #size-cells = <1>;
-
-       nand {
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               partition@0 {
-                       label = "kernel";
-                       reg = <0x00000000 0x00200000>;
-               };
-               partition@200000 {
-                       label = "root";
-                       reg = <0x00200000 0x03E00000>;
-               };
-       };
-};
-
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt b/Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt
deleted file mode 100644 (file)
index 515ebcf..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-PPC440SPe DMA/XOR (DMA Controller and XOR Accelerator)
-
-Device nodes needed for operation of the ppc440spe-adma driver
-are specified hereby. These are I2O/DMA, DMA and XOR nodes
-for DMA engines and Memory Queue Module node. The latter is used
-by ADMA driver for configuration of RAID-6 H/W capabilities of
-the PPC440SPe. In addition to the nodes and properties described
-below, the ranges property of PLB node must specify ranges for
-DMA devices.
-
- i) The I2O node
-
- Required properties:
-
- - compatible          : "ibm,i2o-440spe";
- - reg                 : <registers mapping>
- - dcr-reg             : <DCR registers range>
-
- Example:
-
-       I2O: i2o@400100000 {
-               compatible = "ibm,i2o-440spe";
-               reg = <0x00000004 0x00100000 0x100>;
-               dcr-reg = <0x060 0x020>;
-       };
-
-
- ii) The DMA node
-
- Required properties:
-
- - compatible          : "ibm,dma-440spe";
- - cell-index          : 1 cell, hardware index of the DMA engine
-                         (typically 0x0 and 0x1 for DMA0 and DMA1)
- - reg                 : <registers mapping>
- - dcr-reg             : <DCR registers range>
- - interrupts          : <interrupt mapping for DMA0/1 interrupts sources:
-                          2 sources: DMAx CS FIFO Needs Service IRQ (on UIC0)
-                          and DMA Error IRQ (on UIC1). The latter is common
-                          for both DMA engines>.
- - interrupt-parent    : needed for interrupt mapping
-
- Example:
-
-       DMA0: dma0@400100100 {
-               compatible = "ibm,dma-440spe";
-               cell-index = <0>;
-               reg = <0x00000004 0x00100100 0x100>;
-               dcr-reg = <0x060 0x020>;
-               interrupt-parent = <&DMA0>;
-               interrupts = <0 1>;
-               #interrupt-cells = <1>;
-               #address-cells = <0>;
-               #size-cells = <0>;
-               interrupt-map = <
-                       0 &UIC0 0x14 4
-                       1 &UIC1 0x16 4>;
-       };
-
-
- iii) XOR Accelerator node
-
- Required properties:
-
- - compatible          : "amcc,xor-accelerator";
- - reg                 : <registers mapping>
- - interrupts          : <interrupt mapping for XOR interrupt source>
- - interrupt-parent    : for interrupt mapping
-
- Example:
-
-       xor-accel@400200000 {
-               compatible = "amcc,xor-accelerator";
-               reg = <0x00000004 0x00200000 0x400>;
-               interrupt-parent = <&UIC1>;
-               interrupts = <0x1f 4>;
-       };
-
-
- iv) Memory Queue Module node
-
- Required properties:
-
- - compatible          : "ibm,mq-440spe";
- - dcr-reg             : <DCR registers range>
-
- Example:
-
-       MQ0: mq {
-               compatible = "ibm,mq-440spe";
-               dcr-reg = <0x040 0x020>;
-       };
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/reboot.txt b/Documentation/powerpc/dts-bindings/4xx/reboot.txt
deleted file mode 100644 (file)
index d721726..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Reboot property to control system reboot on PPC4xx systems:
-
-By setting "reset_type" to one of the following values, the default
-software reset mechanism may be overidden. Here the possible values of
-"reset_type":
-
-      1 - PPC4xx core reset
-      2 - PPC4xx chip reset
-      3 - PPC4xx system reset (default)
-
-Example:
-
-               cpu@0 {
-                       device_type = "cpu";
-                       model = "PowerPC,440SPe";
-                       ...
-                       reset-type = <2>;       /* Use chip-reset */
-               };
diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt
deleted file mode 100644 (file)
index d6d209d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
-
-Required properties:
-
-- compatible : should be "nxp,sja1000".
-
-- reg : should specify the chip select, address offset and size required
-       to map the registers of the SJA1000. The size is usually 0x80.
-
-- interrupts: property with a value describing the interrupt source
-       (number and sensitivity) required for the SJA1000.
-
-Optional properties:
-
-- nxp,external-clock-frequency : Frequency of the external oscillator
-       clock in Hz. Note that the internal clock frequency used by the
-       SJA1000 is half of that value. If not specified, a default value
-       of 16000000 (16 MHz) is used.
-
-- nxp,tx-output-mode : operation mode of the TX output control logic:
-       <0x0> : bi-phase output mode
-       <0x1> : normal output mode (default)
-       <0x2> : test output mode
-       <0x3> : clock output mode
-
-- nxp,tx-output-config : TX output pin configuration:
-       <0x01> : TX0 invert
-       <0x02> : TX0 pull-down (default)
-       <0x04> : TX0 pull-up
-       <0x06> : TX0 push-pull
-       <0x08> : TX1 invert
-       <0x10> : TX1 pull-down
-       <0x20> : TX1 pull-up
-       <0x30> : TX1 push-pull
-
-- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin.
-       If not specified or if the specified value is 0, the CLKOUT pin
-       will be disabled.
-
-- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
-
-For futher information, please have a look to the SJA1000 data sheet.
-
-Examples:
-
-can@3,100 {
-       compatible = "nxp,sja1000";
-       reg = <3 0x100 0x80>;
-       interrupts = <2 0>;
-       interrupt-parent = <&mpic>;
-       nxp,external-clock-frequency = <16000000>;
-};
-
diff --git a/Documentation/powerpc/dts-bindings/ecm.txt b/Documentation/powerpc/dts-bindings/ecm.txt
deleted file mode 100644 (file)
index f514f29..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-=====================================================================
-E500 LAW & Coherency Module Device Tree Binding
-Copyright (C) 2009 Freescale Semiconductor Inc.
-=====================================================================
-
-Local Access Window (LAW) Node
-
-The LAW node represents the region of CCSR space where local access
-windows are configured.  For ECM based devices this is the first 4k
-of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
-number of local access windows as specified by fsl,num-laws.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,ecm-law"
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-  - fsl,num-laws
-      Usage: required
-      Value type: <u32>
-      Definition: The value specifies the number of local access
-          windows for this device.
-
-=====================================================================
-
-E500 Coherency Module Node
-
-The E500 LAW node represents the region of CCSR space where ECM config
-and error reporting registers exist, this is the second 4k (0x1000)
-of CCSR space.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,CHIP-ecm", "fsl,ecm" where
-      CHIP is the processor (mpc8572, mpc8544, etc.)
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-   - interrupts
-      Usage: required
-      Value type: <prop-encoded-array>
-
-   - interrupt-parent
-      Usage: required
-      Value type: <phandle>
-
-=====================================================================
diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentation/powerpc/dts-bindings/eeprom.txt
deleted file mode 100644 (file)
index 4342c10..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-EEPROMs (I2C)
-
-Required properties:
-
-  - compatible : should be "<manufacturer>,<type>"
-                If there is no specific driver for <manufacturer>, a generic
-                driver based on <type> is selected. Possible types are:
-                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
-                24c128, 24c256, 24c512, 24c1024, spd
-
-  - reg : the I2C address of the EEPROM
-
-Optional properties:
-
-  - pagesize : the length of the pagesize for writing. Please consult the
-               manual of your device, that value varies a lot. A wrong value
-              may result in data loss! If not specified, a safety value of
-              '1' is used which will be very slow.
-
-  - read-only: this parameterless property disables writes to the eeprom
-
-Example:
-
-eeprom@52 {
-       compatible = "atmel,24c32";
-       reg = <0x52>;
-       pagesize = <32>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt b/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt
deleted file mode 100644 (file)
index 35a4653..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-* Freescale 83xx and 512x PCI bridges
-
-Freescale 83xx and 512x SOCs include the same pci bridge core.
-
-83xx/512x specific notes:
-- reg: should contain two address length tuples
-    The first is for the internal pci bridge registers
-    The second is for the pci config space access registers
-
-Example (MPC8313ERDB)
-       pci0: pci@e0008500 {
-               cell-index = <1>;
-               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-               interrupt-map = <
-                               /* IDSEL 0x0E -mini PCI */
-                                0x7000 0x0 0x0 0x1 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x2 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x3 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x4 &ipic 18 0x8
-
-                               /* IDSEL 0x0F - PCI slot */
-                                0x7800 0x0 0x0 0x1 &ipic 17 0x8
-                                0x7800 0x0 0x0 0x2 &ipic 18 0x8
-                                0x7800 0x0 0x0 0x3 &ipic 17 0x8
-                                0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
-               interrupt-parent = <&ipic>;
-               interrupts = <66 0x8>;
-               bus-range = <0x0 0x0>;
-               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
-                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
-                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
-               clock-frequency = <66666666>;
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               reg = <0xe0008500 0x100         /* internal registers */
-                      0xe0008300 0x8>;         /* config space access registers */
-               compatible = "fsl,mpc8349-pci";
-               device_type = "pci";
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt
deleted file mode 100644 (file)
index b0019eb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-GPIO controllers on MPC8xxx SoCs
-
-This is for the non-QE/CPM/GUTs GPIO controllers as found on
-8349, 8572, 8610 and compatible.
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Required properties:
-- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
-  83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
- - interrupts : Interrupt mapping for GPIO IRQ.
- - interrupt-parent : Phandle for the interrupt controller that
-   services interrupts for this device.
-- gpio-controller : Marks the port as GPIO controller.
-
-Example of gpio-controller nodes for a MPC8347 SoC:
-
-       gpio1: gpio-controller@c00 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
-               reg = <0xc00 0x100>;
-               interrupts = <74 0x8>;
-               interrupt-parent = <&ipic>;
-               gpio-controller;
-       };
-
-       gpio2: gpio-controller@d00 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
-               reg = <0xd00 0x100>;
-               interrupts = <75 0x8>;
-               interrupt-parent = <&ipic>;
-               gpio-controller;
-       };
-
-See booting-without-of.txt for details of how to specify GPIO
-information for devices.
-
-To use GPIO pins as interrupt sources for peripherals, specify the
-GPIO controller as the interrupt parent and define GPIO number +
-trigger mode using the interrupts property, which is defined like
-this:
-
-interrupts = <number trigger>, where:
- - number: GPIO pin (0..31)
- - trigger: trigger mode:
-       2 = trigger on falling edge
-       3 = trigger on both edges
-
-Example of device using this is:
-
-       funkyfpga@0 {
-               compatible = "funky-fpga";
-               ...
-               interrupts = <4 3>;
-               interrupt-parent = <&gpio1>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/board.txt b/Documentation/powerpc/dts-bindings/fsl/board.txt
deleted file mode 100644 (file)
index 39e9415..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-* Board Control and Status (BCSR)
-
-Required properties:
-
- - compatible : Should be "fsl,<board>-bcsr"
- - reg : Offset and length of the register set for the device
-
-Example:
-
-       bcsr@f8000000 {
-               compatible = "fsl,mpc8360mds-bcsr";
-               reg = <f8000000 8000>;
-       };
-
-* Freescale on board FPGA
-
-This is the memory-mapped registers for on board FPGA.
-
-Required properities:
-- compatible : should be "fsl,fpga-pixis".
-- reg : should contain the address and the length of the FPPGA register
-  set.
-- interrupt-parent: should specify phandle for the interrupt controller.
-- interrupts : should specify event (wakeup) IRQ.
-
-Example (MPC8610HPCD):
-
-       board-control@e8000000 {
-               compatible = "fsl,fpga-pixis";
-               reg = <0xe8000000 32>;
-               interrupt-parent = <&mpic>;
-               interrupts = <8 8>;
-       };
-
-* Freescale BCSR GPIO banks
-
-Some BCSR registers act as simple GPIO controllers, each such
-register can be represented by the gpio-controller node.
-
-Required properities:
-- compatible : Should be "fsl,<board>-bcsr-gpio".
-- reg : Should contain the address and the length of the GPIO bank
-  register.
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
-- gpio-controller : Marks the port as GPIO controller.
-
-Example:
-
-       bcsr@1,0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8360mds-bcsr";
-               reg = <1 0 0x8000>;
-               ranges = <0 1 0 0x8000>;
-
-               bcsr13: gpio-controller@d {
-                       #gpio-cells = <2>;
-                       compatible = "fsl,mpc8360mds-bcsr-gpio";
-                       reg = <0xd 1>;
-                       gpio-controller;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/can.txt b/Documentation/powerpc/dts-bindings/fsl/can.txt
deleted file mode 100644 (file)
index 2fa4fcd..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-CAN Device Tree Bindings
-------------------------
-
-(c) 2006-2009 Secret Lab Technologies Ltd
-Grant Likely <grant.likely@secretlab.ca>
-
-fsl,mpc5200-mscan nodes
------------------------
-In addition to the required compatible-, reg- and interrupt-properties, you can
-also specify which clock source shall be used for the controller:
-
-- fsl,mscan-clock-source : a string describing the clock source. Valid values
-                          are: "ip" for ip bus clock
-                                "ref" for reference clock (XTAL)
-                          "ref" is default in case this property is not
-                          present.
-
-fsl,mpc5121-mscan nodes
------------------------
-In addition to the required compatible-, reg- and interrupt-properties, you can
-also specify which clock source and divider shall be used for the controller:
-
-- fsl,mscan-clock-source : a string describing the clock source. Valid values
-                          are: "ip" for ip bus clock
-                               "ref" for reference clock
-                               "sys" for system clock
-                          If this property is not present, an optimal CAN
-                          clock source and frequency based on the system
-                          clock will be selected. If this is not possible,
-                          the reference clock will be used.
-
-- fsl,mscan-clock-divider: for the reference and system clock, an additional
-                          clock divider can be specified. By default, a
-                          value of 1 is used.
-
-Note that the MPC5121 Rev. 1 processor is not supported.
-
-Examples:
-       can@1300 {
-               compatible = "fsl,mpc5121-mscan";
-               interrupts = <12 0x8>;
-               interrupt-parent = <&ipic>;
-               reg = <0x1300 0x80>;
-       };
-
-       can@1380 {
-               compatible = "fsl,mpc5121-mscan";
-               interrupts = <13 0x8>;
-               interrupt-parent = <&ipic>;
-               reg = <0x1380 0x80>;
-               fsl,mscan-clock-source = "ref";
-               fsl,mscan-clock-divider = <3>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt
deleted file mode 100644 (file)
index 160c752..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-* Freescale Communications Processor Module
-
-NOTE: This is an interim binding, and will likely change slightly,
-as more devices are supported.  The QE bindings especially are
-incomplete.
-
-* Root CPM node
-
-Properties:
-- compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe".
-- reg : A 48-byte region beginning with CPCR.
-
-Example:
-     cpm@119c0 {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       #interrupt-cells = <2>;
-       compatible = "fsl,mpc8272-cpm", "fsl,cpm2";
-       reg = <119c0 30>;
-     }
-
-* Properties common to multiple CPM/QE devices
-
-- fsl,cpm-command : This value is ORed with the opcode and command flag
-                    to specify the device on which a CPM command operates.
-
-- fsl,cpm-brg : Indicates which baud rate generator the device
-                is associated with.  If absent, an unused BRG
-                should be dynamically allocated.  If zero, the
-                device uses an external clock rather than a BRG.
-
-- reg : Unless otherwise specified, the first resource represents the
-        scc/fcc/ucc registers, and the second represents the device's
-        parameter RAM region (if it has one).
-
-* Multi-User RAM (MURAM)
-
-The multi-user/dual-ported RAM is expressed as a bus under the CPM node.
-
-Ranges must be set up subject to the following restrictions:
-
-- Children's reg nodes must be offsets from the start of all muram, even
-  if the user-data area does not begin at zero.
-- If multiple range entries are used, the difference between the parent
-  address and the child address must be the same in all, so that a single
-  mapping can cover them all while maintaining the ability to determine
-  CPM-side offsets with pointer subtraction.  It is recommended that
-  multiple range entries not be used.
-- A child address of zero must be translatable, even if no reg resources
-  contain it.
-
-A child "data" node must exist, compatible with "fsl,cpm-muram-data", to
-indicate the portion of muram that is usable by the OS for arbitrary
-purposes.  The data node may have an arbitrary number of reg resources,
-all of which contribute to the allocatable muram pool.
-
-Example, based on mpc8272:
-       muram@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 10000>;
-
-               data@0 {
-                       compatible = "fsl,cpm-muram-data";
-                       reg = <0 2000 9800 800>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt
deleted file mode 100644 (file)
index 4c7d45e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Baud Rate Generators
-
-Currently defined compatibles:
-fsl,cpm-brg
-fsl,cpm1-brg
-fsl,cpm2-brg
-
-Properties:
-- reg : There may be an arbitrary number of reg resources; BRG
-  numbers are assigned to these in order.
-- clock-frequency : Specifies the base frequency driving
-  the BRG.
-
-Example:
-       brg@119f0 {
-               compatible = "fsl,mpc8272-brg",
-                            "fsl,cpm2-brg",
-                            "fsl,cpm-brg";
-               reg = <119f0 10 115f0 10>;
-               clock-frequency = <d#25000000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt
deleted file mode 100644 (file)
index 87bc604..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-* I2C
-
-The I2C controller is expressed as a bus under the CPM node.
-
-Properties:
-- compatible : "fsl,cpm1-i2c", "fsl,cpm2-i2c"
-- reg : On CPM2 devices, the second resource doesn't specify the I2C
-  Parameter RAM itself, but the I2C_BASE field of the CPM2 Parameter RAM
-  (typically 0x8afc 0x2).
-- #address-cells : Should be one. The cell is the i2c device address with
-  the r/w bit set to zero.
-- #size-cells : Should be zero.
-- clock-frequency : Can be used to set the i2c clock frequency. If
-  unspecified, a default frequency of 60kHz is being used.
-The following two properties are deprecated. They are only used by legacy
-i2c drivers to find the bus to probe:
-- linux,i2c-index : Can be used to hard code an i2c bus number. By default,
-  the bus number is dynamically assigned by the i2c core.
-- linux,i2c-class : Can be used to override the i2c class. The class is used
-  by legacy i2c device drivers to find a bus in a specific context like
-  system management, video or sound. By default, I2C_CLASS_HWMON (1) is
-  being used. The definition of the classes can be found in
-  include/i2c/i2c.h
-
-Example, based on mpc823:
-
-       i2c@860 {
-               compatible = "fsl,mpc823-i2c",
-                            "fsl,cpm1-i2c";
-               reg = <0x860 0x20 0x3c80 0x30>;
-               interrupts = <16>;
-               interrupt-parent = <&CPM_PIC>;
-               fsl,cpm-command = <0x10>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               rtc@68 {
-                       compatible = "dallas,ds1307";
-                       reg = <0x68>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt
deleted file mode 100644 (file)
index 8e3ee16..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-* Interrupt Controllers
-
-Currently defined compatibles:
-- fsl,cpm1-pic
-  - only one interrupt cell
-- fsl,pq1-pic
-- fsl,cpm2-pic
-  - second interrupt cell is level/sense:
-    - 2 is falling edge
-    - 8 is active low
-
-Example:
-       interrupt-controller@10c00 {
-               #interrupt-cells = <2>;
-               interrupt-controller;
-               reg = <10c00 80>;
-               compatible = "mpc8272-pic", "fsl,cpm2-pic";
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt
deleted file mode 100644 (file)
index 74bfda4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-* USB (Universal Serial Bus Controller)
-
-Properties:
-- compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb"
-
-Example:
-       usb@11bc0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,cpm2-usb";
-               reg = <11b60 18 8b00 100>;
-               interrupts = <b 8>;
-               interrupt-parent = <&PIC>;
-               fsl,cpm-command = <2e600000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt
deleted file mode 100644 (file)
index 349f79f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-On CPM1 devices, all ports are using slightly different register layouts.
-Ports A, C and D are 16bit ports and Ports B and E are 32bit ports.
-
-On CPM2 devices, all ports are 32bit ports and use a common register layout.
-
-Required properties:
-- compatible : "fsl,cpm1-pario-bank-a", "fsl,cpm1-pario-bank-b",
-  "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d",
-  "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank"
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
-- gpio-controller : Marks the port as GPIO controller.
-
-Example of three SOC GPIO banks defined as gpio-controller nodes:
-
-       CPM1_PIO_A: gpio-controller@950 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-a";
-               reg = <0x950 0x10>;
-               gpio-controller;
-       };
-
-       CPM1_PIO_B: gpio-controller@ab8 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-b";
-               reg = <0xab8 0x10>;
-               gpio-controller;
-       };
-
-       CPM1_PIO_E: gpio-controller@ac8 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-e";
-               reg = <0xac8 0x18>;
-               gpio-controller;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt
deleted file mode 100644 (file)
index 0e42694..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-* Network
-
-Currently defined compatibles:
-- fsl,cpm1-scc-enet
-- fsl,cpm2-scc-enet
-- fsl,cpm1-fec-enet
-- fsl,cpm2-fcc-enet (third resource is GFEMR)
-- fsl,qe-enet
-
-Example:
-
-       ethernet@11300 {
-               device_type = "network";
-               compatible = "fsl,mpc8272-fcc-enet",
-                            "fsl,cpm2-fcc-enet";
-               reg = <11300 20 8400 100 11390 1>;
-               local-mac-address = [ 00 00 00 00 00 00 ];
-               interrupts = <20 8>;
-               interrupt-parent = <&PIC>;
-               phy-handle = <&PHY0>;
-               fsl,cpm-command = <12000300>;
-       };
-
-* MDIO
-
-Currently defined compatibles:
-fsl,pq1-fec-mdio (reg is same as first resource of FEC device)
-fsl,cpm2-mdio-bitbang (reg is port C registers)
-
-Properties for fsl,cpm2-mdio-bitbang:
-fsl,mdio-pin : pin of port C controlling mdio data
-fsl,mdc-pin : pin of port C controlling mdio clock
-
-Example:
-       mdio@10d40 {
-               device_type = "mdio";
-               compatible = "fsl,mpc8272ads-mdio-bitbang",
-                            "fsl,mpc8272-mdio-bitbang",
-                            "fsl,cpm2-mdio-bitbang";
-               reg = <10d40 14>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               fsl,mdio-pin = <12>;
-               fsl,mdc-pin = <13>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt
deleted file mode 100644 (file)
index 4f89302..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-* Freescale QUICC Engine module (QE)
-This represents qe module that is installed on PowerQUICC II Pro.
-
-NOTE:  This is an interim binding; it should be updated to fit
-in with the CPM binding later in this document.
-
-Basically, it is a bus of devices, that could act more or less
-as a complete entity (UCC, USB etc ). All of them should be siblings on
-the "root" qe node, using the common properties from there.
-The description below applies to the qe of MPC8360 and
-more nodes and properties would be extended in the future.
-
-i) Root QE device
-
-Required properties:
-- compatible : should be "fsl,qe";
-- model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
-- reg : offset and length of the device registers.
-- bus-frequency : the clock frequency for QUICC Engine.
-- fsl,qe-num-riscs: define how many RISC engines the QE has.
-- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the
-  threads.
-
-Optional properties:
-- fsl,firmware-phandle:
-    Usage: required only if there is no fsl,qe-firmware child node
-    Value type: <phandle>
-    Definition: Points to a firmware node (see "QE Firmware Node" below)
-        that contains the firmware that should be uploaded for this QE.
-        The compatible property for the firmware node should say,
-        "fsl,qe-firmware".
-
-Recommended properties
-- brg-frequency : the internal clock source frequency for baud-rate
-  generators in Hz.
-
-Example:
-     qe@e0100000 {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       #interrupt-cells = <2>;
-       compatible = "fsl,qe";
-       ranges = <0 e0100000 00100000>;
-       reg = <e0100000 480>;
-       brg-frequency = <0>;
-       bus-frequency = <179A7B00>;
-     }
-
-* Multi-User RAM (MURAM)
-
-Required properties:
-- compatible : should be "fsl,qe-muram", "fsl,cpm-muram".
-- mode : the could be "host" or "slave".
-- ranges : Should be defined as specified in 1) to describe the
-   translation of MURAM addresses.
-- data-only : sub-node which defines the address area under MURAM
-   bus that can be allocated as data/parameter
-
-Example:
-
-     muram@10000 {
-       compatible = "fsl,qe-muram", "fsl,cpm-muram";
-       ranges = <0 00010000 0000c000>;
-
-       data-only@0{
-               compatible = "fsl,qe-muram-data",
-                            "fsl,cpm-muram-data";
-               reg = <0 c000>;
-       };
-     };
-
-* QE Firmware Node
-
-This node defines a firmware binary that is embedded in the device tree, for
-the purpose of passing the firmware from bootloader to the kernel, or from
-the hypervisor to the guest.
-
-The firmware node itself contains the firmware binary contents, a compatible
-property, and any firmware-specific properties.  The node should be placed
-inside a QE node that needs it.  Doing so eliminates the need for a
-fsl,firmware-phandle property.  Other QE nodes that need the same firmware
-should define an fsl,firmware-phandle property that points to the firmware node
-in the first QE node.
-
-The fsl,firmware property can be specified in the DTS (possibly using incbin)
-or can be inserted by the boot loader at boot time.
-
-Required properties:
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: A standard property.  Specify a string that indicates what
-          kind of firmware it is.  For QE, this should be "fsl,qe-firmware".
-
-   - fsl,firmware
-      Usage: required
-      Value type: <prop-encoded-array>, encoded as an array of bytes
-      Definition: A standard property.  This property contains the firmware
-          binary "blob".
-
-Example:
-       qe1@e0080000 {
-               compatible = "fsl,qe";
-               qe_firmware:qe-firmware {
-                       compatible = "fsl,qe-firmware";
-                       fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...];
-               };
-               ...
-       };
-
-       qe2@e0090000 {
-               compatible = "fsl,qe";
-               fsl,firmware-phandle = <&qe_firmware>;
-               ...
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt
deleted file mode 100644 (file)
index 249db3a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-* Uploaded QE firmware
-
-      If a new firmware has been uploaded to the QE (usually by the
-      boot loader), then a 'firmware' child node should be added to the QE
-      node.  This node provides information on the uploaded firmware that
-      device drivers may need.
-
-      Required properties:
-      - id: The string name of the firmware.  This is taken from the 'id'
-            member of the qe_firmware structure of the uploaded firmware.
-            Device drivers can search this string to determine if the
-            firmware they want is already present.
-      - extended-modes: The Extended Modes bitfield, taken from the
-                  firmware binary.  It is a 64-bit number represented
-                  as an array of two 32-bit numbers.
-      - virtual-traps: The virtual traps, taken from the firmware binary.
-                 It is an array of 8 32-bit numbers.
-
-Example:
-       firmware {
-               id = "Soft-UART";
-               extended-modes = <0 0>;
-               virtual-traps = <0 0 0 0 0 0 0 0>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt
deleted file mode 100644 (file)
index 6098426..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-* Parallel I/O Ports
-
-This node configures Parallel I/O ports for CPUs with QE support.
-The node should reside in the "soc" node of the tree.  For each
-device that using parallel I/O ports, a child node should be created.
-See the definition of the Pin configuration nodes below for more
-information.
-
-Required properties:
-- device_type : should be "par_io".
-- reg : offset to the register set and its length.
-- num-ports : number of Parallel I/O ports
-
-Example:
-par_io@1400 {
-       reg = <1400 100>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-       device_type = "par_io";
-       num-ports = <7>;
-       ucc_pin@01 {
-               ......
-       };
-
-Note that "par_io" nodes are obsolete, and should not be used for
-the new device trees. Instead, each Par I/O bank should be represented
-via its own gpio-controller node:
-
-Required properties:
-- #gpio-cells : should be "2".
-- compatible : should be "fsl,<chip>-qe-pario-bank",
-  "fsl,mpc8323-qe-pario-bank".
-- reg : offset to the register set and its length.
-- gpio-controller : node to identify gpio controllers.
-
-Example:
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8360-qe-pario-bank",
-               "fsl,mpc8323-qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-         };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8360-qe-pario-bank",
-                            "fsl,mpc8323-qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-         };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt
deleted file mode 100644 (file)
index c5b4306..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-* Pin configuration nodes
-
-Required properties:
-- linux,phandle : phandle of this node; likely referenced by a QE
-  device.
-- pio-map : array of pin configurations.  Each pin is defined by 6
-  integers.  The six numbers are respectively: port, pin, dir,
-  open_drain, assignment, has_irq.
-  - port : port number of the pin; 0-6 represent port A-G in UM.
-  - pin : pin number in the port.
-  - dir : direction of the pin, should encode as follows:
-
-     0 = The pin is disabled
-     1 = The pin is an output
-     2 = The pin is an input
-     3 = The pin is I/O
-
-  - open_drain : indicates the pin is normal or wired-OR:
-
-     0 = The pin is actively driven as an output
-     1 = The pin is an open-drain driver. As an output, the pin is
-         driven active-low, otherwise it is three-stated.
-
-  - assignment : function number of the pin according to the Pin Assignment
-    tables in User Manual.  Each pin can have up to 4 possible functions in
-    QE and two options for CPM.
-  - has_irq : indicates if the pin is used as source of external
-    interrupts.
-
-Example:
-     ucc_pin@01 {
-       linux,phandle = <140001>;
-       pio-map = <
-       /* port  pin  dir  open_drain  assignment  has_irq */
-               0  3  1  0  1  0        /* TxD0 */
-               0  4  1  0  1  0        /* TxD1 */
-               0  5  1  0  1  0        /* TxD2 */
-               0  6  1  0  1  0        /* TxD3 */
-               1  6  1  0  3  0        /* TxD4 */
-               1  7  1  0  1  0        /* TxD5 */
-               1  9  1  0  2  0        /* TxD6 */
-               1  a  1  0  2  0        /* TxD7 */
-               0  9  2  0  1  0        /* RxD0 */
-               0  a  2  0  1  0        /* RxD1 */
-               0  b  2  0  1  0        /* RxD2 */
-               0  c  2  0  1  0        /* RxD3 */
-               0  d  2  0  1  0        /* RxD4 */
-               1  1  2  0  2  0        /* RxD5 */
-               1  0  2  0  2  0        /* RxD6 */
-               1  4  2  0  2  0        /* RxD7 */
-               0  7  1  0  1  0        /* TX_EN */
-               0  8  1  0  1  0        /* TX_ER */
-               0  f  2  0  1  0        /* RX_DV */
-               0  10 2  0  1  0        /* RX_ER */
-               0  0  2  0  1  0        /* RX_CLK */
-               2  9  1  0  3  0        /* GTX_CLK - CLK10 */
-               2  8  2  0  1  0>;      /* GTX125 - CLK9 */
-     };
-
-
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt
deleted file mode 100644 (file)
index e47734b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-* UCC (Unified Communications Controllers)
-
-Required properties:
-- device_type : should be "network", "hldc", "uart", "transparent"
-  "bisync", "atm", or "serial".
-- compatible : could be "ucc_geth" or "fsl_atm" and so on.
-- cell-index : the ucc number(1-8), corresponding to UCCx in UM.
-- reg : Offset and length of the register set for the device
-- interrupts : <a b> where a is the interrupt number and b is a
-  field that represents an encoding of the sense and level
-  information for the interrupt.  This should be encoded based on
-  the information in section 2) depending on the type of interrupt
-  controller you have.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-- pio-handle : The phandle for the Parallel I/O port configuration.
-- port-number : for UART drivers, the port number to use, between 0 and 3.
-  This usually corresponds to the /dev/ttyQE device, e.g. <0> = /dev/ttyQE0.
-  The port number is added to the minor number of the device.  Unlike the
-  CPM UART driver, the port-number is required for the QE UART driver.
-- soft-uart : for UART drivers, if specified this means the QE UART device
-  driver should use "Soft-UART" mode, which is needed on some SOCs that have
-  broken UART hardware.  Soft-UART is provided via a microcode upload.
-- rx-clock-name: the UCC receive clock source
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- tx-clock-name: the UCC transmit clock source
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-The following two properties are deprecated.  rx-clock has been replaced
-with rx-clock-name, and tx-clock has been replaced with tx-clock-name.
-Drivers that currently use the deprecated properties should continue to
-do so, in order to support older device trees, but they should be updated
-to check for the new properties first.
-- rx-clock : represents the UCC receive clock source.
-  0x00 : clock source is disabled;
-  0x1~0x10 : clock source is BRG1~BRG16 respectively;
-  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
-- tx-clock: represents the UCC transmit clock source;
-  0x00 : clock source is disabled;
-  0x1~0x10 : clock source is BRG1~BRG16 respectively;
-  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
-
-Required properties for network device_type:
-- mac-address : list of bytes representing the ethernet address.
-- phy-handle : The phandle for the PHY connected to this controller.
-
-Recommended properties:
-- phy-connection-type : a string naming the controller/PHY interface type,
-  i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal
-  Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only),
-  "tbi", or "rtbi".
-
-Example:
-       ucc@2000 {
-               device_type = "network";
-               compatible = "ucc_geth";
-               cell-index = <1>;
-               reg = <2000 200>;
-               interrupts = <a0 0>;
-               interrupt-parent = <700>;
-               mac-address = [ 00 04 9f 00 23 23 ];
-               rx-clock = "none";
-               tx-clock = "clk9";
-               phy-handle = <212000>;
-               phy-connection-type = "gmii";
-               pio-handle = <140001>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt
deleted file mode 100644 (file)
index 9ccd5f3..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-Freescale QUICC Engine USB Controller
-
-Required properties:
-- compatible : should be "fsl,<chip>-qe-usb", "fsl,mpc8323-qe-usb".
-- reg : the first two cells should contain usb registers location and
-  length, the next two two cells should contain PRAM location and
-  length.
-- interrupts : should contain USB interrupt.
-- interrupt-parent : interrupt source phandle.
-- fsl,fullspeed-clock : specifies the full speed USB clock source:
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- fsl,lowspeed-clock : specifies the low speed USB clock source:
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- hub-power-budget : USB power budget for the root hub, in mA.
-- gpios : should specify GPIOs in this order: USBOE, USBTP, USBTN, USBRP,
-  USBRN, SPEED (optional), and POWER (optional).
-
-Example:
-
-usb@6c0 {
-       compatible = "fsl,mpc8360-qe-usb", "fsl,mpc8323-qe-usb";
-       reg = <0x6c0 0x40 0x8b00 0x100>;
-       interrupts = <11>;
-       interrupt-parent = <&qeic>;
-       fsl,fullspeed-clock = "clk21";
-       gpios = <&qe_pio_b  2 0 /* USBOE */
-                &qe_pio_b  3 0 /* USBTP */
-                &qe_pio_b  8 0 /* USBTN */
-                &qe_pio_b  9 0 /* USBRP */
-                &qe_pio_b 11 0 /* USBRN */
-                &qe_pio_e 20 0 /* SPEED */
-                &qe_pio_e 21 0 /* POWER */>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt
deleted file mode 100644 (file)
index 2ea76d9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-* Serial
-
-Currently defined compatibles:
-- fsl,cpm1-smc-uart
-- fsl,cpm2-smc-uart
-- fsl,cpm1-scc-uart
-- fsl,cpm2-scc-uart
-- fsl,qe-uart
-
-Modem control lines connected to GPIO controllers are listed in the gpios
-property as described in booting-without-of.txt, section IX.1 in the following
-order:
-
-CTS, RTS, DCD, DSR, DTR, and RI.
-
-The gpios property is optional and can be left out when control lines are
-not used.
-
-Example:
-
-       serial@11a00 {
-               device_type = "serial";
-               compatible = "fsl,mpc8272-scc-uart",
-                            "fsl,cpm2-scc-uart";
-               reg = <11a00 20 8000 100>;
-               interrupts = <28 8>;
-               interrupt-parent = <&PIC>;
-               fsl,cpm-brg = <1>;
-               fsl,cpm-command = <00800000>;
-               gpios = <&gpio_c 15 0
-                        &gpio_d 29 0>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/diu.txt b/Documentation/powerpc/dts-bindings/fsl/diu.txt
deleted file mode 100644 (file)
index b66cb6d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-* Freescale Display Interface Unit
-
-The Freescale DIU is a LCD controller, with proper hardware, it can also
-drive DVI monitors.
-
-Required properties:
-- compatible : should be "fsl,diu" or "fsl,mpc5121-diu".
-- reg : should contain at least address and length of the DIU register
-  set.
-- interrupts : one DIU interrupt should be described here.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Optional properties:
-- edid : verbatim EDID data block describing attached display.
-  Data from the detailed timing descriptor will be used to
-  program the display controller.
-
-Example (MPC8610HPCD):
-       display@2c000 {
-               compatible = "fsl,diu";
-               reg = <0x2c000 100>;
-               interrupts = <72 2>;
-               interrupt-parent = <&mpic>;
-       };
-
-Example for MPC5121:
-       display@2100 {
-               compatible = "fsl,mpc5121-diu";
-               reg = <0x2100 0x100>;
-               interrupts = <64 0x8>;
-               interrupt-parent = <&ipic>;
-               edid = [edid-data];
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/dma.txt b/Documentation/powerpc/dts-bindings/fsl/dma.txt
deleted file mode 100644 (file)
index 2a4b4bc..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-* Freescale 83xx DMA Controller
-
-Freescale PowerPC 83xx have on chip general purpose DMA controllers.
-
-Required properties:
-
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-dma", where CHIP is the processor
-                (mpc8349, mpc8360, etc.) and the second is
-                "fsl,elo-dma"
-- reg               : <registers mapping for DMA general status reg>
-- ranges               : Should be defined as specified in 1) to describe the
-                 DMA controller channels.
-- cell-index        : controller index.  0 for controller @ 0x8100
-- interrupts        : <interrupt mapping for DMA IRQ>
-- interrupt-parent  : optional, if needed for interrupt mapping
-
-
-- DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-                        "fsl,CHIP-dma-channel", where CHIP is the processor
-                        (mpc8349, mpc8350, etc.) and the second is
-                        "fsl,elo-dma-channel". However, see note below.
-        - reg               : <registers mapping for channel>
-        - cell-index        : dma channel index starts at 0.
-
-Optional properties:
-        - interrupts        : <interrupt mapping for DMA channel IRQ>
-                         (on 83xx this is expected to be identical to
-                          the interrupts property of the parent node)
-        - interrupt-parent  : optional, if needed for interrupt mapping
-
-Example:
-       dma@82a8 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8349-dma", "fsl,elo-dma";
-               reg = <0x82a8 4>;
-               ranges = <0 0x8100 0x1a4>;
-               interrupt-parent = <&ipic>;
-               interrupts = <71 8>;
-               cell-index = <0>;
-               dma-channel@0 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <0>;
-                       reg = <0 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@80 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <1>;
-                       reg = <0x80 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@100 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <2>;
-                       reg = <0x100 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@180 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <3>;
-                       reg = <0x180 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-       };
-
-* Freescale 85xx/86xx DMA Controller
-
-Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
-
-Required properties:
-
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-dma", where CHIP is the processor
-                (mpc8540, mpc8540, etc.) and the second is
-                "fsl,eloplus-dma"
-- reg               : <registers mapping for DMA general status reg>
-- cell-index        : controller index.  0 for controller @ 0x21000,
-                                         1 for controller @ 0xc000
-- ranges               : Should be defined as specified in 1) to describe the
-                 DMA controller channels.
-
-- DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-                        "fsl,CHIP-dma-channel", where CHIP is the processor
-                        (mpc8540, mpc8560, etc.) and the second is
-                        "fsl,eloplus-dma-channel". However, see note below.
-        - cell-index        : dma channel index starts at 0.
-        - reg               : <registers mapping for channel>
-        - interrupts        : <interrupt mapping for DMA channel IRQ>
-        - interrupt-parent  : optional, if needed for interrupt mapping
-
-Example:
-       dma@21300 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
-               reg = <0x21300 4>;
-               ranges = <0 0x21100 0x200>;
-               cell-index = <0>;
-               dma-channel@0 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0 0x80>;
-                       cell-index = <0>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <20 2>;
-               };
-               dma-channel@80 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x80 0x80>;
-                       cell-index = <1>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <21 2>;
-               };
-               dma-channel@100 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x100 0x80>;
-                       cell-index = <2>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <22 2>;
-               };
-               dma-channel@180 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x180 0x80>;
-                       cell-index = <3>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <23 2>;
-               };
-       };
-
-Note on DMA channel compatible properties: The compatible property must say
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
-driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
-DMA driver, such as the SSI sound drivers for the MPC8610.  Therefore, any DMA
-channel that should be used for another driver should not use
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel".  For the SSI drivers, for
-example, the compatible property should be "fsl,ssi-dma-channel".  See ssi.txt
-for more information.
diff --git a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt
deleted file mode 100644 (file)
index 64bcb8b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-* Freescale Enhanced Secure Digital Host Controller (eSDHC)
-
-The Enhanced Secure Digital Host Controller provides an interface
-for MMC, SD, and SDIO types of memory cards.
-
-Required properties:
-  - compatible : should be
-    "fsl,<chip>-esdhc", "fsl,esdhc"
-  - reg : should contain eSDHC registers location and length.
-  - interrupts : should contain eSDHC interrupt.
-  - interrupt-parent : interrupt source phandle.
-  - clock-frequency : specifies eSDHC base clock frequency.
-  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
-    reports inverted write-protect state;
-  - sdhci,1-bit-only : (optional) specifies that a controller can
-    only handle 1-bit data transfers.
-  - sdhci,auto-cmd12: (optional) specifies that a controller can
-    only handle auto CMD12.
-
-Example:
-
-sdhci@2e000 {
-       compatible = "fsl,mpc8378-esdhc", "fsl,esdhc";
-       reg = <0x2e000 0x1000>;
-       interrupts = <42 0x8>;
-       interrupt-parent = <&ipic>;
-       /* Filled in by U-Boot */
-       clock-frequency = <0>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/gtm.txt b/Documentation/powerpc/dts-bindings/fsl/gtm.txt
deleted file mode 100644 (file)
index 9a33efd..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-* Freescale General-purpose Timers Module
-
-Required properties:
-  - compatible : should be
-    "fsl,<chip>-gtm", "fsl,gtm" for SOC GTMs
-    "fsl,<chip>-qe-gtm", "fsl,qe-gtm", "fsl,gtm" for QE GTMs
-    "fsl,<chip>-cpm2-gtm", "fsl,cpm2-gtm", "fsl,gtm" for CPM2 GTMs
-  - reg : should contain gtm registers location and length (0x40).
-  - interrupts : should contain four interrupts.
-  - interrupt-parent : interrupt source phandle.
-  - clock-frequency : specifies the frequency driving the timer.
-
-Example:
-
-timer@500 {
-       compatible = "fsl,mpc8360-gtm", "fsl,gtm";
-       reg = <0x500 0x40>;
-       interrupts = <90 8 78 8 84 8 72 8>;
-       interrupt-parent = <&ipic>;
-       /* filled by u-boot */
-       clock-frequency = <0>;
-};
-
-timer@440 {
-       compatible = "fsl,mpc8360-qe-gtm", "fsl,qe-gtm", "fsl,gtm";
-       reg = <0x440 0x40>;
-       interrupts = <12 13 14 15>;
-       interrupt-parent = <&qeic>;
-       /* filled by u-boot */
-       clock-frequency = <0>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/guts.txt b/Documentation/powerpc/dts-bindings/fsl/guts.txt
deleted file mode 100644 (file)
index 9e7a241..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-* Global Utilities Block
-
-The global utilities block controls power management, I/O device
-enabling, power-on-reset configuration monitoring, general-purpose
-I/O signal configuration, alternate function selection for multiplexed
-signals, and clock control.
-
-Required properties:
-
- - compatible : Should define the compatible device type for
-   global-utilities.
- - reg : Offset and length of the register set for the device.
-
-Recommended properties:
-
- - fsl,has-rstcr : Indicates that the global utilities register set
-   contains a functioning "reset control register" (i.e. the board
-   is wired to reset upon setting the HRESET_REQ bit in this register).
-
-Example:
-       global-utilities@e0000 {        /* global utilities block */
-               compatible = "fsl,mpc8548-guts";
-               reg = <e0000 1000>;
-               fsl,has-rstcr;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
deleted file mode 100644 (file)
index 1eacd6b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-* I2C
-
-Required properties :
-
- - reg : Offset and length of the register set for the device
- - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
-   compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
-   mpc5200 or mpc5200b. For the mpc5121, an additional node
-   "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
-
-Recommended properties :
-
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
- - fsl,preserve-clocking : boolean; if defined, the clock settings
-   from the bootloader are preserved (not touched).
- - clock-frequency : desired I2C bus clock frequency in Hz.
- - fsl,timeout : I2C bus timeout in microseconds.
-
-Examples :
-
-       /* MPC5121 based board */
-       i2c@1740 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5121-i2c", "fsl-i2c";
-               reg = <0x1740 0x20>;
-               interrupts = <11 0x8>;
-               interrupt-parent = <&ipic>;
-               clock-frequency = <100000>;
-       };
-
-       i2ccontrol@1760 {
-               compatible = "fsl,mpc5121-i2c-ctrl";
-               reg = <0x1760 0x8>;
-       };
-
-       /* MPC5200B based board */
-       i2c@3d00 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-               reg = <0x3d00 0x40>;
-               interrupts = <2 15 0>;
-               interrupt-parent = <&mpc5200_pic>;
-               fsl,preserve-clocking;
-       };
-
-       /* MPC8544 base board */
-       i2c@3100 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc8544-i2c", "fsl-i2c";
-               reg = <0x3100 0x100>;
-               interrupts = <43 2>;
-               interrupt-parent = <&mpic>;
-               clock-frequency = <400000>;
-               fsl,timeout = <10000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/lbc.txt b/Documentation/powerpc/dts-bindings/fsl/lbc.txt
deleted file mode 100644 (file)
index 3300fec..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-* Chipselect/Local Bus
-
-Properties:
-- name : Should be localbus
-- #address-cells : Should be either two or three.  The first cell is the
-                   chipselect number, and the remaining cells are the
-                   offset into the chipselect.
-- #size-cells : Either one or two, depending on how large each chipselect
-                can be.
-- ranges : Each range corresponds to a single chipselect, and cover
-           the entire access window as configured.
-
-Example:
-       localbus@f0010100 {
-               compatible = "fsl,mpc8272-localbus",
-                          "fsl,pq2-localbus";
-               #address-cells = <2>;
-               #size-cells = <1>;
-               reg = <f0010100 40>;
-
-               ranges = <0 0 fe000000 02000000
-                         1 0 f4500000 00008000>;
-
-               flash@0,0 {
-                       compatible = "jedec-flash";
-                       reg = <0 0 2000000>;
-                       bank-width = <4>;
-                       device-width = <1>;
-               };
-
-               board-control@1,0 {
-                       reg = <1 0 20>;
-                       compatible = "fsl,mpc8272ads-bcsr";
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/mcm.txt b/Documentation/powerpc/dts-bindings/fsl/mcm.txt
deleted file mode 100644 (file)
index 4ceda9b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-=====================================================================
-MPX LAW & Coherency Module Device Tree Binding
-Copyright (C) 2009 Freescale Semiconductor Inc.
-=====================================================================
-
-Local Access Window (LAW) Node
-
-The LAW node represents the region of CCSR space where local access
-windows are configured.  For MCM based devices this is the first 4k
-of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
-number of local access windows as specified by fsl,num-laws.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,mcm-law"
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-  - fsl,num-laws
-      Usage: required
-      Value type: <u32>
-      Definition: The value specifies the number of local access
-          windows for this device.
-
-=====================================================================
-
-MPX Coherency Module Node
-
-The MPX LAW node represents the region of CCSR space where MCM config
-and error reporting registers exist, this is the second 4k (0x1000)
-of CCSR space.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,CHIP-mcm", "fsl,mcm" where
-      CHIP is the processor (mpc8641, mpc8610, etc.)
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-   - interrupts
-      Usage: required
-      Value type: <prop-encoded-array>
-
-   - interrupt-parent
-      Usage: required
-      Value type: <phandle>
-
-=====================================================================
diff --git a/Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt b/Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt
deleted file mode 100644 (file)
index 0f76633..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Freescale MPC8349E-mITX-compatible Power Management Micro Controller Unit (MCU)
-
-Required properties:
-- compatible : "fsl,<mcu-chip>-<board>", "fsl,mcu-mpc8349emitx".
-- reg : should specify I2C address (0x0a).
-- #gpio-cells : should be 2.
-- gpio-controller : should be present.
-
-Example:
-
-mcu@0a {
-       #gpio-cells = <2>;
-       compatible = "fsl,mc9s08qg8-mpc8349emitx",
-                    "fsl,mcu-mpc8349emitx";
-       reg = <0x0a>;
-       gpio-controller;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
deleted file mode 100644 (file)
index 8832e87..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-MPC5121 PSC Device Tree Bindings
-
-PSC in UART mode
-----------------
-
-For PSC in UART mode the needed PSC serial devices
-are specified by fsl,mpc5121-psc-uart nodes in the
-fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
-Controller node fsl,mpc5121-psc-fifo is requered there:
-
-fsl,mpc5121-psc-uart nodes
---------------------------
-
-Required properties :
- - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
- - cell-index : Index of the PSC in hardware
- - reg : Offset and length of the register set for the PSC device
- - interrupts : <a b> where a is the interrupt number of the
-   PSC FIFO Controller and b is a field that represents an
-   encoding of the sense and level information for the interrupt.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-Recommended properties :
- - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
- - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
-
-
-fsl,mpc5121-psc-fifo node
--------------------------
-
-Required properties :
- - compatible : Should be "fsl,mpc5121-psc-fifo"
- - reg : Offset and length of the register set for the PSC
-         FIFO Controller
- - interrupts : <a b> where a is the interrupt number of the
-   PSC FIFO Controller and b is a field that represents an
-   encoding of the sense and level information for the interrupt.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-
-Example for a board using PSC0 and PSC1 devices in serial mode:
-
-serial@11000 {
-       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
-       cell-index = <0>;
-       reg = <0x11000 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-       fsl,rx-fifo-size = <16>;
-       fsl,tx-fifo-size = <16>;
-};
-
-serial@11100 {
-       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
-       cell-index = <1>;
-       reg = <0x11100 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-       fsl,rx-fifo-size = <16>;
-       fsl,tx-fifo-size = <16>;
-};
-
-pscfifo@11f00 {
-       compatible = "fsl,mpc5121-psc-fifo";
-       reg = <0x11f00 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
deleted file mode 100644 (file)
index 4ccb2cd..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-MPC5200 Device Tree Bindings
-----------------------------
-
-(c) 2006-2009 Secret Lab Technologies Ltd
-Grant Likely <grant.likely@secretlab.ca>
-
-Naming conventions
-------------------
-For mpc5200 on-chip devices, the format for each compatible value is
-<chip>-<device>[-<mode>].  The OS should be able to match a device driver
-to the device based solely on the compatible value.  If two drivers
-match on the compatible list; the 'most compatible' driver should be
-selected.
-
-The split between the MPC5200 and the MPC5200B leaves a bit of a
-conundrum.  How should the compatible property be set up to provide
-maximum compatibility information; but still accurately describe the
-chip?  For the MPC5200; the answer is easy.  Most of the SoC devices
-originally appeared on the MPC5200.  Since they didn't exist anywhere
-else; the 5200 compatible properties will contain only one item;
-"fsl,mpc5200-<device>".
-
-The 5200B is almost the same as the 5200, but not quite.  It fixes
-silicon bugs and it adds a small number of enhancements.  Most of the
-devices either provide exactly the same interface as on the 5200.  A few
-devices have extra functions but still have a backwards compatible mode.
-To express this information as completely as possible, 5200B device trees
-should have two items in the compatible list:
-       compatible = "fsl,mpc5200b-<device>","fsl,mpc5200-<device>";
-
-It is *strongly* recommended that 5200B device trees follow this convention
-(instead of only listing the base mpc5200 item).
-
-ie. ethernet on mpc5200: compatible = "fsl,mpc5200-fec";
-    ethernet on mpc5200b: compatible = "fsl,mpc5200b-fec", "fsl,mpc5200-fec";
-
-Modal devices, like PSCs, also append the configured function to the
-end of the compatible field.  ie. A PSC in i2s mode would specify
-"fsl,mpc5200-psc-i2s", not "fsl,mpc5200-i2s".  This convention is chosen to
-avoid naming conflicts with non-psc devices providing the same
-function.  For example, "fsl,mpc5200-spi" and "fsl,mpc5200-psc-spi" describe
-the mpc5200 simple spi device and a PSC spi mode respectively.
-
-At the time of writing, exact chip may be either 'fsl,mpc5200' or
-'fsl,mpc5200b'.
-
-The soc node
-------------
-This node describes the on chip SOC peripherals.  Every mpc5200 based
-board will have this node, and as such there is a common naming
-convention for SOC devices.
-
-Required properties:
-name                   description
-----                   -----------
-ranges                 Memory range of the internal memory mapped registers.
-                       Should be <0 [baseaddr] 0xc000>
-reg                    Should be <[baseaddr] 0x100>
-compatible             mpc5200: "fsl,mpc5200-immr"
-                       mpc5200b: "fsl,mpc5200b-immr"
-system-frequency       'fsystem' frequency in Hz; XLB, IPB, USB and PCI
-                       clocks are derived from the fsystem clock.
-bus-frequency          IPB bus frequency in Hz.  Clock rate
-                       used by most of the soc devices.
-
-soc child nodes
----------------
-Any on chip SOC devices available to Linux must appear as soc5200 child nodes.
-
-Note: The tables below show the value for the mpc5200.  A mpc5200b device
-tree should use the "fsl,mpc5200b-<device>","fsl,mpc5200-<device>" form.
-
-Required soc5200 child nodes:
-name                           compatible              Description
-----                           ----------              -----------
-cdm@<addr>                     fsl,mpc5200-cdm         Clock Distribution
-interrupt-controller@<addr>    fsl,mpc5200-pic         need an interrupt
-                                                       controller to boot
-bestcomm@<addr>                        fsl,mpc5200-bestcomm    Bestcomm DMA controller
-
-Recommended soc5200 child nodes; populate as needed for your board
-name           compatible              Description
-----           ----------              -----------
-timer@<addr>   fsl,mpc5200-gpt          General purpose timers
-gpio@<addr>    fsl,mpc5200-gpio         MPC5200 simple gpio controller
-gpio@<addr>    fsl,mpc5200-gpio-wkup    MPC5200 wakeup gpio controller
-rtc@<addr>     fsl,mpc5200-rtc          Real time clock
-mscan@<addr>   fsl,mpc5200-mscan        CAN bus controller
-pci@<addr>     fsl,mpc5200-pci          PCI bridge
-serial@<addr>  fsl,mpc5200-psc-uart     PSC in serial mode
-i2s@<addr>     fsl,mpc5200-psc-i2s      PSC in i2s mode
-ac97@<addr>    fsl,mpc5200-psc-ac97     PSC in ac97 mode
-spi@<addr>     fsl,mpc5200-psc-spi      PSC in spi mode
-irda@<addr>    fsl,mpc5200-psc-irda     PSC in IrDA mode
-spi@<addr>     fsl,mpc5200-spi          MPC5200 spi device
-ethernet@<addr>        fsl,mpc5200-fec          MPC5200 ethernet device
-ata@<addr>     fsl,mpc5200-ata          IDE ATA interface
-i2c@<addr>     fsl,mpc5200-i2c          I2C controller
-usb@<addr>     fsl,mpc5200-ohci,ohci-be USB controller
-xlb@<addr>     fsl,mpc5200-xlb          XLB arbitrator
-
-fsl,mpc5200-gpt nodes
----------------------
-On the mpc5200 and 5200b, GPT0 has a watchdog timer function.  If the board
-design supports the internal wdt, then the device node for GPT0 should
-include the empty property 'fsl,has-wdt'.  Note that this does not activate
-the watchdog.  The timer will function as a GPT if the timer api is used, and
-it will function as watchdog if the watchdog device is used.  The watchdog
-mode has priority over the gpt mode, i.e. if the watchdog is activated, any
-gpt api call to this timer will fail with -EBUSY.
-
-If you add the property
-       fsl,wdt-on-boot = <n>;
-GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it.
-If n>0, the watchdog is started with a timeout of n seconds.  If n=0, the
-configuration of the watchdog is not touched.  This is useful in two cases:
-- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later;
-- do not touch a configuration assigned by the boot loader which supervises
-  the boot process itself.
-
-The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option.
-
-An mpc5200-gpt can be used as a single line GPIO controller.  To do so,
-add the following properties to the gpt node:
-       gpio-controller;
-       #gpio-cells = <2>;
-When referencing the GPIO line from another node, the first cell must always
-be zero and the second cell represents the gpio flags and described in the
-gpio device tree binding.
-
-An mpc5200-gpt can be used as a single line edge sensitive interrupt
-controller.  To do so, add the following properties to the gpt node:
-       interrupt-controller;
-       #interrupt-cells = <1>;
-When referencing the IRQ line from another node, the cell represents the
-sense mode; 1 for edge rising, 2 for edge falling.
-
-fsl,mpc5200-psc nodes
----------------------
-The PSCs should include a cell-index which is the index of the PSC in
-hardware.  cell-index is used to determine which shared SoC registers to
-use when setting up PSC clocking.  cell-index number starts at '0'.  ie:
-       PSC1 has 'cell-index = <0>'
-       PSC4 has 'cell-index = <3>'
-
-PSC in i2s mode:  The mpc5200 and mpc5200b PSCs are not compatible when in
-i2s mode.  An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the
-compatible field.
-
-
-fsl,mpc5200-gpio and fsl,mpc5200-gpio-wkup nodes
-------------------------------------------------
-Each GPIO controller node should have the empty property gpio-controller and
-#gpio-cells set to 2. First cell is the GPIO number which is interpreted
-according to the bit numbers in the GPIO control registers. The second cell
-is for flags which is currently unused.
-
-fsl,mpc5200-fec nodes
----------------------
-The FEC node can specify one of the following properties to configure
-the MII link:
-- fsl,7-wire-mode - An empty property that specifies the link uses 7-wire
-                    mode instead of MII
-- current-speed   - Specifies that the MII should be configured for a fixed
-                    speed.  This property should contain two cells.  The
-                    first cell specifies the speed in Mbps and the second
-                    should be '0' for half duplex and '1' for full duplex
-- phy-handle      - Contains a phandle to an Ethernet PHY.
-
-Interrupt controller (fsl,mpc5200-pic) node
--------------------------------------------
-The mpc5200 pic binding splits hardware IRQ numbers into two levels.  The
-split reflects the layout of the PIC hardware itself, which groups
-interrupts into one of three groups; CRIT, MAIN or PERP.  Also, the
-Bestcomm dma engine has it's own set of interrupt sources which are
-cascaded off of peripheral interrupt 0, which the driver interprets as a
-fourth group, SDMA.
-
-The interrupts property for device nodes using the mpc5200 pic consists
-of three cells; <L1 L2 level>
-
-    L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3]
-    L2 := interrupt number; directly mapped from the value in the
-          "ICTL PerStat, MainStat, CritStat Encoded Register"
-    level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3]
-
-For external IRQs, use the following interrupt property values (how to
-specify external interrupts is a frequently asked question):
-External interrupts:
-       external irq0:  interrupts = <0 0 n>;
-       external irq1:  interrupts = <1 1 n>;
-       external irq2:  interrupts = <1 2 n>;
-       external irq3:  interrupts = <1 3 n>;
-'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
-
-fsl,mpc5200-mscan nodes
------------------------
-See file can.txt in this directory.
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpic.txt b/Documentation/powerpc/dts-bindings/fsl/mpic.txt
deleted file mode 100644 (file)
index 71e39cf..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
-
-The OpenPIC specification does not specify which interrupt source has to
-become which interrupt number. This is up to the software implementation
-of the interrupt controller. The only requirement is that every
-interrupt source has to have an unique interrupt number / vector number.
-To accomplish this the current implementation assigns the number zero to
-the first source, the number one to the second source and so on until
-all interrupt sources have their unique number.
-Usually the assigned vector number equals the interrupt number mentioned
-in the documentation for a given core / CPU. This is however not true
-for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
-between internal and external interrupt sources and starts counting at
-zero for both of them.
-
-So what to write for external interrupt source X or internal interrupt
-source Y into the device tree? Here is an example:
-
-The memory map for the interrupt controller in the MPC8544[0] shows,
-that the first interrupt source starts at 0x5_0000 (PIC Register Address
-Map-Interrupt Source Configuration Registers). This source becomes the
-number zero therefore:
- External interrupt 0 = interrupt number 0
- External interrupt 1 = interrupt number 1
- External interrupt 2 = interrupt number 2
- ...
-Every interrupt number allocates 0x20 bytes register space. So to get
-its number it is sufficient to shift the lower 16bits to right by five.
-So for the external interrupt 10 we have:
-  0x0140 >> 5 = 10
-
-After the external sources, the internal sources follow. The in core I2C
-controller on the MPC8544 for instance has the internal source number
-27. Oo obtain its interrupt number we take the lower 16bits of its memory
-address (0x5_0560) and shift it right:
- 0x0560 >> 5 = 43
-
-Therefore the I2C device node for the MPC8544 CPU has to have the
-interrupt number 43 specified in the device tree.
-
-[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
-    MPC8544ERM Rev. 1 10/2007
diff --git a/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt b/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt
deleted file mode 100644 (file)
index bcc30ba..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-* Freescale MSI interrupt controller
-
-Required properties:
-- compatible : compatible list, contains 2 entries,
-  first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
-  etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
-  the parent type.
-- reg : should contain the address and the length of the shared message
-  interrupt register set.
-- msi-available-ranges: use <start count> style section to define which
-  msi interrupt can be used in the 256 msi interrupts. This property is
-  optional, without this, all the 256 MSI interrupts can be used.
-- interrupts : each one of the interrupts here is one entry per 32 MSIs,
-  and routed to the host interrupt controller. the interrupts should
-  be set as edge sensitive.
-- interrupt-parent: the phandle for the interrupt controller
-  that services interrupts for this device. for 83xx cpu, the interrupts
-  are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed
-  to MPIC.
-
-Example:
-       msi@41600 {
-               compatible = "fsl,mpc8610-msi", "fsl,mpic-msi";
-               reg = <0x41600 0x80>;
-               msi-available-ranges = <0 0x100>;
-               interrupts = <
-                       0xe0 0
-                       0xe1 0
-                       0xe2 0
-                       0xe3 0
-                       0xe4 0
-                       0xe5 0
-                       0xe6 0
-                       0xe7 0>;
-               interrupt-parent = <&mpic>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/pmc.txt b/Documentation/powerpc/dts-bindings/fsl/pmc.txt
deleted file mode 100644 (file)
index 07256b7..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-* Power Management Controller
-
-Properties:
-- compatible: "fsl,<chip>-pmc".
-
-  "fsl,mpc8349-pmc" should be listed for any chip whose PMC is
-  compatible.  "fsl,mpc8313-pmc" should also be listed for any chip
-  whose PMC is compatible, and implies deep-sleep capability.
-
-  "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
-  compatible.  "fsl,mpc8536-pmc" should also be listed for any chip
-  whose PMC is compatible, and implies deep-sleep capability.
-
-  "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
-  compatible; all statements below that apply to "fsl,mpc8548-pmc" also
-  apply to "fsl,mpc8641d-pmc".
-
-  Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
-  bit assignments are indicated via the sleep specifier in each device's
-  sleep property.
-
-- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
-  is the PMC block, and the second resource is the Clock Configuration
-  block.
-
-  For devices compatible with "fsl,mpc8548-pmc", the first resource
-  is a 32-byte block beginning with DEVDISR.
-
-- interrupts: For "fsl,mpc8349-pmc"-compatible devices, the first
-  resource is the PMC block interrupt.
-
-- fsl,mpc8313-wakeup-timer: For "fsl,mpc8313-pmc"-compatible devices,
-  this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
-  a wakeup source from deep sleep.
-
-Sleep specifiers:
-
-  fsl,mpc8349-pmc: Sleep specifiers consist of one cell.  For each bit
-  that is set in the cell, the corresponding bit in SCCR will be saved
-  and cleared on suspend, and restored on resume.  This sleep controller
-  supports disabling and resuming devices at any time.
-
-  fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
-  which will be ORed into PMCDR upon suspend, and cleared from PMCDR
-  upon resume.  The first two cells are as described for fsl,mpc8578-pmc.
-  This sleep controller only supports disabling devices during system
-  sleep, or permanently.
-
-  fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
-  first of which will be ORed into DEVDISR (and the second into
-  DEVDISR2, if present -- this cell should be zero or absent if the
-  hardware does not have DEVDISR2) upon a request for permanent device
-  disabling.  This sleep controller does not support configuring devices
-  to disable during system sleep (unless supported by another compatible
-  match), or dynamically.
-
-Example:
-
-       power@b00 {
-               compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
-               reg = <0xb00 0x100 0xa00 0x100>;
-               interrupts = <80 8>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/sata.txt b/Documentation/powerpc/dts-bindings/fsl/sata.txt
deleted file mode 100644 (file)
index b46bcf4..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-* Freescale 8xxx/3.0 Gb/s SATA nodes
-
-SATA nodes are defined to describe on-chip Serial ATA controllers.
-Each SATA port should have its own node.
-
-Required properties:
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-sata", where CHIP is the processor
-                (mpc8315, mpc8379, etc.) and the second is
-                "fsl,pq-sata"
-- interrupts        : <interrupt mapping for SATA IRQ>
-- cell-index        : controller index.
-                          1 for controller @ 0x18000
-                          2 for controller @ 0x19000
-                          3 for controller @ 0x1a000
-                          4 for controller @ 0x1b000
-
-Optional properties:
-- interrupt-parent  : optional, if needed for interrupt mapping
-- reg               : <registers mapping>
-
-Example:
-       sata@18000 {
-               compatible = "fsl,mpc8379-sata", "fsl,pq-sata";
-               reg = <0x18000 0x1000>;
-               cell-index = <1>;
-               interrupts = <2c 8>;
-               interrupt-parent = < &ipic >;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/sec.txt b/Documentation/powerpc/dts-bindings/fsl/sec.txt
deleted file mode 100644 (file)
index 2b6f2d4..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-Freescale SoC SEC Security Engines
-
-Required properties:
-
-- compatible : Should contain entries for this and backward compatible
-  SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0"
-- reg : Offset and length of the register set for the device
-- interrupts : the SEC's interrupt number
-- fsl,num-channels : An integer representing the number of channels
-  available.
-- fsl,channel-fifo-len : An integer representing the number of
-  descriptor pointers each channel fetch fifo can hold.
-- fsl,exec-units-mask : The bitmask representing what execution units
-  (EUs) are available. It's a single 32-bit cell. EU information
-  should be encoded following the SEC's Descriptor Header Dword
-  EU_SEL0 field documentation, i.e. as follows:
-
-       bit 0  = reserved - should be 0
-       bit 1  = set if SEC has the ARC4 EU (AFEU)
-       bit 2  = set if SEC has the DES/3DES EU (DEU)
-       bit 3  = set if SEC has the message digest EU (MDEU/MDEU-A)
-       bit 4  = set if SEC has the random number generator EU (RNG)
-       bit 5  = set if SEC has the public key EU (PKEU)
-       bit 6  = set if SEC has the AES EU (AESU)
-       bit 7  = set if SEC has the Kasumi EU (KEU)
-       bit 8  = set if SEC has the CRC EU (CRCU)
-       bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B)
-
-remaining bits are reserved for future SEC EUs.
-
-- fsl,descriptor-types-mask : The bitmask representing what descriptors
-  are available. It's a single 32-bit cell. Descriptor type information
-  should be encoded following the SEC's Descriptor Header Dword DESC_TYPE
-  field documentation, i.e. as follows:
-
-       bit 0  = set if SEC supports the aesu_ctr_nonsnoop desc. type
-       bit 1  = set if SEC supports the ipsec_esp descriptor type
-       bit 2  = set if SEC supports the common_nonsnoop desc. type
-       bit 3  = set if SEC supports the 802.11i AES ccmp desc. type
-       bit 4  = set if SEC supports the hmac_snoop_no_afeu desc. type
-       bit 5  = set if SEC supports the srtp descriptor type
-       bit 6  = set if SEC supports the non_hmac_snoop_no_afeu desc.type
-       bit 7  = set if SEC supports the pkeu_assemble descriptor type
-       bit 8  = set if SEC supports the aesu_key_expand_output desc.type
-       bit 9  = set if SEC supports the pkeu_ptmul descriptor type
-       bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
-       bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
-
-  ..and so on and so forth.
-
-Optional properties:
-
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Example:
-
-       /* MPC8548E */
-       crypto@30000 {
-               compatible = "fsl,sec2.1", "fsl,sec2.0";
-               reg = <0x30000 0x10000>;
-               interrupts = <29 2>;
-               interrupt-parent = <&mpic>;
-               fsl,num-channels = <4>;
-               fsl,channel-fifo-len = <24>;
-               fsl,exec-units-mask = <0xfe>;
-               fsl,descriptor-types-mask = <0x12b0ebf>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
deleted file mode 100644 (file)
index 777abd7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-* SPI (Serial Peripheral Interface)
-
-Required properties:
-- cell-index : QE SPI subblock index.
-               0: QE subblock SPI1
-               1: QE subblock SPI2
-- compatible : should be "fsl,spi".
-- mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
-- reg : Offset and length of the register set for the device
-- interrupts : <a b> where a is the interrupt number and b is a
-  field that represents an encoding of the sense and level
-  information for the interrupt.  This should be encoded based on
-  the information in section 2) depending on the type of interrupt
-  controller you have.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Optional properties:
-- gpios : specifies the gpio pins to be used for chipselects.
-  The gpios will be referred to as reg = <index> in the SPI child nodes.
-  If unspecified, a single SPI device without a chip select can be used.
-
-Example:
-       spi@4c0 {
-               cell-index = <0>;
-               compatible = "fsl,spi";
-               reg = <4c0 40>;
-               interrupts = <82 0>;
-               interrupt-parent = <700>;
-               mode = "cpu";
-               gpios = <&gpio 18 1     // device reg=<0>
-                        &gpio 19 1>;   // device reg=<1>
-       };
-
-
-* eSPI (Enhanced Serial Peripheral Interface)
-
-Required properties:
-- compatible : should be "fsl,mpc8536-espi".
-- reg : Offset and length of the register set for the device.
-- interrupts : should contain eSPI interrupt, the device has one interrupt.
-- fsl,espi-num-chipselects : the number of the chipselect signals.
-
-Example:
-       spi@110000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc8536-espi";
-               reg = <0x110000 0x1000>;
-               interrupts = <53 0x2>;
-               interrupt-parent = <&mpic>;
-               fsl,espi-num-chipselects = <4>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/ssi.txt b/Documentation/powerpc/dts-bindings/fsl/ssi.txt
deleted file mode 100644 (file)
index 5ff76c9..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-Freescale Synchronous Serial Interface
-
-The SSI is a serial device that communicates with audio codecs.  It can
-be programmed in AC97, I2S, left-justified, or right-justified modes.
-
-Required properties:
-- compatible:       Compatible list, contains "fsl,ssi".
-- cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
-- reg:              Offset and length of the register set for the device.
-- interrupts:       <a b> where a is the interrupt number and b is a
-                    field that represents an encoding of the sense and
-                    level information for the interrupt.  This should be
-                    encoded based on the information in section 2)
-                    depending on the type of interrupt controller you
-                    have.
-- interrupt-parent: The phandle for the interrupt controller that
-                    services interrupts for this device.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
-                    "ac97-slave" - AC97 mode, SSI is clock slave
-                    "ac97-master" - AC97 mode, SSI is clock master
-- fsl,playback-dma: Phandle to a node for the DMA channel to use for
-                    playback of audio.  This is typically dictated by SOC
-                    design.  See the notes below.
-- fsl,capture-dma:  Phandle to a node for the DMA channel to use for
-                    capture (recording) of audio.  This is typically dictated
-                    by SOC design.  See the notes below.
-- fsl,fifo-depth:   The number of elements in the transmit and receive FIFOs.
-                    This number is the maximum allowed value for SFCSR[TFWM0].
-- fsl,ssi-asynchronous:
-                    If specified, the SSI is to be programmed in asynchronous
-                    mode.  In this mode, pins SRCK, STCK, SRFS, and STFS must
-                    all be connected to valid signals.  In synchronous mode,
-                    SRCK and SRFS are ignored.  Asynchronous mode allows
-                    playback and capture to use different sample sizes and
-                    sample rates.  Some drivers may require that SRCK and STCK
-                    be connected together, and SRFS and STFS be connected
-                    together.  This would still allow different sample sizes,
-                    but not different sample rates.
-
-Optional properties:
-- codec-handle:     Phandle to a 'codec' node that defines an audio
-                    codec connected to this SSI.  This node is typically
-                    a child of an I2C or other control node.
-
-Child 'codec' node required properties:
-- compatible:       Compatible list, contains the name of the codec
-
-Child 'codec' node optional properties:
-- clock-frequency:  The frequency of the input clock, which typically comes
-                    from an on-board dedicated oscillator.
-
-Notes on fsl,playback-dma and fsl,capture-dma:
-
-On SOCs that have an SSI, specific DMA channels are hard-wired for playback
-and capture.  On the MPC8610, for example, SSI1 must use DMA channel 0 for
-playback and DMA channel 1 for capture.  SSI2 must use DMA channel 2 for
-playback and DMA channel 3 for capture.  The developer can choose which
-DMA controller to use, but the channels themselves are hard-wired.  The
-purpose of these two properties is to represent this hardware design.
-
-The device tree nodes for the DMA channels that are referenced by
-"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
-"fsl,ssi-dma-channel".  The SOC-specific compatible string (e.g.
-"fsl,mpc8610-dma-channel") can remain.  If these nodes are left as
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
-drivers (fsldma) will attempt to use them, and it will conflict with the
-sound drivers.
diff --git a/Documentation/powerpc/dts-bindings/fsl/tsec.txt b/Documentation/powerpc/dts-bindings/fsl/tsec.txt
deleted file mode 100644 (file)
index edb7ae1..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-* MDIO IO device
-
-The MDIO is a bus to which the PHY devices are connected.  For each
-device that exists on this bus, a child node should be created.  See
-the definition of the PHY node in booting-without-of.txt for an example
-of how to define a PHY.
-
-Required properties:
-  - reg : Offset and length of the register set for the device
-  - compatible : Should define the compatible device type for the
-    mdio.  Currently, this is most likely to be "fsl,gianfar-mdio"
-
-Example:
-
-       mdio@24520 {
-               reg = <24520 20>;
-               compatible = "fsl,gianfar-mdio";
-
-               ethernet-phy@0 {
-                       ......
-               };
-       };
-
-* TBI Internal MDIO bus
-
-As of this writing, every tsec is associated with an internal TBI PHY.
-This PHY is accessed through the local MDIO bus.  These buses are defined
-similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi".
-The TBI PHYs underneath them are similar to normal PHYs, but the reg property
-is considered instructive, rather than descriptive.  The reg property should
-be chosen so it doesn't interfere with other PHYs on the bus.
-
-* Gianfar-compatible ethernet nodes
-
-Properties:
-
-  - device_type : Should be "network"
-  - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
-  - compatible : Should be "gianfar"
-  - reg : Offset and length of the register set for the device
-  - local-mac-address : List of bytes representing the ethernet address of
-    this controller
-  - interrupts : For FEC devices, the first interrupt is the device's
-    interrupt.  For TSEC and eTSEC devices, the first interrupt is
-    transmit, the second is receive, and the third is error.
-  - phy-handle : The phandle for the PHY connected to this ethernet
-    controller.
-  - fixed-link : <a b c d e> where a is emulated phy id - choose any,
-    but unique to the all specified fixed-links, b is duplex - 0 half,
-    1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
-    pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
-  - phy-connection-type : a string naming the controller/PHY interface type,
-    i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
-    "tbi", or "rtbi".  This property is only really needed if the connection
-    is of type "rgmii-id", as all other connection types are detected by
-    hardware.
-  - fsl,magic-packet : If present, indicates that the hardware supports
-    waking up via magic packet.
-  - bd-stash : If present, indicates that the hardware supports stashing
-    buffer descriptors in the L2.
-  - rx-stash-len : Denotes the number of bytes of a received buffer to stash
-    in the L2.
-  - rx-stash-idx : Denotes the index of the first byte from the received
-    buffer to stash in the L2.
-
-Example:
-       ethernet@24000 {
-               device_type = "network";
-               model = "TSEC";
-               compatible = "gianfar";
-               reg = <0x24000 0x1000>;
-               local-mac-address = [ 00 E0 0C 00 73 00 ];
-               interrupts = <29 2 30 2 34 2>;
-               interrupt-parent = <&mpic>;
-               phy-handle = <&phy0>
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/upm-nand.txt b/Documentation/powerpc/dts-bindings/fsl/upm-nand.txt
deleted file mode 100644 (file)
index a48b2ca..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-Freescale Localbus UPM programmed to work with NAND flash
-
-Required properties:
-- compatible : "fsl,upm-nand".
-- reg : should specify localbus chip select and size used for the chip.
-- fsl,upm-addr-offset : UPM pattern offset for the address latch.
-- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
-
-Optional properties:
-- fsl,upm-wait-flags : add chip-dependent short delays after running the
-       UPM pattern (0x1), after writing a data byte (0x2) or after
-       writing out a buffer (0x4).
-- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
-       The corresponding address lines are used to select the chip.
-- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
-       (R/B#). For multi-chip devices, "n" GPIO definitions are required
-       according to the number of chips.
-- chip-delay : chip dependent delay for transfering data from array to
-       read registers (tR). Required if property "gpios" is not used
-       (R/B# pins not connected).
-
-Examples:
-
-upm@1,0 {
-       compatible = "fsl,upm-nand";
-       reg = <1 0 1>;
-       fsl,upm-addr-offset = <16>;
-       fsl,upm-cmd-offset = <8>;
-       gpios = <&qe_pio_e 18 0>;
-
-       flash {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "...";
-
-               partition@0 {
-                       ...
-               };
-       };
-};
-
-upm@3,0 {
-       #address-cells = <0>;
-       #size-cells = <0>;
-       compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
-       reg = <3 0x0 0x800>;
-       fsl,upm-addr-offset = <0x10>;
-       fsl,upm-cmd-offset = <0x08>;
-       /* Multi-chip NAND device */
-       fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
-       fsl,upm-wait-flags = <0x5>;
-       chip-delay = <25>; // in micro-seconds
-
-       nand@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               partition@0 {
-                           label = "fs";
-                           reg = <0x00000000 0x10000000>;
-               };
-       };
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/usb.txt b/Documentation/powerpc/dts-bindings/fsl/usb.txt
deleted file mode 100644 (file)
index bd5723f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-Freescale SOC USB controllers
-
-The device node for a USB controller that is part of a Freescale
-SOC is as described in the document "Open Firmware Recommended
-Practice : Universal Serial Bus" with the following modifications
-and additions :
-
-Required properties :
- - compatible : Should be "fsl-usb2-mph" for multi port host USB
-   controllers, or "fsl-usb2-dr" for dual role USB controllers
-   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
- - phy_type : For multi port host USB controllers, should be one of
-   "ulpi", or "serial". For dual role USB controllers, should be
-   one of "ulpi", "utmi", "utmi_wide", or "serial".
- - reg : Offset and length of the register set for the device
- - port0 : boolean; if defined, indicates port0 is connected for
-   fsl-usb2-mph compatible controllers.  Either this property or
-   "port1" (or both) must be defined for "fsl-usb2-mph" compatible
-   controllers.
- - port1 : boolean; if defined, indicates port1 is connected for
-   fsl-usb2-mph compatible controllers.  Either this property or
-   "port0" (or both) must be defined for "fsl-usb2-mph" compatible
-   controllers.
- - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible
-   controllers.  Can be "host", "peripheral", or "otg".  Default to
-   "host" if not defined for backward compatibility.
-
-Recommended properties :
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-Optional properties :
- - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
-   port power polarity of internal PHY signal DRVVBUS is inverted.
- - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
-   the PWR_FAULT signal polarity is inverted.
-
-Example multi port host USB controller device node :
-       usb@22000 {
-               compatible = "fsl-usb2-mph";
-               reg = <22000 1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = <700>;
-               interrupts = <27 1>;
-               phy_type = "ulpi";
-               port0;
-               port1;
-       };
-
-Example dual role USB controller device node :
-       usb@23000 {
-               compatible = "fsl-usb2-dr";
-               reg = <23000 1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = <700>;
-               interrupts = <26 1>;
-               dr_mode = "otg";
-               phy = "ulpi";
-       };
-
-Example dual role USB controller device node for MPC5121ADS:
-
-       usb@4000 {
-               compatible = "fsl,mpc5121-usb2-dr";
-               reg = <0x4000 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = < &ipic >;
-               interrupts = <44 0x8>;
-               dr_mode = "otg";
-               phy_type = "utmi_wide";
-               fsl,invert-drvvbus;
-               fsl,invert-pwr-fault;
-       };
diff --git a/Documentation/powerpc/dts-bindings/gpio/gpio.txt b/Documentation/powerpc/dts-bindings/gpio/gpio.txt
deleted file mode 100644 (file)
index edaa84d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-Specifying GPIO information for devices
-============================================
-
-1) gpios property
------------------
-
-Nodes that makes use of GPIOs should define them using `gpios' property,
-format of which is: <&gpio-controller1-phandle gpio1-specifier
-                    &gpio-controller2-phandle gpio2-specifier
-                    0 /* holes are permitted, means no GPIO 3 */
-                    &gpio-controller4-phandle gpio4-specifier
-                    ...>;
-
-Note that gpio-specifier length is controller dependent.
-
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
-
-Example of the node using GPIOs:
-
-       node {
-               gpios = <&qe_pio_e 18 0>;
-       };
-
-In this example gpio-specifier is "18 0" and encodes GPIO pin number,
-and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
-
-2) gpio-controller nodes
-------------------------
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Example of two SOC GPIO banks defined as gpio-controller nodes:
-
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-       };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-       };
-
-
diff --git a/Documentation/powerpc/dts-bindings/gpio/led.txt b/Documentation/powerpc/dts-bindings/gpio/led.txt
deleted file mode 100644 (file)
index 064db92..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-LEDs connected to GPIO lines
-
-Required properties:
-- compatible : should be "gpio-leds".
-
-Each LED is represented as a sub-node of the gpio-leds device.  Each
-node's name represents the name of the corresponding LED.
-
-LED sub-node properties:
-- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
-  for devices" in Documentation/powerpc/booting-without-of.txt.  Active
-  low LEDs should be indicated using flags in the GPIO specifier.
-- label :  (optional) The label for this LED.  If omitted, the label is
-  taken from the node name (excluding the unit address).
-- linux,default-trigger :  (optional) This parameter, if present, is a
-  string defining the trigger assigned to the LED.  Current triggers are:
-    "backlight" - LED will act as a back-light, controlled by the framebuffer
-                 system
-    "default-on" - LED will turn on, but see "default-state" below
-    "heartbeat" - LED "double" flashes at a load average based rate
-    "ide-disk" - LED indicates disk activity
-    "timer" - LED flashes at a fixed, configurable rate
-- default-state:  (optional) The initial state of the LED.  Valid
-  values are "on", "off", and "keep".  If the LED is already on or off
-  and the default-state property is set the to same value, then no
-  glitch should be produced where the LED momentarily turns off (or
-  on).  The "keep" setting will keep the LED at whatever its current
-  state is, without producing a glitch.  The default is off if this
-  property is not present.
-
-Examples:
-
-leds {
-       compatible = "gpio-leds";
-       hdd {
-               label = "IDE Activity";
-               gpios = <&mcu_pio 0 1>; /* Active low */
-               linux,default-trigger = "ide-disk";
-       };
-
-       fault {
-               gpios = <&mcu_pio 1 0>;
-               /* Keep LED on if BIOS detected hardware fault */
-               default-state = "keep";
-       };
-};
-
-run-control {
-       compatible = "gpio-leds";
-       red {
-               gpios = <&mpc8572 6 0>;
-               default-state = "off";
-       };
-       green {
-               gpios = <&mpc8572 7 0>;
-               default-state = "on";
-       };
-}
diff --git a/Documentation/powerpc/dts-bindings/gpio/mdio.txt b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
deleted file mode 100644 (file)
index bc95495..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-MDIO on GPIOs
-
-Currently defined compatibles:
-- virtual,gpio-mdio
-
-MDC and MDIO lines connected to GPIO controllers are listed in the
-gpios property as described in section VIII.1 in the following order:
-
-MDC, MDIO.
-
-Example:
-
-mdio {
-       compatible = "virtual,mdio-gpio";
-       #address-cells = <1>;
-       #size-cells = <0>;
-       gpios = <&qe_pio_a 11
-                &qe_pio_c 6>;
-};
diff --git a/Documentation/powerpc/dts-bindings/marvell.txt b/Documentation/powerpc/dts-bindings/marvell.txt
deleted file mode 100644 (file)
index f1533d9..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-Marvell Discovery mv64[345]6x System Controller chips
-===========================================================
-
-The Marvell mv64[345]60 series of system controller chips contain
-many of the peripherals needed to implement a complete computer
-system.  In this section, we define device tree nodes to describe
-the system controller chip itself and each of the peripherals
-which it contains.  Compatible string values for each node are
-prefixed with the string "marvell,", for Marvell Technology Group Ltd.
-
-1) The /system-controller node
-
-  This node is used to represent the system-controller and must be
-  present when the system uses a system controller chip. The top-level
-  system-controller node contains information that is global to all
-  devices within the system controller chip. The node name begins
-  with "system-controller" followed by the unit address, which is
-  the base address of the memory-mapped register set for the system
-  controller chip.
-
-  Required properties:
-
-    - ranges : Describes the translation of system controller addresses
-      for memory mapped registers.
-    - clock-frequency: Contains the main clock frequency for the system
-      controller chip.
-    - reg : This property defines the address and size of the
-      memory-mapped registers contained within the system controller
-      chip.  The address specified in the "reg" property should match
-      the unit address of the system-controller node.
-    - #address-cells : Address representation for system controller
-      devices.  This field represents the number of cells needed to
-      represent the address of the memory-mapped registers of devices
-      within the system controller chip.
-    - #size-cells : Size representation for the memory-mapped
-      registers within the system controller chip.
-    - #interrupt-cells : Defines the width of cells used to represent
-      interrupts.
-
-  Optional properties:
-
-    - model : The specific model of the system controller chip.  Such
-      as, "mv64360", "mv64460", or "mv64560".
-    - compatible : A string identifying the compatibility identifiers
-      of the system controller chip.
-
-  The system-controller node contains child nodes for each system
-  controller device that the platform uses.  Nodes should not be created
-  for devices which exist on the system controller chip but are not used
-
-  Example Marvell Discovery mv64360 system-controller node:
-
-    system-controller@f1000000 { /* Marvell Discovery mv64360 */
-           #address-cells = <1>;
-           #size-cells = <1>;
-           model = "mv64360";                      /* Default */
-           compatible = "marvell,mv64360";
-           clock-frequency = <133333333>;
-           reg = <0xf1000000 0x10000>;
-           virtual-reg = <0xf1000000>;
-           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
-                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
-                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
-                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
-                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
-
-           [ child node definitions... ]
-    }
-
-2) Child nodes of /system-controller
-
-   a) Marvell Discovery MDIO bus
-
-   The MDIO is a bus to which the PHY devices are connected.  For each
-   device that exists on this bus, a child node should be created.  See
-   the definition of the PHY node below for an example of how to define
-   a PHY.
-
-   Required properties:
-     - #address-cells : Should be <1>
-     - #size-cells : Should be <0>
-     - device_type : Should be "mdio"
-     - compatible : Should be "marvell,mv64360-mdio"
-
-   Example:
-
-     mdio {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            device_type = "mdio";
-            compatible = "marvell,mv64360-mdio";
-
-            ethernet-phy@0 {
-                    ......
-            };
-     };
-
-
-   b) Marvell Discovery ethernet controller
-
-   The Discover ethernet controller is described with two levels
-   of nodes.  The first level describes an ethernet silicon block
-   and the second level describes up to 3 ethernet nodes within
-   that block.  The reason for the multiple levels is that the
-   registers for the node are interleaved within a single set
-   of registers.  The "ethernet-block" level describes the
-   shared register set, and the "ethernet" nodes describe ethernet
-   port-specific properties.
-
-   Ethernet block node
-
-   Required properties:
-     - #address-cells : <1>
-     - #size-cells : <0>
-     - compatible : "marvell,mv64360-eth-block"
-     - reg : Offset and length of the register set for this block
-
-   Example Discovery Ethernet block node:
-     ethernet-block@2000 {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            compatible = "marvell,mv64360-eth-block";
-            reg = <0x2000 0x2000>;
-            ethernet@0 {
-                    .......
-            };
-     };
-
-   Ethernet port node
-
-   Required properties:
-     - device_type : Should be "network".
-     - compatible : Should be "marvell,mv64360-eth".
-     - reg : Should be <0>, <1>, or <2>, according to which registers
-       within the silicon block the device uses.
-     - interrupts : <a> where a is the interrupt number for the port.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-     - phy : the phandle for the PHY connected to this ethernet
-       controller.
-     - local-mac-address : 6 bytes, MAC address
-
-   Example Discovery Ethernet port node:
-     ethernet@0 {
-            device_type = "network";
-            compatible = "marvell,mv64360-eth";
-            reg = <0>;
-            interrupts = <32>;
-            interrupt-parent = <&PIC>;
-            phy = <&PHY0>;
-            local-mac-address = [ 00 00 00 00 00 00 ];
-     };
-
-
-
-   c) Marvell Discovery PHY nodes
-
-   Required properties:
-     - device_type : Should be "ethernet-phy"
-     - interrupts : <a> where a is the interrupt number for this phy.
-     - interrupt-parent : the phandle for the interrupt controller that
-       services interrupts for this device.
-     - reg : The ID number for the phy, usually a small integer
-
-   Example Discovery PHY node:
-     ethernet-phy@1 {
-            device_type = "ethernet-phy";
-            compatible = "broadcom,bcm5421";
-            interrupts = <76>;      /* GPP 12 */
-            interrupt-parent = <&PIC>;
-            reg = <1>;
-     };
-
-
-   d) Marvell Discovery SDMA nodes
-
-   Represent DMA hardware associated with the MPSC (multiprotocol
-   serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-sdma"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the DMA
-       device.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SDMA node:
-     sdma@4000 {
-            compatible = "marvell,mv64360-sdma";
-            reg = <0x4000 0xc18>;
-            virtual-reg = <0xf1004000>;
-            interrupts = <36>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   e) Marvell Discovery BRG nodes
-
-   Represent baud rate generator hardware associated with the MPSC
-   (multiprotocol serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-brg"
-     - reg : Offset and length of the register set for this device
-     - clock-src : A value from 0 to 15 which selects the clock
-       source for the baud rate generator.  This value corresponds
-       to the CLKS value in the BRGx configuration register.  See
-       the mv64x60 User's Manual.
-     - clock-frequence : The frequency (in Hz) of the baud rate
-       generator's input clock.
-     - current-speed : The current speed setting (presumably by
-       firmware) of the baud rate generator.
-
-   Example Discovery BRG node:
-     brg@b200 {
-            compatible = "marvell,mv64360-brg";
-            reg = <0xb200 0x8>;
-            clock-src = <8>;
-            clock-frequency = <133333333>;
-            current-speed = <9600>;
-     };
-
-
-   f) Marvell Discovery CUNIT nodes
-
-   Represent the Serial Communications Unit device hardware.
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     cunit@f200 {
-            reg = <0xf200 0x200>;
-     };
-
-
-   g) Marvell Discovery MPSCROUTING nodes
-
-   Represent the Discovery's MPSC routing hardware
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     mpscrouting@b500 {
-            reg = <0xb400 0xc>;
-     };
-
-
-   h) Marvell Discovery MPSCINTR nodes
-
-   Represent the Discovery's MPSC DMA interrupt hardware registers
-   (SDMA cause and mask registers).
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPSCINTR node:
-     mpsintr@b800 {
-            reg = <0xb800 0x100>;
-     };
-
-
-   i) Marvell Discovery MPSC nodes
-
-   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
-   serial port.
-
-   Required properties:
-     - device_type : "serial"
-     - compatible : "marvell,mv64360-mpsc"
-     - reg : Offset and length of the register set for this device
-     - sdma : the phandle for the SDMA node used by this port
-     - brg : the phandle for the BRG node used by this port
-     - cunit : the phandle for the CUNIT node used by this port
-     - mpscrouting : the phandle for the MPSCROUTING node used by this port
-     - mpscintr : the phandle for the MPSCINTR node used by this port
-     - cell-index : the hardware index of this cell in the MPSC core
-     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
-       register
-     - interrupts : <a> where a is the interrupt number for the MPSC.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery MPSCINTR node:
-     mpsc@8000 {
-            device_type = "serial";
-            compatible = "marvell,mv64360-mpsc";
-            reg = <0x8000 0x38>;
-            virtual-reg = <0xf1008000>;
-            sdma = <&SDMA0>;
-            brg = <&BRG0>;
-            cunit = <&CUNIT>;
-            mpscrouting = <&MPSCROUTING>;
-            mpscintr = <&MPSCINTR>;
-            cell-index = <0>;
-            max_idle = <40>;
-            interrupts = <40>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   j) Marvell Discovery Watch Dog Timer nodes
-
-   Represent the Discovery's watchdog timer hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-wdt"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery Watch Dog Timer node:
-     wdt@b410 {
-            compatible = "marvell,mv64360-wdt";
-            reg = <0xb410 0x8>;
-     };
-
-
-   k) Marvell Discovery I2C nodes
-
-   Represent the Discovery's I2C hardware
-
-   Required properties:
-     - device_type : "i2c"
-     - compatible : "marvell,mv64360-i2c"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the I2C.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery I2C node:
-            compatible = "marvell,mv64360-i2c";
-            reg = <0xc000 0x20>;
-            virtual-reg = <0xf100c000>;
-            interrupts = <37>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
-
-   Represent the Discovery's PIC hardware
-
-   Required properties:
-     - #interrupt-cells : <1>
-     - #address-cells : <0>
-     - compatible : "marvell,mv64360-pic"
-     - reg : Offset and length of the register set for this device
-     - interrupt-controller
-
-   Example Discovery PIC node:
-     pic {
-            #interrupt-cells = <1>;
-            #address-cells = <0>;
-            compatible = "marvell,mv64360-pic";
-            reg = <0x0 0x88>;
-            interrupt-controller;
-     };
-
-
-   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
-
-   Represent the Discovery's MPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-mpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPP node:
-     mpp@f000 {
-            compatible = "marvell,mv64360-mpp";
-            reg = <0xf000 0x10>;
-     };
-
-
-   n) Marvell Discovery GPP (General Purpose Pins) nodes
-
-   Represent the Discovery's GPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-gpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery GPP node:
-     gpp@f000 {
-            compatible = "marvell,mv64360-gpp";
-            reg = <0xf100 0x20>;
-     };
-
-
-   o) Marvell Discovery PCI host bridge node
-
-   Represents the Discovery's PCI host bridge device.  The properties
-   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
-   1275-1994.  A typical value for the compatible property is
-   "marvell,mv64360-pci".
-
-   Example Discovery PCI host bridge node
-     pci@80000000 {
-            #address-cells = <3>;
-            #size-cells = <2>;
-            #interrupt-cells = <1>;
-            device_type = "pci";
-            compatible = "marvell,mv64360-pci";
-            reg = <0xcf8 0x8>;
-            ranges = <0x01000000 0x0        0x0
-                            0x88000000 0x0 0x01000000
-                      0x02000000 0x0 0x80000000
-                            0x80000000 0x0 0x08000000>;
-            bus-range = <0 255>;
-            clock-frequency = <66000000>;
-            interrupt-parent = <&PIC>;
-            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-            interrupt-map = <
-                    /* IDSEL 0x0a */
-                    0x5000 0 0 1 &PIC 80
-                    0x5000 0 0 2 &PIC 81
-                    0x5000 0 0 3 &PIC 91
-                    0x5000 0 0 4 &PIC 93
-
-                    /* IDSEL 0x0b */
-                    0x5800 0 0 1 &PIC 91
-                    0x5800 0 0 2 &PIC 93
-                    0x5800 0 0 3 &PIC 80
-                    0x5800 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0c */
-                    0x6000 0 0 1 &PIC 91
-                    0x6000 0 0 2 &PIC 93
-                    0x6000 0 0 3 &PIC 80
-                    0x6000 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0d */
-                    0x6800 0 0 1 &PIC 93
-                    0x6800 0 0 2 &PIC 80
-                    0x6800 0 0 3 &PIC 81
-                    0x6800 0 0 4 &PIC 91
-            >;
-     };
-
-
-   p) Marvell Discovery CPU Error nodes
-
-   Represent the Discovery's CPU error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-cpu-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery CPU Error node:
-     cpu-error@0070 {
-            compatible = "marvell,mv64360-cpu-error";
-            reg = <0x70 0x10 0x128 0x28>;
-            interrupts = <3>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   q) Marvell Discovery SRAM Controller nodes
-
-   Represent the Discovery's SRAM controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-sram-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SRAM Controller node:
-     sram-ctrl@0380 {
-            compatible = "marvell,mv64360-sram-ctrl";
-            reg = <0x380 0x80>;
-            interrupts = <13>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   r) Marvell Discovery PCI Error Handler nodes
-
-   Represent the Discovery's PCI error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-pci-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery PCI Error Handler node:
-     pci-error@1d40 {
-            compatible = "marvell,mv64360-pci-error";
-            reg = <0x1d40 0x40 0xc28 0x4>;
-            interrupts = <12>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   s) Marvell Discovery Memory Controller nodes
-
-   Represent the Discovery's memory controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-mem-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery Memory Controller node:
-     mem-ctrl@1400 {
-            compatible = "marvell,mv64360-mem-ctrl";
-            reg = <0x1400 0x60>;
-            interrupts = <17>;
-            interrupt-parent = <&PIC>;
-     };
-
-
diff --git a/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt b/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt
deleted file mode 100644 (file)
index c39ac28..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-MMC/SD/SDIO slot directly connected to a SPI bus
-
-Required properties:
-- compatible : should be "mmc-spi-slot".
-- reg : should specify SPI address (chip-select number).
-- spi-max-frequency : maximum frequency for this device (Hz).
-- voltage-ranges : two cells are required, first cell specifies minimum
-  slot voltage (mV), second cell specifies maximum slot voltage (mV).
-  Several ranges could be specified.
-- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
-  Write-Protect GPIO.
-
-Example:
-
-       mmc-slot@0 {
-               compatible = "fsl,mpc8323rdb-mmc-slot",
-                            "mmc-spi-slot";
-               reg = <0>;
-               gpios = <&qe_pio_d 14 1
-                        &qe_pio_d 15 0>;
-               voltage-ranges = <3300 3300>;
-               spi-max-frequency = <50000000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/mtd-physmap.txt b/Documentation/powerpc/dts-bindings/mtd-physmap.txt
deleted file mode 100644 (file)
index 80152cb..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-CFI or JEDEC memory-mapped NOR flash, MTD-RAM (NVRAM...)
-
-Flash chips (Memory Technology Devices) are often used for solid state
-file systems on embedded devices.
-
- - compatible : should contain the specific model of mtd chip(s)
-   used, if known, followed by either "cfi-flash", "jedec-flash"
-   or "mtd-ram".
- - reg : Address range(s) of the mtd chip(s)
-   It's possible to (optionally) define multiple "reg" tuples so that
-   non-identical chips can be described in one node.
- - bank-width : Width (in bytes) of the bank.  Equal to the
-   device width times the number of interleaved chips.
- - device-width : (optional) Width of a single mtd chip.  If
-   omitted, assumed to be equal to 'bank-width'.
- - #address-cells, #size-cells : Must be present if the device has
-   sub-nodes representing partitions (see below).  In this case
-   both #address-cells and #size-cells must be equal to 1.
-
-For JEDEC compatible devices, the following additional properties
-are defined:
-
- - vendor-id : Contains the flash chip's vendor id (1 byte).
- - device-id : Contains the flash chip's device id (1 byte).
-
-In addition to the information on the mtd bank itself, the
-device tree may optionally contain additional information
-describing partitions of the address space.  This can be
-used on platforms which have strong conventions about which
-portions of a flash are used for what purposes, but which don't
-use an on-flash partition table such as RedBoot.
-
-Each partition is represented as a sub-node of the mtd device.
-Each node's name represents the name of the corresponding
-partition of the mtd device.
-
-Flash partitions
- - reg : The partition's offset and size within the mtd bank.
- - label : (optional) The label / name for this partition.
-   If omitted, the label is taken from the node name (excluding
-   the unit address).
- - read-only : (optional) This parameter, if present, is a hint to
-   Linux that this partition should only be mounted
-   read-only.  This is usually used for flash partitions
-   containing early-boot firmware images or data which should not
-   be clobbered.
-
-Example:
-
-       flash@ff000000 {
-               compatible = "amd,am29lv128ml", "cfi-flash";
-               reg = <ff000000 01000000>;
-               bank-width = <4>;
-               device-width = <1>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               fs@0 {
-                       label = "fs";
-                       reg = <0 f80000>;
-               };
-               firmware@f80000 {
-                       label ="firmware";
-                       reg = <f80000 80000>;
-                       read-only;
-               };
-       };
-
-Here an example with multiple "reg" tuples:
-
-       flash@f0000000,0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "intel,PC48F4400P0VB", "cfi-flash";
-               reg = <0 0x00000000 0x02000000
-                      0 0x02000000 0x02000000>;
-               bank-width = <2>;
-               partition@0 {
-                       label = "test-part1";
-                       reg = <0 0x04000000>;
-               };
-       };
-
-An example using SRAM:
-
-       sram@2,0 {
-               compatible = "samsung,k6f1616u6a", "mtd-ram";
-               reg = <2 0 0x00200000>;
-               bank-width = <2>;
-       };
-
diff --git a/Documentation/powerpc/dts-bindings/nintendo/gamecube.txt b/Documentation/powerpc/dts-bindings/nintendo/gamecube.txt
deleted file mode 100644 (file)
index b558585..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-
-Nintendo GameCube device tree
-=============================
-
-1) The "flipper" node
-
-  This node represents the multi-function "Flipper" chip, which packages
-  many of the devices found in the Nintendo GameCube.
-
-  Required properties:
-
-   - compatible : Should be "nintendo,flipper"
-
-1.a) The Video Interface (VI) node
-
-  Represents the interface between the graphics processor and a external
-  video encoder.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-vi"
-   - reg : should contain the VI registers location and length
-   - interrupts : should contain the VI interrupt
-
-1.b) The Processor Interface (PI) node
-
-  Represents the data and control interface between the main processor
-  and graphics and audio processor.
-
-  Required properties:
-
-  - compatible : should be "nintendo,flipper-pi"
-  - reg : should contain the PI registers location and length
-
-1.b.i) The "Flipper" interrupt controller node
-
-  Represents the interrupt controller within the "Flipper" chip.
-  The node for the "Flipper" interrupt controller must be placed under
-  the PI node.
-
-  Required properties:
-
-  - compatible : should be "nintendo,flipper-pic"
-
-1.c) The Digital Signal Procesor (DSP) node
-
-  Represents the digital signal processor interface, designed to offload
-  audio related tasks.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-dsp"
-   - reg : should contain the DSP registers location and length
-   - interrupts : should contain the DSP interrupt
-
-1.c.i) The Auxiliary RAM (ARAM) node
-
-  Represents the non cpu-addressable ram designed mainly to store audio
-  related information.
-  The ARAM node must be placed under the DSP node.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-aram"
-   - reg : should contain the ARAM start (zero-based) and length
-
-1.d) The Disk Interface (DI) node
-
-  Represents the interface used to communicate with mass storage devices.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-di"
-   - reg : should contain the DI registers location and length
-   - interrupts : should contain the DI interrupt
-
-1.e) The Audio Interface (AI) node
-
-  Represents the interface to the external 16-bit stereo digital-to-analog
-  converter.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-ai"
-   - reg : should contain the AI registers location and length
-   - interrupts : should contain the AI interrupt
-
-1.f) The Serial Interface (SI) node
-
-  Represents the interface to the four single bit serial interfaces.
-  The SI is a proprietary serial interface used normally to control gamepads.
-  It's NOT a RS232-type interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-si"
-   - reg : should contain the SI registers location and length
-   - interrupts : should contain the SI interrupt
-
-1.g) The External Interface (EXI) node
-
-  Represents the multi-channel SPI-like interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-exi"
-   - reg : should contain the EXI registers location and length
-   - interrupts : should contain the EXI interrupt
-
diff --git a/Documentation/powerpc/dts-bindings/nintendo/wii.txt b/Documentation/powerpc/dts-bindings/nintendo/wii.txt
deleted file mode 100644 (file)
index a7e155a..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-
-Nintendo Wii device tree
-========================
-
-0) The root node
-
-  This node represents the Nintendo Wii video game console.
-
-  Required properties:
-
-   - model : Should be "nintendo,wii"
-   - compatible : Should be "nintendo,wii"
-
-1) The "hollywood" node
-
-  This node represents the multi-function "Hollywood" chip, which packages
-  many of the devices found in the Nintendo Wii.
-
-  Required properties:
-
-   - compatible : Should be "nintendo,hollywood"
-
-1.a) The Video Interface (VI) node
-
-  Represents the interface between the graphics processor and a external
-  video encoder.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-vi","nintendo,flipper-vi"
-   - reg : should contain the VI registers location and length
-   - interrupts : should contain the VI interrupt
-
-1.b) The Processor Interface (PI) node
-
-  Represents the data and control interface between the main processor
-  and graphics and audio processor.
-
-  Required properties:
-
-  - compatible : should be "nintendo,hollywood-pi","nintendo,flipper-pi"
-  - reg : should contain the PI registers location and length
-
-1.b.i) The "Flipper" interrupt controller node
-
-  Represents the "Flipper" interrupt controller within the "Hollywood" chip.
-  The node for the "Flipper" interrupt controller must be placed under
-  the PI node.
-
-  Required properties:
-
-  - #interrupt-cells : <1>
-  - compatible : should be "nintendo,flipper-pic"
-  - interrupt-controller
-
-1.c) The Digital Signal Procesor (DSP) node
-
-  Represents the digital signal processor interface, designed to offload
-  audio related tasks.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-dsp","nintendo,flipper-dsp"
-   - reg : should contain the DSP registers location and length
-   - interrupts : should contain the DSP interrupt
-
-1.d) The Serial Interface (SI) node
-
-  Represents the interface to the four single bit serial interfaces.
-  The SI is a proprietary serial interface used normally to control gamepads.
-  It's NOT a RS232-type interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-si","nintendo,flipper-si"
-   - reg : should contain the SI registers location and length
-   - interrupts : should contain the SI interrupt
-
-1.e) The Audio Interface (AI) node
-
-  Represents the interface to the external 16-bit stereo digital-to-analog
-  converter.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-ai","nintendo,flipper-ai"
-   - reg : should contain the AI registers location and length
-   - interrupts : should contain the AI interrupt
-
-1.f) The External Interface (EXI) node
-
-  Represents the multi-channel SPI-like interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-exi","nintendo,flipper-exi"
-   - reg : should contain the EXI registers location and length
-   - interrupts : should contain the EXI interrupt
-
-1.g) The Open Host Controller Interface (OHCI) nodes
-
-  Represent the USB 1.x Open Host Controller Interfaces.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-usb-ohci","usb-ohci"
-   - reg : should contain the OHCI registers location and length
-   - interrupts : should contain the OHCI interrupt
-
-1.h) The Enhanced Host Controller Interface (EHCI) node
-
-  Represents the USB 2.0 Enhanced Host Controller Interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-usb-ehci","usb-ehci"
-   - reg : should contain the EHCI registers location and length
-   - interrupts : should contain the EHCI interrupt
-
-1.i) The Secure Digital Host Controller Interface (SDHCI) nodes
-
-  Represent the Secure Digital Host Controller Interfaces.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-sdhci","sdhci"
-   - reg : should contain the SDHCI registers location and length
-   - interrupts : should contain the SDHCI interrupt
-
-1.j) The Inter-Processsor Communication (IPC) node
-
-  Represent the Inter-Processor Communication interface. This interface
-  enables communications between the Broadway and the Starlet processors.
-
-   - compatible : should be "nintendo,hollywood-ipc"
-   - reg : should contain the IPC registers location and length
-   - interrupts : should contain the IPC interrupt
-
-1.k) The "Hollywood" interrupt controller node
-
-  Represents the "Hollywood" interrupt controller within the
-  "Hollywood" chip.
-
-  Required properties:
-
-  - #interrupt-cells : <1>
-  - compatible : should be "nintendo,hollywood-pic"
-  - reg : should contain the controller registers location and length
-  - interrupt-controller
-  - interrupts : should contain the cascade interrupt of the "flipper" pic
-  - interrupt-parent: should contain the phandle of the "flipper" pic
-
-1.l) The General Purpose I/O (GPIO) controller node
-
-  Represents the dual access 32 GPIO controller interface.
-
-  Required properties:
-
-  - #gpio-cells : <2>
-  - compatible : should be "nintendo,hollywood-gpio"
-  - reg : should contain the IPC registers location and length
-  - gpio-controller
-
-1.m) The control node
-
-  Represents the control interface used to setup several miscellaneous
-  settings of the "Hollywood" chip like boot memory mappings, resets,
-  disk interface mode, etc.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-control"
-   - reg : should contain the control registers location and length
-
-1.n) The Disk Interface (DI) node
-
-  Represents the interface used to communicate with mass storage devices.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-di"
-   - reg : should contain the DI registers location and length
-   - interrupts : should contain the DI interrupt
-
diff --git a/Documentation/powerpc/dts-bindings/phy.txt b/Documentation/powerpc/dts-bindings/phy.txt
deleted file mode 100644 (file)
index bb8c742..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-PHY nodes
-
-Required properties:
-
- - device_type : Should be "ethernet-phy"
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
- - reg : The ID number for the phy, usually a small integer
- - linux,phandle :  phandle for this node; likely referenced by an
-   ethernet controller node.
-
-Example:
-
-ethernet-phy@0 {
-       linux,phandle = <2452000>
-       interrupt-parent = <40000>;
-       interrupts = <35 1>;
-       reg = <0>;
-       device_type = "ethernet-phy";
-};
diff --git a/Documentation/powerpc/dts-bindings/spi-bus.txt b/Documentation/powerpc/dts-bindings/spi-bus.txt
deleted file mode 100644 (file)
index e782add..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-SPI (Serial Peripheral Interface) busses
-
-SPI busses can be described with a node for the SPI master device
-and a set of child nodes for each SPI slave on the bus.  For this
-discussion, it is assumed that the system's SPI controller is in
-SPI master mode.  This binding does not describe SPI controllers
-in slave mode.
-
-The SPI master node requires the following properties:
-- #address-cells  - number of cells required to define a chip select
-               address on the SPI bus.
-- #size-cells     - should be zero.
-- compatible      - name of SPI bus controller following generic names
-               recommended practice.
-No other properties are required in the SPI bus node.  It is assumed
-that a driver for an SPI bus device will understand that it is an SPI bus.
-However, the binding does not attempt to define the specific method for
-assigning chip select numbers.  Since SPI chip select configuration is
-flexible and non-standardized, it is left out of this binding with the
-assumption that board specific platform code will be used to manage
-chip selects.  Individual drivers can define additional properties to
-support describing the chip select layout.
-
-SPI slave nodes must be children of the SPI master node and can
-contain the following properties.
-- reg             - (required) chip select address of device.
-- compatible      - (required) name of SPI device following generic names
-               recommended practice
-- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
-- spi-cpol        - (optional) Empty property indicating device requires
-               inverse clock polarity (CPOL) mode
-- spi-cpha        - (optional) Empty property indicating device requires
-               shifted clock phase (CPHA) mode
-- spi-cs-high     - (optional) Empty property indicating device requires
-               chip select active high
-
-SPI example for an MPC5200 SPI bus:
-       spi@f00 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-               reg = <0xf00 0x20>;
-               interrupts = <2 13 0 2 14 0>;
-               interrupt-parent = <&mpc5200_pic>;
-
-               ethernet-switch@0 {
-                       compatible = "micrel,ks8995m";
-                       spi-max-frequency = <1000000>;
-                       reg = <0>;
-               };
-
-               codec@1 {
-                       compatible = "ti,tlv320aic26";
-                       spi-max-frequency = <100000>;
-                       reg = <1>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/usb-ehci.txt b/Documentation/powerpc/dts-bindings/usb-ehci.txt
deleted file mode 100644 (file)
index fa18612..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-USB EHCI controllers
-
-Required properties:
-  - compatible : should be "usb-ehci".
-  - reg : should contain at least address and length of the standard EHCI
-    register set for the device. Optional platform-dependent registers
-    (debug-port or other) can be also specified here, but only after
-    definition of standard EHCI registers.
-  - interrupts : one EHCI interrupt should be described here.
-If device registers are implemented in big endian mode, the device
-node should have "big-endian-regs" property.
-If controller implementation operates with big endian descriptors,
-"big-endian-desc" property should be specified.
-If both big endian registers and descriptors are used by the controller
-implementation, "big-endian" property can be specified instead of having
-both "big-endian-regs" and "big-endian-desc".
-
-Example (Sequoia 440EPx):
-    ehci@e0000300 {
-          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
-          interrupt-parent = <&UIC0>;
-          interrupts = <1a 4>;
-          reg = <0 e0000300 90 0 e0000390 70>;
-          big-endian;
-   };
diff --git a/Documentation/powerpc/dts-bindings/xilinx.txt b/Documentation/powerpc/dts-bindings/xilinx.txt
deleted file mode 100644 (file)
index 299d092..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-   d) Xilinx IP cores
-
-   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
-   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
-   of standard device types (network, serial, etc.) and miscellaneous
-   devices (gpio, LCD, spi, etc).  Also, since these devices are
-   implemented within the fpga fabric every instance of the device can be
-   synthesised with different options that change the behaviour.
-
-   Each IP-core has a set of parameters which the FPGA designer can use to
-   control how the core is synthesized.  Historically, the EDK tool would
-   extract the device parameters relevant to device drivers and copy them
-   into an 'xparameters.h' in the form of #define symbols.  This tells the
-   device drivers how the IP cores are configured, but it requires the kernel
-   to be recompiled every time the FPGA bitstream is resynthesized.
-
-   The new approach is to export the parameters into the device tree and
-   generate a new device tree each time the FPGA bitstream changes.  The
-   parameters which used to be exported as #defines will now become
-   properties of the device node.  In general, device nodes for IP-cores
-   will take the following form:
-
-       (name): (generic-name)@(base-address) {
-               compatible = "xlnx,(ip-core-name)-(HW_VER)"
-                            [, (list of compatible devices), ...];
-               reg = <(baseaddr) (size)>;
-               interrupt-parent = <&interrupt-controller-phandle>;
-               interrupts = < ... >;
-               xlnx,(parameter1) = "(string-value)";
-               xlnx,(parameter2) = <(int-value)>;
-       };
-
-       (generic-name):   an open firmware-style name that describes the
-                       generic class of device.  Preferably, this is one word, such
-                       as 'serial' or 'ethernet'.
-       (ip-core-name): the name of the ip block (given after the BEGIN
-                       directive in system.mhs).  Should be in lowercase
-                       and all underscores '_' converted to dashes '-'.
-       (name):         is derived from the "PARAMETER INSTANCE" value.
-       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
-                       dropped from the parameter name, the name is converted
-                       to lowercase and all underscore '_' characters are
-                       converted to dashes '-'.
-       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
-       (HW_VER):       from the HW_VER parameter.
-       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
-
-   Typically, the compatible list will include the exact IP core version
-   followed by an older IP core version which implements the same
-   interface or any other device with the same interface.
-
-   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
-
-   For example, the following block from system.mhs:
-
-       BEGIN opb_uartlite
-               PARAMETER INSTANCE = opb_uartlite_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BAUDRATE = 115200
-               PARAMETER C_DATA_BITS = 8
-               PARAMETER C_ODD_PARITY = 0
-               PARAMETER C_USE_PARITY = 0
-               PARAMETER C_CLK_FREQ = 50000000
-               PARAMETER C_BASEADDR = 0xEC100000
-               PARAMETER C_HIGHADDR = 0xEC10FFFF
-               BUS_INTERFACE SOPB = opb_7
-               PORT OPB_Clk = CLK_50MHz
-               PORT Interrupt = opb_uartlite_0_Interrupt
-               PORT RX = opb_uartlite_0_RX
-               PORT TX = opb_uartlite_0_TX
-               PORT OPB_Rst = sys_bus_reset_0
-       END
-
-   becomes the following device tree node:
-
-       opb_uartlite_0: serial@ec100000 {
-               device_type = "serial";
-               compatible = "xlnx,opb-uartlite-1.00.b";
-               reg = <ec100000 10000>;
-               interrupt-parent = <&opb_intc_0>;
-               interrupts = <1 0>; // got this from the opb_intc parameters
-               current-speed = <d#115200>;     // standard serial device prop
-               clock-frequency = <d#50000000>; // standard serial device prop
-               xlnx,data-bits = <8>;
-               xlnx,odd-parity = <0>;
-               xlnx,use-parity = <0>;
-       };
-
-   Some IP cores actually implement 2 or more logical devices.  In
-   this case, the device should still describe the whole IP core with
-   a single node and add a child node for each logical device.  The
-   ranges property can be used to translate from parent IP-core to the
-   registers of each device.  In addition, the parent node should be
-   compatible with the bus type 'xlnx,compound', and should contain
-   #address-cells and #size-cells, as with any other bus.  (Note: this
-   makes the assumption that both logical devices have the same bus
-   binding.  If this is not true, then separate nodes should be used
-   for each logical device).  The 'cell-index' property can be used to
-   enumerate logical devices within an IP core.  For example, the
-   following is the system.mhs entry for the dual ps2 controller found
-   on the ml403 reference design.
-
-       BEGIN opb_ps2_dual_ref
-               PARAMETER INSTANCE = opb_ps2_dual_ref_0
-               PARAMETER HW_VER = 1.00.a
-               PARAMETER C_BASEADDR = 0xA9000000
-               PARAMETER C_HIGHADDR = 0xA9001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-               PORT Sys_Intr1 = ps2_1_intr
-               PORT Sys_Intr2 = ps2_2_intr
-               PORT Clkin1 = ps2_clk_rx_1
-               PORT Clkin2 = ps2_clk_rx_2
-               PORT Clkpd1 = ps2_clk_tx_1
-               PORT Clkpd2 = ps2_clk_tx_2
-               PORT Rx1 = ps2_d_rx_1
-               PORT Rx2 = ps2_d_rx_2
-               PORT Txpd1 = ps2_d_tx_1
-               PORT Txpd2 = ps2_d_tx_2
-       END
-
-   It would result in the following device tree nodes:
-
-       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,compound";
-               ranges = <0 a9000000 2000>;
-               // If this device had extra parameters, then they would
-               // go here.
-               ps2@0 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <0 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-               ps2@1000 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <1000 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-       };
-
-   Also, the system.mhs file defines bus attachments from the processor
-   to the devices.  The device tree structure should reflect the bus
-   attachments.  Again an example; this system.mhs fragment:
-
-       BEGIN ppc405_virtex4
-               PARAMETER INSTANCE = ppc405_0
-               PARAMETER HW_VER = 1.01.a
-               BUS_INTERFACE DPLB = plb_v34_0
-               BUS_INTERFACE IPLB = plb_v34_0
-       END
-
-       BEGIN opb_intc
-               PARAMETER INSTANCE = opb_intc_0
-               PARAMETER HW_VER = 1.00.c
-               PARAMETER C_BASEADDR = 0xD1000FC0
-               PARAMETER C_HIGHADDR = 0xD1000FDF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN opb_uart16550
-               PARAMETER INSTANCE = opb_uart16550_0
-               PARAMETER HW_VER = 1.00.d
-               PARAMETER C_BASEADDR = 0xa0000000
-               PARAMETER C_HIGHADDR = 0xa0001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN plb_v34
-               PARAMETER INSTANCE = plb_v34_0
-               PARAMETER HW_VER = 1.02.a
-       END
-
-       BEGIN plb_bram_if_cntlr
-               PARAMETER INSTANCE = plb_bram_if_cntlr_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BASEADDR = 0xFFFF0000
-               PARAMETER C_HIGHADDR = 0xFFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-       END
-
-       BEGIN plb2opb_bridge
-               PARAMETER INSTANCE = plb2opb_bridge_0
-               PARAMETER HW_VER = 1.01.a
-               PARAMETER C_RNG0_BASEADDR = 0x20000000
-               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
-               PARAMETER C_RNG1_BASEADDR = 0x60000000
-               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
-               PARAMETER C_RNG2_BASEADDR = 0x80000000
-               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
-               PARAMETER C_RNG3_BASEADDR = 0xC0000000
-               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-               BUS_INTERFACE MOPB = opb_v20_0
-       END
-
-   Gives this device tree (some properties removed for clarity):
-
-       plb@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,plb-v34-1.02.a";
-               device_type = "ibm,plb";
-               ranges; // 1:1 translation
-
-               plb_bram_if_cntrl_0: bram@ffff0000 {
-                       reg = <ffff0000 10000>;
-               }
-
-               opb@20000000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <20000000 20000000 20000000
-                                 60000000 60000000 20000000
-                                 80000000 80000000 40000000
-                                 c0000000 c0000000 20000000>;
-
-                       opb_uart16550_0: serial@a0000000 {
-                               reg = <a00000000 2000>;
-                       };
-
-                       opb_intc_0: interrupt-controller@d1000fc0 {
-                               reg = <d1000fc0 20>;
-                       };
-               };
-       };
-
-   That covers the general approach to binding xilinx IP cores into the
-   device tree.  The following are bindings for specific devices:
-
-      i) Xilinx ML300 Framebuffer
-
-      Simple framebuffer device from the ML300 reference design (also on the
-      ML403 reference design as well as others).
-
-      Optional properties:
-       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
-                                    implementations use a different resolution.
-                                    Default is <d#640 d#480>
-       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
-                                           Default is <d#1024 d#480>.
-       - rotate-display (empty) : rotate display 180 degrees.
-
-      ii) Xilinx SystemACE
-
-      The Xilinx SystemACE device is used to program FPGAs from an FPGA
-      bitstream stored on a CF card.  It can also be used as a generic CF
-      interface device.
-
-      Optional properties:
-       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
-
-      iii) Xilinx EMAC and Xilinx TEMAC
-
-      Xilinx Ethernet devices.  In addition to general xilinx properties
-      listed above, nodes for these devices should include a phy-handle
-      property, and may include other common network device properties
-      like local-mac-address.
-
-      iv) Xilinx Uartlite
-
-      Xilinx uartlite devices are simple fixed speed serial ports.
-
-      Required properties:
-       - current-speed : Baud rate of uartlite
-
-      v) Xilinx hwicap
-
-               Xilinx hwicap devices provide access to the configuration logic
-               of the FPGA through the Internal Configuration Access Port
-               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
-               readback of the configuration information, and some control over
-               'warm boots' of the FPGA fabric.
-
-               Required properties:
-               - xlnx,family : The family of the FPGA, necessary since the
-                      capabilities of the underlying ICAP hardware
-                      differ between different families.  May be
-                      'virtex2p', 'virtex4', or 'virtex5'.
-
-      vi) Xilinx Uart 16550
-
-      Xilinx UART 16550 devices are very similar to the NS16550 but with
-      different register spacing and an offset from the base address.
-
-      Required properties:
-       - clock-frequency : Frequency of the clock input
-       - reg-offset : A value of 3 is required
-       - reg-shift : A value of 2 is required
-
-      vii) Xilinx USB Host controller
-
-      The Xilinx USB host controller is EHCI compatible but with a different
-      base address for the EHCI registers, and it is always a big-endian
-      USB Host controller. The hardware can be configured as high speed only,
-      or high speed/full speed hybrid.
-
-      Required properties:
-      - xlnx,support-usb-fs: A value 0 means the core is built as high speed
-                             only. A value 1 means the core also supports
-                             full speed devices.
-
index 01e6940..1cd5d51 100644 (file)
@@ -1,3 +1,7 @@
+Version 15 of schedstats dropped counters for some sched_yield:
+yld_exp_empty, yld_act_empty and yld_both_empty. Otherwise, it is
+identical to version 14.
+
 Version 14 of schedstats includes support for sched_domains, which hit the
 mainline kernel in 2.6.20 although it is identical to the stats from version
 12 which was in the kernel from 2.6.13-2.6.19 (version 13 never saw a kernel
@@ -28,32 +32,25 @@ to write their own scripts, the fields are described here.
 
 CPU statistics
 --------------
-cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12
-
-NOTE: In the sched_yield() statistics, the active queue is considered empty
-    if it has only one process in it, since obviously the process calling
-    sched_yield() is that process.
+cpu<N> 1 2 3 4 5 6 7 8 9
 
-First four fields are sched_yield() statistics:
-     1) # of times both the active and the expired queue were empty
-     2) # of times just the active queue was empty
-     3) # of times just the expired queue was empty
-     4) # of times sched_yield() was called
+First field is a sched_yield() statistic:
+     1) # of times sched_yield() was called
 
 Next three are schedule() statistics:
-     5) # of times we switched to the expired queue and reused it
-     6) # of times schedule() was called
-     7) # of times schedule() left the processor idle
+     2) # of times we switched to the expired queue and reused it
+     3) # of times schedule() was called
+     4) # of times schedule() left the processor idle
 
 Next two are try_to_wake_up() statistics:
-     8) # of times try_to_wake_up() was called
-     9) # of times try_to_wake_up() was called to wake up the local cpu
+     5) # of times try_to_wake_up() was called
+     6) # of times try_to_wake_up() was called to wake up the local cpu
 
 Next three are statistics describing scheduling latency:
-    10) sum of all time spent running by tasks on this processor (in jiffies)
-    11) sum of all time spent waiting to run by tasks on this processor (in
+     7) sum of all time spent running by tasks on this processor (in jiffies)
+     8) sum of all time spent waiting to run by tasks on this processor (in
         jiffies)
-    12) # of timeslices run on this cpu
+     9) # of timeslices run on this cpu
 
 
 Domain statistics
index 8773778..881e7f4 100644 (file)
@@ -285,6 +285,9 @@ implement g_volatile_ctrl like this:
 The 'new value' union is not used in g_volatile_ctrl. In general controls
 that need to implement g_volatile_ctrl are read-only controls.
 
+Note that if one or more controls in a control cluster are marked as volatile,
+then all the controls in the cluster are seen as volatile.
+
 To mark a control as volatile you have to set the is_volatile flag:
 
        ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
@@ -462,6 +465,15 @@ pointer to the v4l2_ctrl_ops struct that is used for that cluster.
 Obviously, all controls in the cluster array must be initialized to either
 a valid control or to NULL.
 
+In rare cases you might want to know which controls of a cluster actually
+were set explicitly by the user. For this you can check the 'is_new' flag of
+each control. For example, in the case of a volume/mute cluster the 'is_new'
+flag of the mute control would be set if the user called VIDIOC_S_CTRL for
+mute only. If the user would call VIDIOC_S_EXT_CTRLS for both mute and volume
+controls, then the 'is_new' flag would be 1 for both controls.
+
+The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
+
 
 VIDIOC_LOG_STATUS Support
 =========================
index 996a27d..01c513f 100644 (file)
@@ -190,9 +190,9 @@ resources, scheduled and executed.
        * Long running CPU intensive workloads which can be better
          managed by the system scheduler.
 
-  WQ_FREEZEABLE
+  WQ_FREEZABLE
 
-       A freezeable wq participates in the freeze phase of the system
+       A freezable wq participates in the freeze phase of the system
        suspend operations.  Work items on the wq are drained and no
        new work item starts execution until thawed.
 
index 1af022e..560ecce 100644 (file)
@@ -162,7 +162,7 @@ L:  linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
-F:     drivers/serial/8250*
+F:     drivers/tty/serial/8250*
 F:     include/linux/serial_8250.h
 
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
@@ -624,11 +624,15 @@ M:        Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
-ARM/ATMEL AT91RM9200 ARM ARCHITECTURE
+ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
 M:     Andrew Victor <linux@maxim.org.za>
+M:     Nicolas Ferre <nicolas.ferre@atmel.com>
+M:     Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://maxim.org.za/at91_26.html
-S:     Maintained
+W:     http://www.linux4sam.org
+S:     Supported
+F:     arch/arm/mach-at91/
 
 ARM/BCMRING ARM ARCHITECTURE
 M:     Jiandong Zheng <jdzheng@broadcom.com>
@@ -881,15 +885,15 @@ S:        Supported
 
 ARM/QUALCOMM MSM MACHINE SUPPORT
 M:     David Brown <davidb@codeaurora.org>
-M:     Daniel Walker <dwalker@codeaurora.org>
+M:     Daniel Walker <dwalker@fifo99.com>
 M:     Bryan Huntsman <bryanh@codeaurora.org>
 L:     linux-arm-msm@vger.kernel.org
 F:     arch/arm/mach-msm/
 F:     drivers/video/msm/
 F:     drivers/mmc/host/msm_sdcc.c
 F:     drivers/mmc/host/msm_sdcc.h
-F:     drivers/serial/msm_serial.h
-F:     drivers/serial/msm_serial.c
+F:     drivers/tty/serial/msm_serial.h
+F:     drivers/tty/serial/msm_serial.c
 T:     git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
 S:     Maintained
 
@@ -974,6 +978,8 @@ S:  Maintained
 F:     arch/arm/plat-samsung/
 F:     arch/arm/plat-s3c24xx/
 F:     arch/arm/plat-s5p/
+F:     drivers/*/*s3c2410*
+F:     drivers/*/*/*s3c2410*
 
 ARM/S3C2410 ARM ARCHITECTURE
 M:     Ben Dooks <ben-linux@fluff.org>
@@ -1004,6 +1010,15 @@ L:       linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-s5p*/
 
+ARM/SAMSUNG MOBILE MACHINE SUPPORT
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-s5pv210/mach-aquila.c
+F:     arch/arm/mach-s5pv210/mach-goni.c
+F:     arch/arm/mach-exynos4/mach-universal_c210.c
+F:     arch/arm/mach-exynos4/mach-nuri.c
+
 ARM/SAMSUNG S5P SERIES FIMC SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
@@ -1256,7 +1271,7 @@ F:        drivers/mmc/host/atmel-mci-regs.h
 ATMEL AT91 / AT32 SERIAL DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
-F:     drivers/serial/atmel_serial.c
+F:     drivers/tty/serial/atmel_serial.c
 
 ATMEL LCDFB DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -1412,7 +1427,7 @@ M:        Sonic Zhang <sonic.zhang@analog.com>
 L:     uclinux-dist-devel@blackfin.uclinux.org
 W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/serial/bfin_5xx.c
+F:     drivers/tty/serial/bfin_5xx.c
 
 BLACKFIN WATCHDOG DRIVER
 M:     Mike Frysinger <vapier.adi@gmail.com>
@@ -1461,6 +1476,7 @@ F:        include/net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <fubar@us.ibm.com>
+M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
@@ -1686,6 +1702,13 @@ M:       Andy Whitcroft <apw@canonical.com>
 S:     Supported
 F:     scripts/checkpatch.pl
 
+CHINESE DOCUMENTATION
+M:     Harry Wei <harryxiyou@gmail.com>
+L:     xiyoulinuxkernelgroup@googlegroups.com
+L:     linux-kernel@zh-kernel.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/zh_CN/
+
 CISCO VIC ETHERNET NIC DRIVER
 M:     Vasanthy Kolluri <vkolluri@cisco.com>
 M:     Roopa Prabhu <roprabhu@cisco.com>
@@ -1877,7 +1900,7 @@ L:        linux-cris-kernel@axis.com
 W:     http://developer.axis.com
 S:     Maintained
 F:     arch/cris/
-F:     drivers/serial/crisv10.*
+F:     drivers/tty/serial/crisv10.*
 
 CRYPTO API
 M:     Herbert Xu <herbert@gondor.apana.org.au>
@@ -2020,7 +2043,7 @@ F:        Documentation/scsi/dc395x.txt
 F:     drivers/scsi/dc395x.*
 
 DCCP PROTOCOL
-M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
+M:     Gerrit Renker <gerrit@erg.abdn.ac.uk>
 L:     dccp@vger.kernel.org
 W:     http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
 S:     Maintained
@@ -2120,6 +2143,7 @@ S:        Supported
 F:     fs/dlm/
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
+M:     Vinod Koul <vinod.koul@intel.com>
 M:     Dan Williams <dan.j.williams@intel.com>
 S:     Supported
 F:     drivers/dma/
@@ -2216,7 +2240,7 @@ F:        drivers/net/wan/dscc4.c
 DZ DECSTATION DZ11 SERIAL DRIVER
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
-F:     drivers/serial/dz.*
+F:     drivers/tty/serial/dz.*
 
 EATA-DMA SCSI DRIVER
 M:     Michael Neuffer <mike@i-Connect.Net>
@@ -2643,7 +2667,7 @@ FREESCALE QUICC ENGINE UCC UART DRIVER
 M:     Timur Tabi <timur@freescale.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
-F:     drivers/serial/ucc_uart.c
+F:     drivers/tty/serial/ucc_uart.c
 
 FREESCALE SOC SOUND DRIVERS
 M:     Timur Tabi <timur@freescale.com>
@@ -2768,6 +2792,15 @@ F:       Documentation/isdn/README.gigaset
 F:     drivers/isdn/gigaset/
 F:     include/linux/gigaset_dev.h
 
+GPIO SUBSYSTEM
+M:     Grant Likely <grant.likely@secretlab.ca>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+T:     git git://git.secretlab.ca/git/linux-2.6.git
+F:     Documentation/gpio/gpio.txt
+F:     drivers/gpio/
+F:     include/linux/gpio*
+
 GRETH 10/100/1G Ethernet MAC device driver
 M:     Kristoffer Glembo <kristoffer@gaisler.com>
 L:     netdev@vger.kernel.org
@@ -2857,7 +2890,6 @@ M:        Guenter Roeck <guenter.roeck@ericsson.com>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
 T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/
-T:     quilt kernel.org/pub/linux/kernel/people/groeck/linux-staging/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
 F:     Documentation/hwmon/
@@ -3135,6 +3167,12 @@ S:       Maintained
 F:     net/ieee802154/
 F:     drivers/ieee802154/
 
+IKANOS/ADI EAGLE ADSL USB DRIVER
+M:     Matthieu Castet <castet.matthieu@free.fr>
+M:     Stanislaw Gruszka <stf_xl@wp.pl>
+S:     Maintained
+F:     drivers/usb/atm/ueagle-atm.c
+
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@us.ibm.com>
 S:     Supported
@@ -3146,7 +3184,7 @@ S:        Orphan
 F:     drivers/video/imsttfb.c
 
 INFINIBAND SUBSYSTEM
-M:     Roland Dreier <rolandd@cisco.com>
+M:     Roland Dreier <roland@kernel.org>
 M:     Sean Hefty <sean.hefty@intel.com>
 M:     Hal Rosenstock <hal.rosenstock@gmail.com>
 L:     linux-rdma@vger.kernel.org
@@ -3323,7 +3361,6 @@ F:        drivers/net/wimax/i2400m/
 F:     include/linux/wimax/i2400m.h
 
 INTEL WIRELESS WIFI LINK (iwlwifi)
-M:     Reinette Chatre <reinette.chatre@intel.com>
 M:     Wey-Yi Guy <wey-yi.w.guy@intel.com>
 M:     Intel Linux Wireless <ilw@linux.intel.com>
 L:     linux-wireless@vger.kernel.org
@@ -3350,7 +3387,7 @@ IOC3 SERIAL DRIVER
 M:     Pat Gefre <pfg@sgi.com>
 L:     linux-serial@vger.kernel.org
 S:     Maintained
-F:     drivers/serial/ioc3_serial.c
+F:     drivers/tty/serial/ioc3_serial.c
 
 IP MASQUERADING
 M:     Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
@@ -3492,7 +3529,7 @@ F:        drivers/hwmon/jc42.c
 F:     Documentation/hwmon/jc42
 
 JFS FILESYSTEM
-M:     Dave Kleikamp <shaggy@linux.vnet.ibm.com>
+M:     Dave Kleikamp <shaggy@kernel.org>
 L:     jfs-discussion@lists.sourceforge.net
 W:     http://jfs.sourceforge.net/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
@@ -3527,7 +3564,7 @@ JSM Neo PCI based serial card
 M:     Breno Leitao <leitao@linux.vnet.ibm.com>
 L:     linux-serial@vger.kernel.org
 S:     Maintained
-F:     drivers/serial/jsm/
+F:     drivers/tty/serial/jsm/
 
 K10TEMP HARDWARE MONITORING DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
@@ -3670,6 +3707,28 @@ F:       include/linux/key-type.h
 F:     include/keys/
 F:     security/keys/
 
+KEYS-TRUSTED
+M:     David Safford <safford@watson.ibm.com>
+M:     Mimi Zohar <zohar@us.ibm.com>
+L:     linux-security-module@vger.kernel.org
+L:     keyrings@linux-nfs.org
+S:     Supported
+F:     Documentation/keys-trusted-encrypted.txt
+F:     include/keys/trusted-type.h
+F:     security/keys/trusted.c
+F:     security/keys/trusted.h
+
+KEYS-ENCRYPTED
+M:     Mimi Zohar <zohar@us.ibm.com>
+M:     David Safford <safford@watson.ibm.com>
+L:     linux-security-module@vger.kernel.org
+L:     keyrings@linux-nfs.org
+S:     Supported
+F:     Documentation/keys-trusted-encrypted.txt
+F:     include/keys/encrypted-type.h
+F:     security/keys/encrypted.c
+F:     security/keys/encrypted.h
+
 KGDB / KDB /debug_core
 M:     Jason Wessel <jason.wessel@windriver.com>
 W:     http://kgdb.wiki.kernel.org/
@@ -3677,7 +3736,7 @@ L:        kgdb-bugreport@lists.sourceforge.net
 S:     Maintained
 F:     Documentation/DocBook/kgdb.tmpl
 F:     drivers/misc/kgdbts.c
-F:     drivers/serial/kgdboc.c
+F:     drivers/tty/serial/kgdboc.c
 F:     include/linux/kdb.h
 F:     include/linux/kgdb.h
 F:     kernel/debug/
@@ -4558,7 +4617,7 @@ F:        drivers/i2c/busses/i2c-ocores.c
 
 OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Grant Likely <grant.likely@secretlab.ca>
-L:     devicetree-discuss@lists.ozlabs.org
+L:     devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
 W:     http://fdt.secretlab.ca
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 S:     Maintained
@@ -5122,6 +5181,7 @@ F:        drivers/char/random.c
 
 RAPIDIO SUBSYSTEM
 M:     Matt Porter <mporter@kernel.crashing.org>
+M:     Alexandre Bounine <alexandre.bounine@idt.com>
 S:     Maintained
 F:     drivers/rapidio/
 
@@ -5224,7 +5284,7 @@ S:        Maintained
 F:     drivers/net/wireless/rtl818x/rtl8180/
 
 RTL8187 WIRELESS DRIVER
-M:     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+M:     Herton Ronaldo Krzesinski <herton@canonical.com>
 M:     Hin-Tak Leung <htl10@users.sourceforge.net>
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
@@ -5518,12 +5578,11 @@ S:      Supported
 F:     drivers/scsi/be2iscsi/
 
 SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
-M:     Sathya Perla <sathyap@serverengines.com>
-M:     Subbu Seetharaman <subbus@serverengines.com>
-M:     Sarveshwar Bandi <sarveshwarb@serverengines.com>
-M:     Ajit Khaparde <ajitk@serverengines.com>
+M:     Sathya Perla <sathya.perla@emulex.com>
+M:     Subbu Seetharaman <subbu.seetharaman@emulex.com>
+M:     Ajit Khaparde <ajit.khaparde@emulex.com>
 L:     netdev@vger.kernel.org
-W:     http://www.serverengines.com
+W:     http://www.emulex.com
 S:     Supported
 F:     drivers/net/benet/
 
@@ -5545,7 +5604,7 @@ M:        Pat Gefre <pfg@sgi.com>
 L:     linux-ia64@vger.kernel.org
 S:     Supported
 F:     Documentation/ia64/serial.txt
-F:     drivers/serial/ioc?_serial.c
+F:     drivers/tty/serial/ioc?_serial.c
 F:     include/linux/ioc?.h
 
 SGI VISUAL WORKSTATION 320 AND 540
@@ -5567,7 +5626,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/arm/Sharp-LH/ADC-LH7-Touchscreen
 F:     arch/arm/mach-lh7a40x/
-F:     drivers/serial/serial_lh7a40x.c
+F:     drivers/tty/serial/serial_lh7a40x.c
 F:     drivers/usb/gadget/lh7a40*
 F:     drivers/usb/host/ohci-lh7a40*
 
@@ -5583,18 +5642,20 @@ F:      include/linux/sfi*.h
 
 SIMTEC EB110ATX (Chalice CATS)
 P:     Ben Dooks
-M:     Vincent Sanders <support@simtec.co.uk>
+P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB110ATX/
 S:     Supported
 
 SIMTEC EB2410ITX (BAST)
 P:     Ben Dooks
-M:     Vincent Sanders <support@simtec.co.uk>
+P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
-F:     arch/arm/mach-s3c2410/
-F:     drivers/*/*s3c2410*
-F:     drivers/*/*/*s3c2410*
+F:     arch/arm/mach-s3c2410/mach-bast.c
+F:     arch/arm/mach-s3c2410/bast-ide.c
+F:     arch/arm/mach-s3c2410/bast-irq.c
 
 TI DAVINCI MACHINE SUPPORT
 M:     Kevin Hilman <khilman@deeprootsystems.com>
@@ -5787,14 +5848,14 @@ L:      sparclinux@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
 S:     Maintained
-F:     drivers/serial/suncore.c
-F:     drivers/serial/suncore.h
-F:     drivers/serial/sunhv.c
-F:     drivers/serial/sunsab.c
-F:     drivers/serial/sunsab.h
-F:     drivers/serial/sunsu.c
-F:     drivers/serial/sunzilog.c
-F:     drivers/serial/sunzilog.h
+F:     drivers/tty/serial/suncore.c
+F:     drivers/tty/serial/suncore.h
+F:     drivers/tty/serial/sunhv.c
+F:     drivers/tty/serial/sunsab.c
+F:     drivers/tty/serial/sunsab.h
+F:     drivers/tty/serial/sunsu.c
+F:     drivers/tty/serial/sunzilog.c
+F:     drivers/tty/serial/sunzilog.h
 
 SPEAR PLATFORM SUPPORT
 M:     Viresh Kumar <viresh.kumar@st.com>
@@ -6061,7 +6122,7 @@ S:        Maintained
 F:     security/tomoyo/
 
 TOPSTAR LAPTOP EXTRAS DRIVER
-M:     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+M:     Herton Ronaldo Krzesinski <herton@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/topstar-laptop.c
@@ -6124,8 +6185,8 @@ TTY LAYER
 M:     Greg Kroah-Hartman <gregkh@suse.de>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
-F:     drivers/char/tty_*
-F:     drivers/serial/serial_core.c
+F:     drivers/tty/*
+F:     drivers/tty/serial/serial_core.c
 F:     include/linux/serial_core.h
 F:     include/linux/serial.h
 F:     include/linux/tty.h
@@ -6569,6 +6630,16 @@ S:       Maintained
 F:     drivers/char/virtio_console.c
 F:     include/linux/virtio_console.h
 
+VIRTIO CORE, NET AND BLOCK DRIVERS
+M:     Rusty Russell <rusty@rustcorp.com.au>
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/virtio/
+F:     drivers/net/virtio_net.c
+F:     drivers/block/virtio_blk.c
+F:     include/linux/virtio_*.h
+
 VIRTIO HOST (VHOST)
 M:     "Michael S. Tsirkin" <mst@redhat.com>
 L:     kvm@vger.kernel.org
@@ -6742,12 +6813,12 @@ S:      Maintained
 F:     drivers/net/wireless/wl1251/*
 
 WL1271 WIRELESS DRIVER
-M:     Luciano Coelho <luciano.coelho@nokia.com>
+M:     Luciano Coelho <coelho@ti.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org
+W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
 S:     Maintained
-F:     drivers/net/wireless/wl12xx/wl1271*
+F:     drivers/net/wireless/wl12xx/
 F:     include/linux/wl12xx.h
 
 WL3501 WIRELESS PCMCIA CARD DRIVER
@@ -6870,7 +6941,7 @@ XILINX UARTLITE SERIAL DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
 L:     linux-serial@vger.kernel.org
 S:     Maintained
-F:     drivers/serial/uartlite.c
+F:     drivers/tty/serial/uartlite.c
 
 YAM DRIVER FOR AX.25
 M:     Jean-Paul Roubelat <jpr@f6fbb.org>
@@ -6916,7 +6987,7 @@ F:        drivers/media/video/zoran/
 ZS DECSTATION Z85C30 SERIAL DRIVER
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
-F:     drivers/serial/zs.*
+F:     drivers/tty/serial/zs.*
 
 GRE DEMULTIPLEXER DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
index abb49bf..2f7d922 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 38
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc7
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index fc95ee1..cc31bec 100644 (file)
@@ -8,6 +8,10 @@ config ALPHA
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_DMA_ATTRS
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select AUTO_IRQ_AFFINITY if SMP
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -68,22 +72,6 @@ config GENERIC_IOMAP
        bool
        default n
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_IRQ_PROBE
-       bool
-       default y
-
-config AUTO_IRQ_AFFINITY
-       bool
-       depends on SMP
-       default y
-
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
index 9ab234f..a19d600 100644 (file)
@@ -44,11 +44,16 @@ static char irq_user_affinity[NR_IRQS];
 
 int irq_select_affinity(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc[irq];
+       struct irq_data *data = irq_get_irq_data(irq);
+       struct irq_chip *chip;
        static int last_cpu;
        int cpu = last_cpu + 1;
 
-       if (!desc || !get_irq_desc_chip(desc)->set_affinity || irq_user_affinity[irq])
+       if (!data)
+               return 1;
+       chip = irq_data_get_irq_chip(data);
+
+       if (!chip->irq_set_affinity || irq_user_affinity[irq])
                return 1;
 
        while (!cpu_possible(cpu) ||
@@ -56,8 +61,8 @@ int irq_select_affinity(unsigned int irq)
                cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
        last_cpu = cpu;
 
-       cpumask_copy(desc->affinity, cpumask_of(cpu));
-       get_irq_desc_chip(desc)->set_affinity(irq, cpumask_of(cpu));
+       cpumask_copy(data->affinity, cpumask_of(cpu));
+       chip->irq_set_affinity(data, cpumask_of(cpu), false);
        return 0;
 }
 #endif /* CONFIG_SMP */
index 2d0679b..411ca11 100644 (file)
@@ -228,14 +228,9 @@ struct irqaction timer_irqaction = {
 void __init
 init_rtc_irq(void)
 {
-       struct irq_desc *desc = irq_to_desc(RTC_IRQ);
-
-       if (desc) {
-               desc->status |= IRQ_DISABLED;
-               set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
-                       handle_simple_irq, "RTC");
-               setup_irq(RTC_IRQ, &timer_irqaction);
-       }
+       set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
+                                     handle_simple_irq, "RTC");
+       setup_irq(RTC_IRQ, &timer_irqaction);
 }
 
 /* Dummy irqactions.  */
index 956ea0e..c7cc981 100644 (file)
@@ -33,10 +33,10 @@ i8259_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 inline void
-i8259a_enable_irq(unsigned int irq)
+i8259a_enable_irq(struct irq_data *d)
 {
        spin_lock(&i8259_irq_lock);
-       i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+       i8259_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
        spin_unlock(&i8259_irq_lock);
 }
 
@@ -47,16 +47,18 @@ __i8259a_disable_irq(unsigned int irq)
 }
 
 void
-i8259a_disable_irq(unsigned int irq)
+i8259a_disable_irq(struct irq_data *d)
 {
        spin_lock(&i8259_irq_lock);
-       __i8259a_disable_irq(irq);
+       __i8259a_disable_irq(d->irq);
        spin_unlock(&i8259_irq_lock);
 }
 
 void
-i8259a_mask_and_ack_irq(unsigned int irq)
+i8259a_mask_and_ack_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        spin_lock(&i8259_irq_lock);
        __i8259a_disable_irq(irq);
 
@@ -71,9 +73,9 @@ i8259a_mask_and_ack_irq(unsigned int irq)
 
 struct irq_chip i8259a_irq_type = {
        .name           = "XT-PIC",
-       .unmask         = i8259a_enable_irq,
-       .mask           = i8259a_disable_irq,
-       .mask_ack       = i8259a_mask_and_ack_irq,
+       .irq_unmask     = i8259a_enable_irq,
+       .irq_mask       = i8259a_disable_irq,
+       .irq_mask_ack   = i8259a_mask_and_ack_irq,
 };
 
 void __init
index b63ccd7..d507a23 100644 (file)
@@ -31,11 +31,9 @@ extern void init_rtc_irq(void);
 
 extern void common_init_isa_dma(void);
 
-extern void i8259a_enable_irq(unsigned int);
-extern void i8259a_disable_irq(unsigned int);
-extern void i8259a_mask_and_ack_irq(unsigned int);
-extern unsigned int i8259a_startup_irq(unsigned int);
-extern void i8259a_end_irq(unsigned int);
+extern void i8259a_enable_irq(struct irq_data *d);
+extern void i8259a_disable_irq(struct irq_data *d);
+extern void i8259a_mask_and_ack_irq(struct irq_data *d);
 extern struct irq_chip i8259a_irq_type;
 extern void init_i8259a_irqs(void);
 
index 2863458..b30227f 100644 (file)
@@ -29,21 +29,21 @@ pyxis_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-pyxis_enable_irq(unsigned int irq)
+pyxis_enable_irq(struct irq_data *d)
 {
-       pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       pyxis_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-pyxis_disable_irq(unsigned int irq)
+pyxis_disable_irq(struct irq_data *d)
 {
-       pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static void
-pyxis_mask_and_ack_irq(unsigned int irq)
+pyxis_mask_and_ack_irq(struct irq_data *d)
 {
-       unsigned long bit = 1UL << (irq - 16);
+       unsigned long bit = 1UL << (d->irq - 16);
        unsigned long mask = cached_irq_mask &= ~bit;
 
        /* Disable the interrupt.  */
@@ -58,9 +58,9 @@ pyxis_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip pyxis_irq_type = {
        .name           = "PYXIS",
-       .mask_ack       = pyxis_mask_and_ack_irq,
-       .mask           = pyxis_disable_irq,
-       .unmask         = pyxis_enable_irq,
+       .irq_mask_ack   = pyxis_mask_and_ack_irq,
+       .irq_mask       = pyxis_disable_irq,
+       .irq_unmask     = pyxis_enable_irq,
 };
 
 void 
@@ -103,7 +103,7 @@ init_pyxis_irqs(unsigned long ignore_mask)
                if ((ignore_mask >> i) & 1)
                        continue;
                set_irq_chip_and_handler(i, &pyxis_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        setup_irq(16+7, &isa_cascade_irqaction);
index 0e57e82..82a47bb 100644 (file)
 DEFINE_SPINLOCK(srm_irq_lock);
 
 static inline void
-srm_enable_irq(unsigned int irq)
+srm_enable_irq(struct irq_data *d)
 {
        spin_lock(&srm_irq_lock);
-       cserve_ena(irq - 16);
+       cserve_ena(d->irq - 16);
        spin_unlock(&srm_irq_lock);
 }
 
 static void
-srm_disable_irq(unsigned int irq)
+srm_disable_irq(struct irq_data *d)
 {
        spin_lock(&srm_irq_lock);
-       cserve_dis(irq - 16);
+       cserve_dis(d->irq - 16);
        spin_unlock(&srm_irq_lock);
 }
 
 /* Handle interrupts from the SRM, assuming no additional weirdness.  */
 static struct irq_chip srm_irq_type = {
        .name           = "SRM",
-       .unmask         = srm_enable_irq,
-       .mask           = srm_disable_irq,
-       .mask_ack       = srm_disable_irq,
+       .irq_unmask     = srm_enable_irq,
+       .irq_mask       = srm_disable_irq,
+       .irq_mask_ack   = srm_disable_irq,
 };
 
 void __init
@@ -52,7 +52,7 @@ init_srm_irqs(long max, unsigned long ignore_mask)
                if (i < 64 && ((ignore_mask >> i) & 1))
                        continue;
                set_irq_chip_and_handler(i, &srm_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index 7bef617..88d95e8 100644 (file)
@@ -44,31 +44,31 @@ alcor_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-alcor_enable_irq(unsigned int irq)
+alcor_enable_irq(struct irq_data *d)
 {
-       alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       alcor_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-alcor_disable_irq(unsigned int irq)
+alcor_disable_irq(struct irq_data *d)
 {
-       alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static void
-alcor_mask_and_ack_irq(unsigned int irq)
+alcor_mask_and_ack_irq(struct irq_data *d)
 {
-       alcor_disable_irq(irq);
+       alcor_disable_irq(d);
 
        /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
-       *(vuip)GRU_INT_CLEAR = 1 << (irq - 16); mb();
+       *(vuip)GRU_INT_CLEAR = 1 << (d->irq - 16); mb();
        *(vuip)GRU_INT_CLEAR = 0; mb();
 }
 
 static void
-alcor_isa_mask_and_ack_irq(unsigned int irq)
+alcor_isa_mask_and_ack_irq(struct irq_data *d)
 {
-       i8259a_mask_and_ack_irq(irq);
+       i8259a_mask_and_ack_irq(d);
 
        /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
        *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
@@ -77,9 +77,9 @@ alcor_isa_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip alcor_irq_type = {
        .name           = "ALCOR",
-       .unmask         = alcor_enable_irq,
-       .mask           = alcor_disable_irq,
-       .mask_ack       = alcor_mask_and_ack_irq,
+       .irq_unmask     = alcor_enable_irq,
+       .irq_mask       = alcor_disable_irq,
+       .irq_mask_ack   = alcor_mask_and_ack_irq,
 };
 
 static void
@@ -126,9 +126,9 @@ alcor_init_irq(void)
                if (i >= 16+20 && i <= 16+30)
                        continue;
                set_irq_chip_and_handler(i, &alcor_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
-       i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
+       i8259a_irq_type.irq_ack = alcor_isa_mask_and_ack_irq;
 
        init_i8259a_irqs();
        common_init_isa_dma();
index b0c9164..57eb630 100644 (file)
@@ -46,22 +46,22 @@ cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 static inline void
-cabriolet_enable_irq(unsigned int irq)
+cabriolet_enable_irq(struct irq_data *d)
 {
-       cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
+       cabriolet_update_irq_hw(d->irq, cached_irq_mask &= ~(1UL << d->irq));
 }
 
 static void
-cabriolet_disable_irq(unsigned int irq)
+cabriolet_disable_irq(struct irq_data *d)
 {
-       cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
+       cabriolet_update_irq_hw(d->irq, cached_irq_mask |= 1UL << d->irq);
 }
 
 static struct irq_chip cabriolet_irq_type = {
        .name           = "CABRIOLET",
-       .unmask         = cabriolet_enable_irq,
-       .mask           = cabriolet_disable_irq,
-       .mask_ack       = cabriolet_disable_irq,
+       .irq_unmask     = cabriolet_enable_irq,
+       .irq_mask       = cabriolet_disable_irq,
+       .irq_mask_ack   = cabriolet_disable_irq,
 };
 
 static void 
@@ -107,7 +107,7 @@ common_init_irq(void (*srm_dev_int)(unsigned long v))
                for (i = 16; i < 35; ++i) {
                        set_irq_chip_and_handler(i, &cabriolet_irq_type,
                                handle_level_irq);
-                       irq_to_desc(i)->status |= IRQ_LEVEL;
+                       irq_set_status_flags(i, IRQ_LEVEL);
                }
        }
 
index edad5f7..481df4e 100644 (file)
@@ -98,37 +98,37 @@ tsunami_update_irq_hw(unsigned long mask)
 }
 
 static void
-dp264_enable_irq(unsigned int irq)
+dp264_enable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask |= 1UL << irq;
+       cached_irq_mask |= 1UL << d->irq;
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-dp264_disable_irq(unsigned int irq)
+dp264_disable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask &= ~(1UL << irq);
+       cached_irq_mask &= ~(1UL << d->irq);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-clipper_enable_irq(unsigned int irq)
+clipper_enable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask |= 1UL << (irq - 16);
+       cached_irq_mask |= 1UL << (d->irq - 16);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-clipper_disable_irq(unsigned int irq)
+clipper_disable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask &= ~(1UL << (irq - 16));
+       cached_irq_mask &= ~(1UL << (d->irq - 16));
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
@@ -149,10 +149,11 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 }
 
 static int
-dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
-{ 
+dp264_set_affinity(struct irq_data *d, const struct cpumask *affinity,
+                  bool force)
+{
        spin_lock(&dp264_irq_lock);
-       cpu_set_irq_affinity(irq, *affinity);
+       cpu_set_irq_affinity(d->irq, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 
@@ -160,10 +161,11 @@ dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
 }
 
 static int
-clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
-{ 
+clipper_set_affinity(struct irq_data *d, const struct cpumask *affinity,
+                    bool force)
+{
        spin_lock(&dp264_irq_lock);
-       cpu_set_irq_affinity(irq - 16, *affinity);
+       cpu_set_irq_affinity(d->irq - 16, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 
@@ -171,19 +173,19 @@ clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
 }
 
 static struct irq_chip dp264_irq_type = {
-       .name           = "DP264",
-       .unmask         = dp264_enable_irq,
-       .mask           = dp264_disable_irq,
-       .mask_ack       = dp264_disable_irq,
-       .set_affinity   = dp264_set_affinity,
+       .name                   = "DP264",
+       .irq_unmask             = dp264_enable_irq,
+       .irq_mask               = dp264_disable_irq,
+       .irq_mask_ack           = dp264_disable_irq,
+       .irq_set_affinity       = dp264_set_affinity,
 };
 
 static struct irq_chip clipper_irq_type = {
-       .name           = "CLIPPER",
-       .unmask         = clipper_enable_irq,
-       .mask           = clipper_disable_irq,
-       .mask_ack       = clipper_disable_irq,
-       .set_affinity   = clipper_set_affinity,
+       .name                   = "CLIPPER",
+       .irq_unmask             = clipper_enable_irq,
+       .irq_mask               = clipper_disable_irq,
+       .irq_mask_ack           = clipper_disable_irq,
+       .irq_set_affinity       = clipper_set_affinity,
 };
 
 static void
@@ -268,8 +270,8 @@ init_tsunami_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index ae5f29d..402e908 100644 (file)
@@ -44,22 +44,22 @@ eb64p_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 static inline void
-eb64p_enable_irq(unsigned int irq)
+eb64p_enable_irq(struct irq_data *d)
 {
-       eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+       eb64p_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
 }
 
 static void
-eb64p_disable_irq(unsigned int irq)
+eb64p_disable_irq(struct irq_data *d)
 {
-       eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+       eb64p_update_irq_hw(d->irq, cached_irq_mask |= 1 << d->irq);
 }
 
 static struct irq_chip eb64p_irq_type = {
        .name           = "EB64P",
-       .unmask         = eb64p_enable_irq,
-       .mask           = eb64p_disable_irq,
-       .mask_ack       = eb64p_disable_irq,
+       .irq_unmask     = eb64p_enable_irq,
+       .irq_mask       = eb64p_disable_irq,
+       .irq_mask_ack   = eb64p_disable_irq,
 };
 
 static void 
@@ -118,9 +118,9 @@ eb64p_init_irq(void)
        init_i8259a_irqs();
 
        for (i = 16; i < 32; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &eb64p_irq_type, handle_level_irq);
-       }               
+               irq_set_status_flags(i, IRQ_LEVEL);
+       }
 
        common_init_isa_dma();
        setup_irq(16+5, &isa_cascade_irqaction);
index 1121bc5..0b44a54 100644 (file)
@@ -51,16 +51,18 @@ eiger_update_irq_hw(unsigned long irq, unsigned long mask)
 }
 
 static inline void
-eiger_enable_irq(unsigned int irq)
+eiger_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
        eiger_update_irq_hw(irq, mask);
 }
 
 static void
-eiger_disable_irq(unsigned int irq)
+eiger_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
        eiger_update_irq_hw(irq, mask);
@@ -68,9 +70,9 @@ eiger_disable_irq(unsigned int irq)
 
 static struct irq_chip eiger_irq_type = {
        .name           = "EIGER",
-       .unmask         = eiger_enable_irq,
-       .mask           = eiger_disable_irq,
-       .mask_ack       = eiger_disable_irq,
+       .irq_unmask     = eiger_enable_irq,
+       .irq_mask       = eiger_disable_irq,
+       .irq_mask_ack   = eiger_disable_irq,
 };
 
 static void
@@ -136,8 +138,8 @@ eiger_init_irq(void)
        init_i8259a_irqs();
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &eiger_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index 34f55e0..00341b7 100644 (file)
  */
 
 static void
-jensen_local_enable(unsigned int irq)
+jensen_local_enable(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_enable_irq(1);
+       if (d->irq == 7)
+               i8259a_enable_irq(d);
 }
 
 static void
-jensen_local_disable(unsigned int irq)
+jensen_local_disable(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_disable_irq(1);
+       if (d->irq == 7)
+               i8259a_disable_irq(d);
 }
 
 static void
-jensen_local_mask_ack(unsigned int irq)
+jensen_local_mask_ack(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_mask_and_ack_irq(1);
+       if (d->irq == 7)
+               i8259a_mask_and_ack_irq(d);
 }
 
 static struct irq_chip jensen_local_irq_type = {
        .name           = "LOCAL",
-       .unmask         = jensen_local_enable,
-       .mask           = jensen_local_disable,
-       .mask_ack       = jensen_local_mask_ack,
+       .irq_unmask     = jensen_local_enable,
+       .irq_mask       = jensen_local_disable,
+       .irq_mask_ack   = jensen_local_mask_ack,
 };
 
 static void 
index 2bfc9f1..e619107 100644 (file)
@@ -104,9 +104,10 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
 }
 
 static void
-io7_enable_irq(unsigned int irq)
+io7_enable_irq(struct irq_data *d)
 {
        volatile unsigned long *ctl;
+       unsigned int irq = d->irq;
        struct io7 *io7;
 
        ctl = io7_get_irq_ctl(irq, &io7);
@@ -115,7 +116,7 @@ io7_enable_irq(unsigned int irq)
                       __func__, irq);
                return;
        }
-               
+
        spin_lock(&io7->irq_lock);
        *ctl |= 1UL << 24;
        mb();
@@ -124,9 +125,10 @@ io7_enable_irq(unsigned int irq)
 }
 
 static void
-io7_disable_irq(unsigned int irq)
+io7_disable_irq(struct irq_data *d)
 {
        volatile unsigned long *ctl;
+       unsigned int irq = d->irq;
        struct io7 *io7;
 
        ctl = io7_get_irq_ctl(irq, &io7);
@@ -135,7 +137,7 @@ io7_disable_irq(unsigned int irq)
                       __func__, irq);
                return;
        }
-               
+
        spin_lock(&io7->irq_lock);
        *ctl &= ~(1UL << 24);
        mb();
@@ -144,35 +146,29 @@ io7_disable_irq(unsigned int irq)
 }
 
 static void
-marvel_irq_noop(unsigned int irq) 
-{ 
-       return; 
-}
-
-static unsigned int
-marvel_irq_noop_return(unsigned int irq) 
-{ 
-       return 0; 
+marvel_irq_noop(struct irq_data *d)
+{
+       return;
 }
 
 static struct irq_chip marvel_legacy_irq_type = {
        .name           = "LEGACY",
-       .mask           = marvel_irq_noop,
-       .unmask         = marvel_irq_noop,
+       .irq_mask       = marvel_irq_noop,
+       .irq_unmask     = marvel_irq_noop,
 };
 
 static struct irq_chip io7_lsi_irq_type = {
        .name           = "LSI",
-       .unmask         = io7_enable_irq,
-       .mask           = io7_disable_irq,
-       .mask_ack       = io7_disable_irq,
+       .irq_unmask     = io7_enable_irq,
+       .irq_mask       = io7_disable_irq,
+       .irq_mask_ack   = io7_disable_irq,
 };
 
 static struct irq_chip io7_msi_irq_type = {
        .name           = "MSI",
-       .unmask         = io7_enable_irq,
-       .mask           = io7_disable_irq,
-       .ack            = marvel_irq_noop,
+       .irq_unmask     = io7_enable_irq,
+       .irq_mask       = io7_disable_irq,
+       .irq_ack        = marvel_irq_noop,
 };
 
 static void
@@ -280,8 +276,8 @@ init_io7_irqs(struct io7 *io7,
 
        /* Set up the lsi irqs.  */
        for (i = 0; i < 128; ++i) {
-               irq_to_desc(base + i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(base + i, lsi_ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        /* Disable the implemented irqs in hardware.  */
@@ -294,8 +290,8 @@ init_io7_irqs(struct io7 *io7,
 
        /* Set up the msi irqs.  */
        for (i = 128; i < (128 + 512); ++i) {
-               irq_to_desc(base + i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(base + i, msi_ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        for (i = 0; i < 16; ++i)
index bcc1639..cf7f43d 100644 (file)
@@ -43,22 +43,22 @@ mikasa_update_irq_hw(int mask)
 }
 
 static inline void
-mikasa_enable_irq(unsigned int irq)
+mikasa_enable_irq(struct irq_data *d)
 {
-       mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16));
+       mikasa_update_irq_hw(cached_irq_mask |= 1 << (d->irq - 16));
 }
 
 static void
-mikasa_disable_irq(unsigned int irq)
+mikasa_disable_irq(struct irq_data *d)
 {
-       mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16)));
+       mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (d->irq - 16)));
 }
 
 static struct irq_chip mikasa_irq_type = {
        .name           = "MIKASA",
-       .unmask         = mikasa_enable_irq,
-       .mask           = mikasa_disable_irq,
-       .mask_ack       = mikasa_disable_irq,
+       .irq_unmask     = mikasa_enable_irq,
+       .irq_mask       = mikasa_disable_irq,
+       .irq_mask_ack   = mikasa_disable_irq,
 };
 
 static void 
@@ -98,8 +98,8 @@ mikasa_init_irq(void)
        mikasa_update_irq_hw(0);
 
        for (i = 16; i < 32; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &mikasa_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index e88f4ae..92bc188 100644 (file)
@@ -48,22 +48,22 @@ noritake_update_irq_hw(int irq, int mask)
 }
 
 static void
-noritake_enable_irq(unsigned int irq)
+noritake_enable_irq(struct irq_data *d)
 {
-       noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16));
+       noritake_update_irq_hw(d->irq, cached_irq_mask |= 1 << (d->irq - 16));
 }
 
 static void
-noritake_disable_irq(unsigned int irq)
+noritake_disable_irq(struct irq_data *d)
 {
-       noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16)));
+       noritake_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << (d->irq - 16)));
 }
 
 static struct irq_chip noritake_irq_type = {
        .name           = "NORITAKE",
-       .unmask         = noritake_enable_irq,
-       .mask           = noritake_disable_irq,
-       .mask_ack       = noritake_disable_irq,
+       .irq_unmask     = noritake_enable_irq,
+       .irq_mask       = noritake_disable_irq,
+       .irq_mask_ack   = noritake_disable_irq,
 };
 
 static void 
@@ -127,8 +127,8 @@ noritake_init_irq(void)
        outw(0, 0x54c);
 
        for (i = 16; i < 48; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &noritake_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 6a51364..936d414 100644 (file)
@@ -56,9 +56,10 @@ rawhide_update_irq_hw(int hose, int mask)
   (((h) < MCPCIA_MAX_HOSES) && (cached_irq_masks[(h)] != 0))
 
 static inline void 
-rawhide_enable_irq(unsigned int irq)
+rawhide_enable_irq(struct irq_data *d)
 {
        unsigned int mask, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -76,9 +77,10 @@ rawhide_enable_irq(unsigned int irq)
 }
 
 static void 
-rawhide_disable_irq(unsigned int irq)
+rawhide_disable_irq(struct irq_data *d)
 {
        unsigned int mask, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -96,9 +98,10 @@ rawhide_disable_irq(unsigned int irq)
 }
 
 static void
-rawhide_mask_and_ack_irq(unsigned int irq)
+rawhide_mask_and_ack_irq(struct irq_data *d)
 {
        unsigned int mask, mask1, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -123,9 +126,9 @@ rawhide_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip rawhide_irq_type = {
        .name           = "RAWHIDE",
-       .unmask         = rawhide_enable_irq,
-       .mask           = rawhide_disable_irq,
-       .mask_ack       = rawhide_mask_and_ack_irq,
+       .irq_unmask     = rawhide_enable_irq,
+       .irq_mask       = rawhide_disable_irq,
+       .irq_mask_ack   = rawhide_mask_and_ack_irq,
 };
 
 static void 
@@ -177,8 +180,8 @@ rawhide_init_irq(void)
        }
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &rawhide_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 89e7e37..cea22a6 100644 (file)
@@ -47,22 +47,22 @@ rx164_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-rx164_enable_irq(unsigned int irq)
+rx164_enable_irq(struct irq_data *d)
 {
-       rx164_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       rx164_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-rx164_disable_irq(unsigned int irq)
+rx164_disable_irq(struct irq_data *d)
 {
-       rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static struct irq_chip rx164_irq_type = {
        .name           = "RX164",
-       .unmask         = rx164_enable_irq,
-       .mask           = rx164_disable_irq,
-       .mask_ack       = rx164_disable_irq,
+       .irq_unmask     = rx164_enable_irq,
+       .irq_mask       = rx164_disable_irq,
+       .irq_mask_ack   = rx164_disable_irq,
 };
 
 static void 
@@ -99,8 +99,8 @@ rx164_init_irq(void)
 
        rx164_update_irq_hw(0);
        for (i = 16; i < 40; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &rx164_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 5c4423d..a349538 100644 (file)
@@ -443,11 +443,11 @@ lynx_swizzle(struct pci_dev *dev, u8 *pinp)
 /* GENERIC irq routines */
 
 static inline void
-sable_lynx_enable_irq(unsigned int irq)
+sable_lynx_enable_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask &= ~(1UL << bit);
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -459,11 +459,11 @@ sable_lynx_enable_irq(unsigned int irq)
 }
 
 static void
-sable_lynx_disable_irq(unsigned int irq)
+sable_lynx_disable_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -475,11 +475,11 @@ sable_lynx_disable_irq(unsigned int irq)
 }
 
 static void
-sable_lynx_mask_and_ack_irq(unsigned int irq)
+sable_lynx_mask_and_ack_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -489,9 +489,9 @@ sable_lynx_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip sable_lynx_irq_type = {
        .name           = "SABLE/LYNX",
-       .unmask         = sable_lynx_enable_irq,
-       .mask           = sable_lynx_disable_irq,
-       .mask_ack       = sable_lynx_mask_and_ack_irq,
+       .irq_unmask     = sable_lynx_enable_irq,
+       .irq_mask       = sable_lynx_disable_irq,
+       .irq_mask_ack   = sable_lynx_mask_and_ack_irq,
 };
 
 static void 
@@ -518,9 +518,9 @@ sable_lynx_init_irq(int nr_of_irqs)
        long i;
 
        for (i = 0; i < nr_of_irqs; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &sable_lynx_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        common_init_isa_dma();
index f8a1e8a..42a5331 100644 (file)
@@ -45,16 +45,18 @@ takara_update_irq_hw(unsigned long irq, unsigned long mask)
 }
 
 static inline void
-takara_enable_irq(unsigned int irq)
+takara_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
        takara_update_irq_hw(irq, mask);
 }
 
 static void
-takara_disable_irq(unsigned int irq)
+takara_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
        takara_update_irq_hw(irq, mask);
@@ -62,9 +64,9 @@ takara_disable_irq(unsigned int irq)
 
 static struct irq_chip takara_irq_type = {
        .name           = "TAKARA",
-       .unmask         = takara_enable_irq,
-       .mask           = takara_disable_irq,
-       .mask_ack       = takara_disable_irq,
+       .irq_unmask     = takara_enable_irq,
+       .irq_mask       = takara_disable_irq,
+       .irq_mask_ack   = takara_disable_irq,
 };
 
 static void
@@ -136,8 +138,8 @@ takara_init_irq(void)
                takara_update_irq_hw(i, -1);
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &takara_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        common_init_isa_dma();
index e02494b..f6c108a 100644 (file)
@@ -112,8 +112,9 @@ titan_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-titan_enable_irq(unsigned int irq)
+titan_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        spin_lock(&titan_irq_lock);
        titan_cached_irq_mask |= 1UL << (irq - 16);
        titan_update_irq_hw(titan_cached_irq_mask);
@@ -121,8 +122,9 @@ titan_enable_irq(unsigned int irq)
 }
 
 static inline void
-titan_disable_irq(unsigned int irq)
+titan_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        spin_lock(&titan_irq_lock);
        titan_cached_irq_mask &= ~(1UL << (irq - 16));
        titan_update_irq_hw(titan_cached_irq_mask);
@@ -144,7 +146,8 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 }
 
 static int
-titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
+titan_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
+                      bool force)
 { 
        spin_lock(&titan_irq_lock);
        titan_cpu_set_irq_affinity(irq - 16, *affinity);
@@ -175,17 +178,17 @@ init_titan_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
 static struct irq_chip titan_irq_type = {
-       .name           = "TITAN",
-       .unmask         = titan_enable_irq,
-       .mask           = titan_disable_irq,
-       .mask_ack       = titan_disable_irq,
-       .set_affinity   = titan_set_irq_affinity,
+       .name                   = "TITAN",
+       .irq_unmask             = titan_enable_irq,
+       .irq_mask               = titan_disable_irq,
+       .irq_mask_ack           = titan_disable_irq,
+       .irq_set_affinity       = titan_set_irq_affinity,
 };
 
 static irqreturn_t
index eec5259..ca60a38 100644 (file)
@@ -104,10 +104,12 @@ wildfire_init_irq_hw(void)
 }
 
 static void
-wildfire_enable_irq(unsigned int irq)
+wildfire_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_enable_irq(irq);
+               i8259a_enable_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        set_bit(irq, &cached_irq_mask);
@@ -116,10 +118,12 @@ wildfire_enable_irq(unsigned int irq)
 }
 
 static void
-wildfire_disable_irq(unsigned int irq)
+wildfire_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_disable_irq(irq);
+               i8259a_disable_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        clear_bit(irq, &cached_irq_mask);
@@ -128,10 +132,12 @@ wildfire_disable_irq(unsigned int irq)
 }
 
 static void
-wildfire_mask_and_ack_irq(unsigned int irq)
+wildfire_mask_and_ack_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_mask_and_ack_irq(irq);
+               i8259a_mask_and_ack_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        clear_bit(irq, &cached_irq_mask);
@@ -141,9 +147,9 @@ wildfire_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip wildfire_irq_type = {
        .name           = "WILDFIRE",
-       .unmask         = wildfire_enable_irq,
-       .mask           = wildfire_disable_irq,
-       .mask_ack       = wildfire_mask_and_ack_irq,
+       .irq_unmask     = wildfire_enable_irq,
+       .irq_mask       = wildfire_disable_irq,
+       .irq_mask_ack   = wildfire_mask_and_ack_irq,
 };
 
 static void __init
@@ -177,21 +183,21 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
        for (i = 0; i < 16; ++i) {
                if (i == 2)
                        continue;
-               irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
        }
 
-       irq_to_desc(36+irq_bias)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(36+irq_bias, &wildfire_irq_type,
                handle_level_irq);
+       irq_set_status_flags(36 + irq_bias, IRQ_LEVEL);
        for (i = 40; i < 64; ++i) {
-               irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
        }
 
-       setup_irq(32+irq_bias, &isa_enable);    
+       setup_irq(32+irq_bias, &isa_enable);
 }
 
 static void __init
index 5cff165..166efa2 100644 (file)
@@ -1177,6 +1177,31 @@ config ARM_ERRATA_743622
          visible impact on the overall performance or power consumption of the
          processor.
 
+config ARM_ERRATA_751472
+       bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
+       depends on CPU_V7 && SMP
+       help
+         This option enables the workaround for the 751472 Cortex-A9 (prior
+         to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
+         completion of a following broadcasted operation if the second
+         operation is received by a CPU before the ICIALLUIS has completed,
+         potentially leading to corrupted entries in the cache or TLB.
+
+config ARM_ERRATA_753970
+       bool "ARM errata: cache sync operation may be faulty"
+       depends on CACHE_PL310
+       help
+         This option enables the workaround for the 753970 PL310 (r3p0) erratum.
+
+         Under some condition the effect of cache sync operation on
+         the store buffer still remains when the operation completes.
+         This means that the store buffer is always asked to drain and
+         this prevents it from merging any further writes. The workaround
+         is to replace the normal offset of cache sync operation (0x730)
+         by another offset targeting an unmapped PL310 register 0x740.
+         This has the same effect as the cache sync operation: store buffer
+         drain and waiting for all buffers empty.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
@@ -1391,7 +1416,7 @@ config AEABI
 
 config OABI_COMPAT
        bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"
-       depends on AEABI && EXPERIMENTAL
+       depends on AEABI && EXPERIMENTAL && !THUMB2_KERNEL
        default y
        help
          This option preserves the old syscall interface along with the
index c22c1ad..6f7b292 100644 (file)
@@ -15,7 +15,7 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux        += --be8
 endif
 
-OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
+OBJCOPYFLAGS   :=-O binary -R .comment -S
 GZFLAGS                :=-9
 #KBUILD_CFLAGS +=-pipe
 # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
index ab204db..c602896 100644 (file)
@@ -1,3 +1,7 @@
 font.c
-piggy.gz
+lib1funcs.S
+piggy.gzip
+piggy.lzo
+piggy.lzma
+vmlinux
 vmlinux.lds
index 2b9cf56..212ead3 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_NAMESPACES=y
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
index 5536c48..f0dea52 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_LOCALVERSION="gum"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SHMEM is not set
index 695e32d..1b1158a 100644 (file)
@@ -17,7 +17,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
index 3a1ad15..5b54abb 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
 CONFIG_ARCH_SA1100=y
index 75984cd..795374d 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_ELF_CORE is not set
index dcfbcf3..a93ff8d 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
index f52c64e..2ef2c5e 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 310f9a6..6c56ad0 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BASE_FULL is not set
 # CONFIG_EPOLL is not set
 CONFIG_SLOB=y
index 4a1fa81..e53c475 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
index cdc40c4..88ccde0 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
index 2519cc5..889922a 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
index 9359e1b..54bf5ee 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index c319418..14559db 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_ARCH_EBSA110=y
 CONFIG_PCCARD=m
index 7b62be1..d52ded3 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_ARCH_CLPS711X=y
 CONFIG_ARCH_EDB7211=y
index d7db34f..60a21e0 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
index 6d6689c..8e97b2f 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 1691dea..d68ac67 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
index c4eeb6d..227a477 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 4f925ea..038518a 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_MODULES=y
 CONFIG_ARCH_FOOTBRIDGE=y
index e11c7ea..840fced 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_ARCH_CLPS711X=y
 CONFIG_ARCH_FORTUNET=y
index ac336f1..37903e3 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index ade55c8..176ec22 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 9083246..8405ade 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 7fc056a..6887176 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 5c50239..063e2ab 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
index e1eaff7..1ba752b 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 20caaab..5a48f17 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
 # CONFIG_IOSCHED_DEADLINE is not set
index 1efcce9..22d0631 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
 CONFIG_SLAB=y
index af805e8..a88e64d 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index b0d0824..7305ebd 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
index 2f38d97..b39b5ce 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 6454e18..411f88d 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 813cfb3..9ad4c65 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
index e648ea3..7c4b30b 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 5c7a872..9cba68c 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_MODULES=y
index 0e2dc26..37207d1 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index a350cc6..7b63462 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
index ccedde1..ae890ca 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
index 439323b..a288d70 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
index 583a061..2f136c3 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index b42ee62..c75c9fc 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index d1efbdc..cb08cc5 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_SHMEM is not set
 CONFIG_MODULES=y
index bd481f0..35a31cc 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_AUDIT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index af3b12e..d335815 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_LOCALVERSION="oe1"
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index aebd4bb..7015827 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
index 94a2d90..1079c2b 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index d8ee58c..564a5cc 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index e89ca19..95c0f0d 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_BUG is not set
 # CONFIG_ELF_CORE is not set
index 37f4834..3162173 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index c1c252c..4a5a126 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_AIO is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_MODULES=y
index 9d7bf5e..8b0c717 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=13
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_SHMEM is not set
 CONFIG_SLAB=y
index 70d47db..5b55041 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SHMEM is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index 5aeec1e..16bd480 100644 (file)
@@ -36,6 +36,7 @@
 #define L2X0_RAW_INTR_STAT             0x21C
 #define L2X0_INTR_CLEAR                        0x220
 #define L2X0_CACHE_SYNC                        0x730
+#define L2X0_DUMMY_REG                 0x740
 #define L2X0_INV_LINE_PA               0x770
 #define L2X0_INV_WAY                   0x77C
 #define L2X0_CLEAN_LINE_PA             0x7B0
index a101f10..e0d1c0c 100644 (file)
 #define SCPCELLID2             0xFF8
 #define SCPCELLID3             0xFFC
 
+#define SCCTRL_TIMEREN0SEL_REFCLK      (0 << 15)
+#define SCCTRL_TIMEREN0SEL_TIMCLK      (1 << 15)
+
+#define SCCTRL_TIMEREN1SEL_REFCLK      (0 << 17)
+#define SCCTRL_TIMEREN1SEL_TIMCLK      (1 << 17)
+
 static inline void sysctl_soft_reset(void __iomem *base)
 {
+       /* switch to slow mode */
+       writel(0x2, base + SCCTRL);
+
        /* writing any value to SCSYSSTAT reg will reset system */
        writel(0, base + SCSYSSTAT);
 }
index 20e0f7c..d66605d 100644 (file)
@@ -95,6 +95,15 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
        return (void __iomem *)addr;
 }
 
+/* IO barriers */
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+#define __iormb()              rmb()
+#define __iowmb()              wmb()
+#else
+#define __iormb()              do { } while (0)
+#define __iowmb()              do { } while (0)
+#endif
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
@@ -125,17 +134,17 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
  * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
  */
 #ifdef __io
-#define outb(v,p)              __raw_writeb(v,__io(p))
-#define outw(v,p)              __raw_writew((__force __u16) \
-                                       cpu_to_le16(v),__io(p))
-#define outl(v,p)              __raw_writel((__force __u32) \
-                                       cpu_to_le32(v),__io(p))
+#define outb(v,p)      ({ __iowmb(); __raw_writeb(v,__io(p)); })
+#define outw(v,p)      ({ __iowmb(); __raw_writew((__force __u16) \
+                                       cpu_to_le16(v),__io(p)); })
+#define outl(v,p)      ({ __iowmb(); __raw_writel((__force __u32) \
+                                       cpu_to_le32(v),__io(p)); })
 
-#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __v; })
+#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __iormb(); __v; })
 #define inw(p) ({ __u16 __v = le16_to_cpu((__force __le16) \
-                       __raw_readw(__io(p))); __v; })
+                       __raw_readw(__io(p))); __iormb(); __v; })
 #define inl(p) ({ __u32 __v = le32_to_cpu((__force __le32) \
-                       __raw_readl(__io(p))); __v; })
+                       __raw_readl(__io(p))); __iormb(); __v; })
 
 #define outsb(p,d,l)           __raw_writesb(__io(p),d,l)
 #define outsw(p,d,l)           __raw_writesw(__io(p),d,l)
@@ -192,14 +201,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
 #define writel_relaxed(v,c)    ((void)__raw_writel((__force u32) \
                                        cpu_to_le32(v),__mem_pci(c)))
 
-#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
-#define __iormb()              rmb()
-#define __iowmb()              wmb()
-#else
-#define __iormb()              do { } while (0)
-#define __iowmb()              do { } while (0)
-#endif
-
 #define readb(c)               ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)               ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
 #define readl(c)               ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
index 23c2e8e..d0ee74b 100644 (file)
  * translation for translating DMA addresses.  Use the driver
  * DMA support - see dma-mapping.h.
  */
-static inline unsigned long virt_to_phys(void *x)
+static inline unsigned long virt_to_phys(const volatile void *x)
 {
        return __virt_to_phys((unsigned long)(x));
 }
index f41a6f5..82dfe5d 100644 (file)
 #define __ASMARM_TLB_H
 
 #include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
 
 #ifndef CONFIG_MMU
 
 #include <linux/pagemap.h>
+
+#define tlb_flush(tlb) ((void) tlb)
+
 #include <asm-generic/tlb.h>
 
 #else /* !CONFIG_MMU */
 
+#include <linux/swap.h>
 #include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+/*
+ * We need to delay page freeing for SMP as other CPUs can access pages
+ * which have been removed but not yet had their TLB entries invalidated.
+ * Also, as ARMv7 speculative prefetch can drag new entries into the TLB,
+ * we need to apply this same delaying tactic to ensure correct operation.
+ */
+#if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
+#define tlb_fast_mode(tlb)     0
+#define FREE_PTE_NR            500
+#else
+#define tlb_fast_mode(tlb)     1
+#define FREE_PTE_NR            0
+#endif
 
 /*
  * TLB handling.  This allows us to remove pages from the page
 struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            fullmm;
+       struct vm_area_struct   *vma;
        unsigned long           range_start;
        unsigned long           range_end;
+       unsigned int            nr;
+       struct page             *pages[FREE_PTE_NR];
 };
 
 DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
 
+/*
+ * This is unnecessarily complex.  There's three ways the TLB shootdown
+ * code is used:
+ *  1. Unmapping a range of vmas.  See zap_page_range(), unmap_region().
+ *     tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.
+ *  2. Unmapping all vmas.  See exit_mmap().
+ *     tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.  Additionally, page tables will be freed.
+ *  3. Unmapping argument pages.  See shift_arg_pages().
+ *     tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
+ *     tlb->vma will be NULL.
+ */
+static inline void tlb_flush(struct mmu_gather *tlb)
+{
+       if (tlb->fullmm || !tlb->vma)
+               flush_tlb_mm(tlb->mm);
+       else if (tlb->range_end > 0) {
+               flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
+               tlb->range_start = TASK_SIZE;
+               tlb->range_end = 0;
+       }
+}
+
+static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
+{
+       if (!tlb->fullmm) {
+               if (addr < tlb->range_start)
+                       tlb->range_start = addr;
+               if (addr + PAGE_SIZE > tlb->range_end)
+                       tlb->range_end = addr + PAGE_SIZE;
+       }
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       tlb_flush(tlb);
+       if (!tlb_fast_mode(tlb)) {
+               free_pages_and_swap_cache(tlb->pages, tlb->nr);
+               tlb->nr = 0;
+       }
+}
+
 static inline struct mmu_gather *
 tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 {
@@ -49,6 +113,8 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
+       tlb->vma = NULL;
+       tlb->nr = 0;
 
        return tlb;
 }
@@ -56,8 +122,7 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-       if (tlb->fullmm)
-               flush_tlb_mm(tlb->mm);
+       tlb_flush_mmu(tlb);
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
@@ -71,12 +136,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 static inline void
 tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
 {
-       if (!tlb->fullmm) {
-               if (addr < tlb->range_start)
-                       tlb->range_start = addr;
-               if (addr + PAGE_SIZE > tlb->range_end)
-                       tlb->range_end = addr + PAGE_SIZE;
-       }
+       tlb_add_flush(tlb, addr);
 }
 
 /*
@@ -89,6 +149,7 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (!tlb->fullmm) {
                flush_cache_range(vma, vma->vm_start, vma->vm_end);
+               tlb->vma = vma;
                tlb->range_start = TASK_SIZE;
                tlb->range_end = 0;
        }
@@ -97,12 +158,30 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 static inline void
 tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
-       if (!tlb->fullmm && tlb->range_end > 0)
-               flush_tlb_range(vma, tlb->range_start, tlb->range_end);
+       if (!tlb->fullmm)
+               tlb_flush(tlb);
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (tlb_fast_mode(tlb)) {
+               free_page_and_swap_cache(page);
+       } else {
+               tlb->pages[tlb->nr++] = page;
+               if (tlb->nr >= FREE_PTE_NR)
+                       tlb_flush_mmu(tlb);
+       }
+}
+
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+       unsigned long addr)
+{
+       pgtable_page_dtor(pte);
+       tlb_add_flush(tlb, addr);
+       tlb_remove_page(tlb, pte);
 }
 
-#define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep, addr)  pte_free((tlb)->mm, ptep)
+#define pte_free_tlb(tlb, ptep, addr)  __pte_free_tlb(tlb, ptep, addr)
 #define pmd_free_tlb(tlb, pmdp, addr)  pmd_free((tlb)->mm, pmdp)
 
 #define tlb_migrate_finish(mm)         do { } while (0)
index ce7378e..d2005de 100644 (file)
 #ifndef _ASMARM_TLBFLUSH_H
 #define _ASMARM_TLBFLUSH_H
 
-
-#ifndef CONFIG_MMU
-
-#define tlb_flush(tlb) ((void) tlb)
-
-#else /* CONFIG_MMU */
+#ifdef CONFIG_MMU
 
 #include <asm/glue.h>
 
index f17d9a0..f06ff9f 100644 (file)
@@ -391,25 +391,24 @@ ENDPROC(__turn_mmu_on)
 
 
 #ifdef CONFIG_SMP_ON_UP
+       __INIT
 __fixup_smp:
-       mov     r4, #0x00070000
-       orr     r3, r4, #0xff000000     @ mask 0xff070000
-       orr     r4, r4, #0x41000000     @ val 0x41070000
-       and     r0, r9, r3
-       teq     r0, r4                  @ ARM CPU and ARMv6/v7?
+       and     r3, r9, #0x000f0000     @ architecture version
+       teq     r3, #0x000f0000         @ CPU ID supported?
        bne     __fixup_smp_on_up       @ no, assume UP
 
-       orr     r3, r3, #0x0000ff00
-       orr     r3, r3, #0x000000f0     @ mask 0xff07fff0
+       bic     r3, r9, #0x00ff0000
+       bic     r3, r3, #0x0000000f     @ mask 0xff00fff0
+       mov     r4, #0x41000000
        orr     r4, r4, #0x0000b000
-       orr     r4, r4, #0x00000020     @ val 0x4107b020
-       and     r0, r9, r3
-       teq     r0, r4                  @ ARM 11MPCore?
+       orr     r4, r4, #0x00000020     @ val 0x4100b020
+       teq     r3, r4                  @ ARM 11MPCore?
        moveq   pc, lr                  @ yes, assume SMP
 
        mrc     p15, 0, r0, c0, c0, 5   @ read MPIDR
-       tst     r0, #1 << 31
-       movne   pc, lr                  @ bit 31 => SMP
+       and     r0, r0, #0xc0000000     @ multiprocessing extensions and
+       teq     r0, #0x80000000         @ not part of a uniprocessor system?
+       moveq   pc, lr                  @ yes, assume SMP
 
 __fixup_smp_on_up:
        adr     r0, 1f
@@ -417,18 +416,7 @@ __fixup_smp_on_up:
        sub     r3, r0, r3
        add     r4, r4, r3
        add     r5, r5, r3
-2:     cmp     r4, r5
-       movhs   pc, lr
-       ldmia   r4!, {r0, r6}
- ARM(  str     r6, [r0, r3]    )
- THUMB(        add     r0, r0, r3      )
-#ifdef __ARMEB__
- THUMB(        mov     r6, r6, ror #16 )       @ Convert word order for big-endian.
-#endif
- THUMB(        strh    r6, [r0], #2    )       @ For Thumb-2, store as two halfwords
- THUMB(        mov     r6, r6, lsr #16 )       @ to be robust against misaligned r3.
- THUMB(        strh    r6, [r0]        )
-       b       2b
+       b       __do_fixup_smp_on_up
 ENDPROC(__fixup_smp)
 
        .align
@@ -442,7 +430,31 @@ smp_on_up:
        ALT_SMP(.long   1)
        ALT_UP(.long    0)
        .popsection
+#endif
 
+       .text
+__do_fixup_smp_on_up:
+       cmp     r4, r5
+       movhs   pc, lr
+       ldmia   r4!, {r0, r6}
+ ARM(  str     r6, [r0, r3]    )
+ THUMB(        add     r0, r0, r3      )
+#ifdef __ARMEB__
+ THUMB(        mov     r6, r6, ror #16 )       @ Convert word order for big-endian.
 #endif
+ THUMB(        strh    r6, [r0], #2    )       @ For Thumb-2, store as two halfwords
+ THUMB(        mov     r6, r6, lsr #16 )       @ to be robust against misaligned r3.
+ THUMB(        strh    r6, [r0]        )
+       b       __do_fixup_smp_on_up
+ENDPROC(__do_fixup_smp_on_up)
+
+ENTRY(fixup_smp)
+       stmfd   sp!, {r4 - r6, lr}
+       mov     r4, r0
+       add     r5, r0, r1
+       mov     r3, #0
+       bl      __do_fixup_smp_on_up
+       ldmfd   sp!, {r4 - r6, pc}
+ENDPROC(fixup_smp)
 
 #include "head-common.S"
index c9f3f04..d600bd3 100644 (file)
@@ -137,11 +137,10 @@ static u8 get_debug_arch(void)
        u32 didr;
 
        /* Do we implement the extended CPUID interface? */
-       if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
-               pr_warning("CPUID feature registers not supported. "
-                               "Assuming v6 debug is present.\n");
+       if (WARN_ONCE((((read_cpuid_id() >> 16) & 0xf) != 0xf),
+           "CPUID feature registers not supported. "
+           "Assuming v6 debug is present.\n"))
                return ARM_DEBUG_ARCH_V6;
-       }
 
        ARM_DBG_READ(c0, 0, didr);
        return (didr >> 16) & 0xf;
@@ -152,6 +151,12 @@ u8 arch_get_debug_arch(void)
        return debug_arch;
 }
 
+static int debug_arch_supported(void)
+{
+       u8 arch = get_debug_arch();
+       return arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14;
+}
+
 /* Determine number of BRP register available. */
 static int get_num_brp_resources(void)
 {
@@ -268,6 +273,9 @@ out:
 
 int hw_breakpoint_slots(int type)
 {
+       if (!debug_arch_supported())
+               return 0;
+
        /*
         * We can be called early, so don't rely on
         * our static variables being initialised.
@@ -834,11 +842,11 @@ static void reset_ctrl_regs(void *unused)
 
        /*
         * v7 debug contains save and restore registers so that debug state
-        * can be maintained across low-power modes without leaving
-        * the debug logic powered up. It is IMPLEMENTATION DEFINED whether
-        * we can write to the debug registers out of reset, so we must
-        * unlock the OS Lock Access Register to avoid taking undefined
-        * instruction exceptions later on.
+        * can be maintained across low-power modes without leaving the debug
+        * logic powered up. It is IMPLEMENTATION DEFINED whether we can access
+        * the debug registers out of reset, so we must unlock the OS Lock
+        * Access Register to avoid taking undefined instruction exceptions
+        * later on.
         */
        if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
                /*
@@ -882,7 +890,7 @@ static int __init arch_hw_breakpoint_init(void)
 
        debug_arch = get_debug_arch();
 
-       if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
+       if (!debug_arch_supported()) {
                pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
                return 0;
        }
@@ -899,18 +907,18 @@ static int __init arch_hw_breakpoint_init(void)
                pr_info("%d breakpoint(s) reserved for watchpoint "
                                "single-step.\n", core_num_reserved_brps);
 
+       /*
+        * Reset the breakpoint resources. We assume that a halting
+        * debugger will leave the world in a nice state for us.
+        */
+       on_each_cpu(reset_ctrl_regs, NULL, 1);
+
        ARM_DBG_READ(c1, 0, dscr);
        if (dscr & ARM_DSCR_HDBGEN) {
+               max_watchpoint_len = 4;
                pr_warning("halting debug mode enabled. Assuming maximum "
-                               "watchpoint size of 4 bytes.");
+                          "watchpoint size of %u bytes.", max_watchpoint_len);
        } else {
-               /*
-                * Reset the breakpoint resources. We assume that a halting
-                * debugger will leave the world in a nice state for us.
-                */
-               smp_call_function(reset_ctrl_regs, NULL, 1);
-               reset_ctrl_regs(NULL);
-
                /* Work out the maximum supported watchpoint length. */
                max_watchpoint_len = get_max_wp_len();
                pr_info("maximum watchpoint size is %u bytes.\n",
index 2c1f005..8f6ed43 100644 (file)
@@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
                return space_cccc_1100_010x(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x0c400000) {
+       } else if ((insn & 0x0e000000) == 0x0c000000) {
 
                return space_cccc_110x(insn, asi);
 
index 2cfe816..6d4105e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/sections.h>
+#include <asm/smp_plat.h>
 #include <asm/unwind.h>
 
 #ifdef CONFIG_XIP_KERNEL
@@ -268,12 +269,28 @@ struct mod_unwind_map {
        const Elf_Shdr *txt_sec;
 };
 
+static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
+       const Elf_Shdr *sechdrs, const char *name)
+{
+       const Elf_Shdr *s, *se;
+       const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++)
+               if (strcmp(name, secstrs + s->sh_name) == 0)
+                       return s;
+
+       return NULL;
+}
+
+extern void fixup_smp(const void *, unsigned long);
+
 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                    struct module *mod)
 {
+       const Elf_Shdr * __maybe_unused s = NULL;
 #ifdef CONFIG_ARM_UNWIND
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-       const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+       const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
        struct mod_unwind_map maps[ARM_SEC_MAX];
        int i;
 
@@ -315,6 +332,9 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                                                 maps[i].txt_sec->sh_addr,
                                                 maps[i].txt_sec->sh_size);
 #endif
+       s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
+       if (s && !is_smp())
+               fixup_smp((void *)s->sh_addr, s->sh_size);
        return 0;
 }
 
index 5efa264..d150ad1 100644 (file)
@@ -700,7 +700,7 @@ user_backtrace(struct frame_tail __user *tail,
         * Frame pointers should strictly progress back up the stack
         * (towards higher addresses).
         */
-       if (tail >= buftail.fp)
+       if (tail + 1 >= buftail.fp)
                return NULL;
 
        return buftail.fp - 1;
index b8af96e..2c79eec 100644 (file)
@@ -97,28 +97,34 @@ set_irq_affinity(int irq,
                           irq, cpu);
        return err;
 #else
-       return 0;
+       return -EINVAL;
 #endif
 }
 
 static int
 init_cpu_pmu(void)
 {
-       int i, err = 0;
+       int i, irqs, err = 0;
        struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
 
-       if (!pdev) {
-               err = -ENODEV;
-               goto out;
-       }
+       if (!pdev)
+               return -ENODEV;
+
+       irqs = pdev->num_resources;
+
+       /*
+        * If we have a single PMU interrupt that we can't shift, assume that
+        * we're running on a uniprocessor machine and continue.
+        */
+       if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
+               return 0;
 
-       for (i = 0; i < pdev->num_resources; ++i) {
+       for (i = 0; i < irqs; ++i) {
                err = set_irq_affinity(platform_get_irq(pdev, i), i);
                if (err)
                        break;
        }
 
-out:
        return err;
 }
 
index 420b8d6..5ea4fb7 100644 (file)
@@ -226,8 +226,8 @@ int cpu_architecture(void)
                 * Register 0 and check for VMSAv7 or PMSAv7 */
                asm("mrc        p15, 0, %0, c0, c1, 4"
                    : "=r" (mmfr0));
-               if ((mmfr0 & 0x0000000f) == 0x00000003 ||
-                   (mmfr0 & 0x000000f0) == 0x00000030)
+               if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
+                   (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
                else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
                         (mmfr0 & 0x000000f0) == 0x00000020)
index 907d5a6..abaf844 100644 (file)
@@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
        unsigned long handler = (unsigned long)ka->sa.sa_handler;
        unsigned long retcode;
        int thumb = 0;
-       unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
+       unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
+
+       cpsr |= PSR_ENDSTATE;
 
        /*
         * Maybe we need to deliver a 32-bit signal to a 26-bit task.
index fd91566..60636f4 100644 (file)
@@ -36,6 +36,7 @@ static void twd_set_mode(enum clock_event_mode mode,
                /* timer load already set up */
                ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
                        | TWD_TIMER_CONTROL_PERIODIC;
+               __raw_writel(twd_timer_rate / HZ, twd_base + TWD_TIMER_LOAD);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                /* period set, and timer enabled in 'next_event' hook */
@@ -81,7 +82,7 @@ int twd_timer_ack(void)
 
 static void __cpuinit twd_calibrate_rate(void)
 {
-       unsigned long load, count;
+       unsigned long count;
        u64 waitjiffies;
 
        /*
@@ -116,10 +117,6 @@ static void __cpuinit twd_calibrate_rate(void)
                printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
                        (twd_timer_rate / 1000000) % 100);
        }
-
-       load = twd_timer_rate / HZ;
-
-       __raw_writel(load, twd_base + TWD_TIMER_LOAD);
 }
 
 /*
index 86b66f3..6146279 100644 (file)
 #define ARM_CPU_KEEP(x)
 #endif
 
+#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
+#define ARM_EXIT_KEEP(x)       x
+#else
+#define ARM_EXIT_KEEP(x)
+#endif
+
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -43,6 +49,7 @@ SECTIONS
                _sinittext = .;
                        HEAD_TEXT
                        INIT_TEXT
+                       ARM_EXIT_KEEP(EXIT_TEXT)
                _einittext = .;
                ARM_CPU_DISCARD(PROC_INFO)
                __arch_info_begin = .;
@@ -67,6 +74,7 @@ SECTIONS
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
+               ARM_EXIT_KEEP(EXIT_DATA)
 #endif
        }
 
@@ -162,6 +170,7 @@ SECTIONS
                . = ALIGN(PAGE_SIZE);
                __init_begin = .;
                INIT_DATA
+               ARM_EXIT_KEEP(EXIT_DATA)
                . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
@@ -247,6 +256,8 @@ SECTIONS
        }
 #endif
 
+       NOTES
+
        BSS_SECTION(0, 0, 0)
        _end = .;
 
index ffdf87b..8207954 100644 (file)
@@ -838,7 +838,7 @@ EXPORT_SYMBOL(ep93xx_i2s_release);
 static struct resource ep93xx_ac97_resources[] = {
        {
                .start  = EP93XX_AAC_PHYS_BASE,
-               .end    = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+               .end    = EP93XX_AAC_PHYS_BASE + 0xac - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
index f3dc76f..bec34b8 100644 (file)
@@ -427,6 +427,13 @@ void __init ep93xx_gpio_init(void)
 {
        int i;
 
+       /* Set Ports C, D, E, G, and H for GPIO use */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+                                EP93XX_SYSCON_DEVCFG_GONK |
+                                EP93XX_SYSCON_DEVCFG_EONIDE |
+                                EP93XX_SYSCON_DEVCFG_GONIDE |
+                                EP93XX_SYSCON_DEVCFG_HONIDE);
+
        for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++)
                gpiochip_add(&ep93xx_gpio_banks[i].chip);
 }
index 3c9e0c4..30b971d 100644 (file)
@@ -17,8 +17,8 @@
        /* For NetWinder debugging */
                .macro  addruart, rp, rv
                mov     \rp, #0x000003f8
-               orr     \rv, \rp, #0x7c000000   @ physical
-               orr     \rp, \rp, #0xff000000   @ virtual
+               orr     \rv, \rp, #0xff000000   @ virtual
+               orr     \rp, \rp, #0x7c000000   @ physical
                .endm
 
 #define UART_SHIFT     0
index aa76cfd..8382e79 100644 (file)
@@ -180,7 +180,7 @@ static const uint32_t mx25pdk_keymap[] = {
        KEY(3, 3, KEY_POWER),
 };
 
-static const struct matrix_keymap_data mx25pdk_keymap_data __initdata = {
+static const struct matrix_keymap_data mx25pdk_keymap_data __initconst = {
        .keymap         = mx25pdk_keymap,
        .keymap_size    = ARRAY_SIZE(mx25pdk_keymap),
 };
index 4dc68d6..9fd8942 100644 (file)
@@ -432,7 +432,7 @@ static struct clocksource clocksource_ixp4xx = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-unsigned long ixp4xx_timer_freq = FREQ;
+unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
 EXPORT_SYMBOL(ixp4xx_timer_freq);
 static void __init ixp4xx_clocksource_init(void)
 {
@@ -496,7 +496,7 @@ static struct clock_event_device clockevent_ixp4xx = {
 
 static void __init ixp4xx_clockevent_init(void)
 {
-       clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
+       clockevent_ixp4xx.mult = div_sc(IXP4XX_TIMER_FREQ, NSEC_PER_SEC,
                                        clockevent_ixp4xx.shift);
        clockevent_ixp4xx.max_delta_ns =
                clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
index 2c3f93c..c9e930f 100644 (file)
@@ -10,6 +10,7 @@
  * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the
  * timer register ignores the bottom 2 bits of the LATCH value.
  */
-#define FREQ 66666000
-#define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
+#define IXP4XX_TIMER_FREQ 66666000
+#define CLOCK_TICK_RATE \
+       (((IXP4XX_TIMER_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
 
index bfdbe4b..852f7c9 100644 (file)
@@ -265,6 +265,11 @@ void qmgr_release_queue(unsigned int queue)
               qmgr_queue_descs[queue], queue);
        qmgr_queue_descs[queue][0] = '\x0';
 #endif
+
+       while ((addr = qmgr_get_entry(queue)))
+               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
+                      queue, addr);
+
        __raw_writel(0, &qmgr_regs->sram[queue]);
 
        used_sram_bitmap[0] &= ~mask[0];
@@ -275,10 +280,6 @@ void qmgr_release_queue(unsigned int queue)
        spin_unlock_irq(&qmgr_lock);
 
        module_put(THIS_MODULE);
-
-       while ((addr = qmgr_get_entry(queue)))
-               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
-                      queue, addr);
 }
 
 static int qmgr_init(void)
index 2e83913..6dde818 100644 (file)
@@ -43,7 +43,7 @@ static const unsigned        qsd8x50_surf_smc91x_gpio __initdata = 156;
  * at run-time: they vary from board to board, and the true
  * configuration won't be known until boot.
  */
-static struct resource smc91x_resources[] __initdata = {
+static struct resource smc91x_resources[] = {
        [0] = {
                .flags = IORESOURCE_MEM,
        },
@@ -52,7 +52,7 @@ static struct resource smc91x_resources[] __initdata = {
        },
 };
 
-static struct platform_device smc91x_device __initdata = {
+static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
index b1a362e..ca72a05 100644 (file)
@@ -304,7 +304,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
        reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
        reg &= ~BM_CLKCTRL_##dr##_DIV;                                  \
        reg |= div << BP_CLKCTRL_##dr##_DIV;                            \
-       if (reg | (1 << clk->enable_shift)) {                           \
+       if (reg & (1 << clk->enable_shift)) {                           \
                pr_err("%s: clock is gated\n", __func__);               \
                return -EINVAL;                                         \
        }                                                               \
@@ -347,7 +347,7 @@ static int name##_set_parent(struct clk *clk, struct clk *parent)   \
 {                                                                      \
        if (parent != clk->parent) {                                    \
                __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit,            \
-                        HW_CLKCTRL_CLKSEQ_TOG);                        \
+                        CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG);    \
                clk->parent = parent;                                   \
        }                                                               \
                                                                        \
index 56312c0..fd1c4c5 100644 (file)
@@ -355,12 +355,12 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)           \
        } else {                                                        \
                reg &= ~BM_CLKCTRL_##dr##_DIV;                          \
                reg |= div << BP_CLKCTRL_##dr##_DIV;                    \
-               if (reg | (1 << clk->enable_shift)) {                   \
+               if (reg & (1 << clk->enable_shift)) {                   \
                        pr_err("%s: clock is gated\n", __func__);       \
                        return -EINVAL;                                 \
                }                                                       \
        }                                                               \
-       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);          \
+       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
                                                                        \
        for (i = 10000; i; i--)                                         \
                if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
@@ -483,7 +483,7 @@ static int name##_set_parent(struct clk *clk, struct clk *parent)   \
 {                                                                      \
        if (parent != clk->parent) {                                    \
                __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit,            \
-                        HW_CLKCTRL_CLKSEQ_TOG);                        \
+                        CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG);    \
                clk->parent = parent;                                   \
        }                                                               \
                                                                        \
@@ -609,7 +609,6 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("duart", NULL, uart_clk)
        _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("rtc", NULL, rtc_clk)
        _REGISTER_CLOCK("pll2", NULL, pll2_clk)
        _REGISTER_CLOCK(NULL, "hclk", hbus_clk)
index e7d2269..a7093c8 100644 (file)
@@ -57,7 +57,6 @@ static void __clk_disable(struct clk *clk)
                if (clk->disable)
                        clk->disable(clk);
                __clk_disable(clk->parent);
-               __clk_disable(clk->secondary);
        }
 }
 
@@ -68,7 +67,6 @@ static int __clk_enable(struct clk *clk)
 
        if (clk->usecount++ == 0) {
                __clk_enable(clk->parent);
-               __clk_enable(clk->secondary);
 
                if (clk->enable)
                        clk->enable(clk);
index d7ad7a6..cb0c0e8 100644 (file)
@@ -139,6 +139,8 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
        struct mxs_gpio_port *port = (struct mxs_gpio_port *)get_irq_data(irq);
        u32 gpio_irq_no_base = port->virtual_irq_start;
 
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+
        irq_stat = __raw_readl(port->base + PINCTRL_IRQSTAT(port->id)) &
                        __raw_readl(port->base + PINCTRL_IRQEN(port->id));
 
index 041e276..592c9ab 100644 (file)
@@ -29,8 +29,6 @@ struct clk {
        int id;
        /* Source clock this clk depends on */
        struct clk *parent;
-       /* Secondary clock to enable/disable with this clock */
-       struct clk *secondary;
        /* Reference count of clock enable/disable */
        __s8 usecount;
        /* Register bit position for clock's enable/disable control. */
index 8d2f2da..e0a0281 100644 (file)
@@ -9,6 +9,7 @@ config ARCH_OMAP730
        depends on ARCH_OMAP1
        bool "OMAP730 Based System"
        select CPU_ARM926T
+       select OMAP_MPU_TIMER
        select ARCH_OMAP_OTG
 
 config ARCH_OMAP850
@@ -22,6 +23,7 @@ config ARCH_OMAP15XX
        default y
        bool "OMAP15xx Based System"
        select CPU_ARM925T
+       select OMAP_MPU_TIMER
 
 config ARCH_OMAP16XX
        depends on ARCH_OMAP1
index 6ee1950..ba6009f 100644 (file)
@@ -3,12 +3,11 @@
 #
 
 # Common support
-obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o dma.o
+obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
 obj-y += clock.o clock_data.o opp_data.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
-obj-$(CONFIG_OMAP_MPU_TIMER)   += time.o
 obj-$(CONFIG_OMAP_32K_TIMER)   += timer32k.o
 
 # Power Management
index c9be6d4..bfb4fb1 100644 (file)
 #include <mach/irqs.h>
 #include <asm/hardware/gic.h>
 
-/*
- * We use __glue to avoid errors with multiple definitions of
- * .globl omap_irq_flags as it's included from entry-armv.S but not
- * from entry-common.S.
- */
-#ifdef __glue
-               .pushsection .data
-               .globl  omap_irq_flags
-omap_irq_flags:
-               .word   0
-               .popsection
-#endif
-
                .macro  disable_fiq
                .endm
 
index 4770158..731dd33 100644 (file)
@@ -57,6 +57,7 @@ struct omap_irq_bank {
        unsigned long wake_enable;
 };
 
+u32 omap_irq_flags;
 static unsigned int irq_bank_count;
 static struct omap_irq_bank *irq_banks;
 
@@ -176,7 +177,6 @@ static struct irq_chip omap_irq_chip = {
 
 void __init omap_init_irq(void)
 {
-       extern unsigned int omap_irq_flags;
        int i, j;
 
 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
index c9088d8..4538093 100644 (file)
@@ -37,7 +37,7 @@ int omap_lcd_dma_running(void)
         * On OMAP1510, internal LCD controller will start the transfer
         * when it gets enabled, so assume DMA running if LCD enabled.
         */
-       if (cpu_is_omap1510())
+       if (cpu_is_omap15xx())
                if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
                        return 1;
 
@@ -95,7 +95,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
 
 void omap_set_lcd_dma_b1_rotation(int rotate)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
                BUG();
                return;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
 
 void omap_set_lcd_dma_b1_mirror(int mirror)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
                BUG();
        }
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
 
 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA virtual resulotion is not supported "
                                "in 1510 mode\n");
                BUG();
@@ -127,7 +127,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
 
 void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
                BUG();
        }
@@ -177,7 +177,7 @@ static void set_b1_regs(void)
                        bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
                        /* 1510 DMA requires the bottom address to be 2 more
                         * than the actual last memory access location. */
-                       if (cpu_is_omap1510() &&
+                       if (cpu_is_omap15xx() &&
                                lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
                                        bottom += 2;
                        ei = PIXSTEP(0, 0, 1, 0);
@@ -241,7 +241,7 @@ static void set_b1_regs(void)
                return; /* Suppress warning about uninitialized vars */
        }
 
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
                omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
                omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
@@ -343,7 +343,7 @@ void omap_free_lcd_dma(void)
                BUG();
                return;
        }
-       if (!cpu_is_omap1510())
+       if (!cpu_is_omap15xx())
                omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
                            OMAP1610_DMA_LCD_CCR);
        lcd_dma.reserved = 0;
@@ -360,7 +360,7 @@ void omap_enable_lcd_dma(void)
         * connected. Otherwise the OMAP internal controller will
         * start the transfer when it gets enabled.
         */
-       if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
+       if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
                return;
 
        w = omap_readw(OMAP1610_DMA_LCD_CTRL);
@@ -378,14 +378,14 @@ EXPORT_SYMBOL(omap_enable_lcd_dma);
 void omap_setup_lcd_dma(void)
 {
        BUG_ON(lcd_dma.active);
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                /* Set some reasonable defaults */
                omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
                omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
                omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
        }
        set_b1_regs();
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                u16 w;
 
                w = omap_readw(OMAP1610_DMA_LCD_CCR);
@@ -407,7 +407,7 @@ void omap_stop_lcd_dma(void)
        u16 w;
 
        lcd_dma.active = 0;
-       if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
+       if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
                return;
 
        w = omap_readw(OMAP1610_DMA_LCD_CCR);
index ed7a61f..6885d2f 100644 (file)
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
+#include <asm/sched_clock.h>
+
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
 #include <plat/common.h>
 
+#ifdef CONFIG_OMAP_MPU_TIMER
+
 #define OMAP_MPU_TIMER_BASE            OMAP_MPU_TIMER1_BASE
 #define OMAP_MPU_TIMER_OFFSET          0x100
 
@@ -67,7 +71,7 @@ typedef struct {
 ((volatile omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE +       \
                                 (n)*OMAP_MPU_TIMER_OFFSET))
 
-static inline unsigned long omap_mpu_timer_read(int nr)
+static inline unsigned long notrace omap_mpu_timer_read(int nr)
 {
        volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
        return timer->read_tim;
@@ -212,6 +216,32 @@ static struct clocksource clocksource_mpu = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static DEFINE_CLOCK_DATA(cd);
+
+static inline unsigned long long notrace _omap_mpu_sched_clock(void)
+{
+       u32 cyc = mpu_read(&clocksource_mpu);
+       return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+}
+
+#ifndef CONFIG_OMAP_32K_TIMER
+unsigned long long notrace sched_clock(void)
+{
+       return _omap_mpu_sched_clock();
+}
+#else
+static unsigned long long notrace omap_mpu_sched_clock(void)
+{
+       return _omap_mpu_sched_clock();
+}
+#endif
+
+static void notrace mpu_update_sched_clock(void)
+{
+       u32 cyc = mpu_read(&clocksource_mpu);
+       update_sched_clock(&cd, cyc, (u32)~0);
+}
+
 static void __init omap_init_clocksource(unsigned long rate)
 {
        static char err[] __initdata = KERN_ERR
@@ -219,17 +249,13 @@ static void __init omap_init_clocksource(unsigned long rate)
 
        setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
        omap_mpu_timer_start(1, ~0, 1);
+       init_sched_clock(&cd, mpu_update_sched_clock, 32, rate);
 
        if (clocksource_register_hz(&clocksource_mpu, rate))
                printk(err, clocksource_mpu.name);
 }
 
-/*
- * ---------------------------------------------------------------------------
- * Timer initialization
- * ---------------------------------------------------------------------------
- */
-static void __init omap_timer_init(void)
+static void __init omap_mpu_timer_init(void)
 {
        struct clk      *ck_ref = clk_get(NULL, "ck_ref");
        unsigned long   rate;
@@ -246,6 +272,66 @@ static void __init omap_timer_init(void)
        omap_init_clocksource(rate);
 }
 
+#else
+static inline void omap_mpu_timer_init(void)
+{
+       pr_err("Bogus timer, should not happen\n");
+}
+#endif /* CONFIG_OMAP_MPU_TIMER */
+
+#if defined(CONFIG_OMAP_MPU_TIMER) && defined(CONFIG_OMAP_32K_TIMER)
+static unsigned long long (*preferred_sched_clock)(void);
+
+unsigned long long notrace sched_clock(void)
+{
+       if (!preferred_sched_clock)
+               return 0;
+
+       return preferred_sched_clock();
+}
+
+static inline void preferred_sched_clock_init(bool use_32k_sched_clock)
+{
+       if (use_32k_sched_clock)
+               preferred_sched_clock = omap_32k_sched_clock;
+       else
+               preferred_sched_clock = omap_mpu_sched_clock;
+}
+#else
+static inline void preferred_sched_clock_init(bool use_32k_sched_clcok)
+{
+}
+#endif
+
+static inline int omap_32k_timer_usable(void)
+{
+       int res = false;
+
+       if (cpu_is_omap730() || cpu_is_omap15xx())
+               return res;
+
+#ifdef CONFIG_OMAP_32K_TIMER
+       res = omap_32k_timer_init();
+#endif
+
+       return res;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init omap_timer_init(void)
+{
+       if (omap_32k_timer_usable()) {
+               preferred_sched_clock_init(1);
+       } else {
+               omap_mpu_timer_init();
+               preferred_sched_clock_init(0);
+       }
+}
+
 struct sys_timer omap_timer = {
        .init           = omap_timer_init,
 };
index 20cfbcc..13d7b8f 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
+#include <plat/common.h>
 #include <plat/dmtimer.h>
 
-struct sys_timer omap_timer;
-
 /*
  * ---------------------------------------------------------------------------
  * 32KHz OS timer
@@ -181,14 +180,14 @@ static __init void omap_init_32k_timer(void)
  * Timer initialization
  * ---------------------------------------------------------------------------
  */
-static void __init omap_timer_init(void)
+bool __init omap_32k_timer_init(void)
 {
+       omap_init_clocksource_32k();
+
 #ifdef CONFIG_OMAP_DM_TIMER
        omap_dm_timer_init();
 #endif
        omap_init_32k_timer();
-}
 
-struct sys_timer omap_timer = {
-       .init           = omap_timer_init,
-};
+       return true;
+}
index 5b0c777..8f9a64d 100644 (file)
@@ -124,8 +124,9 @@ static inline void cm_t3517_init_hecc(void) {}
 #if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
 #define RTC_IO_GPIO            (153)
 #define RTC_WR_GPIO            (154)
-#define RTC_RD_GPIO            (160)
+#define RTC_RD_GPIO            (53)
 #define RTC_CS_GPIO            (163)
+#define RTC_CS_EN_GPIO         (160)
 
 struct v3020_platform_data cm_t3517_v3020_pdata = {
        .use_gpio       = 1,
@@ -145,6 +146,16 @@ static struct platform_device cm_t3517_rtc_device = {
 
 static void __init cm_t3517_init_rtc(void)
 {
+       int err;
+
+       err = gpio_request(RTC_CS_EN_GPIO, "rtc cs en");
+       if (err) {
+               pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err);
+               return;
+       }
+
+       gpio_direction_output(RTC_CS_EN_GPIO, 1);
+
        platform_device_register(&cm_t3517_rtc_device);
 }
 #else
@@ -214,12 +225,12 @@ static struct mtd_partition cm_t3517_nand_partitions[] = {
        },
        {
                .name           = "linux",
-               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x2A0000 */
                .size           = 32 * NAND_BLOCK_SIZE,
        },
        {
                .name           = "rootfs",
-               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x6A0000 */
                .size           = MTDPART_SIZ_FULL,
        },
 };
@@ -256,11 +267,19 @@ static void __init cm_t3517_init_irq(void)
 static struct omap_board_mux board_mux[] __initdata = {
        /* GPIO186 - Green LED */
        OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-       /* RTC GPIOs: IO, WR#, RD#, CS# */
+
+       /* RTC GPIOs: */
+       /* IO - GPIO153 */
        OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       /* WR# - GPIO154 */
        OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-       OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       /* RD# - GPIO53 */
+       OMAP3_MUX(GPMC_NCS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       /* CS# - GPIO163 */
        OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+       /* CS EN - GPIO160 */
+       OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+
        /* HSUSB1 RESET */
        OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
        /* HSUSB2 RESET */
index 00bb1fc..9a2a31e 100644 (file)
@@ -115,9 +115,6 @@ static struct omap2_hsmmc_info mmc[] = {
 
 static int devkit8000_panel_enable_lcd(struct omap_dss_device *dssdev)
 {
-       twl_i2c_write_u8(TWL4030_MODULE_GPIO, 0x80, REG_GPIODATADIR1);
-       twl_i2c_write_u8(TWL4030_MODULE_LED, 0x0, 0x0);
-
        if (gpio_is_valid(dssdev->reset_gpio))
                gpio_set_value_cansleep(dssdev->reset_gpio, 1);
        return 0;
@@ -247,6 +244,8 @@ static struct gpio_led gpio_leds[];
 static int devkit8000_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
+       int ret;
+
        omap_mux_init_gpio(29, OMAP_PIN_INPUT);
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
@@ -255,17 +254,23 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
-        /* gpio + 1 is "LCD_PWREN" (out, active high) */
-       devkit8000_lcd_device.reset_gpio = gpio + 1;
-       gpio_request(devkit8000_lcd_device.reset_gpio, "LCD_PWREN");
-       /* Disable until needed */
-       gpio_direction_output(devkit8000_lcd_device.reset_gpio, 0);
+       /* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */
+       devkit8000_lcd_device.reset_gpio = gpio + TWL4030_GPIO_MAX + 0;
+       ret = gpio_request_one(devkit8000_lcd_device.reset_gpio,
+                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "LCD_PWREN");
+       if (ret < 0) {
+               devkit8000_lcd_device.reset_gpio = -EINVAL;
+               printk(KERN_ERR "Failed to request GPIO for LCD_PWRN\n");
+       }
 
        /* gpio + 7 is "DVI_PD" (out, active low) */
        devkit8000_dvi_device.reset_gpio = gpio + 7;
-       gpio_request(devkit8000_dvi_device.reset_gpio, "DVI PowerDown");
-       /* Disable until needed */
-       gpio_direction_output(devkit8000_dvi_device.reset_gpio, 0);
+       ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
+                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "DVI PowerDown");
+       if (ret < 0) {
+               devkit8000_dvi_device.reset_gpio = -EINVAL;
+               printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
+       }
 
        return 0;
 }
@@ -275,8 +280,7 @@ static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
        .use_leds       = true,
-       .pullups        = BIT(1),
-       .pulldowns      = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
+       .pulldowns      = BIT(1) | BIT(2) | BIT(6) | BIT(8) | BIT(13)
                                | BIT(15) | BIT(16) | BIT(17),
        .setup          = devkit8000_twl_gpio_setup,
 };
index e001a04..e944025 100644 (file)
@@ -409,8 +409,6 @@ static void __init omap4_panda_init(void)
        platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
        omap_serial_init();
        omap4_twl6030_hsmmc_init(mmc);
-       /* OMAP4 Panda uses internal transceiver so register nop transceiver */
-       usb_nop_xceiv_register();
        omap4_ehci_init();
        usb_musb_init(&musb_board_data);
 }
index cb77be7..39a71bb 100644 (file)
@@ -40,9 +40,6 @@ static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
 static struct regulator_init_data rm680_vemmc = {
        .constraints =  {
                .name                   = "rm680_vemmc",
-               .min_uV                 = 2900000,
-               .max_uV                 = 2900000,
-               .apply_uV               = 1,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_STATUS
index 337392c..acb7ae5 100644 (file)
@@ -77,7 +77,7 @@ static int _dpll_test_fint(struct clk *clk, u8 n)
        dd = clk->dpll_data;
 
        /* DPLL divider must result in a valid jitter correction val */
-       fint = clk->parent->rate / (n + 1);
+       fint = clk->parent->rate / n;
        if (fint < DPLL_FINT_BAND1_MIN) {
 
                pr_debug("rejecting n=%d due to Fint failure, "
index e8cb32f..de9ec8d 100644 (file)
@@ -34,7 +34,6 @@
 #include "cm2_44xx.h"
 #include "cm-regbits-44xx.h"
 #include "prm44xx.h"
-#include "prm44xx.h"
 #include "prm-regbits-44xx.h"
 #include "control.h"
 #include "scrm44xx.h"
index e20b986..58e42f7 100644 (file)
@@ -423,6 +423,12 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
 {
        struct clkdm_dep *cd;
 
+       if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+               pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+                      clkdm1->name, clkdm2->name, __func__);
+               return -EINVAL;
+       }
+
        if (!clkdm1 || !clkdm2)
                return -EINVAL;
 
@@ -458,6 +464,12 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
 {
        struct clkdm_dep *cd;
 
+       if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+               pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+                      clkdm1->name, clkdm2->name, __func__);
+               return -EINVAL;
+       }
+
        if (!clkdm1 || !clkdm2)
                return -EINVAL;
 
@@ -500,6 +512,12 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
        if (!clkdm1 || !clkdm2)
                return -EINVAL;
 
+       if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+               pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+                      clkdm1->name, clkdm2->name, __func__);
+               return -EINVAL;
+       }
+
        cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
        if (IS_ERR(cd)) {
                pr_debug("clockdomain: hardware cannot set/clear wake up of "
@@ -527,6 +545,12 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
        struct clkdm_dep *cd;
        u32 mask = 0;
 
+       if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+               pr_err("clockdomain: %s: %s: not yet implemented\n",
+                      clkdm->name, __func__);
+               return -EINVAL;
+       }
+
        if (!clkdm)
                return -EINVAL;
 
@@ -830,8 +854,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
         * dependency code and data for OMAP4.
         */
        if (cpu_is_omap44xx()) {
-               WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
-                         "support is not yet implemented\n");
+               pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
        } else {
                if (atomic_read(&clkdm->usecount) > 0)
                        _clkdm_add_autodeps(clkdm);
@@ -872,8 +895,7 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
         * dependency code and data for OMAP4.
         */
        if (cpu_is_omap44xx()) {
-               WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
-                         "support is not yet implemented\n");
+               pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
        } else {
                if (atomic_read(&clkdm->usecount) > 0)
                        _clkdm_del_autodeps(clkdm);
index 51920fc..10622c9 100644 (file)
@@ -30,8 +30,6 @@
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
 
-#include "cm1_44xx.h"
-#include "cm2_44xx.h"
 #include "cm-regbits-44xx.h"
 #include "prm44xx.h"
 #include "prcm44xx.h"
index d2f15f5..34922b2 100644 (file)
@@ -264,7 +264,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
        if (IS_ERR(od)) {
                pr_err("%s: Cant build omap_device for %s:%s.\n",
                        __func__, name, oh->name);
-               return IS_ERR(od);
+               return PTR_ERR(od);
        }
 
        mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
index befa321..81985a6 100644 (file)
  */
 
 #ifdef MULTI_OMAP2
-
-/*
- * We use __glue to avoid errors with multiple definitions of
- * .globl omap_irq_base as it's included from entry-armv.S but not
- * from entry-common.S.
- */
-#ifdef __glue
-               .pushsection .data
-               .globl  omap_irq_base
-omap_irq_base:
-               .word   0
-               .popsection
-#endif
-
                /*
                 * Configure the interrupt base on the first interrupt.
                 * See also omap_irq_base_init for setting omap_irq_base.
index e66687b..c203204 100644 (file)
@@ -314,14 +314,13 @@ static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
        return omap_hwmod_set_postsetup_state(oh, *(u8 *)data);
 }
 
+void __iomem *omap_irq_base;
+
 /*
  * Initialize asm_irq_base for entry-macro.S
  */
 static inline void omap_irq_base_init(void)
 {
-       extern void __iomem *omap_irq_base;
-
-#ifdef MULTI_OMAP2
        if (cpu_is_omap24xx())
                omap_irq_base = OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE);
        else if (cpu_is_omap34xx())
@@ -330,7 +329,6 @@ static inline void omap_irq_base_init(void)
                omap_irq_base = OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE);
        else
                pr_err("Could not initialize omap_irq_base\n");
-#endif
 }
 
 void __init omap2_init_common_infrastructure(void)
index 394413d..0a585df 100644 (file)
@@ -334,7 +334,7 @@ static struct omap_mbox mbox_iva_info = {
        .priv   = &omap2_mbox_iva_priv,
 };
 
-struct omap_mbox *omap2_mboxes[] = { &mbox_iva_info, &mbox_dsp_info, NULL };
+struct omap_mbox *omap2_mboxes[] = { &mbox_dsp_info, &mbox_iva_info, NULL };
 #endif
 
 #if defined(CONFIG_ARCH_OMAP4)
index df8d2f2..6c84659 100644 (file)
@@ -160,7 +160,7 @@ static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
        struct omap_mux *mux = NULL;
        struct omap_mux_entry *e;
        const char *mode_name;
-       int found = 0, found_mode, mode0_len = 0;
+       int found = 0, found_mode = 0, mode0_len = 0;
        struct list_head *muxmodes = &partition->muxmodes;
 
        mode_name = strchr(muxname, '.');
@@ -605,7 +605,7 @@ static void __init omap_mux_dbg_create_entry(
        list_for_each_entry(e, &partition->muxmodes, node) {
                struct omap_mux *m = &e->mux;
 
-               (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir,
+               (void)debugfs_create_file(m->muxnames[0], S_IWUSR, mux_dbg_dir,
                                          m, &omap_mux_dbg_signal_fops);
        }
 }
@@ -1000,6 +1000,7 @@ int __init omap_mux_init(const char *name, u32 flags,
        if (!partition->base) {
                pr_err("%s: Could not ioremap mux partition at 0x%08x\n",
                        __func__, partition->phys);
+               kfree(partition);
                return -ENODEV;
        }
 
index 125f565..a5a83b3 100644 (file)
@@ -637,14 +637,14 @@ static int __init pm_dbg_init(void)
 
                }
 
-       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
                                   &enable_off_mode, &pm_dbg_option_fops);
-       (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUSR, d,
                                   &sleep_while_idle, &pm_dbg_option_fops);
-       (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUSR, d,
                                   &wakeup_timer_seconds, &pm_dbg_option_fops);
        (void) debugfs_create_file("wakeup_timer_milliseconds",
-                       S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
+                       S_IRUGO | S_IWUSR, d, &wakeup_timer_milliseconds,
                        &pm_dbg_option_fops);
        pm_dbg_init_done = 1;
 
index 9e5dc8e..97feb3a 100644 (file)
@@ -134,7 +134,7 @@ static void omap2_enter_full_retention(void)
 
        /* Block console output in case it is on one of the OMAP UARTs */
        if (!is_suspending())
-               if (try_acquire_console_sem())
+               if (!console_trylock())
                        goto no_sleep;
 
        omap_uart_prepare_idle(0);
@@ -151,7 +151,7 @@ static void omap2_enter_full_retention(void)
        omap_uart_resume_idle(0);
 
        if (!is_suspending())
-               release_console_sem();
+               console_unlock();
 
 no_sleep:
        if (omap2_pm_debug) {
index 8cbbead..2f864e4 100644 (file)
@@ -168,9 +168,10 @@ static void omap3_core_restore_context(void)
  * once during boot sequence, but this works as we are not using secure
  * services.
  */
-static void omap3_save_secure_ram_context(u32 target_mpu_state)
+static void omap3_save_secure_ram_context(void)
 {
        u32 ret;
+       int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
 
        if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
                /*
@@ -181,7 +182,7 @@ static void omap3_save_secure_ram_context(u32 target_mpu_state)
                pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
                ret = _omap_save_secure_sram((u32 *)
                                __pa(omap3_secure_ram_storage));
-               pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state);
+               pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
                /* Following is for error tracking, it should not happen */
                if (ret) {
                        printk(KERN_ERR "save_secure_sram() returns %08x\n",
@@ -398,7 +399,7 @@ void omap_sram_idle(void)
        if (!is_suspending())
                if (per_next_state < PWRDM_POWER_ON ||
                    core_next_state < PWRDM_POWER_ON)
-                       if (try_acquire_console_sem())
+                       if (!console_trylock())
                                goto console_still_active;
 
        /* PER */
@@ -481,7 +482,7 @@ void omap_sram_idle(void)
        }
 
        if (!is_suspending())
-               release_console_sem();
+               console_unlock();
 
 console_still_active:
        /* Disable IO-PAD and IO-CHAIN wakeup */
@@ -1094,7 +1095,7 @@ static int __init omap3_pm_init(void)
                local_fiq_disable();
 
                omap_dma_global_context_save();
-               omap3_save_secure_ram_context(PWRDM_POWER_ON);
+               omap3_save_secure_ram_context();
                omap_dma_global_context_restore();
 
                local_irq_enable();
index d523389..cf600e2 100644 (file)
@@ -19,7 +19,6 @@
 #include <plat/prcm.h>
 
 #include "powerdomain.h"
-#include "prm-regbits-34xx.h"
 #include "prm.h"
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-34xx.h"
index 729a644..3300ff6 100644 (file)
@@ -38,8 +38,8 @@
 #define OMAP4430_PRCM_MPU_CPU1_INST            0x0800
 
 /* PRCM_MPU clockdomain register offsets (from instance start) */
-#define OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS      0x0000
-#define OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS      0x0000
+#define OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS      0x0018
+#define OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS      0x0018
 
 
 /*
index 302da74..32e91a9 100644 (file)
@@ -812,7 +812,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
        oh->dev_attr = uart;
 
-       acquire_console_sem(); /* in case the earlycon is on the UART */
+       console_lock(); /* in case the earlycon is on the UART */
 
        /*
         * Because of early UART probing, UART did not get idled
@@ -838,7 +838,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
        omap_uart_block_sleep(uart);
        uart->timeout = DEFAULT_TIMEOUT;
 
-       release_console_sem();
+       console_unlock();
 
        if ((cpu_is_omap34xx() && uart->padconf) ||
            (uart->wk_en && uart->wk_mask)) {
index 77ecebf..95ac336 100644 (file)
@@ -780,8 +780,7 @@ static int omap_sr_autocomp_show(void *data, u64 *val)
        struct omap_sr *sr_info = (struct omap_sr *) data;
 
        if (!sr_info) {
-               pr_warning("%s: omap_sr struct for sr_%s not found\n",
-                       __func__, sr_info->voltdm->name);
+               pr_warning("%s: omap_sr struct not found\n", __func__);
                return -EINVAL;
        }
 
@@ -795,8 +794,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)
        struct omap_sr *sr_info = (struct omap_sr *) data;
 
        if (!sr_info) {
-               pr_warning("%s: omap_sr struct for sr_%s not found\n",
-                       __func__, sr_info->voltdm->name);
+               pr_warning("%s: omap_sr struct not found\n", __func__);
                return -EINVAL;
        }
 
@@ -834,7 +832,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
        if (!pdata) {
                dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_free_devinfo;
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -901,7 +900,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                return PTR_ERR(dbg_dir);
        }
 
-       (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
+       (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, dbg_dir,
                                (void *)sr_info, &pm_sr_fops);
        (void) debugfs_create_x32("errweight", S_IRUGO, dbg_dir,
                        &sr_info->err_weight);
@@ -940,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                strcpy(name, "volt_");
                sprintf(volt_name, "%d", volt_data[i].volt_nominal);
                strcat(name, volt_name);
-               (void) debugfs_create_x32(name, S_IRUGO | S_IWUGO, nvalue_dir,
+               (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
                                &(sr_info->nvalue_table[i].nvalue));
        }
 
@@ -966,7 +965,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
        }
 
        sr_info = _sr_lookup(pdata->voltdm);
-       if (!sr_info) {
+       if (IS_ERR(sr_info)) {
                dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
                        __func__);
                return -EINVAL;
index 4e48e78..0fc550e 100644 (file)
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
 #include <asm/localtimer.h>
+#include <asm/sched_clock.h>
 
 #include "timer-gp.h"
 
+#include <plat/common.h>
+
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID         12
 
@@ -176,14 +179,19 @@ static void __init omap2_gp_clockevent_init(void)
 /* 
  * When 32k-timer is enabled, don't use GPTimer for clocksource
  * instead, just leave default clocksource which uses the 32k
- * sync counter.  See clocksource setup in see plat-omap/common.c. 
+ * sync counter.  See clocksource setup in plat-omap/counter_32k.c
  */
 
-static inline void __init omap2_gp_clocksource_init(void) {}
+static void __init omap2_gp_clocksource_init(void)
+{
+       omap_init_clocksource_32k();
+}
+
 #else
 /*
  * clocksource
  */
+static DEFINE_CLOCK_DATA(cd);
 static struct omap_dm_timer *gpt_clocksource;
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
@@ -198,6 +206,15 @@ static struct clocksource clocksource_gpt = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static void notrace dmtimer_update_sched_clock(void)
+{
+       u32 cyc;
+
+       cyc = omap_dm_timer_read_counter(gpt_clocksource);
+
+       update_sched_clock(&cd, cyc, (u32)~0);
+}
+
 /* Setup free-running counter for clocksource */
 static void __init omap2_gp_clocksource_init(void)
 {
@@ -218,6 +235,8 @@ static void __init omap2_gp_clocksource_init(void)
 
        omap_dm_timer_set_load_start(gpt, 1, 0);
 
+       init_sched_clock(&cd, dmtimer_update_sched_clock, 32, tick_rate);
+
        if (clocksource_register_hz(&clocksource_gpt, tick_rate))
                printk(err2, clocksource_gpt.name);
 }
index ed6079c..12be525 100644 (file)
@@ -471,6 +471,7 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
        strcat(name, vdd->voltdm.name);
 
        vdd->debug_dir = debugfs_create_dir(name, voltage_dir);
+       kfree(name);
        if (IS_ERR(vdd->debug_dir)) {
                pr_warning("%s: Unable to create debugfs directory for"
                        " vdd_%s\n", __func__, vdd->voltdm.name);
index 6b2c800..28f667e 100644 (file)
@@ -50,7 +50,7 @@ static void __init colibri_mmc_init(void)
                        GPIO0_COLIBRI_PXA270_SD_DETECT;
        if (machine_is_colibri300())    /* PXA300 Colibri */
                colibri_mci_platform_data.gpio_card_detect =
-                       GPIO39_COLIBRI_PXA300_SD_DETECT;
+                       GPIO13_COLIBRI_PXA300_SD_DETECT;
        else                            /* PXA320 Colibri */
                colibri_mci_platform_data.gpio_card_detect =
                        GPIO28_COLIBRI_PXA320_SD_DETECT;
index fddb16d..66dd81c 100644 (file)
@@ -41,7 +41,7 @@ static mfp_cfg_t colibri_pxa300_evalboard_pin_config[] __initdata = {
        GPIO4_MMC1_DAT1,
        GPIO5_MMC1_DAT2,
        GPIO6_MMC1_DAT3,
-       GPIO39_GPIO,    /* SD detect */
+       GPIO13_GPIO,    /* GPIO13_COLIBRI_PXA300_SD_DETECT */
 
        /* UHC */
        GPIO0_2_USBH_PEN,
index 388a96f..cb4236e 100644 (file)
@@ -60,7 +60,7 @@ static inline void colibri_pxa3xx_init_nand(void) {}
 #define GPIO113_COLIBRI_PXA270_TS_IRQ  113
 
 /* GPIO definitions for Colibri PXA300/310 */
-#define GPIO39_COLIBRI_PXA300_SD_DETECT        39
+#define GPIO13_COLIBRI_PXA300_SD_DETECT        13
 
 /* GPIO definitions for Colibri PXA320 */
 #define GPIO28_COLIBRI_PXA320_SD_DETECT        28
index 405b92a..35572c4 100644 (file)
@@ -323,7 +323,7 @@ static struct platform_pwm_backlight_data palm27x_backlight_data = {
        .pwm_id         = 0,
        .max_brightness = 0xfe,
        .dft_brightness = 0x7e,
-       .pwm_period_ns  = 3500,
+       .pwm_period_ns  = 3500 * 1024,
        .init           = palm27x_backlight_init,
        .notify         = palm27x_backlight_notify,
        .exit           = palm27x_backlight_exit,
index 978e1b2..1807c9a 100644 (file)
@@ -33,7 +33,7 @@ int pxa_pm_enter(suspend_state_t state)
 #endif
 
        /* skip registers saving for standby */
-       if (state != PM_SUSPEND_STANDBY) {
+       if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->save) {
                pxa_cpu_pm_fns->save(sleep_save);
                /* before sleeping, calculate and save a checksum */
                for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
@@ -44,7 +44,7 @@ int pxa_pm_enter(suspend_state_t state)
        pxa_cpu_pm_fns->enter(state);
        cpu_init();
 
-       if (state != PM_SUSPEND_STANDBY) {
+       if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) {
                /* after sleeping, validate the checksum */
                for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
                        checksum += sleep_save[i];
index b4575ae..7ca138a 100644 (file)
@@ -2,52 +2,56 @@ menu "RealView platform type"
        depends on ARCH_REALVIEW
 
 config MACH_REALVIEW_EB
-       bool "Support RealView/EB platform"
+       bool "Support RealView(R) Emulation Baseboard"
        select ARM_GIC
        help
-         Include support for the ARM(R) RealView Emulation Baseboard platform.
+         Include support for the ARM(R) RealView(R) Emulation Baseboard
+         platform.
 
 config REALVIEW_EB_A9MP
-       bool "Support Multicore Cortex-A9"
+       bool "Support Multicore Cortex-A9 Tile"
        depends on MACH_REALVIEW_EB
        select CPU_V7
        help
-         Enable support for the Cortex-A9MPCore tile on the Realview platform.
+         Enable support for the Cortex-A9MPCore tile fitted to the
+         Realview(R) Emulation Baseboard platform.
 
 config REALVIEW_EB_ARM11MP
-       bool "Support ARM11MPCore tile"
+       bool "Support ARM11MPCore Tile"
        depends on MACH_REALVIEW_EB
        select CPU_V6
        select ARCH_HAS_BARRIERS if SMP
        help
-         Enable support for the ARM11MPCore tile on the Realview platform.
+         Enable support for the ARM11MPCore tile fitted to the Realview(R)
+         Emulation Baseboard platform.
 
 config REALVIEW_EB_ARM11MP_REVB
-       bool "Support ARM11MPCore RevB tile"
+       bool "Support ARM11MPCore RevB Tile"
        depends on REALVIEW_EB_ARM11MP
        help
-         Enable support for the ARM11MPCore RevB tile on the Realview
-         platform. Since there are device address differences, a
-         kernel built with this option enabled is not compatible with
-         other revisions of the ARM11MPCore tile.
+         Enable support for the ARM11MPCore Revision B tile on the
+         Realview(R) Emulation Baseboard platform. Since there are device
+         address differences, a kernel built with this option enabled is
+         not compatible with other revisions of the ARM11MPCore tile.
 
 config MACH_REALVIEW_PB11MP
-       bool "Support RealView/PB11MPCore platform"
+       bool "Support RealView(R) Platform Baseboard for ARM11MPCore"
        select CPU_V6
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        select ARCH_HAS_BARRIERS if SMP
        help
-         Include support for the ARM(R) RealView MPCore Platform Baseboard.
-         PB11MPCore is a platform with an on-board ARM11MPCore and has
+         Include support for the ARM(R) RealView(R) Platform Baseboard for
+         the ARM11MPCore.  This platform has an on-board ARM11MPCore and has
          support for PCI-E and Compact Flash.
 
 config MACH_REALVIEW_PB1176
-       bool "Support RealView/PB1176 platform"
+       bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S"
        select CPU_V6
        select ARM_GIC
        help
-         Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
+         Include support for the ARM(R) RealView(R) Platform Baseboard for
+         ARM1176JZF-S.
 
 config REALVIEW_PB1176_SECURE_FLASH
        bool "Allow access to the secure flash memory block"
@@ -59,23 +63,24 @@ config REALVIEW_PB1176_SECURE_FLASH
          block (64MB @ 0x3c000000) is required.
 
 config MACH_REALVIEW_PBA8
-       bool "Support RealView/PB-A8 platform"
+       bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform"
        select CPU_V7
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        help
-         Include support for the ARM(R) RealView Cortex-A8 Platform Baseboard.
-         PB-A8 is a platform with an on-board Cortex-A8 and has support for
-         PCI-E and Compact Flash.
+         Include support for the ARM(R) RealView Platform Baseboard for
+         Cortex(tm)-A8.  This platform has an on-board Cortex-A8 and has
+         support for PCI-E and Compact Flash.
 
 config MACH_REALVIEW_PBX
-       bool "Support RealView/PBX platform"
+       bool "Support RealView(R) Platform Baseboard Explore"
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
        select ZONE_DMA if SPARSEMEM
        help
-         Include support for the ARM(R) RealView PBX platform.
+         Include support for the ARM(R) RealView(R) Platform Baseboard
+         Explore.
 
 config REALVIEW_HIGH_PHYS_OFFSET
        bool "High physical base address for the RealView platform"
index a22bf67..6959d13 100644 (file)
@@ -41,7 +41,7 @@ volatile int __cpuinitdata pen_release = -1;
  * observers, irrespective of whether they're taking part in coherency
  * or not.  This is necessary for the hotplug code to work reliably.
  */
-static void write_pen_release(int val)
+static void __cpuinit write_pen_release(int val)
 {
        pen_release = val;
        smp_wmb();
index 203dd5a..058dab4 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5p6442/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5P6442 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5P6442_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5P6442_PA_CHIPID
+#define S5P6442_PA_SDRAM       0x20000000
 
-#define S5P6442_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5P6442_PA_SYSCON
+#define S5P6442_PA_I2S0                0xC0B00000
+#define S5P6442_PA_I2S1                0xF2200000
 
-#define S5P6442_PA_GPIO                (0xE0200000)
+#define S5P6442_PA_CHIPID      0xE0000000
 
-#define S5P6442_PA_VIC0                (0xE4000000)
-#define S5P6442_PA_VIC1                (0xE4100000)
-#define S5P6442_PA_VIC2                (0xE4200000)
+#define S5P6442_PA_SYSCON      0xE0100000
 
-#define S5P6442_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5P6442_PA_SROMC
+#define S5P6442_PA_GPIO                0xE0200000
 
-#define S5P6442_PA_MDMA                0xE8000000
-#define S5P6442_PA_PDMA                0xE9000000
+#define S5P6442_PA_VIC0                0xE4000000
+#define S5P6442_PA_VIC1                0xE4100000
+#define S5P6442_PA_VIC2                0xE4200000
 
-#define S5P6442_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5P6442_PA_TIMER
+#define S5P6442_PA_SROMC       0xE7000000
 
-#define S5P6442_PA_SYSTIMER    (0xEA100000)
+#define S5P6442_PA_MDMA                0xE8000000
+#define S5P6442_PA_PDMA                0xE9000000
 
-#define S5P6442_PA_WATCHDOG    (0xEA200000)
+#define S5P6442_PA_TIMER       0xEA000000
 
-#define S5P6442_PA_UART                (0xEC000000)
+#define S5P6442_PA_SYSTIMER    0xEA100000
 
-#define S5P_PA_UART0           (S5P6442_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5P6442_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5P6442_PA_UART + 0x800)
-#define S5P_SZ_UART            SZ_256
+#define S5P6442_PA_WATCHDOG    0xEA200000
 
-#define S5P6442_PA_IIC0                (0xEC100000)
+#define S5P6442_PA_UART                0xEC000000
 
-#define S5P6442_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5P6442_PA_SDRAM
+#define S5P6442_PA_IIC0                0xEC100000
 
 #define S5P6442_PA_SPI         0xEC300000
 
-/* I2S */
-#define S5P6442_PA_I2S0                0xC0B00000
-#define S5P6442_PA_I2S1                0xF2200000
-
-/* PCM */
 #define S5P6442_PA_PCM0                0xF2400000
 #define S5P6442_PA_PCM1                0xF2500000
 
-/* compatibiltiy defines. */
+/* Compatibiltiy Defines */
+
+#define S3C_PA_IIC             S5P6442_PA_IIC0
 #define S3C_PA_WDT             S5P6442_PA_WATCHDOG
+
+#define S5P_PA_CHIPID          S5P6442_PA_CHIPID
+#define S5P_PA_SDRAM           S5P6442_PA_SDRAM
+#define S5P_PA_SROMC           S5P6442_PA_SROMC
+#define S5P_PA_SYSCON          S5P6442_PA_SYSCON
+#define S5P_PA_TIMER           S5P6442_PA_TIMER
+
+/* UART */
+
 #define S3C_PA_UART            S5P6442_PA_UART
-#define S3C_PA_IIC             S5P6442_PA_IIC0
+
+#define S5P_PA_UART(x)         (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0           S5P_PA_UART(0)
+#define S5P_PA_UART1           S5P_PA_UART(1)
+#define S5P_PA_UART2           S5P_PA_UART(2)
+
+#define S5P_SZ_UART            SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index a9365e5..95c9125 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5p64x0/include/mach/map.h
  *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * S5P64X0 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5P64X0_PA_SDRAM       (0x20000000)
+#define S5P64X0_PA_SDRAM       0x20000000
 
-#define S5P64X0_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5P64X0_PA_CHIPID
-
-#define S5P64X0_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5P64X0_PA_SYSCON
-
-#define S5P64X0_PA_GPIO                (0xE0308000)
-
-#define S5P64X0_PA_VIC0                (0xE4000000)
-#define S5P64X0_PA_VIC1                (0xE4100000)
+#define S5P64X0_PA_CHIPID      0xE0000000
 
-#define S5P64X0_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5P64X0_PA_SROMC
-
-#define S5P64X0_PA_PDMA                (0xE9000000)
-
-#define S5P64X0_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5P64X0_PA_TIMER
+#define S5P64X0_PA_SYSCON      0xE0100000
 
-#define S5P64X0_PA_RTC         (0xEA100000)
+#define S5P64X0_PA_GPIO                0xE0308000
 
-#define S5P64X0_PA_WDT         (0xEA200000)
+#define S5P64X0_PA_VIC0                0xE4000000
+#define S5P64X0_PA_VIC1                0xE4100000
 
-#define S5P6440_PA_UART(x)     (0xEC000000 + ((x) * S3C_UART_OFFSET))
-#define S5P6450_PA_UART(x)     ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+#define S5P64X0_PA_SROMC       0xE7000000
 
-#define S5P_PA_UART0           S5P6450_PA_UART(0)
-#define S5P_PA_UART1           S5P6450_PA_UART(1)
-#define S5P_PA_UART2           S5P6450_PA_UART(2)
-#define S5P_PA_UART3           S5P6450_PA_UART(3)
-#define S5P_PA_UART4           S5P6450_PA_UART(4)
-#define S5P_PA_UART5           S5P6450_PA_UART(5)
+#define S5P64X0_PA_PDMA                0xE9000000
 
-#define S5P_SZ_UART            SZ_256
+#define S5P64X0_PA_TIMER       0xEA000000
+#define S5P64X0_PA_RTC         0xEA100000
+#define S5P64X0_PA_WDT         0xEA200000
 
-#define S5P6440_PA_IIC0                (0xEC104000)
-#define S5P6440_PA_IIC1                (0xEC20F000)
-#define S5P6450_PA_IIC0                (0xEC100000)
-#define S5P6450_PA_IIC1                (0xEC200000)
+#define S5P6440_PA_IIC0                0xEC104000
+#define S5P6440_PA_IIC1                0xEC20F000
+#define S5P6450_PA_IIC0                0xEC100000
+#define S5P6450_PA_IIC1                0xEC200000
 
-#define S5P64X0_PA_SPI0                (0xEC400000)
-#define S5P64X0_PA_SPI1                (0xEC500000)
+#define S5P64X0_PA_SPI0                0xEC400000
+#define S5P64X0_PA_SPI1                0xEC500000
 
-#define S5P64X0_PA_HSOTG       (0xED100000)
+#define S5P64X0_PA_HSOTG       0xED100000
 
 #define S5P64X0_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
 
-#define S5P64X0_PA_I2S         (0xF2000000)
+#define S5P64X0_PA_I2S         0xF2000000
 #define S5P6450_PA_I2S1                0xF2800000
 #define S5P6450_PA_I2S2                0xF2900000
 
-#define S5P64X0_PA_PCM         (0xF2100000)
+#define S5P64X0_PA_PCM         0xF2100000
 
-#define S5P64X0_PA_ADC         (0xF3000000)
+#define S5P64X0_PA_ADC         0xF3000000
 
-/* compatibiltiy defines. */
+/* Compatibiltiy Defines */
 
 #define S3C_PA_HSMMC0          S5P64X0_PA_HSMMC(0)
 #define S3C_PA_HSMMC1          S5P64X0_PA_HSMMC(1)
 #define S3C_PA_RTC             S5P64X0_PA_RTC
 #define S3C_PA_WDT             S5P64X0_PA_WDT
 
+#define S5P_PA_CHIPID          S5P64X0_PA_CHIPID
+#define S5P_PA_SROMC           S5P64X0_PA_SROMC
+#define S5P_PA_SYSCON          S5P64X0_PA_SYSCON
+#define S5P_PA_TIMER           S5P64X0_PA_TIMER
+
 #define SAMSUNG_PA_ADC         S5P64X0_PA_ADC
 
+/* UART */
+
+#define S5P6440_PA_UART(x)     (0xEC000000 + ((x) * S3C_UART_OFFSET))
+#define S5P6450_PA_UART(x)     ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+
+#define S5P_PA_UART0           S5P6450_PA_UART(0)
+#define S5P_PA_UART1           S5P6450_PA_UART(1)
+#define S5P_PA_UART2           S5P6450_PA_UART(2)
+#define S5P_PA_UART3           S5P6450_PA_UART(3)
+#define S5P_PA_UART4           S5P6450_PA_UART(4)
+#define S5P_PA_UART5           S5P6450_PA_UART(5)
+
+#define S5P_SZ_UART            SZ_256
+
 #endif /* __ASM_ARCH_MAP_H */
index 328467b..ccbe6b7 100644 (file)
@@ -1,5 +1,8 @@
 /* linux/arch/arm/mach-s5pc100/include/mach/map.h
  *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
  * Copyright 2009 Samsung Electronics Co.
  *     Byungho Min <bhmin@samsung.com>
  *
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-/*
- * map-base.h has already defined virtual memory address
- * S3C_VA_IRQ          S3C_ADDR(0x00000000)    irq controller(s)
- * S3C_VA_SYS          S3C_ADDR(0x00100000)    system control
- * S3C_VA_MEM          S3C_ADDR(0x00200000)    system control (not used)
- * S3C_VA_TIMER                S3C_ADDR(0x00300000)    timer block
- * S3C_VA_WATCHDOG     S3C_ADDR(0x00400000)    watchdog
- * S3C_VA_UART         S3C_ADDR(0x01000000)    UART
- *
- * S5PC100 specific virtual memory address can be defined here
- * S5PC1XX_VA_GPIO     S3C_ADDR(0x00500000)    GPIO
- *
- */
+#define S5PC100_PA_SDRAM               0x20000000
+
+#define S5PC100_PA_ONENAND             0xE7100000
+#define S5PC100_PA_ONENAND_BUF         0xB0000000
+
+#define S5PC100_PA_CHIPID              0xE0000000
 
-#define S5PC100_PA_ONENAND_BUF (0xB0000000)
-#define S5PC100_SZ_ONENAND_BUF (SZ_256M - SZ_32M)
+#define S5PC100_PA_SYSCON              0xE0100000
 
-/* Chip ID */
+#define S5PC100_PA_OTHERS              0xE0200000
 
-#define S5PC100_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5PC100_PA_CHIPID
+#define S5PC100_PA_GPIO                        0xE0300000
 
-#define S5PC100_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5PC100_PA_SYSCON
+#define S5PC100_PA_VIC0                        0xE4000000
+#define S5PC100_PA_VIC1                        0xE4100000
+#define S5PC100_PA_VIC2                        0xE4200000
 
-#define S5PC100_PA_OTHERS      (0xE0200000)
-#define S5PC100_VA_OTHERS      (S3C_VA_SYS + 0x10000)
+#define S5PC100_PA_SROMC               0xE7000000
 
-#define S5PC100_PA_GPIO                (0xE0300000)
-#define S5PC1XX_VA_GPIO                S3C_ADDR(0x00500000)
+#define S5PC100_PA_CFCON               0xE7800000
 
-/* Interrupt */
-#define S5PC100_PA_VIC0                (0xE4000000)
-#define S5PC100_PA_VIC1                (0xE4100000)
-#define S5PC100_PA_VIC2                (0xE4200000)
-#define S5PC100_VA_VIC         S3C_VA_IRQ
-#define S5PC100_VA_VIC_OFFSET  0x10000
-#define S5PC1XX_VA_VIC(x)      (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
+#define S5PC100_PA_MDMA                        0xE8100000
+#define S5PC100_PA_PDMA0               0xE9000000
+#define S5PC100_PA_PDMA1               0xE9200000
 
-#define S5PC100_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5PC100_PA_SROMC
+#define S5PC100_PA_TIMER               0xEA000000
+#define S5PC100_PA_SYSTIMER            0xEA100000
+#define S5PC100_PA_WATCHDOG            0xEA200000
+#define S5PC100_PA_RTC                 0xEA300000
 
-#define S5PC100_PA_ONENAND     (0xE7100000)
+#define S5PC100_PA_UART                        0xEC000000
 
-#define S5PC100_PA_CFCON       (0xE7800000)
+#define S5PC100_PA_IIC0                        0xEC100000
+#define S5PC100_PA_IIC1                        0xEC200000
 
-/* DMA */
-#define S5PC100_PA_MDMA                (0xE8100000)
-#define S5PC100_PA_PDMA0       (0xE9000000)
-#define S5PC100_PA_PDMA1       (0xE9200000)
+#define S5PC100_PA_SPI0                        0xEC300000
+#define S5PC100_PA_SPI1                        0xEC400000
+#define S5PC100_PA_SPI2                        0xEC500000
 
-/* Timer */
-#define S5PC100_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5PC100_PA_TIMER
+#define S5PC100_PA_USB_HSOTG           0xED200000
+#define S5PC100_PA_USB_HSPHY           0xED300000
 
-#define S5PC100_PA_SYSTIMER    (0xEA100000)
+#define S5PC100_PA_HSMMC(x)            (0xED800000 + ((x) * 0x100000))
 
-#define S5PC100_PA_WATCHDOG    (0xEA200000)
-#define S5PC100_PA_RTC         (0xEA300000)
+#define S5PC100_PA_FB                  0xEE000000
 
-#define S5PC100_PA_UART                (0xEC000000)
+#define S5PC100_PA_FIMC0               0xEE200000
+#define S5PC100_PA_FIMC1               0xEE300000
+#define S5PC100_PA_FIMC2               0xEE400000
 
-#define S5P_PA_UART0           (S5PC100_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5PC100_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5PC100_PA_UART + 0x800)
-#define S5P_PA_UART3           (S5PC100_PA_UART + 0xC00)
-#define S5P_SZ_UART            SZ_256
+#define S5PC100_PA_I2S0                        0xF2000000
+#define S5PC100_PA_I2S1                        0xF2100000
+#define S5PC100_PA_I2S2                        0xF2200000
 
-#define S5PC100_PA_IIC0                (0xEC100000)
-#define S5PC100_PA_IIC1                (0xEC200000)
+#define S5PC100_PA_AC97                        0xF2300000
 
-/* SPI */
-#define S5PC100_PA_SPI0                0xEC300000
-#define S5PC100_PA_SPI1                0xEC400000
-#define S5PC100_PA_SPI2                0xEC500000
+#define S5PC100_PA_PCM0                        0xF2400000
+#define S5PC100_PA_PCM1                        0xF2500000
 
-/* USB HS OTG */
-#define S5PC100_PA_USB_HSOTG   (0xED200000)
-#define S5PC100_PA_USB_HSPHY   (0xED300000)
+#define S5PC100_PA_SPDIF               0xF2600000
 
-#define S5PC100_PA_FB          (0xEE000000)
+#define S5PC100_PA_TSADC               0xF3000000
 
-#define S5PC100_PA_FIMC0       (0xEE200000)
-#define S5PC100_PA_FIMC1       (0xEE300000)
-#define S5PC100_PA_FIMC2       (0xEE400000)
+#define S5PC100_PA_KEYPAD              0xF3100000
 
-#define S5PC100_PA_I2S0                (0xF2000000)
-#define S5PC100_PA_I2S1                (0xF2100000)
-#define S5PC100_PA_I2S2                (0xF2200000)
+/* Compatibiltiy Defines */
 
-#define S5PC100_PA_AC97                0xF2300000
+#define S3C_PA_FB                      S5PC100_PA_FB
+#define S3C_PA_HSMMC0                  S5PC100_PA_HSMMC(0)
+#define S3C_PA_HSMMC1                  S5PC100_PA_HSMMC(1)
+#define S3C_PA_HSMMC2                  S5PC100_PA_HSMMC(2)
+#define S3C_PA_IIC                     S5PC100_PA_IIC0
+#define S3C_PA_IIC1                    S5PC100_PA_IIC1
+#define S3C_PA_KEYPAD                  S5PC100_PA_KEYPAD
+#define S3C_PA_ONENAND                 S5PC100_PA_ONENAND
+#define S3C_PA_ONENAND_BUF             S5PC100_PA_ONENAND_BUF
+#define S3C_PA_RTC                     S5PC100_PA_RTC
+#define S3C_PA_TSADC                   S5PC100_PA_TSADC
+#define S3C_PA_USB_HSOTG               S5PC100_PA_USB_HSOTG
+#define S3C_PA_USB_HSPHY               S5PC100_PA_USB_HSPHY
+#define S3C_PA_WDT                     S5PC100_PA_WATCHDOG
 
-/* PCM */
-#define S5PC100_PA_PCM0                0xF2400000
-#define S5PC100_PA_PCM1                0xF2500000
+#define S5P_PA_CHIPID                  S5PC100_PA_CHIPID
+#define S5P_PA_FIMC0                   S5PC100_PA_FIMC0
+#define S5P_PA_FIMC1                   S5PC100_PA_FIMC1
+#define S5P_PA_FIMC2                   S5PC100_PA_FIMC2
+#define S5P_PA_SDRAM                   S5PC100_PA_SDRAM
+#define S5P_PA_SROMC                   S5PC100_PA_SROMC
+#define S5P_PA_SYSCON                  S5PC100_PA_SYSCON
+#define S5P_PA_TIMER                   S5PC100_PA_TIMER
 
-#define S5PC100_PA_SPDIF       0xF2600000
+#define SAMSUNG_PA_ADC                 S5PC100_PA_TSADC
+#define SAMSUNG_PA_CFCON               S5PC100_PA_CFCON
+#define SAMSUNG_PA_KEYPAD              S5PC100_PA_KEYPAD
 
-#define S5PC100_PA_TSADC       (0xF3000000)
+#define S5PC100_VA_OTHERS              (S3C_VA_SYS + 0x10000)
 
-/* KEYPAD */
-#define S5PC100_PA_KEYPAD      (0xF3100000)
+#define S3C_SZ_ONENAND_BUF             (SZ_256M - SZ_32M)
 
-#define S5PC100_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
+/* UART */
 
-#define S5PC100_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5PC100_PA_SDRAM
+#define S3C_PA_UART                    S5PC100_PA_UART
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART            S5PC100_PA_UART
-#define S3C_PA_IIC             S5PC100_PA_IIC0
-#define S3C_PA_IIC1            S5PC100_PA_IIC1
-#define S3C_PA_FB              S5PC100_PA_FB
-#define S3C_PA_G2D             S5PC100_PA_G2D
-#define S3C_PA_G3D             S5PC100_PA_G3D
-#define S3C_PA_JPEG            S5PC100_PA_JPEG
-#define S3C_PA_ROTATOR         S5PC100_PA_ROTATOR
-#define S5P_VA_VIC0            S5PC1XX_VA_VIC(0)
-#define S5P_VA_VIC1            S5PC1XX_VA_VIC(1)
-#define S5P_VA_VIC2            S5PC1XX_VA_VIC(2)
-#define S3C_PA_USB_HSOTG       S5PC100_PA_USB_HSOTG
-#define S3C_PA_USB_HSPHY       S5PC100_PA_USB_HSPHY
-#define S3C_PA_HSMMC0          S5PC100_PA_HSMMC(0)
-#define S3C_PA_HSMMC1          S5PC100_PA_HSMMC(1)
-#define S3C_PA_HSMMC2          S5PC100_PA_HSMMC(2)
-#define S3C_PA_KEYPAD          S5PC100_PA_KEYPAD
-#define S3C_PA_WDT             S5PC100_PA_WATCHDOG
-#define S3C_PA_TSADC           S5PC100_PA_TSADC
-#define S3C_PA_ONENAND         S5PC100_PA_ONENAND
-#define S3C_PA_ONENAND_BUF     S5PC100_PA_ONENAND_BUF
-#define S3C_SZ_ONENAND_BUF     S5PC100_SZ_ONENAND_BUF
-#define S3C_PA_RTC             S5PC100_PA_RTC
-
-#define SAMSUNG_PA_ADC         S5PC100_PA_TSADC
-#define SAMSUNG_PA_CFCON       S5PC100_PA_CFCON
-#define SAMSUNG_PA_KEYPAD      S5PC100_PA_KEYPAD
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
 
-#define S5P_PA_FIMC0           S5PC100_PA_FIMC0
-#define S5P_PA_FIMC1           S5PC100_PA_FIMC1
-#define S5P_PA_FIMC2           S5PC100_PA_FIMC2
+#define S5P_SZ_UART                    SZ_256
 
-#endif /* __ASM_ARCH_C100_MAP_H */
+#endif /* __ASM_ARCH_MAP_H */
index 3611492..1dd5883 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5pv210/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5PV210 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5PV210_PA_SROM_BANK5  (0xA8000000)
+#define S5PV210_PA_SDRAM               0x20000000
 
-#define S5PC110_PA_ONENAND     (0xB0000000)
-#define S5P_PA_ONENAND         S5PC110_PA_ONENAND
+#define S5PV210_PA_SROM_BANK5          0xA8000000
 
-#define S5PC110_PA_ONENAND_DMA (0xB0600000)
-#define S5P_PA_ONENAND_DMA     S5PC110_PA_ONENAND_DMA
+#define S5PC110_PA_ONENAND             0xB0000000
+#define S5PC110_PA_ONENAND_DMA         0xB0600000
 
-#define S5PV210_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5PV210_PA_CHIPID
+#define S5PV210_PA_CHIPID              0xE0000000
 
-#define S5PV210_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5PV210_PA_SYSCON
+#define S5PV210_PA_SYSCON              0xE0100000
 
-#define S5PV210_PA_GPIO                (0xE0200000)
+#define S5PV210_PA_GPIO                        0xE0200000
 
-/* SPI */
-#define S5PV210_PA_SPI0                0xE1300000
-#define S5PV210_PA_SPI1                0xE1400000
+#define S5PV210_PA_SPDIF               0xE1100000
 
-#define S5PV210_PA_KEYPAD      (0xE1600000)
+#define S5PV210_PA_SPI0                        0xE1300000
+#define S5PV210_PA_SPI1                        0xE1400000
 
-#define S5PV210_PA_IIC0                (0xE1800000)
-#define S5PV210_PA_IIC1                (0xFAB00000)
-#define S5PV210_PA_IIC2                (0xE1A00000)
+#define S5PV210_PA_KEYPAD              0xE1600000
 
-#define S5PV210_PA_TIMER       (0xE2500000)
-#define S5P_PA_TIMER           S5PV210_PA_TIMER
+#define S5PV210_PA_ADC                 0xE1700000
 
-#define S5PV210_PA_SYSTIMER    (0xE2600000)
+#define S5PV210_PA_IIC0                        0xE1800000
+#define S5PV210_PA_IIC1                        0xFAB00000
+#define S5PV210_PA_IIC2                        0xE1A00000
 
-#define S5PV210_PA_WATCHDOG    (0xE2700000)
+#define S5PV210_PA_AC97                        0xE2200000
 
-#define S5PV210_PA_RTC         (0xE2800000)
-#define S5PV210_PA_UART                (0xE2900000)
+#define S5PV210_PA_PCM0                        0xE2300000
+#define S5PV210_PA_PCM1                        0xE1200000
+#define S5PV210_PA_PCM2                        0xE2B00000
 
-#define S5P_PA_UART0           (S5PV210_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5PV210_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5PV210_PA_UART + 0x800)
-#define S5P_PA_UART3           (S5PV210_PA_UART + 0xC00)
+#define S5PV210_PA_TIMER               0xE2500000
+#define S5PV210_PA_SYSTIMER            0xE2600000
+#define S5PV210_PA_WATCHDOG            0xE2700000
+#define S5PV210_PA_RTC                 0xE2800000
 
-#define S5P_SZ_UART            SZ_256
+#define S5PV210_PA_UART                        0xE2900000
 
-#define S3C_VA_UARTx(x)                (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+#define S5PV210_PA_SROMC               0xE8000000
 
-#define S5PV210_PA_SROMC       (0xE8000000)
-#define S5P_PA_SROMC           S5PV210_PA_SROMC
+#define S5PV210_PA_CFCON               0xE8200000
 
-#define S5PV210_PA_CFCON       (0xE8200000)
+#define S5PV210_PA_HSMMC(x)            (0xEB000000 + ((x) * 0x100000))
 
-#define S5PV210_PA_MDMA                0xFA200000
-#define S5PV210_PA_PDMA0       0xE0900000
-#define S5PV210_PA_PDMA1       0xE0A00000
+#define S5PV210_PA_HSOTG               0xEC000000
+#define S5PV210_PA_HSPHY               0xEC100000
 
-#define S5PV210_PA_FB          (0xF8000000)
+#define S5PV210_PA_IIS0                        0xEEE30000
+#define S5PV210_PA_IIS1                        0xE2100000
+#define S5PV210_PA_IIS2                        0xE2A00000
 
-#define S5PV210_PA_FIMC0       (0xFB200000)
-#define S5PV210_PA_FIMC1       (0xFB300000)
-#define S5PV210_PA_FIMC2       (0xFB400000)
+#define S5PV210_PA_DMC0                        0xF0000000
+#define S5PV210_PA_DMC1                        0xF1400000
 
-#define S5PV210_PA_HSMMC(x)    (0xEB000000 + ((x) * 0x100000))
+#define S5PV210_PA_VIC0                        0xF2000000
+#define S5PV210_PA_VIC1                        0xF2100000
+#define S5PV210_PA_VIC2                        0xF2200000
+#define S5PV210_PA_VIC3                        0xF2300000
 
-#define S5PV210_PA_HSOTG       (0xEC000000)
-#define S5PV210_PA_HSPHY       (0xEC100000)
+#define S5PV210_PA_FB                  0xF8000000
 
-#define S5PV210_PA_VIC0                (0xF2000000)
-#define S5PV210_PA_VIC1                (0xF2100000)
-#define S5PV210_PA_VIC2                (0xF2200000)
-#define S5PV210_PA_VIC3                (0xF2300000)
+#define S5PV210_PA_MDMA                        0xFA200000
+#define S5PV210_PA_PDMA0               0xE0900000
+#define S5PV210_PA_PDMA1               0xE0A00000
 
-#define S5PV210_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5PV210_PA_SDRAM
+#define S5PV210_PA_MIPI_CSIS           0xFA600000
 
-/* S/PDIF */
-#define S5PV210_PA_SPDIF       0xE1100000
+#define S5PV210_PA_FIMC0               0xFB200000
+#define S5PV210_PA_FIMC1               0xFB300000
+#define S5PV210_PA_FIMC2               0xFB400000
 
-/* I2S */
-#define S5PV210_PA_IIS0                0xEEE30000
-#define S5PV210_PA_IIS1                0xE2100000
-#define S5PV210_PA_IIS2                0xE2A00000
+/* Compatibiltiy Defines */
 
-/* PCM */
-#define S5PV210_PA_PCM0                0xE2300000
-#define S5PV210_PA_PCM1                0xE1200000
-#define S5PV210_PA_PCM2                0xE2B00000
+#define S3C_PA_FB                      S5PV210_PA_FB
+#define S3C_PA_HSMMC0                  S5PV210_PA_HSMMC(0)
+#define S3C_PA_HSMMC1                  S5PV210_PA_HSMMC(1)
+#define S3C_PA_HSMMC2                  S5PV210_PA_HSMMC(2)
+#define S3C_PA_HSMMC3                  S5PV210_PA_HSMMC(3)
+#define S3C_PA_IIC                     S5PV210_PA_IIC0
+#define S3C_PA_IIC1                    S5PV210_PA_IIC1
+#define S3C_PA_IIC2                    S5PV210_PA_IIC2
+#define S3C_PA_RTC                     S5PV210_PA_RTC
+#define S3C_PA_USB_HSOTG               S5PV210_PA_HSOTG
+#define S3C_PA_WDT                     S5PV210_PA_WATCHDOG
 
-/* AC97 */
-#define S5PV210_PA_AC97                0xE2200000
+#define S5P_PA_CHIPID                  S5PV210_PA_CHIPID
+#define S5P_PA_FIMC0                   S5PV210_PA_FIMC0
+#define S5P_PA_FIMC1                   S5PV210_PA_FIMC1
+#define S5P_PA_FIMC2                   S5PV210_PA_FIMC2
+#define S5P_PA_MIPI_CSIS0              S5PV210_PA_MIPI_CSIS
+#define S5P_PA_ONENAND                 S5PC110_PA_ONENAND
+#define S5P_PA_ONENAND_DMA             S5PC110_PA_ONENAND_DMA
+#define S5P_PA_SDRAM                   S5PV210_PA_SDRAM
+#define S5P_PA_SROMC                   S5PV210_PA_SROMC
+#define S5P_PA_SYSCON                  S5PV210_PA_SYSCON
+#define S5P_PA_TIMER                   S5PV210_PA_TIMER
 
-#define S5PV210_PA_ADC         (0xE1700000)
+#define SAMSUNG_PA_ADC                 S5PV210_PA_ADC
+#define SAMSUNG_PA_CFCON               S5PV210_PA_CFCON
+#define SAMSUNG_PA_KEYPAD              S5PV210_PA_KEYPAD
 
-#define S5PV210_PA_DMC0                (0xF0000000)
-#define S5PV210_PA_DMC1                (0xF1400000)
+/* UART */
 
-#define S5PV210_PA_MIPI_CSIS   0xFA600000
+#define S3C_VA_UARTx(x)                        (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART            S5PV210_PA_UART
-#define S3C_PA_HSMMC0          S5PV210_PA_HSMMC(0)
-#define S3C_PA_HSMMC1          S5PV210_PA_HSMMC(1)
-#define S3C_PA_HSMMC2          S5PV210_PA_HSMMC(2)
-#define S3C_PA_HSMMC3          S5PV210_PA_HSMMC(3)
-#define S3C_PA_IIC             S5PV210_PA_IIC0
-#define S3C_PA_IIC1            S5PV210_PA_IIC1
-#define S3C_PA_IIC2            S5PV210_PA_IIC2
-#define S3C_PA_FB              S5PV210_PA_FB
-#define S3C_PA_RTC             S5PV210_PA_RTC
-#define S3C_PA_WDT             S5PV210_PA_WATCHDOG
-#define S3C_PA_USB_HSOTG       S5PV210_PA_HSOTG
-#define S5P_PA_FIMC0           S5PV210_PA_FIMC0
-#define S5P_PA_FIMC1           S5PV210_PA_FIMC1
-#define S5P_PA_FIMC2           S5PV210_PA_FIMC2
-#define S5P_PA_MIPI_CSIS0      S5PV210_PA_MIPI_CSIS
+#define S3C_PA_UART                    S5PV210_PA_UART
 
-#define SAMSUNG_PA_ADC         S5PV210_PA_ADC
-#define SAMSUNG_PA_CFCON       S5PV210_PA_CFCON
-#define SAMSUNG_PA_KEYPAD      S5PV210_PA_KEYPAD
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
+
+#define S5P_SZ_UART                    SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index 461aa03..557add4 100644 (file)
@@ -149,7 +149,7 @@ static struct regulator_init_data aquila_ldo2_data = {
 
 static struct regulator_init_data aquila_ldo3_data = {
        .constraints    = {
-               .name           = "VUSB/MIPI_1.1V",
+               .name           = "VUSB+MIPI_1.1V",
                .min_uV         = 1100000,
                .max_uV         = 1100000,
                .apply_uV       = 1,
@@ -197,7 +197,7 @@ static struct regulator_init_data aquila_ldo7_data = {
 
 static struct regulator_init_data aquila_ldo8_data = {
        .constraints    = {
-               .name           = "VUSB/VADC_3.3V",
+               .name           = "VUSB+VADC_3.3V",
                .min_uV         = 3300000,
                .max_uV         = 3300000,
                .apply_uV       = 1,
@@ -207,7 +207,7 @@ static struct regulator_init_data aquila_ldo8_data = {
 
 static struct regulator_init_data aquila_ldo9_data = {
        .constraints    = {
-               .name           = "VCC/VCAM_2.8V",
+               .name           = "VCC+VCAM_2.8V",
                .min_uV         = 2800000,
                .max_uV         = 2800000,
                .apply_uV       = 1,
@@ -381,9 +381,12 @@ static struct max8998_platform_data aquila_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_max_voltage1 = 1200000,
-       .buck1_max_voltage2 = 1200000,
-       .buck2_max_voltage = 1200000,
+       .buck1_voltage1 = 1200000,
+       .buck1_voltage2 = 1200000,
+       .buck1_voltage3 = 1200000,
+       .buck1_voltage4 = 1200000,
+       .buck2_voltage1 = 1200000,
+       .buck2_voltage2 = 1200000,
 };
 #endif
 
index e22d511..056f5c7 100644 (file)
@@ -288,7 +288,7 @@ static struct regulator_init_data goni_ldo2_data = {
 
 static struct regulator_init_data goni_ldo3_data = {
        .constraints    = {
-               .name           = "VUSB/MIPI_1.1V",
+               .name           = "VUSB+MIPI_1.1V",
                .min_uV         = 1100000,
                .max_uV         = 1100000,
                .apply_uV       = 1,
@@ -337,7 +337,7 @@ static struct regulator_init_data goni_ldo7_data = {
 
 static struct regulator_init_data goni_ldo8_data = {
        .constraints    = {
-               .name           = "VUSB/VADC_3.3V",
+               .name           = "VUSB+VADC_3.3V",
                .min_uV         = 3300000,
                .max_uV         = 3300000,
                .apply_uV       = 1,
@@ -347,7 +347,7 @@ static struct regulator_init_data goni_ldo8_data = {
 
 static struct regulator_init_data goni_ldo9_data = {
        .constraints    = {
-               .name           = "VCC/VCAM_2.8V",
+               .name           = "VCC+VCAM_2.8V",
                .min_uV         = 2800000,
                .max_uV         = 2800000,
                .apply_uV       = 1,
@@ -521,9 +521,12 @@ static struct max8998_platform_data goni_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_max_voltage1 = 1200000,
-       .buck1_max_voltage2 = 1200000,
-       .buck2_max_voltage = 1200000,
+       .buck1_voltage1 = 1200000,
+       .buck1_voltage2 = 1200000,
+       .buck1_voltage3 = 1200000,
+       .buck1_voltage4 = 1200000,
+       .buck2_voltage1 = 1200000,
+       .buck2_voltage2 = 1200000,
 };
 #endif
 
index 09c4c21..b2a9acc 100644 (file)
@@ -122,6 +122,7 @@ config MACH_SMDKV310
        select S3C_DEV_HSMMC2
        select S3C_DEV_HSMMC3
        select S5PV310_DEV_PD
+       select S5PV310_DEV_SYSMMU
        select S5PV310_SETUP_I2C1
        select S5PV310_SETUP_SDHCI
        help
index 74d4006..901657f 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5pv310/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5PV310 - Memory map definitions
 
 #include <plat/map-s5p.h>
 
-#define S5PV310_PA_SYSRAM              (0x02025000)
+#define S5PV310_PA_SYSRAM              0x02025000
 
-#define S5PV310_PA_SROM_BANK(x)                (0x04000000 + ((x) * 0x01000000))
-
-#define S5PC210_PA_ONENAND             (0x0C000000)
-#define S5P_PA_ONENAND                 S5PC210_PA_ONENAND
-
-#define S5PC210_PA_ONENAND_DMA         (0x0C600000)
-#define S5P_PA_ONENAND_DMA             S5PC210_PA_ONENAND_DMA
-
-#define S5PV310_PA_CHIPID              (0x10000000)
-#define S5P_PA_CHIPID                  S5PV310_PA_CHIPID
-
-#define S5PV310_PA_SYSCON              (0x10010000)
-#define S5P_PA_SYSCON                  S5PV310_PA_SYSCON
+#define S5PV310_PA_I2S0                        0x03830000
+#define S5PV310_PA_I2S1                        0xE3100000
+#define S5PV310_PA_I2S2                        0xE2A00000
 
-#define S5PV310_PA_PMU                 (0x10020000)
+#define S5PV310_PA_PCM0                        0x03840000
+#define S5PV310_PA_PCM1                        0x13980000
+#define S5PV310_PA_PCM2                        0x13990000
 
-#define S5PV310_PA_CMU                 (0x10030000)
-
-#define S5PV310_PA_WATCHDOG            (0x10060000)
-#define S5PV310_PA_RTC                 (0x10070000)
-
-#define S5PV310_PA_DMC0                        (0x10400000)
-
-#define S5PV310_PA_COMBINER            (0x10448000)
-
-#define S5PV310_PA_COREPERI            (0x10500000)
-#define S5PV310_PA_GIC_CPU             (0x10500100)
-#define S5PV310_PA_TWD                 (0x10500600)
-#define S5PV310_PA_GIC_DIST            (0x10501000)
-#define S5PV310_PA_L2CC                        (0x10502000)
-
-/* DMA */
-#define S5PV310_PA_MDMA                0x10810000
-#define S5PV310_PA_PDMA0       0x12680000
-#define S5PV310_PA_PDMA1       0x12690000
-
-#define S5PV310_PA_GPIO1               (0x11400000)
-#define S5PV310_PA_GPIO2               (0x11000000)
-#define S5PV310_PA_GPIO3               (0x03860000)
-
-#define S5PV310_PA_MIPI_CSIS0          0x11880000
-#define S5PV310_PA_MIPI_CSIS1          0x11890000
+#define S5PV310_PA_SROM_BANK(x)                (0x04000000 + ((x) * 0x01000000))
 
-#define S5PV310_PA_HSMMC(x)            (0x12510000 + ((x) * 0x10000))
+#define S5PC210_PA_ONENAND             0x0C000000
+#define S5PC210_PA_ONENAND_DMA         0x0C600000
 
-#define S5PV310_PA_SROMC               (0x12570000)
-#define S5P_PA_SROMC                   S5PV310_PA_SROMC
+#define S5PV310_PA_CHIPID              0x10000000
 
-/* S/PDIF */
-#define S5PV310_PA_SPDIF       0xE1100000
+#define S5PV310_PA_SYSCON              0x10010000
+#define S5PV310_PA_PMU                 0x10020000
+#define S5PV310_PA_CMU                 0x10030000
 
-/* I2S */
-#define S5PV310_PA_I2S0                0x03830000
-#define S5PV310_PA_I2S1                0xE3100000
-#define S5PV310_PA_I2S2                0xE2A00000
+#define S5PV310_PA_WATCHDOG            0x10060000
+#define S5PV310_PA_RTC                 0x10070000
 
-/* PCM */
-#define S5PV310_PA_PCM0                0x03840000
-#define S5PV310_PA_PCM1                0x13980000
-#define S5PV310_PA_PCM2                0x13990000
+#define S5PV310_PA_DMC0                        0x10400000
 
-/* AC97 */
-#define S5PV310_PA_AC97                0x139A0000
+#define S5PV310_PA_COMBINER            0x10448000
 
-#define S5PV310_PA_UART                        (0x13800000)
+#define S5PV310_PA_COREPERI            0x10500000
+#define S5PV310_PA_GIC_CPU             0x10500100
+#define S5PV310_PA_TWD                 0x10500600
+#define S5PV310_PA_GIC_DIST            0x10501000
+#define S5PV310_PA_L2CC                        0x10502000
 
-#define S5P_PA_UART(x)                 (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0                   S5P_PA_UART(0)
-#define S5P_PA_UART1                   S5P_PA_UART(1)
-#define S5P_PA_UART2                   S5P_PA_UART(2)
-#define S5P_PA_UART3                   S5P_PA_UART(3)
-#define S5P_PA_UART4                   S5P_PA_UART(4)
-
-#define S5P_SZ_UART                    SZ_256
-
-#define S5PV310_PA_IIC(x)              (0x13860000 + ((x) * 0x10000))
-
-#define S5PV310_PA_TIMER               (0x139D0000)
-#define S5P_PA_TIMER                   S5PV310_PA_TIMER
-
-#define S5PV310_PA_SDRAM               (0x40000000)
-#define S5P_PA_SDRAM                   S5PV310_PA_SDRAM
+#define S5PV310_PA_MDMA                        0x10810000
+#define S5PV310_PA_PDMA0               0x12680000
+#define S5PV310_PA_PDMA1               0x12690000
 
 #define S5PV310_PA_SYSMMU_MDMA         0x10A40000
 #define S5PV310_PA_SYSMMU_SSS          0x10A50000
 #define S5PV310_PA_SYSMMU_TV           0x12E20000
 #define S5PV310_PA_SYSMMU_MFC_L                0x13620000
 #define S5PV310_PA_SYSMMU_MFC_R                0x13630000
-#define S5PV310_SYSMMU_TOTAL_IPNUM     16
-#define S5P_SYSMMU_TOTAL_IPNUM         S5PV310_SYSMMU_TOTAL_IPNUM
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART                    S5PV310_PA_UART
+#define S5PV310_PA_GPIO1               0x11400000
+#define S5PV310_PA_GPIO2               0x11000000
+#define S5PV310_PA_GPIO3               0x03860000
+
+#define S5PV310_PA_MIPI_CSIS0          0x11880000
+#define S5PV310_PA_MIPI_CSIS1          0x11890000
+
+#define S5PV310_PA_HSMMC(x)            (0x12510000 + ((x) * 0x10000))
+
+#define S5PV310_PA_SROMC               0x12570000
+
+#define S5PV310_PA_UART                        0x13800000
+
+#define S5PV310_PA_IIC(x)              (0x13860000 + ((x) * 0x10000))
+
+#define S5PV310_PA_AC97                        0x139A0000
+
+#define S5PV310_PA_TIMER               0x139D0000
+
+#define S5PV310_PA_SDRAM               0x40000000
+
+#define S5PV310_PA_SPDIF               0xE1100000
+
+/* Compatibiltiy Defines */
+
 #define S3C_PA_HSMMC0                  S5PV310_PA_HSMMC(0)
 #define S3C_PA_HSMMC1                  S5PV310_PA_HSMMC(1)
 #define S3C_PA_HSMMC2                  S5PV310_PA_HSMMC(2)
 #define S3C_PA_IIC7                    S5PV310_PA_IIC(7)
 #define S3C_PA_RTC                     S5PV310_PA_RTC
 #define S3C_PA_WDT                     S5PV310_PA_WATCHDOG
+
+#define S5P_PA_CHIPID                  S5PV310_PA_CHIPID
 #define S5P_PA_MIPI_CSIS0              S5PV310_PA_MIPI_CSIS0
 #define S5P_PA_MIPI_CSIS1              S5PV310_PA_MIPI_CSIS1
+#define S5P_PA_ONENAND                 S5PC210_PA_ONENAND
+#define S5P_PA_ONENAND_DMA             S5PC210_PA_ONENAND_DMA
+#define S5P_PA_SDRAM                   S5PV310_PA_SDRAM
+#define S5P_PA_SROMC                   S5PV310_PA_SROMC
+#define S5P_PA_SYSCON                  S5PV310_PA_SYSCON
+#define S5P_PA_TIMER                   S5PV310_PA_TIMER
+
+/* UART */
+
+#define S3C_PA_UART                    S5PV310_PA_UART
+
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
+#define S5P_PA_UART4                   S5P_PA_UART(4)
+
+#define S5P_SZ_UART                    SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index 662fe85..598fc5c 100644 (file)
@@ -13,6 +13,9 @@
 #ifndef __ASM_ARM_ARCH_SYSMMU_H
 #define __ASM_ARM_ARCH_SYSMMU_H __FILE__
 
+#define S5PV310_SYSMMU_TOTAL_IPNUM     16
+#define S5P_SYSMMU_TOTAL_IPNUM         S5PV310_SYSMMU_TOTAL_IPNUM
+
 enum s5pv310_sysmmu_ips {
        SYSMMU_MDMA,
        SYSMMU_SSS,
@@ -32,7 +35,7 @@ enum s5pv310_sysmmu_ips {
        SYSMMU_MFC_R,
 };
 
-static char *sysmmu_ips_name[S5P_SYSMMU_TOTAL_IPNUM] = {
+static char *sysmmu_ips_name[S5PV310_SYSMMU_TOTAL_IPNUM] = {
        "SYSMMU_MDMA"   ,
        "SYSMMU_SSS"    ,
        "SYSMMU_FIMC0"  ,
index d43c5ef..bd3e1bf 100644 (file)
@@ -241,6 +241,9 @@ static struct locomo_platform_data locomo_info = {
 struct platform_device collie_locomo_device = {
        .name           = "locomo",
        .id             = 0,
+       .dev            = {
+               .platform_data  = &locomo_info,
+       },
        .num_resources  = ARRAY_SIZE(locomo_resources),
        .resource       = locomo_resources,
 };
index 4d1b4c5..0c8f6cf 100644 (file)
@@ -60,6 +60,8 @@ endchoice
 
 config MACH_AG5EVM
        bool "AG5EVM board"
+       select ARCH_REQUIRE_GPIOLIB
+       select SH_LCD_MIPI_DSI
        depends on ARCH_SH73A0
 
 config MACH_MACKEREL
index c18a740..4303a86 100644 (file)
 #include <linux/input/sh_keysc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
-
+#include <linux/sh_clk.h>
+#include <video/sh_mobile_lcdc.h>
+#include <video/sh_mipi_dsi.h>
 #include <sound/sh_fsi.h>
-
 #include <mach/hardware.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
@@ -183,11 +184,165 @@ static struct platform_device mmc_device = {
        .resource       = sh_mmcif_resources,
 };
 
+/* IrDA */
+static struct resource irda_resources[] = {
+       [0] = {
+               .start  = 0xE6D00000,
+               .end    = 0xE6D01FD4 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(95),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device irda_device = {
+       .name           = "sh_irda",
+       .id             = 0,
+       .resource       = irda_resources,
+       .num_resources  = ARRAY_SIZE(irda_resources),
+};
+
+static unsigned char lcd_backlight_seq[3][2] = {
+       { 0x04, 0x07 },
+       { 0x23, 0x80 },
+       { 0x03, 0x01 },
+};
+
+static void lcd_backlight_on(void)
+{
+       struct i2c_adapter *a;
+       struct i2c_msg msg;
+       int k;
+
+       a = i2c_get_adapter(1);
+       for (k = 0; a && k < 3; k++) {
+               msg.addr = 0x6d;
+               msg.buf = &lcd_backlight_seq[k][0];
+               msg.len = 2;
+               msg.flags = 0;
+               if (i2c_transfer(a, &msg, 1) != 1)
+                       break;
+       }
+}
+
+static void lcd_backlight_reset(void)
+{
+       gpio_set_value(GPIO_PORT235, 0);
+       mdelay(24);
+       gpio_set_value(GPIO_PORT235, 1);
+}
+
+static void lcd_on(void *board_data, struct fb_info *info)
+{
+       lcd_backlight_on();
+}
+
+static void lcd_off(void *board_data)
+{
+       lcd_backlight_reset();
+}
+
+/* LCDC0 */
+static const struct fb_videomode lcdc0_modes[] = {
+       {
+               .name           = "R63302(QHD)",
+               .xres           = 544,
+               .yres           = 961,
+               .left_margin    = 72,
+               .right_margin   = 600,
+               .hsync_len      = 16,
+               .upper_margin   = 8,
+               .lower_margin   = 8,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+       },
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+       .clock_source = LCDC_CLK_PERIPHERAL,
+       .ch[0] = {
+               .chan = LCDC_CHAN_MAINLCD,
+               .interface_type = RGB24,
+               .clock_divider = 1,
+               .flags = LCDC_FLAGS_DWPOL,
+               .lcd_size_cfg.width = 44,
+               .lcd_size_cfg.height = 79,
+               .bpp = 16,
+               .lcd_cfg = lcdc0_modes,
+               .num_cfg = ARRAY_SIZE(lcdc0_modes),
+               .board_cfg = {
+                       .display_on = lcd_on,
+                       .display_off = lcd_off,
+               },
+       }
+};
+
+static struct resource lcdc0_resources[] = {
+       [0] = {
+               .name   = "LCDC0",
+               .start  = 0xfe940000, /* P4-only space */
+               .end    = 0xfe943fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x580),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device lcdc0_device = {
+       .name           = "sh_mobile_lcdc_fb",
+       .num_resources  = ARRAY_SIZE(lcdc0_resources),
+       .resource       = lcdc0_resources,
+       .id             = 0,
+       .dev    = {
+               .platform_data  = &lcdc0_info,
+               .coherent_dma_mask = ~0,
+       },
+};
+
+/* MIPI-DSI */
+static struct resource mipidsi0_resources[] = {
+       [0] = {
+               .start  = 0xfeab0000,
+               .end    = 0xfeab3fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0xfeab4000,
+               .end    = 0xfeab7fff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct sh_mipi_dsi_info mipidsi0_info = {
+       .data_format    = MIPI_RGB888,
+       .lcd_chan       = &lcdc0_info.ch[0],
+       .vsynw_offset   = 20,
+       .clksrc         = 1,
+       .flags          = SH_MIPI_DSI_HSABM,
+};
+
+static struct platform_device mipidsi0_device = {
+       .name           = "sh-mipi-dsi",
+       .num_resources  = ARRAY_SIZE(mipidsi0_resources),
+       .resource       = mipidsi0_resources,
+       .id             = 0,
+       .dev    = {
+               .platform_data  = &mipidsi0_info,
+       },
+};
+
 static struct platform_device *ag5evm_devices[] __initdata = {
        &eth_device,
        &keysc_device,
        &fsi_device,
        &mmc_device,
+       &irda_device,
+       &lcdc0_device,
+       &mipidsi0_device,
 };
 
 static struct map_desc ag5evm_io_desc[] __initdata = {
@@ -224,6 +379,8 @@ void __init ag5evm_init_irq(void)
        __raw_writew(__raw_readw(PINTCR0A) | (2<<10), PINTCR0A);
 }
 
+#define DSI0PHYCR      0xe615006c
+
 static void __init ag5evm_init(void)
 {
        sh73a0_pinmux_init();
@@ -287,6 +444,26 @@ static void __init ag5evm_init(void)
        gpio_request(GPIO_FN_FSIAISLD, NULL);
        gpio_request(GPIO_FN_FSIAOSLD, NULL);
 
+       /* IrDA */
+       gpio_request(GPIO_FN_PORT241_IRDA_OUT, NULL);
+       gpio_request(GPIO_FN_PORT242_IRDA_IN,  NULL);
+       gpio_request(GPIO_FN_PORT243_IRDA_FIRSEL, NULL);
+
+       /* LCD panel */
+       gpio_request(GPIO_PORT217, NULL); /* RESET */
+       gpio_direction_output(GPIO_PORT217, 0);
+       mdelay(1);
+       gpio_set_value(GPIO_PORT217, 1);
+       mdelay(100);
+
+       /* LCD backlight controller */
+       gpio_request(GPIO_PORT235, NULL); /* RESET */
+       gpio_direction_output(GPIO_PORT235, 0);
+       lcd_backlight_reset();
+
+       /* MIPI-DSI clock setup */
+       __raw_writel(0x2a809010, DSI0PHYCR);
+
 #ifdef CONFIG_CACHE_L2X0
        /* Shared attribute override enable, 64K*8way */
        l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
index 3cf0951..81d6536 100644 (file)
@@ -1303,7 +1303,7 @@ static void __init ap4evb_init(void)
 
        lcdc_info.clock_source                  = LCDC_CLK_BUS;
        lcdc_info.ch[0].interface_type          = RGB18;
-       lcdc_info.ch[0].clock_divider           = 2;
+       lcdc_info.ch[0].clock_divider           = 3;
        lcdc_info.ch[0].flags                   = 0;
        lcdc_info.ch[0].lcd_size_cfg.width      = 152;
        lcdc_info.ch[0].lcd_size_cfg.height     = 91;
index 686b304..ef4613b 100644 (file)
@@ -347,7 +347,6 @@ static void __init g3evm_init(void)
        gpio_request(GPIO_FN_IRDA_OUT, NULL);
        gpio_request(GPIO_FN_IRDA_IN, NULL);
        gpio_request(GPIO_FN_IRDA_FIRSEL, NULL);
-       set_irq_type(evt2irq(0x480), IRQ_TYPE_LEVEL_LOW);
 
        sh7367_add_standard_devices();
 
index 7b15d21..1657eac 100644 (file)
  *     SW1     |       SW33
  *             | bit1 | bit2 | bit3 | bit4
  * -------------+------+------+------+-------
- * MMC0          OFF   |  OFF |  ON  |  ON  |  X
- * MMC1          ON    |  OFF |  ON  |  X   | ON
- * SDHI1  OFF  |  ON  |   X  |  OFF | ON
+ * MMC0   OFF  |  OFF |   X  |  ON  |  X       (Use MMCIF)
+ * SDHI1  OFF  |  ON  |   X  |  OFF |  X       (Use MFD_SH_MOBILE_SDHI)
  *
  */
 
@@ -304,7 +303,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                .lcd_cfg = mackerel_lcdc_modes,
                .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
                .interface_type         = RGB24,
-               .clock_divider          = 2,
+               .clock_divider          = 3,
                .flags                  = 0,
                .lcd_size_cfg.width     = 152,
                .lcd_size_cfg.height    = 91,
index 9aa8d68..e9731b5 100644 (file)
@@ -234,7 +234,9 @@ static int pllc2_set_rate(struct clk *clk, unsigned long rate)
 
        value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
 
-       __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
+       __raw_writel(value | ((idx + 19) << 24), PLLC2CR);
+
+       clk->rate = clk->freq_table[idx].frequency;
 
        return 0;
 }
index 720a714..7e58904 100644 (file)
@@ -118,8 +118,16 @@ static unsigned long pll_recalc(struct clk *clk)
 {
        unsigned long mult = 1;
 
-       if (__raw_readl(PLLECR) & (1 << clk->enable_bit))
+       if (__raw_readl(PLLECR) & (1 << clk->enable_bit)) {
                mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1);
+               /* handle CFG bit for PLL1 and PLL2 */
+               switch (clk->enable_bit) {
+               case 1:
+               case 2:
+                       if (__raw_readl(clk->enable_reg) & (1 << 20))
+                               mult *= 2;
+               }
+       }
 
        return clk->parent->rate * mult;
 }
@@ -212,7 +220,7 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2,
 static struct clk div4_clks[DIV4_NR] = {
        [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT),
-       [DIV4_M3] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
+       [DIV4_M3] = DIV4(FRQCRA, 12, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0),
        [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0),
@@ -255,10 +263,10 @@ static struct clk div6_clks[DIV6_NR] = {
 };
 
 enum { MSTP001,
-       MSTP125, MSTP116,
+       MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
        MSTP219,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP331, MSTP329, MSTP323, MSTP312,
+       MSTP331, MSTP329, MSTP325, MSTP323, MSTP312,
        MSTP411, MSTP410, MSTP403,
        MSTP_NR };
 
@@ -267,8 +275,14 @@ enum { MSTP001,
 
 static struct clk mstp_clks[MSTP_NR] = {
        [MSTP001] = MSTP(&div4_clks[DIV4_HP], SMSTPCR0, 1, 0), /* IIC2 */
+       [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* CEU1 */
+       [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* CSI2-RX1 */
+       [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU0 */
+       [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2-RX0 */
        [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
+       [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX0 */
        [MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
        [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */
        [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
        [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
@@ -279,6 +293,7 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
        [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+       [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
        [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
        [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
        [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
@@ -288,16 +303,32 @@ static struct clk mstp_clks[MSTP_NR] = {
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
 
+       /* DIV6 clocks */
+       CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
+       CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
+       CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+       CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
+       CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
+       CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
+       CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
+
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */
+       CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP129]), /* CEU1 */
+       CLKDEV_DEV_ID("sh-mobile-csi2.1", &mstp_clks[MSTP128]), /* CSI2-RX1 */
+       CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU0 */
+       CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2-RX0 */
        CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */
        CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */
+       CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */
@@ -308,6 +339,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
        CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
        CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
+       CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
        CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
index efd3687..3029aba 100644 (file)
@@ -6,13 +6,10 @@ LIST "RWT Setting"
 EW 0xE6020004, 0xA500
 EW 0xE6030004, 0xA500
 
-DD 0x01001000, 0x01001000
-
 LIST "GPIO Setting"
 EB 0xE6051013, 0xA2
 
 LIST "CPG"
-ED 0xE6150080, 0x00000180
 ED 0xE61500C0, 0x00000002
 
 WAIT 1, 0xFE40009C
@@ -37,6 +34,9 @@ ED 0xE615002C, 0x93000040
 
 WAIT 1, 0xFE40009C
 
+LIST "SUB/USBClk"
+ED 0xE6150080, 0x00000180
+
 LIST "BSC"
 ED 0xFEC10000, 0x00E0001B
 
@@ -53,7 +53,7 @@ ED 0xFE400048, 0x20C18505
 ED 0xFE40004C, 0x00110209
 ED 0xFE400010, 0x00000087
 
-WAIT 10, 0xFE40009C
+WAIT 30, 0xFE40009C
 
 ED 0xFE400084, 0x0000003F
 EB 0xFE500000, 0x00
@@ -84,7 +84,7 @@ ED 0xE6150004, 0x80331050
 
 WAIT 1, 0xFE40009C
 
-ED 0xE6150354, 0x00000002
+ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
 EB 0xE6053098, 0x11
index efd3687..3029aba 100644 (file)
@@ -6,13 +6,10 @@ LIST "RWT Setting"
 EW 0xE6020004, 0xA500
 EW 0xE6030004, 0xA500
 
-DD 0x01001000, 0x01001000
-
 LIST "GPIO Setting"
 EB 0xE6051013, 0xA2
 
 LIST "CPG"
-ED 0xE6150080, 0x00000180
 ED 0xE61500C0, 0x00000002
 
 WAIT 1, 0xFE40009C
@@ -37,6 +34,9 @@ ED 0xE615002C, 0x93000040
 
 WAIT 1, 0xFE40009C
 
+LIST "SUB/USBClk"
+ED 0xE6150080, 0x00000180
+
 LIST "BSC"
 ED 0xFEC10000, 0x00E0001B
 
@@ -53,7 +53,7 @@ ED 0xFE400048, 0x20C18505
 ED 0xFE40004C, 0x00110209
 ED 0xFE400010, 0x00000087
 
-WAIT 10, 0xFE40009C
+WAIT 30, 0xFE40009C
 
 ED 0xFE400084, 0x0000003F
 EB 0xFE500000, 0x00
@@ -84,7 +84,7 @@ ED 0xE6150004, 0x80331050
 
 WAIT 1, 0xFE40009C
 
-ED 0xE6150354, 0x00000002
+ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
 EB 0xE6053098, 0x11
index f78a1ea..ca5f9d1 100644 (file)
@@ -365,6 +365,7 @@ static struct intc_desc intca_desc __initdata = {
 
 enum {
        UNUSED_INTCS = 0,
+       ENABLED_INTCS,
 
        INTCS,
 
@@ -413,7 +414,7 @@ enum {
        CMT4,
        DSITX1_DSITX1_0,
        DSITX1_DSITX1_1,
-       /* MFIS2 */
+       MFIS2_INTCS, /* Priority always enabled using ENABLED_INTCS */
        CPORTS2R,
        /* CEC */
        JPU6E,
@@ -477,7 +478,7 @@ static struct intc_vect intcs_vectors[] = {
        INTCS_VECT(CMT4, 0x1980),
        INTCS_VECT(DSITX1_DSITX1_0, 0x19a0),
        INTCS_VECT(DSITX1_DSITX1_1, 0x19c0),
-       /* MFIS2 */
+       INTCS_VECT(MFIS2_INTCS, 0x1a00),
        INTCS_VECT(CPORTS2R, 0x1a20),
        /* CEC */
        INTCS_VECT(JPU6E, 0x1a80),
@@ -543,7 +544,7 @@ static struct intc_mask_reg intcs_mask_registers[] = {
          { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
            CMT4, DSITX1_DSITX1_0, DSITX1_DSITX1_1, 0 } },
        { 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */
-         { 0, CPORTS2R, 0, 0,
+         { MFIS2_INTCS, CPORTS2R, 0, 0,
            JPU6E, 0, 0, 0 } },
        { 0xffd20104, 0, 16, /* INTAMASK */
          { 0, 0, 0, 0, 0, 0, 0, 0,
@@ -571,7 +572,8 @@ static struct intc_prio_reg intcs_prio_registers[] = {
        { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } },
        { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DSITX1_DSITX1_0,
                                               DSITX1_DSITX1_1, 0 } },
-       { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0, CPORTS2R, 0, 0 } },
+       { 0xffd50038, 0, 16, 4, /* IPROS3 */ { ENABLED_INTCS, CPORTS2R,
+                                              0, 0 } },
        { 0xffd5003c, 0, 16, 4, /* IPRPS3 */ { JPU6E, 0, 0, 0 } },
 };
 
@@ -590,6 +592,7 @@ static struct resource intcs_resources[] __initdata = {
 
 static struct intc_desc intcs_desc __initdata = {
        .name = "sh7372-intcs",
+       .force_enable = ENABLED_INTCS,
        .resource = intcs_resources,
        .num_resources = ARRAY_SIZE(intcs_resources),
        .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
index 322d8d5..5d0e150 100644 (file)
@@ -252,10 +252,11 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id)
 
 void __init sh73a0_init_irq(void)
 {
-       void __iomem *gic_base = __io(0xf0001000);
+       void __iomem *gic_dist_base = __io(0xf0001000);
+       void __iomem *gic_cpu_base = __io(0xf0000100);
        void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
 
-       gic_init(0, 29, gic_base, gic_base);
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
 
        register_intc_controller(&intcs_desc);
 
index cacf17a..53677e4 100644 (file)
@@ -62,7 +62,7 @@
 #define SPEAR320_SMII1_BASE            0xAB000000
 #define SPEAR320_SMII1_SIZE            0x01000000
 
-#define SPEAR320_SOC_CONFIG_BASE       0xB4000000
+#define SPEAR320_SOC_CONFIG_BASE       0xB3000000
 #define SPEAR320_SOC_CONFIG_SIZE       0x00000070
 /* Interrupt registers offsets and masks */
 #define INT_STS_MASK_REG               0x04
index bd06620..ad80488 100644 (file)
@@ -207,9 +207,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
 
        if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
-               __set_irq_handler_unlocked(irq, handle_level_irq);
+               __set_irq_handler_unlocked(d->irq, handle_level_irq);
        else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
-               __set_irq_handler_unlocked(irq, handle_edge_irq);
+               __set_irq_handler_unlocked(d->irq, handle_edge_irq);
 
        return 0;
 }
index d772395..a217f68 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __MACH_CLK_H
 #define __MACH_CLK_H
 
+struct clk;
+
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
index 412f5c6..66cd3f4 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __MACH_CLKDEV_H
 #define __MACH_CLKDEV_H
 
+struct clk;
+
 static inline int __clk_get(struct clk *clk)
 {
        return 1;
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
new file mode 100644 (file)
index 0000000..04c7798
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Platform definitions for tegra-kbc keyboard input driver
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef ASMARM_ARCH_TEGRA_KBC_H
+#define ASMARM_ARCH_TEGRA_KBC_H
+
+#include <linux/types.h>
+#include <linux/input/matrix_keypad.h>
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define KBC_MAX_GPIO   24
+#define KBC_MAX_KPENT  8
+#else
+#define KBC_MAX_GPIO   20
+#define KBC_MAX_KPENT  7
+#endif
+
+#define KBC_MAX_ROW    16
+#define KBC_MAX_COL    8
+#define KBC_MAX_KEY    (KBC_MAX_ROW * KBC_MAX_COL)
+
+struct tegra_kbc_pin_cfg {
+       bool is_row;
+       unsigned char num;
+};
+
+struct tegra_kbc_wake_key {
+       u8 row:4;
+       u8 col:4;
+};
+
+struct tegra_kbc_platform_data {
+       unsigned int debounce_cnt;
+       unsigned int repeat_cnt;
+
+       unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
+       const struct tegra_kbc_wake_key *wake_cfg;
+
+       struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
+       const struct matrix_keymap_data *keymap_data;
+
+       bool wakeup;
+       bool use_fn_map;
+};
+#endif
index de7dfad..17c74d2 100644 (file)
 #define ICTLR_COP_IER_CLR      0x38
 #define ICTLR_COP_IEP_CLASS    0x3c
 
-static void (*gic_mask_irq)(struct irq_data *d);
-static void (*gic_unmask_irq)(struct irq_data *d);
+static void (*tegra_gic_mask_irq)(struct irq_data *d);
+static void (*tegra_gic_unmask_irq)(struct irq_data *d);
 
-#define irq_to_ictlr(irq) (((irq)-32) >> 5)
+#define irq_to_ictlr(irq) (((irq) - 32) >> 5)
 static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
-#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
+#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr) * 0x100)
 
 static void tegra_mask(struct irq_data *d)
 {
        void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
-       gic_mask_irq(d);
-       writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_CLR);
+       tegra_gic_mask_irq(d);
+       writel(1 << (d->irq & 31), addr+ICTLR_CPU_IER_CLR);
 }
 
 static void tegra_unmask(struct irq_data *d)
 {
        void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
-       gic_unmask_irq(d);
+       tegra_gic_unmask_irq(d);
        writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_SET);
 }
 
@@ -98,8 +98,8 @@ void __init tegra_init_irq(void)
                 IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
 
        gic = get_irq_chip(29);
-       gic_unmask_irq = gic->irq_unmask;
-       gic_mask_irq = gic->irq_mask;
+       tegra_gic_unmask_irq = gic->irq_unmask;
+       tegra_gic_mask_irq = gic->irq_mask;
        tegra_irq.irq_ack = gic->irq_ack;
 #ifdef CONFIG_SMP
        tegra_irq.irq_set_affinity = gic->irq_set_affinity;
index 3f7b5e9..9cdec5a 100644 (file)
@@ -2,17 +2,19 @@ menu "Versatile platform type"
        depends on ARCH_VERSATILE
 
 config ARCH_VERSATILE_PB
-       bool "Support Versatile/PB platform"
+       bool "Support Versatile Platform Baseboard for ARM926EJ-S"
        select CPU_ARM926T
        select MIGHT_HAVE_PCI
        default y
        help
-         Include support for the ARM(R) Versatile/PB platform.
+         Include support for the ARM(R) Versatile Platform Baseboard
+         for the ARM926EJ-S.
 
 config MACH_VERSATILE_AB
-       bool "Support Versatile/AB platform"
+       bool "Support Versatile Application Baseboard for ARM926EJ-S"
        select CPU_ARM926T
        help
-         Include support for the ARM(R) Versatile/AP platform.
+         Include support for the ARM(R) Versatile Application Baseboard
+         for the ARM926EJ-S.
 
 endmenu
index b1687b6..634bf1d 100644 (file)
@@ -39,7 +39,7 @@ volatile int __cpuinitdata pen_release = -1;
  * observers, irrespective of whether they're taking part in coherency
  * or not.  This is necessary for the hotplug code to work reliably.
  */
-static void write_pen_release(int val)
+static void __cpuinit write_pen_release(int val)
 {
        pen_release = val;
        smp_wmb();
index a9ed342..1edae65 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/mach/time.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
+#include <asm/hardware/sp810.h>
 
 #include <mach/motherboard.h>
 
@@ -50,8 +51,16 @@ void __init v2m_map_io(struct map_desc *tile, size_t num)
 
 static void __init v2m_timer_init(void)
 {
+       u32 scctrl;
+
        versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
 
+       /* Select 1MHz TIMCLK as the reference clock for SP804 timers */
+       scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+       scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
+       scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
+       writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+
        writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
        writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
 
index 9d30c6f..e4509ba 100644 (file)
@@ -405,7 +405,7 @@ config CPU_V6
 config CPU_32v6K
        bool "Support ARM V6K processor extensions" if !SMP
        depends on CPU_V6 || CPU_V7
-       default y if SMP && !(ARCH_MX3 || ARCH_OMAP2)
+       default y if SMP
        help
          Say Y here if your ARMv6 processor supports the 'K' extension.
          This enables the kernel to use some instructions not present
@@ -416,7 +416,7 @@ config CPU_32v6K
 # ARMv7
 config CPU_V7
        bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
-       select CPU_32v6K if !ARCH_OMAP2
+       select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
        select CPU_PABRT_V7
@@ -644,7 +644,7 @@ config ARM_THUMBEE
 
 config SWP_EMULATE
        bool "Emulate SWP/SWPB instructions"
-       depends on CPU_V7 && !CPU_V6
+       depends on !CPU_USE_DOMAINS && CPU_V7 && !CPU_V6
        select HAVE_PROC_CPU if PROC_FS
        default y if SMP
        help
index 170c9bb..f2ce38e 100644 (file)
@@ -49,7 +49,13 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask)
 static inline void cache_sync(void)
 {
        void __iomem *base = l2x0_base;
+
+#ifdef CONFIG_ARM_ERRATA_753970
+       /* write to an unmmapped register */
+       writel_relaxed(0, base + L2X0_DUMMY_REG);
+#else
        writel_relaxed(0, base + L2X0_CACHE_SYNC);
+#endif
        cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
index 5164069..cddd684 100644 (file)
@@ -297,6 +297,12 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
        memblock_reserve(__pa(_stext), _end - _stext);
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
+       if (phys_initrd_size &&
+           memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
+               pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+                      phys_initrd_start, phys_initrd_size);
+               phys_initrd_start = phys_initrd_size = 0;
+       }
        if (phys_initrd_size) {
                memblock_reserve(phys_initrd_start, phys_initrd_size);
 
index 0c1172b..8e33562 100644 (file)
@@ -264,6 +264,12 @@ __v7_setup:
        orreq   r10, r10, #1 << 6               @ set bit #6
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
 #endif
+#ifdef CONFIG_ARM_ERRATA_751472
+       cmp     r6, #0x30                       @ present prior to r3p0
+       mrclt   p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orrlt   r10, r10, #1 << 11              @ set bit #11
+       mcrlt   p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
 
 3:     mov     r10, #0
 #ifdef HARVARD_CACHE
index 8aa9744..c074e66 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include <linux/cpumask.h>
-#include <linux/err.h>
-#include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/oprofile.h>
@@ -46,6 +44,7 @@ char *op_name_from_perf_id(void)
                return NULL;
        }
 }
+#endif
 
 static int report_trace(struct stackframe *frame, void *d)
 {
@@ -85,7 +84,7 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
 
        /* frame pointers should strictly progress back up the stack
         * (towards higher addresses) */
-       if (tail >= buftail[0].fp)
+       if (tail + 1 >= buftail[0].fp)
                return NULL;
 
        return buftail[0].fp-1;
@@ -111,6 +110,7 @@ static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
+       /* provide backtrace support also in timer mode: */
        ops->backtrace          = arm_backtrace;
 
        return oprofile_perf_init(ops);
@@ -120,11 +120,3 @@ void __exit oprofile_arch_exit(void)
 {
        oprofile_perf_exit();
 }
-#else
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
-       pr_info("oprofile: hardware counters not available\n");
-       return -ENODEV;
-}
-void __exit oprofile_arch_exit(void) {}
-#endif /* CONFIG_HW_PERF_EVENTS */
index 3a70ebf..ff469c4 100644 (file)
@@ -95,6 +95,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
        case MACH_TYPE_MX35_3DS:
        case MACH_TYPE_PCM043:
        case MACH_TYPE_LILLY1131:
+       case MACH_TYPE_VPR200:
                uart_base = MX3X_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MAGX_ZN5:
@@ -102,6 +103,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
                break;
        case MACH_TYPE_MX51_BABBAGE:
        case MACH_TYPE_EUKREA_CPUIMX51SD:
+       case MACH_TYPE_MX51_3DS:
                uart_base = MX51_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MX50_RDP:
index 18fe3cb..b6333ae 100644 (file)
@@ -144,12 +144,9 @@ config OMAP_IOMMU_DEBUG
 config OMAP_IOMMU_IVA2
        bool
 
-choice
-       prompt "System timer"
-       default OMAP_32K_TIMER if !ARCH_OMAP15XX
-
 config OMAP_MPU_TIMER
        bool "Use mpu timer"
+       depends on ARCH_OMAP1
        help
          Select this option if you want to use the OMAP mpu timer. This
          timer provides more intra-tick resolution than the 32KHz timer,
@@ -158,6 +155,7 @@ config OMAP_MPU_TIMER
 config OMAP_32K_TIMER
        bool "Use 32KHz timer"
        depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+       default y if (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
        help
          Select this option if you want to enable the OMAP 32KHz timer.
          This timer saves power compared to the OMAP_MPU_TIMER, and has
@@ -165,8 +163,6 @@ config OMAP_32K_TIMER
          intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
          currently only available for OMAP16XX, 24XX, 34XX and OMAP4.
 
-endchoice
-
 config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
        bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
        depends on ARCH_OMAP3 && PM
index ea46440..862dda9 100644 (file)
@@ -36,8 +36,6 @@
 
 #define OMAP16XX_TIMER_32K_SYNCHRONIZED                0xfffbc410
 
-#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
-
 #include <linux/clocksource.h>
 
 /*
@@ -122,12 +120,24 @@ static DEFINE_CLOCK_DATA(cd);
 #define SC_MULT                4000000000u
 #define SC_SHIFT       17
 
-unsigned long long notrace sched_clock(void)
+static inline unsigned long long notrace _omap_32k_sched_clock(void)
 {
        u32 cyc = clocksource_32k.read(&clocksource_32k);
        return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
 }
 
+#ifndef CONFIG_OMAP_MPU_TIMER
+unsigned long long notrace sched_clock(void)
+{
+       return _omap_32k_sched_clock();
+}
+#else
+unsigned long long notrace omap_32k_sched_clock(void)
+{
+       return _omap_32k_sched_clock();
+}
+#endif
+
 static void notrace omap_update_sched_clock(void)
 {
        u32 cyc = clocksource_32k.read(&clocksource_32k);
@@ -160,7 +170,7 @@ void read_persistent_clock(struct timespec *ts)
        *ts = *tsp;
 }
 
-static int __init omap_init_clocksource_32k(void)
+int __init omap_init_clocksource_32k(void)
 {
        static char err[] __initdata = KERN_ERR
                        "%s: can't register clocksource!\n";
@@ -195,7 +205,3 @@ static int __init omap_init_clocksource_32k(void)
        }
        return 0;
 }
-arch_initcall(omap_init_clocksource_32k);
-
-#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
-
index c4b2b47..8536308 100644 (file)
@@ -53,7 +53,7 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
 #endif
 
 #define OMAP_DMA_ACTIVE                        0x01
-#define OMAP2_DMA_CSR_CLEAR_MASK       0xffe
+#define OMAP2_DMA_CSR_CLEAR_MASK       0xffffffff
 
 #define OMAP_FUNC_MUX_ARM_BASE         (0xfffe1000 + 0xec)
 
@@ -1873,7 +1873,7 @@ static int omap2_dma_handle_ch(int ch)
                printk(KERN_INFO "DMA misaligned error with device %d\n",
                       dma_chan[ch].dev_id);
 
-       p->dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR, ch);
+       p->dma_write(status, CSR, ch);
        p->dma_write(1 << ch, IRQSTATUS_L0, ch);
        /* read back the register to flush the write */
        p->dma_read(IRQSTATUS_L0, ch);
@@ -1893,10 +1893,9 @@ static int omap2_dma_handle_ch(int ch)
                        OMAP_DMA_CHAIN_INCQHEAD(chain_id);
 
                status = p->dma_read(CSR, ch);
+               p->dma_write(status, CSR, ch);
        }
 
-       p->dma_write(status, CSR, ch);
-
        if (likely(dma_chan[ch].callback != NULL))
                dma_chan[ch].callback(ch, status, dma_chan[ch].data);
 
index 6b8088e..29b2afb 100644 (file)
@@ -35,6 +35,9 @@ struct sys_timer;
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
+extern bool omap_32k_timer_init(void);
+extern int __init omap_init_clocksource_32k(void);
+extern unsigned long long notrace omap_32k_sched_clock(void);
 
 extern void omap_reserve(void);
 
index 459b319..49d3208 100644 (file)
@@ -322,15 +322,18 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
 
 struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
 {
-       struct omap_mbox *mbox;
-       int ret;
+       struct omap_mbox *_mbox, *mbox = NULL;
+       int i, ret;
 
        if (!mboxes)
                return ERR_PTR(-EINVAL);
 
-       for (mbox = *mboxes; mbox; mbox++)
-               if (!strcmp(mbox->name, name))
+       for (i = 0; (_mbox = mboxes[i]); i++) {
+               if (!strcmp(_mbox->name, name)) {
+                       mbox = _mbox;
                        break;
+               }
+       }
 
        if (!mbox)
                return ERR_PTR(-ENOENT);
index b77e018..a9aa5ad 100644 (file)
@@ -139,10 +139,11 @@ static const unsigned long mfpr_edge[] = {
 #define mfp_configured(p)      ((p)->config != -1)
 
 /*
- * perform a read-back of any MFPR register to make sure the
+ * perform a read-back of any valid MFPR register to make sure the
  * previous writings are finished
  */
-#define mfpr_sync()    (void)__raw_readl(mfpr_mmio_base + 0)
+static unsigned long mfpr_off_readback;
+#define mfpr_sync()    (void)__raw_readl(mfpr_mmio_base + mfpr_off_readback)
 
 static inline void __mfp_config_run(struct mfp_pin *p)
 {
@@ -248,6 +249,9 @@ void __init mfp_init_addr(struct mfp_addr_map *map)
 
        spin_lock_irqsave(&mfp_spin_lock, flags);
 
+       /* mfp offset for readback */
+       mfpr_off_readback = map[0].offset;
+
        for (p = map; p->start != MFP_PIN_INVALID; p++) {
                offset = p->offset;
                i = p->start;
index deb3995..557f8c5 100644 (file)
@@ -37,6 +37,14 @@ config S5P_GPIO_INT
        help
          Common code for the GPIO interrupts (other than external interrupts.)
 
+comment "System MMU"
+
+config S5P_SYSTEM_MMU
+       bool "S5P SYSTEM MMU"
+       depends on ARCH_S5PV310
+       help
+         Say Y here if you want to enable System MMU
+
 config S5P_DEV_FIMC0
        bool
        help
@@ -66,19 +74,3 @@ config S5P_DEV_CSIS1
        bool
        help
          Compile in platform device definitions for MIPI-CSIS channel 1
-
-menuconfig S5P_SYSMMU
-       bool "SYSMMU support"
-       depends on ARCH_S5PV310
-       help
-         This is a System MMU driver for Samsung ARM based Soc.
-
-if S5P_SYSMMU
-
-config S5P_SYSMMU_DEBUG
-       bool "Enables debug messages"
-       depends on S5P_SYSMMU
-       help
-         This enables SYSMMU driver debug massages.
-
-endif
index 92efe1a..4bd5cf9 100644 (file)
@@ -19,6 +19,7 @@ obj-y                         += clock.o
 obj-y                          += irq.o
 obj-$(CONFIG_S5P_EXT_INT)      += irq-eint.o
 obj-$(CONFIG_S5P_GPIO_INT)     += irq-gpioint.o
+obj-$(CONFIG_S5P_SYSTEM_MMU)   += sysmmu.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += irq-pm.o
 
@@ -30,4 +31,3 @@ obj-$(CONFIG_S5P_DEV_FIMC2)   += dev-fimc2.o
 obj-$(CONFIG_S5P_DEV_ONENAND)  += dev-onenand.o
 obj-$(CONFIG_S5P_DEV_CSIS0)    += dev-csis0.o
 obj-$(CONFIG_S5P_DEV_CSIS1)    += dev-csis1.o
-obj-$(CONFIG_S5P_SYSMMU)       += sysmmu.o
index 6a73428..afaf87f 100644 (file)
@@ -28,7 +28,7 @@
 static struct resource s5p_uart0_resource[] = {
        [0] = {
                .start  = S5P_PA_UART0,
-               .end    = S5P_PA_UART0 + S5P_SZ_UART,
+               .end    = S5P_PA_UART0 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -51,7 +51,7 @@ static struct resource s5p_uart0_resource[] = {
 static struct resource s5p_uart1_resource[] = {
        [0] = {
                .start  = S5P_PA_UART1,
-               .end    = S5P_PA_UART1 + S5P_SZ_UART,
+               .end    = S5P_PA_UART1 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -74,7 +74,7 @@ static struct resource s5p_uart1_resource[] = {
 static struct resource s5p_uart2_resource[] = {
        [0] = {
                .start  = S5P_PA_UART2,
-               .end    = S5P_PA_UART2 + S5P_SZ_UART,
+               .end    = S5P_PA_UART2 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -98,7 +98,7 @@ static struct resource s5p_uart3_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
        [0] = {
                .start  = S5P_PA_UART3,
-               .end    = S5P_PA_UART3 + S5P_SZ_UART,
+               .end    = S5P_PA_UART3 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -123,7 +123,7 @@ static struct resource s5p_uart4_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 4
        [0] = {
                .start  = S5P_PA_UART4,
-               .end    = S5P_PA_UART4 + S5P_SZ_UART,
+               .end    = S5P_PA_UART4 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -148,7 +148,7 @@ static struct resource s5p_uart5_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 5
        [0] = {
                .start  = S5P_PA_UART5,
-               .end    = S5P_PA_UART5 + S5P_SZ_UART,
+               .end    = S5P_PA_UART5 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
deleted file mode 100644 (file)
index db298fc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Samsung sysmmu driver
- *
- * 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.
-*/
-
-#ifndef __ASM_PLAT_S5P_SYSMMU_H
-#define __ASM_PLAT_S5P_SYSMMU_H __FILE__
-
-/* debug macro */
-#ifdef CONFIG_S5P_SYSMMU_DEBUG
-#define sysmmu_debug(fmt, arg...)      printk(KERN_INFO "[%s] " fmt, __func__, ## arg)
-#else
-#define sysmmu_debug(fmt, arg...)      do { } while (0)
-#endif
-
-#endif /* __ASM_PLAT_S5P_SYSMMU_H */
index d804914..ffe8a48 100644 (file)
@@ -16,8 +16,6 @@
 #include <mach/regs-sysmmu.h>
 #include <mach/sysmmu.h>
 
-#include <plat/sysmmu.h>
-
 struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
 
 void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
@@ -123,7 +121,7 @@ static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
                : "=r" (pg) : : "cc");          \
                pg &= ~0x3fff;
 
-       sysmmu_debug("CP15 TTBR0 : 0x%x\n", pg);
+       printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
 
        /* Set sysmmu page table base address */
        __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
index 236ef84..3e4bd81 100644 (file)
@@ -58,4 +58,3 @@ void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
 
        s3c_device_ts.dev.platform_data = npd;
 }
-EXPORT_SYMBOL(s3c24xx_ts_set_platdata);
index d9025e3..30518cc 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <linux/irq.h>
 
+struct sys_device;
+
 #ifdef CONFIG_PM
 
 extern __init int s3c_pm_init(void);
index 99ba678..6dd455b 100644 (file)
@@ -24,10 +24,10 @@ static inline void putc(int c)
 {
        void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE;
 
-       while (readl(base + UART01x_FR) & UART01x_FR_TXFF)
+       while (readl_relaxed(base + UART01x_FR) & UART01x_FR_TXFF)
                barrier();
 
-       writel(c, base + UART01x_DR);
+       writel_relaxed(c, base + UART01x_DR);
 }
 
 static inline void flush(void)
index 09e9372..8c8b24d 100644 (file)
@@ -14,6 +14,6 @@
 #ifndef __PLAT_VMALLOC_H
 #define __PLAT_VMALLOC_H
 
-#define VMALLOC_END            0xF0000000
+#define VMALLOC_END            0xF0000000UL
 
 #endif /* __PLAT_VMALLOC_H */
index 2fea897..9d6feaa 100644 (file)
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Sun Dec 12 23:24:27 2010
+# Last update: Mon Feb 7 08:59:27 2011
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -2240,7 +2240,7 @@ arm_ultimator2            MACH_ARM_ULTIMATOR2     ARM_ULTIMATOR2          2250
 vs_v210                        MACH_VS_V210            VS_V210                 2252
 vs_v212                        MACH_VS_V212            VS_V212                 2253
 hmt                    MACH_HMT                HMT                     2254
-suen3                  MACH_SUEN3              SUEN3                   2255
+km_kirkwood            MACH_KM_KIRKWOOD        KM_KIRKWOOD             2255
 vesper                 MACH_VESPER             VESPER                  2256
 str9                   MACH_STR9               STR9                    2257
 omap3_wl_ff            MACH_OMAP3_WL_FF        OMAP3_WL_FF             2258
@@ -2987,7 +2987,7 @@ pxwnas_500_1000           MACH_PXWNAS_500_1000    PXWNAS_500_1000         3001
 ea20                   MACH_EA20               EA20                    3002
 awm2                   MACH_AWM2               AWM2                    3003
 ti8148evm              MACH_TI8148EVM          TI8148EVM               3004
-tegra_seaboard         MACH_TEGRA_SEABOARD     TEGRA_SEABOARD          3005
+seaboard               MACH_SEABOARD           SEABOARD                3005
 linkstation_chlv2      MACH_LINKSTATION_CHLV2  LINKSTATION_CHLV2       3006
 tera_pro2_rack         MACH_TERA_PRO2_RACK     TERA_PRO2_RACK          3007
 rubys                  MACH_RUBYS              RUBYS                   3008
@@ -3190,7 +3190,7 @@ synergy                   MACH_SYNERGY            SYNERGY                 3205
 ics_if_voip            MACH_ICS_IF_VOIP        ICS_IF_VOIP             3206
 wlf_cragg_6410         MACH_WLF_CRAGG_6410     WLF_CRAGG_6410          3207
 punica                 MACH_PUNICA             PUNICA                  3208
-sbc_nt250              MACH_SBC_NT250          SBC_NT250               3209
+trimslice              MACH_TRIMSLICE          TRIMSLICE               3209
 mx27_wmultra           MACH_MX27_WMULTRA       MX27_WMULTRA            3210
 mackerel               MACH_MACKEREL           MACKEREL                3211
 fa9x27                 MACH_FA9X27             FA9X27                  3213
@@ -3219,3 +3219,100 @@ pivicc                  MACH_PIVICC             PIVICC                  3235
 pcm048                 MACH_PCM048             PCM048                  3236
 dds                    MACH_DDS                DDS                     3237
 chalten_xa1            MACH_CHALTEN_XA1        CHALTEN_XA1             3238
+ts48xx                 MACH_TS48XX             TS48XX                  3239
+tonga2_tfttimer                MACH_TONGA2_TFTTIMER    TONGA2_TFTTIMER         3240
+whistler               MACH_WHISTLER           WHISTLER                3241
+asl_phoenix            MACH_ASL_PHOENIX        ASL_PHOENIX             3242
+at91sam9263otlite      MACH_AT91SAM9263OTLITE  AT91SAM9263OTLITE       3243
+ddplug                 MACH_DDPLUG             DDPLUG                  3244
+d2plug                 MACH_D2PLUG             D2PLUG                  3245
+kzm9d                  MACH_KZM9D              KZM9D                   3246
+verdi_lte              MACH_VERDI_LTE          VERDI_LTE               3247
+nanozoom               MACH_NANOZOOM           NANOZOOM                3248
+dm3730_som_lv          MACH_DM3730_SOM_LV      DM3730_SOM_LV           3249
+dm3730_torpedo         MACH_DM3730_TORPEDO     DM3730_TORPEDO          3250
+anchovy                        MACH_ANCHOVY            ANCHOVY                 3251
+re2rev20               MACH_RE2REV20           RE2REV20                3253
+re2rev21               MACH_RE2REV21           RE2REV21                3254
+cns21xx                        MACH_CNS21XX            CNS21XX                 3255
+rider                  MACH_RIDER              RIDER                   3257
+nsk330                 MACH_NSK330             NSK330                  3258
+cns2133evb             MACH_CNS2133EVB         CNS2133EVB              3259
+z3_816x_mod            MACH_Z3_816X_MOD        Z3_816X_MOD             3260
+z3_814x_mod            MACH_Z3_814X_MOD        Z3_814X_MOD             3261
+beect                  MACH_BEECT              BEECT                   3262
+dma_thunderbug         MACH_DMA_THUNDERBUG     DMA_THUNDERBUG          3263
+omn_at91sam9g20                MACH_OMN_AT91SAM9G20    OMN_AT91SAM9G20         3264
+mx25_e2s_uc            MACH_MX25_E2S_UC        MX25_E2S_UC             3265
+mione                  MACH_MIONE              MIONE                   3266
+top9000_tcu            MACH_TOP9000_TCU        TOP9000_TCU             3267
+top9000_bsl            MACH_TOP9000_BSL        TOP9000_BSL             3268
+kingdom                        MACH_KINGDOM            KINGDOM                 3269
+armadillo460           MACH_ARMADILLO460       ARMADILLO460            3270
+lq2                    MACH_LQ2                LQ2                     3271
+sweda_tms2             MACH_SWEDA_TMS2         SWEDA_TMS2              3272
+mx53_loco              MACH_MX53_LOCO          MX53_LOCO               3273
+acer_a8                        MACH_ACER_A8            ACER_A8                 3275
+acer_gauguin           MACH_ACER_GAUGUIN       ACER_GAUGUIN            3276
+guppy                  MACH_GUPPY              GUPPY                   3277
+mx61_ard               MACH_MX61_ARD           MX61_ARD                3278
+tx53                   MACH_TX53               TX53                    3279
+omapl138_case_a3       MACH_OMAPL138_CASE_A3   OMAPL138_CASE_A3        3280
+uemd                   MACH_UEMD               UEMD                    3281
+ccwmx51mut             MACH_CCWMX51MUT         CCWMX51MUT              3282
+rockhopper             MACH_ROCKHOPPER         ROCKHOPPER              3283
+nookcolor              MACH_NOOKCOLOR          NOOKCOLOR               3284
+hkdkc100               MACH_HKDKC100           HKDKC100                3285
+ts42xx                 MACH_TS42XX             TS42XX                  3286
+aebl                   MACH_AEBL               AEBL                    3287
+wario                  MACH_WARIO              WARIO                   3288
+gfs_spm                        MACH_GFS_SPM            GFS_SPM                 3289
+cm_t3730               MACH_CM_T3730           CM_T3730                3290
+isc3                   MACH_ISC3               ISC3                    3291
+rascal                 MACH_RASCAL             RASCAL                  3292
+hrefv60                        MACH_HREFV60            HREFV60                 3293
+tpt_2_0                        MACH_TPT_2_0            TPT_2_0                 3294
+pyramid_td             MACH_PYRAMID_TD         PYRAMID_TD              3295
+splendor               MACH_SPLENDOR           SPLENDOR                3296
+guf_planet             MACH_GUF_PLANET         GUF_PLANET              3297
+msm8x60_qt             MACH_MSM8X60_QT         MSM8X60_QT              3298
+htc_hd_mini            MACH_HTC_HD_MINI        HTC_HD_MINI             3299
+athene                 MACH_ATHENE             ATHENE                  3300
+deep_r_ek_1            MACH_DEEP_R_EK_1        DEEP_R_EK_1             3301
+vivow_ct               MACH_VIVOW_CT           VIVOW_CT                3302
+nery_1000              MACH_NERY_1000          NERY_1000               3303
+rfl109145_ssrv         MACH_RFL109145_SSRV     RFL109145_SSRV          3304
+nmh                    MACH_NMH                NMH                     3305
+wn802t                 MACH_WN802T             WN802T                  3306
+dragonet               MACH_DRAGONET           DRAGONET                3307
+geneva_b               MACH_GENEVA_B           GENEVA_B                3308
+at91sam9263desk16l     MACH_AT91SAM9263DESK16L AT91SAM9263DESK16L      3309
+bcmhana_sv             MACH_BCMHANA_SV         BCMHANA_SV              3310
+bcmhana_tablet         MACH_BCMHANA_TABLET     BCMHANA_TABLET          3311
+koi                    MACH_KOI                KOI                     3312
+ts4800                 MACH_TS4800             TS4800                  3313
+tqma9263               MACH_TQMA9263           TQMA9263                3314
+holiday                        MACH_HOLIDAY            HOLIDAY                 3315
+dma_6410               MACH_DMA6410            DMA6410                 3316
+pcats_overlay          MACH_PCATS_OVERLAY      PCATS_OVERLAY           3317
+hwgw6410               MACH_HWGW6410           HWGW6410                3318
+shenzhou               MACH_SHENZHOU           SHENZHOU                3319
+cwme9210               MACH_CWME9210           CWME9210                3320
+cwme9210js             MACH_CWME9210JS         CWME9210JS              3321
+pgs_v1                 MACH_PGS_SITARA         PGS_SITARA              3322
+colibri_tegra2         MACH_COLIBRI_TEGRA2     COLIBRI_TEGRA2          3323
+w21                    MACH_W21                W21                     3324
+polysat1               MACH_POLYSAT1           POLYSAT1                3325
+dataway                        MACH_DATAWAY            DATAWAY                 3326
+cobral138              MACH_COBRAL138          COBRAL138               3327
+roverpcs8              MACH_ROVERPCS8          ROVERPCS8               3328
+marvelc                        MACH_MARVELC            MARVELC                 3329
+navefihid              MACH_NAVEFIHID          NAVEFIHID               3330
+dm365_cv100            MACH_DM365_CV100        DM365_CV100             3331
+able                   MACH_ABLE               ABLE                    3332
+legacy                 MACH_LEGACY             LEGACY                  3333
+icong                  MACH_ICONG              ICONG                   3334
+rover_g8               MACH_ROVER_G8           ROVER_G8                3335
+t5388p                 MACH_T5388P             T5388P                  3336
+dingo                  MACH_DINGO              DINGO                   3337
+goflexhome             MACH_GOFLEXHOME         GOFLEXHOME              3338
index 313b130..cd2062f 100644 (file)
@@ -1,8 +1,8 @@
 config AVR32
        def_bool y
-       # With EMBEDDED=n, we get lots of stuff automatically selected
+       # With EXPERT=n, we get lots of stuff automatically selected
        # that we usually don't need on AVR32.
-       select EMBEDDED
+       select EXPERT
        select HAVE_CLK
        select HAVE_OPROFILE
        select HAVE_KPROBES
index 92ecd84..bc7e8ae 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASM_AVR32_PGALLOC_H
 #define __ASM_AVR32_PGALLOC_H
 
+#include <linux/mm.h>
 #include <linux/quicklist.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 0a221d4..c09577d 100644 (file)
@@ -30,6 +30,9 @@ config BLACKFIN
        select HAVE_KERNEL_LZO if RAMKERNEL
        select HAVE_OPROFILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select IRQ_PER_CPU if SMP
 
 config GENERIC_CSUM
        def_bool y
@@ -44,15 +47,6 @@ config ZONE_DMA
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config GENERIC_GPIO
        def_bool y
 
@@ -254,11 +248,6 @@ config HOTPLUG_CPU
        depends on SMP && HOTPLUG
        default y
 
-config IRQ_PER_CPU
-       bool
-       depends on SMP
-       default y
-
 config HAVE_LEGACY_PER_CPU_AREA
        def_bool y
        depends on SMP
index c0b988e..db8d38a 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 864af5b..3e50d78 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 7b6a337..362f59d 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_AIO is not set
 CONFIG_SLAB=y
index 4faa6b4..023ff0d 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 9d893eb..4e5a121 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 97a2767..cd0636b 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index f847743..9f8fc84 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 0e7262c..ccc432b 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 4d14a00..5666954 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index fbee9d7..ac22124 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 05dd11d..944404b 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index bcb14d1..b7c8451 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 4cf4510..7e67ba3 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 843aaa5..141e593 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index dae7adf..97ebe09 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index f341424..c245754 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 8c7e08f..baf1c15 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index bd3cb76..707cbf8 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index 82224f3..4596935 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index 433598c..df26758 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index ded7d84..6c7b215 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index 0ebc7d9..f503136 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLOB=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_CFQ is not set
index 700fb70..7450127 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index b40156d..5e797cf 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_ELF_CORE is not set
index be866d9..a566a2f 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index b64bdf7..8538095 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_ELF_CORE is not set
index 1bccd9a..d496ae9 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
index 00ce899..65f6421 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
index 1ff9f14..7dbc664 100644 (file)
@@ -10,6 +10,7 @@
 #define __BFIN_ASM_SERIAL_H__
 
 #include <linux/serial_core.h>
+#include <linux/spinlock.h>
 #include <mach/anomaly.h>
 #include <mach/bfin_serial.h>
 
@@ -41,6 +42,7 @@ struct bfin_serial_port {
        struct circ_buf rx_dma_buf;
        struct timer_list rx_dma_timer;
        int rx_dma_nrows;
+       spinlock_t rx_lock;
        unsigned int tx_dma_channel;
        unsigned int rx_dma_channel;
        struct work_struct tx_dma_workqueue;
index 250f4d4..06a5e67 100644 (file)
@@ -13,6 +13,8 @@
 .align 2
 
 ENTRY(_outsl)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -20,10 +22,12 @@ ENTRY(_outsl)
        LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
 .Llong_loop_s: R0 = [P1++];
 .Llong_loop_e: [P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsl)
 
 ENTRY(_outsw)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -31,10 +35,12 @@ ENTRY(_outsw)
        LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
 .Lword_loop_s: R0 = W[P1++];
 .Lword_loop_e: W[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsw)
 
 ENTRY(_outsb)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -42,10 +48,12 @@ ENTRY(_outsb)
        LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
 .Lbyte_loop_s: R0 = B[P1++];
 .Lbyte_loop_e: B[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsb)
 
 ENTRY(_outsw_8)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -56,5 +64,5 @@ ENTRY(_outsw_8)
                R0 = R0 << 8;
                R0 = R0 + R1;
 .Lword8_loop_e: W[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsw_8)
index 790c767..ab4a925 100644 (file)
@@ -58,6 +58,8 @@
 1:
 .ifeqs "\flushins", BROK_FLUSH_INST
        \flushins [P0++];
+       nop;
+       nop;
 2:     nop;
 .else
 2:     \flushins [P0++];
index 613e628..0a7a4c1 100644 (file)
@@ -54,6 +54,8 @@ config CRIS
        bool
        default y
        select HAVE_IDE
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
 config HZ
        int
@@ -67,10 +69,6 @@ menu "General setup"
 
 source "fs/Kconfig.binfmt"
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
 config ETRAX_CMDLINE
        string "Kernel command line"
        default "root=/dev/mtdblock3"
index a0c0df8..7328a7c 100644 (file)
@@ -104,43 +104,21 @@ static void (*interrupt[NR_IRQS])(void) = {
        IRQ31_interrupt
 };
 
-static void enable_crisv10_irq(unsigned int irq);
-
-static unsigned int startup_crisv10_irq(unsigned int irq)
-{
-       enable_crisv10_irq(irq);
-       return 0;
-}
-
-#define shutdown_crisv10_irq   disable_crisv10_irq
-
-static void enable_crisv10_irq(unsigned int irq)
-{
-       crisv10_unmask_irq(irq);
-}
-
-static void disable_crisv10_irq(unsigned int irq)
-{
-       crisv10_mask_irq(irq);
-}
-
-static void ack_crisv10_irq(unsigned int irq)
+static void enable_crisv10_irq(struct irq_data *data)
 {
+       crisv10_unmask_irq(data->irq);
 }
 
-static void end_crisv10_irq(unsigned int irq)
+static void disable_crisv10_irq(struct irq_data *data)
 {
+       crisv10_mask_irq(data->irq);
 }
 
 static struct irq_chip crisv10_irq_type = {
-       .name =        "CRISv10",
-       .startup =     startup_crisv10_irq,
-       .shutdown =    shutdown_crisv10_irq,
-       .enable =      enable_crisv10_irq,
-       .disable =     disable_crisv10_irq,
-       .ack =         ack_crisv10_irq,
-       .end =         end_crisv10_irq,
-       .set_affinity = NULL
+       .name           = "CRISv10",
+       .irq_shutdown   = disable_crisv10_irq,
+       .irq_enable     = enable_crisv10_irq,
+       .irq_disable    = disable_crisv10_irq,
 };
 
 void weird_irq(void);
@@ -221,7 +199,8 @@ init_IRQ(void)
 
        /* Initialize IRQ handler descriptors. */
        for(i = 2; i < NR_IRQS; i++) {
-               irq_desc[i].chip = &crisv10_irq_type;
+               set_irq_desc_and_handler(i, &crisv10_irq_type,
+                                        handle_simple_irq);
                set_int_vector(i, interrupt[i]);
        }
 
index 2ed48ae..0ad9db5 100644 (file)
@@ -291,54 +291,33 @@ void crisv32_unmask_irq(int irq)
 }
 
 
-static unsigned int startup_crisv32_irq(unsigned int irq)
+static void enable_crisv32_irq(struct irq_data *data)
 {
-       crisv32_unmask_irq(irq);
-       return 0;
-}
-
-static void shutdown_crisv32_irq(unsigned int irq)
-{
-       crisv32_mask_irq(irq);
+       crisv32_unmask_irq(data->irq);
 }
 
-static void enable_crisv32_irq(unsigned int irq)
+static void disable_crisv32_irq(struct irq_data *data)
 {
-       crisv32_unmask_irq(irq);
+       crisv32_mask_irq(data->irq);
 }
 
-static void disable_crisv32_irq(unsigned int irq)
-{
-       crisv32_mask_irq(irq);
-}
-
-static void ack_crisv32_irq(unsigned int irq)
-{
-}
-
-static void end_crisv32_irq(unsigned int irq)
-{
-}
-
-int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
+static int set_affinity_crisv32_irq(struct irq_data *data,
+                                   const struct cpumask *dest, bool force)
 {
        unsigned long flags;
+
        spin_lock_irqsave(&irq_lock, flags);
-       irq_allocations[irq - FIRST_IRQ].mask = *dest;
+       irq_allocations[data->irq - FIRST_IRQ].mask = *dest;
        spin_unlock_irqrestore(&irq_lock, flags);
-
        return 0;
 }
 
 static struct irq_chip crisv32_irq_type = {
-       .name =        "CRISv32",
-       .startup =     startup_crisv32_irq,
-       .shutdown =    shutdown_crisv32_irq,
-       .enable =      enable_crisv32_irq,
-       .disable =     disable_crisv32_irq,
-       .ack =         ack_crisv32_irq,
-       .end =         end_crisv32_irq,
-       .set_affinity = set_affinity_crisv32_irq
+       .name                   = "CRISv32",
+       .irq_shutdown           = disable_crisv32_irq,
+       .irq_enable             = enable_crisv32_irq,
+       .irq_disable            = disable_crisv32_irq,
+       .irq_set_affinity       = set_affinity_crisv32_irq,
 };
 
 void
@@ -472,7 +451,8 @@ init_IRQ(void)
 
        /* Point all IRQ's to bad handlers. */
        for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
-               irq_desc[j].chip = &crisv32_irq_type;
+               set_irq_chip_and_handler(j, &crisv32_irq_type,
+                                        handle_simple_irq);
                set_exception_vector(i, interrupt[j]);
        }
 
index 590f72c..71854d4 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_BLK_DEV_BSG is not set
index 1b2853e..a85aabf 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_BLK_DEV_BSG is not set
index f73d38c..87c7227 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_BLK_DEV_BSG is not set
index 469f7f9..c346952 100644 (file)
@@ -62,7 +62,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
+               seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -93,8 +93,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
                printk("do_IRQ: stack overflow: %lX\n", sp);
                show_stack(NULL, (unsigned long *)sp);
        }
-       __do_IRQ(irq);
-        irq_exit();
+       generic_handle_irq(irq);
+       irq_exit();
        set_irq_regs(old_regs);
 }
 
index 4422189..c49be84 100644 (file)
@@ -72,11 +72,6 @@ SECTIONS
        INIT_TEXT_SECTION(PAGE_SIZE)
        .init.data : { INIT_DATA }
        .init.setup : { INIT_SETUP(16) }
-#ifdef CONFIG_ETRAX_ARCH_V32
-       __start___param = .;
-       __param : { *(__param) }
-       __stop___param = .;
-#endif
        .initcall.init : {
                INIT_CALLS
        }
index f6bcb03..747499a 100644 (file)
@@ -5,6 +5,7 @@ config FRV
        select HAVE_ARCH_TRACEHOOK
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
+       select HAVE_GENERIC_HARDIRQS
 
 config ZONE_DMA
        bool
@@ -29,14 +30,6 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default n
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       default y
-
 config TIME_LOW_RES
        bool
        default y
index b8ebe9e..b1b7926 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_MMU=y
 CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y
index 65f897d..6df692d 100644 (file)
@@ -2,6 +2,8 @@ config H8300
        bool
        default y
        select HAVE_IDE
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
 config SYMBOL_PREFIX
        string
@@ -47,10 +49,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
index 342f777..042425a 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
index c25dc2c..7643d39 100644 (file)
@@ -38,34 +38,30 @@ static inline int is_ext_irq(unsigned int irq)
        return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS));
 }
 
-static void h8300_enable_irq(unsigned int irq)
+static void h8300_enable_irq(struct irq_data *data)
 {
-       if (is_ext_irq(irq))
-               IER_REGS |= 1 << (irq - EXT_IRQ0);
+       if (is_ext_irq(data->irq))
+               IER_REGS |= 1 << (data->irq - EXT_IRQ0);
 }
 
-static void h8300_disable_irq(unsigned int irq)
+static void h8300_disable_irq(struct irq_data *data)
 {
-       if (is_ext_irq(irq))
-               IER_REGS &= ~(1 << (irq - EXT_IRQ0));
+       if (is_ext_irq(data->irq))
+               IER_REGS &= ~(1 << (data->irq - EXT_IRQ0));
 }
 
-static void h8300_end_irq(unsigned int irq)
+static unsigned int h8300_startup_irq(struct irq_data *data)
 {
-}
-
-static unsigned int h8300_startup_irq(unsigned int irq)
-{
-       if (is_ext_irq(irq))
-               return h8300_enable_irq_pin(irq);
+       if (is_ext_irq(data->irq))
+               return h8300_enable_irq_pin(data->irq);
        else
                return 0;
 }
 
-static void h8300_shutdown_irq(unsigned int irq)
+static void h8300_shutdown_irq(struct irq_data *data)
 {
-       if (is_ext_irq(irq))
-               h8300_disable_irq_pin(irq);
+       if (is_ext_irq(data->irq))
+               h8300_disable_irq_pin(data->irq);
 }
 
 /*
@@ -73,12 +69,10 @@ static void h8300_shutdown_irq(unsigned int irq)
  */
 struct irq_chip h8300irq_chip = {
        .name           = "H8300-INTC",
-       .startup        = h8300_startup_irq,
-       .shutdown       = h8300_shutdown_irq,
-       .enable         = h8300_enable_irq,
-       .disable        = h8300_disable_irq,
-       .ack            = NULL,
-       .end            = h8300_end_irq,
+       .irq_startup    = h8300_startup_irq,
+       .irq_shutdown   = h8300_shutdown_irq,
+       .irq_enable     = h8300_enable_irq,
+       .irq_disable    = h8300_disable_irq,
 };
 
 #if defined(CONFIG_RAMKERNEL)
@@ -160,18 +154,14 @@ void __init init_IRQ(void)
 
        setup_vector();
 
-       for (c = 0; c < NR_IRQS; c++) {
-               irq_desc[c].status = IRQ_DISABLED;
-               irq_desc[c].action = NULL;
-               irq_desc[c].depth = 1;
-               irq_desc[c].chip = &h8300irq_chip;
-       }
+       for (c = 0; c < NR_IRQS; c++)
+               set_irq_chip_and_handler(c, &h8300irq_chip, handle_simple_irq);
 }
 
 asmlinkage void do_IRQ(int irq)
 {
        irq_enter();
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
 }
 
@@ -192,7 +182,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        goto unlock;
                seq_printf(p, "%3d: ",i);
                seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
+               seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
                seq_printf(p, "-%-8s", irq_desc[i].name);
                seq_printf(p, "  %s", action->name);
 
index e0f5b6d..fcf3b43 100644 (file)
@@ -22,6 +22,10 @@ config IA64
        select HAVE_KVM
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select GENERIC_PENDING_IRQ if SMP
+       select IRQ_PER_CPU
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -678,28 +682,6 @@ source "arch/ia64/kvm/Kconfig"
 
 source "lib/Kconfig"
 
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       bool
-       default y
-
-config GENERIC_PENDING_IRQ
-       bool
-       depends on GENERIC_HARDIRQS && SMP
-       default y
-
-config IRQ_PER_CPU
-       bool
-       default y
-
 config IOMMU_HELPER
        def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB)
 
index 5c291d6..ef4c1e4 100644 (file)
@@ -7,6 +7,9 @@ config M32R
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
+       select GENERIC_IRQ_PROBE
 
 config SBUS
        bool
@@ -19,14 +22,6 @@ config ZONE_DMA
        bool
        default y
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_IRQ_PROBE
-       bool
-       default y
-
 config NO_IOPORT
        def_bool y
 
index 816c3ec..a3d727e 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=15
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 8478568..b833416 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 354a964..7c90ce2 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 9022307..367d07c 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 3726068..cb11384 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 6136fad..3bff779 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index dce1fc7..75246c9 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index b204e2e..27cefd4 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 5aa4ea9..5087a51 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 8494c6a..50c6f52 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 1df293b..a3cfaae 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 7db26f1..76eaf38 100644 (file)
@@ -40,8 +40,10 @@ int show_interrupts(struct seq_file *p, void *v)
        }
 
        if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
+               struct irq_desc *desc = irq_to_desc(i);
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+               action = desc->action;
                if (!action)
                        goto skip;
                seq_printf(p, "%3d: ",i);
@@ -51,7 +53,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
+               seq_printf(p, " %14s", desc->irq_data.chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -59,7 +61,7 @@ int show_interrupts(struct seq_file *p, void *v)
 
                seq_putc(p, '\n');
 skip:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
        }
        return 0;
 }
@@ -78,7 +80,7 @@ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
        /* FIXME M32R */
 #endif
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
        set_irq_regs(old_regs);
 
index 402a59d..4a693d0 100644 (file)
@@ -39,39 +39,30 @@ static void enable_m32104ut_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_m32104ut(unsigned int irq)
+static void mask_m32104ut_irq(struct irq_data *data)
 {
-       disable_m32104ut_irq(irq);
+       disable_m32104ut_irq(data->irq);
 }
 
-static void end_m32104ut_irq(unsigned int irq)
+static void unmask_m32104ut_irq(struct irq_data *data)
 {
-       enable_m32104ut_irq(irq);
+       enable_m32104ut_irq(data->irq);
 }
 
-static unsigned int startup_m32104ut_irq(unsigned int irq)
+static void shutdown_m32104ut_irq(struct irq_data *data)
 {
-       enable_m32104ut_irq(irq);
-       return (0);
-}
-
-static void shutdown_m32104ut_irq(unsigned int irq)
-{
-       unsigned long port;
+       unsigned int irq = data->irq;
+       unsigned long port = irq2port(irq);
 
-       port = irq2port(irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32104ut_irq_type =
 {
-       .name = "M32104UT-IRQ",
-       .startup = startup_m32104ut_irq,
-       .shutdown = shutdown_m32104ut_irq,
-       .enable = enable_m32104ut_irq,
-       .disable = disable_m32104ut_irq,
-       .ack = mask_and_ack_m32104ut,
-       .end = end_m32104ut_irq
+       .name           = "M32104UT-IRQ",
+       .irq_shutdown   = shutdown_m32104ut_irq,
+       .irq_unmask     = unmask_m32104ut_irq,
+       .irq_mask       = mask_m32104ut_irq,
 };
 
 void __init init_IRQ(void)
@@ -85,36 +76,29 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/
-       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].chip = &m32104ut_irq_type;
-       irq_desc[M32R_IRQ_INT0].action = 0;
-       irq_desc[M32R_IRQ_INT0].depth = 1;
-       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; /* "H" level sense */
+       set_irq_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type,
+                                handle_level_irq);
+       /* "H" level sense */
+       cu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11;
        disable_m32104ut_irq(M32R_IRQ_INT0);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &m32104ut_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &m32104ut_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &m32104ut_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_SIO0_S);
 #endif /* CONFIG_SERIAL_M32R_SIO */
index 80b1a02..2074bcc 100644 (file)
@@ -45,39 +45,30 @@ static void enable_m32700ut_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_m32700ut(unsigned int irq)
+static void mask_m32700ut(struct irq_data *data)
 {
-       disable_m32700ut_irq(irq);
+       disable_m32700ut_irq(data->irq);
 }
 
-static void end_m32700ut_irq(unsigned int irq)
+static void unmask_m32700ut(struct irq_data *data)
 {
-       enable_m32700ut_irq(irq);
+       enable_m32700ut_irq(data->irq);
 }
 
-static unsigned int startup_m32700ut_irq(unsigned int irq)
-{
-       enable_m32700ut_irq(irq);
-       return (0);
-}
-
-static void shutdown_m32700ut_irq(unsigned int irq)
+static void shutdown_m32700ut(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32700ut_irq_type =
 {
-       .name = "M32700UT-IRQ",
-       .startup = startup_m32700ut_irq,
-       .shutdown = shutdown_m32700ut_irq,
-       .enable = enable_m32700ut_irq,
-       .disable = disable_m32700ut_irq,
-       .ack = mask_and_ack_m32700ut,
-       .end = end_m32700ut_irq
+       .name           = "M32700UT-IRQ",
+       .irq_shutdown   = shutdown_m32700ut,
+       .irq_mask       = mask_m32700ut,
+       .irq_unmask     = unmask_m32700ut
 };
 
 /*
@@ -99,7 +90,6 @@ static void disable_m32700ut_pld_irq(unsigned int irq)
        unsigned int pldirq;
 
        pldirq = irq2pldirq(irq);
-//     disable_m32700ut_irq(M32R_IRQ_INT1);
        port = pldirq2port(pldirq);
        data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
        outw(data, port);
@@ -111,50 +101,38 @@ static void enable_m32700ut_pld_irq(unsigned int irq)
        unsigned int pldirq;
 
        pldirq = irq2pldirq(irq);
-//     enable_m32700ut_irq(M32R_IRQ_INT1);
        port = pldirq2port(pldirq);
        data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
        outw(data, port);
 }
 
-static void mask_and_ack_m32700ut_pld(unsigned int irq)
-{
-       disable_m32700ut_pld_irq(irq);
-//     mask_and_ack_m32700ut(M32R_IRQ_INT1);
-}
-
-static void end_m32700ut_pld_irq(unsigned int irq)
+static void mask_m32700ut_pld(struct irq_data *data)
 {
-       enable_m32700ut_pld_irq(irq);
-       end_m32700ut_irq(M32R_IRQ_INT1);
+       disable_m32700ut_pld_irq(data->irq);
 }
 
-static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
+static void unmask_m32700ut_pld(struct irq_data *data)
 {
-       enable_m32700ut_pld_irq(irq);
-       return (0);
+       enable_m32700ut_pld_irq(data->irq);
+       enable_m32700ut_irq(M32R_IRQ_INT1);
 }
 
-static void shutdown_m32700ut_pld_irq(unsigned int irq)
+static void shutdown_m32700ut_pld_irq(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2pldirq(irq);
-//     shutdown_m32700ut_irq(M32R_IRQ_INT1);
+       pldirq = irq2pldirq(data->irq);
        port = pldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-       .name = "M32700UT-PLD-IRQ",
-       .startup = startup_m32700ut_pld_irq,
-       .shutdown = shutdown_m32700ut_pld_irq,
-       .enable = enable_m32700ut_pld_irq,
-       .disable = disable_m32700ut_pld_irq,
-       .ack = mask_and_ack_m32700ut_pld,
-       .end = end_m32700ut_pld_irq
+       .name           = "M32700UT-PLD-IRQ",
+       .irq_shutdown   = shutdown_m32700ut_pld_irq,
+       .irq_mask       = mask_m32700ut_pld,
+       .irq_unmask     = unmask_m32700ut_pld,
 };
 
 /*
@@ -188,42 +166,33 @@ static void enable_m32700ut_lanpld_irq(unsigned int irq)
        outw(data, port);
 }
 
-static void mask_and_ack_m32700ut_lanpld(unsigned int irq)
+static void mask_m32700ut_lanpld(struct irq_data *data)
 {
-       disable_m32700ut_lanpld_irq(irq);
+       disable_m32700ut_lanpld_irq(data->irq);
 }
 
-static void end_m32700ut_lanpld_irq(unsigned int irq)
+static void unmask_m32700ut_lanpld(struct irq_data *data)
 {
-       enable_m32700ut_lanpld_irq(irq);
-       end_m32700ut_irq(M32R_IRQ_INT0);
-}
-
-static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq)
-{
-       enable_m32700ut_lanpld_irq(irq);
-       return (0);
+       enable_m32700ut_lanpld_irq(data->irq);
+       enable_m32700ut_irq(M32R_IRQ_INT0);
 }
 
-static void shutdown_m32700ut_lanpld_irq(unsigned int irq)
+static void shutdown_m32700ut_lanpld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2lanpldirq(irq);
+       pldirq = irq2lanpldirq(data->irq);
        port = lanpldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32700ut_lanpld_irq_type =
 {
-       .name = "M32700UT-PLD-LAN-IRQ",
-       .startup = startup_m32700ut_lanpld_irq,
-       .shutdown = shutdown_m32700ut_lanpld_irq,
-       .enable = enable_m32700ut_lanpld_irq,
-       .disable = disable_m32700ut_lanpld_irq,
-       .ack = mask_and_ack_m32700ut_lanpld,
-       .end = end_m32700ut_lanpld_irq
+       .name           = "M32700UT-PLD-LAN-IRQ",
+       .irq_shutdown   = shutdown_m32700ut_lanpld,
+       .irq_mask       = mask_m32700ut_lanpld,
+       .irq_unmask     = unmask_m32700ut_lanpld,
 };
 
 /*
@@ -257,143 +226,110 @@ static void enable_m32700ut_lcdpld_irq(unsigned int irq)
        outw(data, port);
 }
 
-static void mask_and_ack_m32700ut_lcdpld(unsigned int irq)
+static void mask_m32700ut_lcdpld(struct irq_data *data)
 {
-       disable_m32700ut_lcdpld_irq(irq);
+       disable_m32700ut_lcdpld_irq(data->irq);
 }
 
-static void end_m32700ut_lcdpld_irq(unsigned int irq)
+static void unmask_m32700ut_lcdpld(struct irq_data *data)
 {
-       enable_m32700ut_lcdpld_irq(irq);
-       end_m32700ut_irq(M32R_IRQ_INT2);
-}
-
-static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq)
-{
-       enable_m32700ut_lcdpld_irq(irq);
-       return (0);
+       enable_m32700ut_lcdpld_irq(data->irq);
+       enable_m32700ut_irq(M32R_IRQ_INT2);
 }
 
-static void shutdown_m32700ut_lcdpld_irq(unsigned int irq)
+static void shutdown_m32700ut_lcdpld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2lcdpldirq(irq);
+       pldirq = irq2lcdpldirq(data->irq);
        port = lcdpldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32700ut_lcdpld_irq_type =
 {
-       .name = "M32700UT-PLD-LCD-IRQ",
-       .startup = startup_m32700ut_lcdpld_irq,
-       .shutdown = shutdown_m32700ut_lcdpld_irq,
-       .enable = enable_m32700ut_lcdpld_irq,
-       .disable = disable_m32700ut_lcdpld_irq,
-       .ack = mask_and_ack_m32700ut_lcdpld,
-       .end = end_m32700ut_lcdpld_irq
+       .name           = "M32700UT-PLD-LCD-IRQ",
+       .irq_shutdown   = shutdown_m32700ut_lcdpld,
+       .irq_mask       = mask_m32700ut_lcdpld,
+       .irq_unmask     = unmask_m32700ut_lcdpld,
 };
 
 void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
-       irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[M32700UT_LAN_IRQ_LAN].chip = &m32700ut_lanpld_irq_type;
-       irq_desc[M32700UT_LAN_IRQ_LAN].action = 0;
-       irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1;       /* disable nested irq */
+       set_irq_chip_and_handler(M32700UT_LAN_IRQ_LAN,
+                                &m32700ut_lanpld_irq_type, handle_level_irq);
        lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;   /* "H" edge sense */
        disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_m32700ut_irq(M32R_IRQ_MFT2);
 
        /* SIO0 : receive */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0 : send */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1 : receive */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1 : send */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO1_S);
 
        /* DMA1 : */
-       irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_DMA1].action = 0;
-       irq_desc[M32R_IRQ_DMA1].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_DMA1].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_DMA1);
 
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
-       irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
-       irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV);
 
        /* INT#1: SIO0 Send on PLD */
-       irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_SIO0_SND].action = 0;
-       irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND);
 #endif  /* CONFIG_SERIAL_M32R_PLDSIO */
 
        /* INT#1: CFC IREQ on PLD */
-       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_CFIREQ].action = 0;
-       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ);
 
        /* INT#1: CFC Insert on PLD */
-       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
-       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT);
 
        /* INT#1: CFC Eject on PLD */
-       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
-       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT);
 
@@ -413,13 +349,11 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_USB)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
+       set_irq_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1,
+                                &m32700ut_lcdpld_irq_type, handle_level_irq);
 
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].chip = &m32700ut_lcdpld_irq_type;
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0;
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1;
-    lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
-    disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1);
+       lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;      /* "L" level sense */
+       disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1);
 #endif
        /*
         * INT2# is used for BAT, USB, AUDIO
@@ -432,10 +366,8 @@ void __init init_IRQ(void)
        /*
         * INT3# is used for AR
         */
-       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].chip = &m32700ut_irq_type;
-       irq_desc[M32R_IRQ_INT3].action = 0;
-       irq_desc[M32R_IRQ_INT3].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_m32700ut_irq(M32R_IRQ_INT3);
 #endif /* CONFIG_VIDEO_M32R_AR */
index ea00c84..cdd8c45 100644 (file)
@@ -38,40 +38,30 @@ static void enable_mappi_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_mappi(struct irq_data *data)
 {
-       disable_mappi_irq(irq);
+       disable_mappi_irq(data->irq);
 }
 
-static void end_mappi_irq(unsigned int irq)
+static void unmask_mappi(struct irq_data *data)
 {
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               enable_mappi_irq(irq);
+       enable_mappi_irq(data->irq);
 }
 
-static unsigned int startup_mappi_irq(unsigned int irq)
-{
-       enable_mappi_irq(irq);
-       return (0);
-}
-
-static void shutdown_mappi_irq(unsigned int irq)
+static void shutdown_mappi(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip mappi_irq_type =
 {
-       .name = "MAPPI-IRQ",
-       .startup = startup_mappi_irq,
-       .shutdown = shutdown_mappi_irq,
-       .enable = enable_mappi_irq,
-       .disable = disable_mappi_irq,
-       .ack = mask_and_ack_mappi,
-       .end = end_mappi_irq
+       .name           = "MAPPI-IRQ",
+       .irq_shutdown   = shutdown_mappi,
+       .irq_mask       = mask_mappi,
+       .irq_unmask     = unmask_mappi,
 };
 
 void __init init_IRQ(void)
@@ -85,70 +75,54 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_NE2000
        /* INT0 : LAN controller (RTL8019AS) */
-       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_INT0].action = NULL;
-       irq_desc[M32R_IRQ_INT0].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
        disable_mappi_irq(M32R_IRQ_INT0);
 #endif /* CONFIG_M32R_NE2000 */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = NULL;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = NULL;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = NULL;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = NULL;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = NULL;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_S);
 #endif /* CONFIG_SERIAL_M32R_SIO */
 
 #if defined(CONFIG_M32R_PCC)
        /* INT1 : pccard0 interrupt */
-       irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_INT1].action = NULL;
-       irq_desc[M32R_IRQ_INT1].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
        disable_mappi_irq(M32R_IRQ_INT1);
 
        /* INT2 : pccard1 interrupt */
-       irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_INT2].action = NULL;
-       irq_desc[M32R_IRQ_INT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
        disable_mappi_irq(M32R_IRQ_INT2);
 #endif /* CONFIG_M32RPCC */
index c049376..9117c30 100644 (file)
@@ -46,126 +46,97 @@ static void enable_mappi2_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_mappi2(unsigned int irq)
+static void mask_mappi2(struct irq_data *data)
 {
-       disable_mappi2_irq(irq);
+       disable_mappi2_irq(data->irq);
 }
 
-static void end_mappi2_irq(unsigned int irq)
+static void unmask_mappi2(struct irq_data *data)
 {
-       enable_mappi2_irq(irq);
+       enable_mappi2_irq(data->irq);
 }
 
-static unsigned int startup_mappi2_irq(unsigned int irq)
-{
-       enable_mappi2_irq(irq);
-       return (0);
-}
-
-static void shutdown_mappi2_irq(unsigned int irq)
+static void shutdown_mappi2(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip mappi2_irq_type =
 {
-       .name = "MAPPI2-IRQ",
-       .startup = startup_mappi2_irq,
-       .shutdown = shutdown_mappi2_irq,
-       .enable = enable_mappi2_irq,
-       .disable = disable_mappi2_irq,
-       .ack = mask_and_ack_mappi2,
-       .end = end_mappi2_irq
+       .name           = "MAPPI2-IRQ",
+       .irq_shutdown   = shutdown_mappi2,
+       .irq_mask       = mask_mappi2,
+       .irq_unmask     = unmask_mappi2,
 };
 
 void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
-       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_INT0].action = 0;
-       irq_desc[M32R_IRQ_INT0].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi2_irq(M32R_IRQ_INT0);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi2_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO1_S);
 #endif  /* CONFIG_M32R_USE_DBG_CONSOLE */
 
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
-       irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].chip = &mappi2_irq_type;
-       irq_desc[M32R_IRQ_INT1].action = 0;
-       irq_desc[M32R_IRQ_INT1].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
        disable_mappi2_irq(M32R_IRQ_INT1);
 #endif /* CONFIG_USB */
 
        /* ICUCR40: CFC IREQ */
-       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi2_irq_type;
-       irq_desc[PLD_IRQ_CFIREQ].action = 0;
-       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        disable_mappi2_irq(PLD_IRQ_CFIREQ);
 
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert */
-       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi2_irq_type;
-       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
-       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
        disable_mappi2_irq(PLD_IRQ_CFC_INSERT);
 
        /* ICUCR42: CFC Eject */
-       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].chip = &mappi2_irq_type;
-       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
-       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi2_irq(PLD_IRQ_CFC_EJECT);
 #endif /* CONFIG_MAPPI2_CFC */
index 882de25..b44f5de 100644 (file)
@@ -46,128 +46,98 @@ static void enable_mappi3_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_mappi3(unsigned int irq)
+static void mask_mappi3(struct irq_data *data)
 {
-       disable_mappi3_irq(irq);
+       disable_mappi3_irq(data->irq);
 }
 
-static void end_mappi3_irq(unsigned int irq)
+static void unmask_mappi3(struct irq_data *data)
 {
-       enable_mappi3_irq(irq);
+       enable_mappi3_irq(data->irq);
 }
 
-static unsigned int startup_mappi3_irq(unsigned int irq)
-{
-       enable_mappi3_irq(irq);
-       return (0);
-}
-
-static void shutdown_mappi3_irq(unsigned int irq)
+static void shutdown_mappi3(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct irq_chip mappi3_irq_type =
-{
-       .name = "MAPPI3-IRQ",
-       .startup = startup_mappi3_irq,
-       .shutdown = shutdown_mappi3_irq,
-       .enable = enable_mappi3_irq,
-       .disable = disable_mappi3_irq,
-       .ack = mask_and_ack_mappi3,
-       .end = end_mappi3_irq
+static struct irq_chip mappi3_irq_type = {
+       .name           = "MAPPI3-IRQ",
+       .irq_shutdown   = shutdown_mappi3,
+       .irq_mask       = mask_mappi3,
+       .irq_unmask     = unmask_mappi3,
 };
 
 void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
-       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_INT0].action = 0;
-       irq_desc[M32R_IRQ_INT0].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi3_irq(M32R_IRQ_INT0);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi3_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO1_S);
 #endif  /* CONFIG_M32R_USE_DBG_CONSOLE */
 
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
-       irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].chip = &mappi3_irq_type;
-       irq_desc[M32R_IRQ_INT1].action = 0;
-       irq_desc[M32R_IRQ_INT1].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
        disable_mappi3_irq(M32R_IRQ_INT1);
 #endif /* CONFIG_USB */
 
        /* CFC IREQ */
-       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi3_irq_type;
-       irq_desc[PLD_IRQ_CFIREQ].action = 0;
-       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        disable_mappi3_irq(PLD_IRQ_CFIREQ);
 
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert & eject */
-       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi3_irq_type;
-       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
-       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
        disable_mappi3_irq(PLD_IRQ_CFC_INSERT);
 
 #endif /* CONFIG_M32R_CFC */
 
        /* IDE IREQ */
-       irq_desc[PLD_IRQ_IDEIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_IDEIREQ].chip = &mappi3_irq_type;
-       irq_desc[PLD_IRQ_IDEIREQ].action = 0;
-       irq_desc[PLD_IRQ_IDEIREQ].depth = 1;    /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type,
+                                handle_level_irq);
        icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi3_irq(PLD_IRQ_IDEIREQ);
 
index d11d93b..19a02db 100644 (file)
@@ -37,39 +37,30 @@ static void enable_oaks32r_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_oaks32r(struct irq_data *data)
 {
-       disable_oaks32r_irq(irq);
+       disable_oaks32r_irq(data->irq);
 }
 
-static void end_oaks32r_irq(unsigned int irq)
+static void unmask_oaks32r(struct irq_data *data)
 {
-       enable_oaks32r_irq(irq);
+       enable_oaks32r_irq(data->irq);
 }
 
-static unsigned int startup_oaks32r_irq(unsigned int irq)
-{
-       enable_oaks32r_irq(irq);
-       return (0);
-}
-
-static void shutdown_oaks32r_irq(unsigned int irq)
+static void shutdown_oaks32r(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip oaks32r_irq_type =
 {
-       .name = "OAKS32R-IRQ",
-       .startup = startup_oaks32r_irq,
-       .shutdown = shutdown_oaks32r_irq,
-       .enable = enable_oaks32r_irq,
-       .disable = disable_oaks32r_irq,
-       .ack = mask_and_ack_mappi,
-       .end = end_oaks32r_irq
+       .name           = "OAKS32R-IRQ",
+       .irq_shutdown   = shutdown_oaks32r,
+       .irq_mask       = mask_oaks32r,
+       .irq_unmask     = unmask_oaks32r,
 };
 
 void __init init_IRQ(void)
@@ -83,52 +74,40 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_NE2000
        /* INT3 : LAN controller (RTL8019AS) */
-       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_INT3].action = 0;
-       irq_desc[M32R_IRQ_INT3].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_oaks32r_irq(M32R_IRQ_INT3);
 #endif /* CONFIG_M32R_NE2000 */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_oaks32r_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &oaks32r_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO1_S);
 #endif /* CONFIG_SERIAL_M32R_SIO */
index 5f3402a..1273154 100644 (file)
@@ -46,39 +46,30 @@ static void enable_opsput_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_opsput(unsigned int irq)
+static void mask_opsput(struct irq_data *data)
 {
-       disable_opsput_irq(irq);
+       disable_opsput_irq(data->irq);
 }
 
-static void end_opsput_irq(unsigned int irq)
+static void unmask_opsput(struct irq_data *data)
 {
-       enable_opsput_irq(irq);
+       enable_opsput_irq(data->irq);
 }
 
-static unsigned int startup_opsput_irq(unsigned int irq)
-{
-       enable_opsput_irq(irq);
-       return (0);
-}
-
-static void shutdown_opsput_irq(unsigned int irq)
+static void shutdown_opsput(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip opsput_irq_type =
 {
-       .name = "OPSPUT-IRQ",
-       .startup = startup_opsput_irq,
-       .shutdown = shutdown_opsput_irq,
-       .enable = enable_opsput_irq,
-       .disable = disable_opsput_irq,
-       .ack = mask_and_ack_opsput,
-       .end = end_opsput_irq
+       .name           = "OPSPUT-IRQ",
+       .irq_shutdown   = shutdown_opsput,
+       .irq_mask       = mask_opsput,
+       .irq_unmask     = unmask_opsput,
 };
 
 /*
@@ -100,7 +91,6 @@ static void disable_opsput_pld_irq(unsigned int irq)
        unsigned int pldirq;
 
        pldirq = irq2pldirq(irq);
-//     disable_opsput_irq(M32R_IRQ_INT1);
        port = pldirq2port(pldirq);
        data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
        outw(data, port);
@@ -112,50 +102,38 @@ static void enable_opsput_pld_irq(unsigned int irq)
        unsigned int pldirq;
 
        pldirq = irq2pldirq(irq);
-//     enable_opsput_irq(M32R_IRQ_INT1);
        port = pldirq2port(pldirq);
        data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
        outw(data, port);
 }
 
-static void mask_and_ack_opsput_pld(unsigned int irq)
-{
-       disable_opsput_pld_irq(irq);
-//     mask_and_ack_opsput(M32R_IRQ_INT1);
-}
-
-static void end_opsput_pld_irq(unsigned int irq)
+static void mask_opsput_pld(struct irq_data *data)
 {
-       enable_opsput_pld_irq(irq);
-       end_opsput_irq(M32R_IRQ_INT1);
+       disable_opsput_pld_irq(data->irq);
 }
 
-static unsigned int startup_opsput_pld_irq(unsigned int irq)
+static void unmask_opsput_pld(struct irq_data *data)
 {
-       enable_opsput_pld_irq(irq);
-       return (0);
+       enable_opsput_pld_irq(data->irq);
+       enable_opsput_irq(M32R_IRQ_INT1);
 }
 
-static void shutdown_opsput_pld_irq(unsigned int irq)
+static void shutdown_opsput_pld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2pldirq(irq);
-//     shutdown_opsput_irq(M32R_IRQ_INT1);
+       pldirq = irq2pldirq(data->irq);
        port = pldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip opsput_pld_irq_type =
 {
-       .name = "OPSPUT-PLD-IRQ",
-       .startup = startup_opsput_pld_irq,
-       .shutdown = shutdown_opsput_pld_irq,
-       .enable = enable_opsput_pld_irq,
-       .disable = disable_opsput_pld_irq,
-       .ack = mask_and_ack_opsput_pld,
-       .end = end_opsput_pld_irq
+       .name           = "OPSPUT-PLD-IRQ",
+       .irq_shutdown   = shutdown_opsput_pld,
+       .irq_mask       = mask_opsput_pld,
+       .irq_unmask     = unmask_opsput_pld,
 };
 
 /*
@@ -189,42 +167,33 @@ static void enable_opsput_lanpld_irq(unsigned int irq)
        outw(data, port);
 }
 
-static void mask_and_ack_opsput_lanpld(unsigned int irq)
-{
-       disable_opsput_lanpld_irq(irq);
-}
-
-static void end_opsput_lanpld_irq(unsigned int irq)
+static void mask_opsput_lanpld(struct irq_data *data)
 {
-       enable_opsput_lanpld_irq(irq);
-       end_opsput_irq(M32R_IRQ_INT0);
+       disable_opsput_lanpld_irq(data->irq);
 }
 
-static unsigned int startup_opsput_lanpld_irq(unsigned int irq)
+static void unmask_opsput_lanpld(struct irq_data *data)
 {
-       enable_opsput_lanpld_irq(irq);
-       return (0);
+       enable_opsput_lanpld_irq(data->irq);
+       enable_opsput_irq(M32R_IRQ_INT0);
 }
 
-static void shutdown_opsput_lanpld_irq(unsigned int irq)
+static void shutdown_opsput_lanpld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2lanpldirq(irq);
+       pldirq = irq2lanpldirq(data->irq);
        port = lanpldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip opsput_lanpld_irq_type =
 {
-       .name = "OPSPUT-PLD-LAN-IRQ",
-       .startup = startup_opsput_lanpld_irq,
-       .shutdown = shutdown_opsput_lanpld_irq,
-       .enable = enable_opsput_lanpld_irq,
-       .disable = disable_opsput_lanpld_irq,
-       .ack = mask_and_ack_opsput_lanpld,
-       .end = end_opsput_lanpld_irq
+       .name           = "OPSPUT-PLD-LAN-IRQ",
+       .irq_shutdown   = shutdown_opsput_lanpld,
+       .irq_mask       = mask_opsput_lanpld,
+       .irq_unmask     = unmask_opsput_lanpld,
 };
 
 /*
@@ -258,143 +227,109 @@ static void enable_opsput_lcdpld_irq(unsigned int irq)
        outw(data, port);
 }
 
-static void mask_and_ack_opsput_lcdpld(unsigned int irq)
-{
-       disable_opsput_lcdpld_irq(irq);
-}
-
-static void end_opsput_lcdpld_irq(unsigned int irq)
+static void mask_opsput_lcdpld(struct irq_data *data)
 {
-       enable_opsput_lcdpld_irq(irq);
-       end_opsput_irq(M32R_IRQ_INT2);
+       disable_opsput_lcdpld_irq(data->irq);
 }
 
-static unsigned int startup_opsput_lcdpld_irq(unsigned int irq)
+static void unmask_opsput_lcdpld(struct irq_data *data)
 {
-       enable_opsput_lcdpld_irq(irq);
-       return (0);
+       enable_opsput_lcdpld_irq(data->irq);
+       enable_opsput_irq(M32R_IRQ_INT2);
 }
 
-static void shutdown_opsput_lcdpld_irq(unsigned int irq)
+static void shutdown_opsput_lcdpld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2lcdpldirq(irq);
+       pldirq = irq2lcdpldirq(data->irq);
        port = lcdpldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct irq_chip opsput_lcdpld_irq_type =
-{
-       "OPSPUT-PLD-LCD-IRQ",
-       startup_opsput_lcdpld_irq,
-       shutdown_opsput_lcdpld_irq,
-       enable_opsput_lcdpld_irq,
-       disable_opsput_lcdpld_irq,
-       mask_and_ack_opsput_lcdpld,
-       end_opsput_lcdpld_irq
+static struct irq_chip opsput_lcdpld_irq_type = {
+       .name           = "OPSPUT-PLD-LCD-IRQ",
+       .irq_shutdown   = shutdown_opsput_lcdpld,
+       .irq_mask       = mask_opsput_lcdpld,
+       .irq_unmask     = unmask_opsput_lcdpld,
 };
 
 void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
-       irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[OPSPUT_LAN_IRQ_LAN].chip = &opsput_lanpld_irq_type;
-       irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0;
-       irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
+       set_irq_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type,
+                                handle_level_irq);
        lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;     /* "H" edge sense */
        disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_opsput_irq(M32R_IRQ_MFT2);
 
        /* SIO0 : receive */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0 : send */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1 : receive */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1 : send */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO1_S);
 
        /* DMA1 : */
-       irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_DMA1].action = 0;
-       irq_desc[M32R_IRQ_DMA1].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_DMA1].icucr = 0;
        disable_opsput_irq(M32R_IRQ_DMA1);
 
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
-       irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].chip = &opsput_pld_irq_type;
-       irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
-       irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV);
 
        /* INT#1: SIO0 Send on PLD */
-       irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].chip = &opsput_pld_irq_type;
-       irq_desc[PLD_IRQ_SIO0_SND].action = 0;
-       irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
 #endif  /* CONFIG_SERIAL_M32R_PLDSIO */
 
        /* INT#1: CFC IREQ on PLD */
-       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
-       irq_desc[PLD_IRQ_CFIREQ].action = 0;
-       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
        disable_opsput_pld_irq(PLD_IRQ_CFIREQ);
 
        /* INT#1: CFC Insert on PLD */
-       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].chip = &opsput_pld_irq_type;
-       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
-       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
        disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT);
 
        /* INT#1: CFC Eject on PLD */
-       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].chip = &opsput_pld_irq_type;
-       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
-       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
        disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
 
@@ -413,14 +348,11 @@ void __init init_IRQ(void)
        enable_opsput_irq(M32R_IRQ_INT1);
 
 #if defined(CONFIG_USB)
-       outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
-
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].chip = &opsput_lcdpld_irq_type;
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0;
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1;
-    lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;   /* "L" level sense */
-    disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
+       outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
+       set_irq_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1,
+                                &opsput_lcdpld_irq_type, handle_level_irq);
+       lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;        /* "L" level sense */
+       disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
 #endif
        /*
         * INT2# is used for BAT, USB, AUDIO
@@ -433,10 +365,8 @@ void __init init_IRQ(void)
        /*
         * INT3# is used for AR
         */
-       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].chip = &opsput_irq_type;
-       irq_desc[M32R_IRQ_INT3].action = 0;
-       irq_desc[M32R_IRQ_INT3].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_opsput_irq(M32R_IRQ_INT3);
 #endif /* CONFIG_VIDEO_M32R_AR */
index 1beac7a..f3cff26 100644 (file)
@@ -37,39 +37,30 @@ static void enable_mappi_irq(unsigned int irq)
        outl(data, port);
 }
 
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_mappi(struct irq_data *data)
 {
-       disable_mappi_irq(irq);
+       disable_mappi_irq(data->irq);
 }
 
-static void end_mappi_irq(unsigned int irq)
+static void unmask_mappi(struct irq_data *data)
 {
-       enable_mappi_irq(irq);
+       enable_mappi_irq(data->irq);
 }
 
-static unsigned int startup_mappi_irq(unsigned int irq)
-{
-       enable_mappi_irq(irq);
-       return 0;
-}
-
-static void shutdown_mappi_irq(unsigned int irq)
+static void shutdown_mappi(struct irq_data *data)
 {
        unsigned long port;
 
-       port = irq2port(irq);
+       port = irq2port(data->irq);
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip mappi_irq_type =
 {
-       .name = "M32700-IRQ",
-       .startup = startup_mappi_irq,
-       .shutdown = shutdown_mappi_irq,
-       .enable = enable_mappi_irq,
-       .disable = disable_mappi_irq,
-       .ack = mask_and_ack_mappi,
-       .end = end_mappi_irq
+       .name           = "M32700-IRQ",
+       .irq_shutdown   = shutdown_mappi,
+       .irq_mask       = mask_mappi,
+       .irq_unmask     = unmask_mappi,
 };
 
 /*
@@ -107,42 +98,33 @@ static void enable_m32700ut_pld_irq(unsigned int irq)
        outw(data, port);
 }
 
-static void mask_and_ack_m32700ut_pld(unsigned int irq)
+static void mask_m32700ut_pld(struct irq_data *data)
 {
-       disable_m32700ut_pld_irq(irq);
+       disable_m32700ut_pld_irq(data->irq);
 }
 
-static void end_m32700ut_pld_irq(unsigned int irq)
+static void unmask_m32700ut_pld(struct irq_data *data)
 {
-       enable_m32700ut_pld_irq(irq);
-       end_mappi_irq(M32R_IRQ_INT1);
-}
-
-static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
-{
-       enable_m32700ut_pld_irq(irq);
-       return 0;
+       enable_m32700ut_pld_irq(data->irq);
+       enable_mappi_irq(M32R_IRQ_INT1);
 }
 
-static void shutdown_m32700ut_pld_irq(unsigned int irq)
+static void shutdown_m32700ut_pld(struct irq_data *data)
 {
        unsigned long port;
        unsigned int pldirq;
 
-       pldirq = irq2pldirq(irq);
+       pldirq = irq2pldirq(data->irq);
        port = pldirq2port(pldirq);
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-       .name = "USRV-PLD-IRQ",
-       .startup = startup_m32700ut_pld_irq,
-       .shutdown = shutdown_m32700ut_pld_irq,
-       .enable = enable_m32700ut_pld_irq,
-       .disable = disable_m32700ut_pld_irq,
-       .ack = mask_and_ack_m32700ut_pld,
-       .end = end_m32700ut_pld_irq
+       .name           = "USRV-PLD-IRQ",
+       .irq_shutdown   = shutdown_m32700ut_pld,
+       .irq_mask       = mask_m32700ut_pld,
+       .irq_unmask     = unmask_m32700ut_pld,
 };
 
 void __init init_IRQ(void)
@@ -156,53 +138,42 @@ void __init init_IRQ(void)
                once++;
 
        /* MFT2 : system timer */
-       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_MFT2].action = 0;
-       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi_irq(M32R_IRQ_MFT2);
 
 #if defined(CONFIG_SERIAL_M32R_SIO)
        /* SIO0_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO0_R].action = 0;
-       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO0_S].action = 0;
-       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO1_R].action = 0;
-       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
-       irq_desc[M32R_IRQ_SIO1_S].action = 0;
-       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+                                handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_S);
 #endif  /* CONFIG_SERIAL_M32R_SIO */
 
        /* INT#67-#71: CFC#0 IREQ on PLD */
        for (i = 0 ; i < CONFIG_M32R_CFC_NUM ; i++ ) {
-               irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED;
-               irq_desc[PLD_IRQ_CF0 + i].chip = &m32700ut_pld_irq_type;
-               irq_desc[PLD_IRQ_CF0 + i].action = 0;
-               irq_desc[PLD_IRQ_CF0 + i].depth = 1;    /* disable nested irq */
+               set_irq_chip_and_handler(PLD_IRQ_CF0 + i,
+                                        &m32700ut_pld_irq_type,
+                                        handle_level_irq);
                pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
                        = PLD_ICUCR_ISMOD01;    /* 'L' level sense */
                disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i);
@@ -210,19 +181,15 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        /* INT#76: 16552D#0 IREQ on PLD */
-       irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART0].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_UART0].action = 0;
-       irq_desc[PLD_IRQ_UART0].depth = 1;      /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
                = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_UART0);
 
        /* INT#77: 16552D#1 IREQ on PLD */
-       irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART1].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_UART1].action = 0;
-       irq_desc[PLD_IRQ_UART1].depth = 1;      /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
                = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_UART1);
@@ -230,10 +197,8 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
        /* INT#80: AK4524 IREQ on PLD */
-       irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SNDINT].chip = &m32700ut_pld_irq_type;
-       irq_desc[PLD_IRQ_SNDINT].action = 0;
-       irq_desc[PLD_IRQ_SNDINT].depth = 1;     /* disable nested irq */
+       set_irq_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type,
+                                handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
                = PLD_ICUCR_ISMOD01;    /* 'L' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_SNDINT);
index b1577f7..82a4bb5 100644 (file)
@@ -610,17 +610,17 @@ static void amiga_mem_console_write(struct console *co, const char *s,
 
 static int __init amiga_savekmsg_setup(char *arg)
 {
-       static struct resource debug_res = { .name = "Debug" };
-
        if (!MACH_IS_AMIGA || strcmp(arg, "mem"))
-               goto done;
+               return 0;
 
-       if (!AMIGAHW_PRESENT(CHIP_RAM)) {
-               printk("Warning: no chipram present for debugging\n");
-               goto done;
+       if (amiga_chip_size < SAVEKMSG_MAXMEM) {
+               pr_err("Not enough chipram for debugging\n");
+               return -ENOMEM;
        }
 
-       savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
+       /* Just steal the block, the chipram allocator isn't functional yet */
+       amiga_chip_size -= SAVEKMSG_MAXMEM;
+       savekmsg = (void *)ZTWO_VADDR(CHIP_PHYSADDR + amiga_chip_size);
        savekmsg->magic1 = SAVEKMSG_MAGIC1;
        savekmsg->magic2 = SAVEKMSG_MAGIC2;
        savekmsg->magicptr = ZTWO_PADDR(savekmsg);
@@ -628,8 +628,6 @@ static int __init amiga_savekmsg_setup(char *arg)
 
        amiga_console_driver.write = amiga_mem_console_write;
        register_console(&amiga_console_driver);
-
-done:
        return 0;
 }
 
index 39478dd..26a804e 100644 (file)
@@ -388,9 +388,9 @@ void __init atari_init_IRQ(void)
        }
 
        if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
-               scc.cha_a_ctrl = 9;
+               atari_scc.cha_a_ctrl = 9;
                MFPDELAY();
-               scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
+               atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
        }
 
        if (ATARIHW_PRESENT(SCU)) {
index ae2d96e..4203d10 100644 (file)
@@ -315,7 +315,7 @@ void __init config_atari(void)
                ATARIHW_SET(SCC_DMA);
                printk("SCC_DMA ");
        }
-       if (scc_test(&scc.cha_a_ctrl)) {
+       if (scc_test(&atari_scc.cha_a_ctrl)) {
                ATARIHW_SET(SCC);
                printk("SCC ");
        }
index 28efdc3..5a48424 100644 (file)
@@ -53,9 +53,9 @@ static inline void ata_scc_out(char c)
 {
        do {
                MFPDELAY();
-       } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+       } while (!(atari_scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
        MFPDELAY();
-       scc.cha_b_data = c;
+       atari_scc.cha_b_data = c;
 }
 
 static void atari_scc_console_write(struct console *co, const char *str,
@@ -140,9 +140,9 @@ int atari_scc_console_wait_key(struct console *co)
 {
        do {
                MFPDELAY();
-       } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
+       } while (!(atari_scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
        MFPDELAY();
-       return scc.cha_b_data;
+       return atari_scc.cha_b_data;
 }
 
 int atari_midi_console_wait_key(struct console *co)
@@ -185,9 +185,9 @@ static void __init atari_init_mfp_port(int cflag)
 
 #define SCC_WRITE(reg, val)                            \
        do {                                            \
-               scc.cha_b_ctrl = (reg);                 \
+               atari_scc.cha_b_ctrl = (reg);           \
                MFPDELAY();                             \
-               scc.cha_b_ctrl = (val);                 \
+               atari_scc.cha_b_ctrl = (val);           \
                MFPDELAY();                             \
        } while (0)
 
@@ -240,7 +240,7 @@ static void __init atari_init_scc_port(int cflag)
        reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
        reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
 
-       (void)scc.cha_b_ctrl;           /* reset reg pointer */
+       (void)atari_scc.cha_b_ctrl;     /* reset reg pointer */
        SCC_WRITE(9, 0xc0);             /* reset */
        LONG_DELAY();                   /* extra delay after WR9 access */
        SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
index a714e1a..f51f709 100644 (file)
@@ -449,7 +449,7 @@ struct SCC
   u_char char_dummy3;
   u_char cha_b_data;
  };
-# define scc ((*(volatile struct SCC*)SCC_BAS))
+# define atari_scc ((*(volatile struct SCC*)SCC_BAS))
 
 /* The ESCC (Z85230) in an Atari ST. The channels are reversed! */
 # define st_escc ((*(volatile struct SCC*)0xfffffa31))
index 2936dda..3219845 100644 (file)
@@ -81,18 +81,6 @@ static inline char *strncpy(char *dest, const char *src, size_t n)
        strcpy(__d + strlen(__d), (s));         \
 })
 
-#define __HAVE_ARCH_STRCHR
-static inline char *strchr(const char *s, int c)
-{
-       char sc, ch = c;
-
-       for (; (sc = *s++) != ch; ) {
-               if (!sc)
-                       return NULL;
-       }
-       return (char *)s - 1;
-}
-
 #ifndef CONFIG_COLDFIRE
 #define __HAVE_ARCH_STRCMP
 static inline int strcmp(const char *cs, const char *ct)
@@ -111,14 +99,12 @@ static inline int strcmp(const char *cs, const char *ct)
                : "+a" (cs), "+a" (ct), "=d" (res));
        return res;
 }
+#endif /* CONFIG_COLDFIRE */
 
 #define __HAVE_ARCH_MEMMOVE
 extern void *memmove(void *, const void *, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, __kernel_size_t);
 #define memcmp(d, s, n) __builtin_memcmp(d, s, n)
-#endif /* CONFIG_COLDFIRE */
 
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, __kernel_size_t);
index 4253f87..d399c5f 100644 (file)
@@ -243,14 +243,3 @@ void *memmove(void *dest, const void *src, size_t n)
        return xdest;
 }
 EXPORT_SYMBOL(memmove);
-
-int memcmp(const void *cs, const void *ct, size_t count)
-{
-       const unsigned char *su1, *su2;
-
-       for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
-               if (*su1 != *su2)
-                       return *su1 < *su2 ? -1 : +1;
-       return 0;
-}
-EXPORT_SYMBOL(memcmp);
index 704e7b9..8b9daca 100644 (file)
@@ -2,6 +2,7 @@ config M68K
        bool
        default y
        select HAVE_IDE
+       select HAVE_GENERIC_HARDIRQS
 
 config MMU
        bool
@@ -48,14 +49,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       default y
-
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
index 6ac2981..2f5655c 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index 14934ff..16df72b 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index 5985a3b..4e6ea50 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index 5a7857e..f3dd741 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index e810201..bce0a20 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index 5c124a7..618cc32 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index 6ac2981..2f5655c 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
index ef33213..47e15eb 100644 (file)
@@ -141,6 +141,12 @@ SECTIONS {
                *(__param)
                __stop___param = .;
 
+               /* Built-in module versions */
+               . = ALIGN(4) ;
+               __start___modver = .;
+               *(__modver)
+               __stop___modver = .;
+
                . = ALIGN(4) ;
                _etext = . ;
        } > TEXT
index d94d709..32d852e 100644 (file)
@@ -4,4 +4,4 @@
 
 lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
           muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o memcpy.o memset.o delay.o
+          checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68knommu/lib/memmove.c b/arch/m68knommu/lib/memmove.c
new file mode 100644 (file)
index 0000000..b3dcfe9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#define __IN_STRING_C
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       void *xdest = dest;
+       size_t temp;
+
+       if (!n)
+               return xdest;
+
+       if (dest < src) {
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest++ = *csrc++;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *ldest++ = *lsrc++;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest = *csrc;
+               }
+       } else {
+               dest = (char *)dest + n;
+               src = (const char *)src + n;
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *--ldest = *--lsrc;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+               }
+       }
+       return xdest;
+}
+EXPORT_SYMBOL(memmove);
index d09d9da..c5151f8 100644 (file)
@@ -50,8 +50,10 @@ static int __init mcf_intc2_init(void)
        int irq;
 
        /* GPIO interrupt sources */
-       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++)
+       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++) {
                irq_desc[irq].chip = &intc2_irq_gpio_chip;
+               set_irq_handler(irq, handle_edge_irq);
+       }
 
        return 0;
 }
index 240a7a6..676960c 100644 (file)
@@ -108,7 +108,6 @@ Luser_return:
        movel   %d1,%a2
 1:
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       andl    #_TIF_WORK_MASK,%d1
        jne     Lwork_to_do
        RESTORE_ALL
 
index f27e688..8e4e10c 100644 (file)
@@ -210,7 +210,7 @@ void
 cpm_install_handler(int vec, void (*handler)(), void *dev_id)
 {
 
-       request_irq(vec, handler, IRQ_FLG_LOCK, "timer", dev_id);
+       request_irq(vec, handler, 0, "timer", dev_id);
 
 /*     if (cpm_vecs[vec].handler != 0) */
 /*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
index ac629fa..9dd5bca 100644 (file)
@@ -75,7 +75,7 @@ void hw_timer_init(void)
   /* Set compare register  32Khz / 32 / 10 = 100 */
   TCMP = 10;                                                              
 
-  request_irq(IRQ_MACHSPEC | 1, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
+  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
 #endif
 
   /* General purpose quicc timers: MC68360UM p7-20 */
index 8a28788..46c1b18 100644 (file)
@@ -104,7 +104,6 @@ Luser_return:
        movel   %d1,%a2
 1:
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       andl    #_TIF_WORK_MASK,%d1
        jne     Lwork_to_do
        RESTORE_ALL
 
index ad96ab1..a29041c 100644 (file)
@@ -132,8 +132,8 @@ void init_IRQ(void)
        pquicc->intr_cimr = 0x00000000;
 
        for (i = 0; (i < NR_IRQS); i++) {
-               set_irq_chip(irq, &intc_irq_chip);
-               set_irq_handler(irq, handle_level_irq);
+               set_irq_chip(i, &intc_irq_chip);
+               set_irq_handler(i, handle_level_irq);
        }
 }
 
index 4ddfc3d..5837cf0 100644 (file)
@@ -138,7 +138,6 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
        movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
-       andl    #0xefff,%d1
        jne     Lwork_to_do             /* still work to do */
 
 Lreturn:
index 5f5018a..3168003 100644 (file)
@@ -15,6 +15,8 @@ config MICROBLAZE
        select TRACING_SUPPORT
        select OF
        select OF_EARLY_FLATTREE
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
 
 config SWAP
        def_bool n
@@ -37,12 +39,6 @@ config GENERIC_FIND_NEXT_BIT
 config GENERIC_HWEIGHT
        def_bool y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       def_bool y
-
 config GENERIC_CALIBRATE_DELAY
        def_bool y
 
@@ -52,9 +48,6 @@ config GENERIC_TIME_VSYSCALL
 config GENERIC_CLOCKEVENTS
        def_bool y
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config GENERIC_GPIO
        def_bool y
 
index ab8fbe7..b3f5eec 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="rootfs.cpio"
 CONFIG_INITRAMFS_COMPRESSION_GZIP=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_HOTPLUG is not set
index ebc143c..0249e4b 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_HOTPLUG is not set
index 5fd3190..c4532f0 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/types.h>
 #include <asm/registers.h>
 
-#ifdef CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
 static inline unsigned long arch_local_irq_save(void)
 {
index b23f680..885574a 100644 (file)
@@ -411,20 +411,19 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 static inline unsigned long pte_update(pte_t *p, unsigned long clr,
                                unsigned long set)
 {
-       unsigned long old, tmp, msr;
-
-       __asm__ __volatile__("\
-       msrclr  %2, 0x2\n\
-       nop\n\
-       lw      %0, %4, r0\n\
-       andn    %1, %0, %5\n\
-       or      %1, %1, %6\n\
-       sw      %1, %4, r0\n\
-       mts     rmsr, %2\n\
-       nop"
-       : "=&r" (old), "=&r" (tmp), "=&r" (msr), "=m" (*p)
-       : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set), "m" (*p)
-       : "cc");
+       unsigned long flags, old, tmp;
+
+       raw_local_irq_save(flags);
+
+       __asm__ __volatile__(   "lw     %0, %2, r0      \n"
+                               "andn   %1, %0, %3      \n"
+                               "or     %1, %1, %4      \n"
+                               "sw     %1, %2, r0      \n"
+                       : "=&r" (old), "=&r" (tmp)
+                       : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set)
+                       : "cc");
+
+       raw_local_irq_restore(flags);
 
        return old;
 }
index e01afa6..488c1ed 100644 (file)
@@ -27,7 +27,7 @@
        register unsigned tmp __asm__("r3");                    \
        tmp = 0x0;      /* Prevent warning about unused */      \
        __asm__ __volatile__ (                                  \
-                       "mfs    %0, rpvr" #pvrid ";"    \
+                       "mfs    %0, rpvr" #pvrid ";"            \
                        : "=r" (tmp) : : "memory");             \
        val = tmp;                                              \
 }
@@ -54,7 +54,7 @@ int cpu_has_pvr(void)
        if (!(flags & PVR_MSR_BIT))
                return 0;
 
-       get_single_pvr(0x00, pvr0);
+       get_single_pvr(0, pvr0);
        pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
 
        if (pvr0 & PVR0_PVR_FULL_MASK)
index 4243400..778a5ce 100644 (file)
@@ -62,23 +62,32 @@ real_start:
        andi    r1, r1, ~2
        mts     rmsr, r1
 /*
- * Here is checking mechanism which check if Microblaze has msr instructions
- * We load msr and compare it with previous r1 value - if is the same,
- * msr instructions works if not - cpu don't have them.
+ * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
+ * if the msrclr instruction is not enabled. We use this to detect
+ * if the opcode is available, by issuing msrclr and then testing the result.
+ * r8 == 0 - msr instructions are implemented
+ * r8 != 0 - msr instructions are not implemented
  */
-       /* r8=0 - I have msr instr, 1 - I don't have them */
-       rsubi   r0, r0, 1       /* set the carry bit */
-       msrclr  r0, 0x4         /* try to clear it */
-       /* read the carry bit, r8 will be '0' if msrclr exists */
-       addik   r8, r0, 0
+       msrclr  r8, 0 /* clear nothing - just read msr for test */
+       cmpu    r8, r8, r1 /* r1 must contain msr reg content */
 
 /* r7 may point to an FDT, or there may be one linked in.
    if it's in r7, we've got to save it away ASAP.
    We ensure r7 points to a valid FDT, just in case the bootloader
    is broken or non-existent */
        beqi    r7, no_fdt_arg                  /* NULL pointer?  don't copy */
-       lw      r11, r0, r7                     /* Does r7 point to a */
-       rsubi   r11, r11, OF_DT_HEADER          /* valid FDT? */
+/* Does r7 point to a valid FDT? Load HEADER magic number */
+       /* Run time Big/Little endian platform */
+       /* Save 1 as word and load byte - 0 - BIG, 1 - LITTLE */
+       addik   r11, r0, 0x1 /* BIG/LITTLE checking value */
+       /* __bss_start will be zeroed later - it is just temp location */
+       swi     r11, r0, TOPHYS(__bss_start)
+       lbui    r11, r0, TOPHYS(__bss_start)
+       beqid   r11, big_endian /* DO NOT break delay stop dependency */
+       lw      r11, r0, r7 /* Big endian load in delay slot */
+       lwr     r11, r0, r7 /* Little endian load */
+big_endian:
+       rsubi   r11, r11, OF_DT_HEADER  /* Check FDT header */
        beqi    r11, _prepare_copy_fdt
        or      r7, r0, r0              /* clear R7 when not valid DTB */
        bnei    r11, no_fdt_arg                 /* No - get out of here */
index 25f6e07..782680d 100644 (file)
        #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0
        #define BSRLI(rD, rA, imm)      \
                bsrli rD, rA, imm
-       #elif CONFIG_XILINX_MICROBLAZE0_USE_DIV > 0
-       #define BSRLI(rD, rA, imm)      \
-               ori rD, r0, (1 << imm); \
-               idivu rD, rD, rA
        #else
        #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA)
        /* Only the used shift constants defined here - add more if needed */
index bb1558e..9312fbb 100644 (file)
@@ -161,11 +161,11 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
        if (msr)
                eprintk("!!!Your kernel has setup MSR instruction but "
-                               "CPU don't have it %d\n", msr);
+                               "CPU don't have it %x\n", msr);
 #else
        if (!msr)
                eprintk("!!!Your kernel not setup MSR instruction but "
-                               "CPU have it %d\n", msr);
+                               "CPU have it %x\n", msr);
 #endif
 
        for (src = __ivt_start; src < __ivt_end; src++, dst++)
index fdc48bb..62021d7 100644 (file)
  *     between mem locations with size of xfer spec'd in bytes
  */
 
+#ifdef __MICROBLAZEEL__
+#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM.
+#endif
+
 #include <linux/linkage.h>
        .text
        .globl  memcpy
index 548e6cc..f5ecc05 100644 (file)
@@ -793,9 +793,6 @@ config SCHED_OMIT_FRAME_POINTER
        bool
        default y
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 #
 # Select some configuration options automatically based on user selections.
 #
index f437cd1..5358f90 100644 (file)
@@ -7,7 +7,7 @@ config TRACE_IRQFLAGS_SUPPORT
 source "lib/Kconfig.debug"
 
 config EARLY_PRINTK
-       bool "Early printk" if EMBEDDED
+       bool "Early printk" if EXPERT
        depends on SYS_HAS_EARLY_PRINTK
        default y
        help
index c78c7e7..6cd5a51 100644 (file)
@@ -14,7 +14,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index 927d58b..22fdf2f 100644 (file)
@@ -21,7 +21,7 @@ CONFIG_CGROUP_CPUACCT=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index b806a4e..9190051 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_TINY_RCU=y
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
index 9749bc8..1cdff6b 100644 (file)
@@ -26,7 +26,7 @@ CONFIG_PID_NS=y
 CONFIG_NET_NS=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
index 502a8e9..5135dc0 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 3567b6f..75165df 100644 (file)
@@ -15,7 +15,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 6c4f7e9..5419adb 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index dda158b..4044c9e 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index 7e4fc76..c6b4993 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index 6fe205f..1f69249 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index a741c55..b6e21c7 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_LOCALVERSION="-db1500"
 CONFIG_KERNEL_LZMA=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index cd32dd8..798a553 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index b15bfd1..87d0340 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
index 0b60c06..0126e66 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 63944a1..e5b73de 100644 (file)
@@ -17,7 +17,7 @@ CONFIG_NAMESPACES=y
 CONFIG_USER_NS=y
 CONFIG_PID_NS=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
index 53edc13..48a40ae 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
index 36de199..d160656 100644 (file)
@@ -17,7 +17,7 @@ CONFIG_IPC_NS=y
 CONFIG_USER_NS=y
 CONFIG_PID_NS=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_COMPAT_BRK is not set
index 4b16c48..0e36abc 100644 (file)
@@ -15,7 +15,7 @@ CONFIG_CGROUPS=y
 CONFIG_CPUSETS=y
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 98f2c77..4dbf626 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 5bea99b..7bbd521 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
index 6ae46bc..92a60ae 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index bf24e93..db5705e 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_TOSHIBA_JMR3927=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
index 6447261..d9f3db2 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_HZ_1000=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
index f7033f3..167c1d0 100644 (file)
@@ -21,7 +21,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
index 9d03b68..7270f31 100644 (file)
@@ -15,7 +15,7 @@ CONFIG_UTS_NS=y
 CONFIG_IPC_NS=y
 CONFIG_PID_NS=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
index 86bf001..9c9a123 100644 (file)
@@ -9,7 +9,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 4925f50..b5ad738 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index efb779f..c16de98 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index ab05145..d1142e9 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_LOCALVERSION="-pmc"
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SHMEM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 8146997..a97a42c 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_AUDIT=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
index 1597aa1..75eb1b1 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index 96f0d43..dcbe270 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index b4bfd48..fa00487 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index 5a66002..e83d649 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_PCSPKR_PLATFORM is not set
index 39926a1..f292576 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 3376bc8..1d1f206 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 6514f1b..15c66a5 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
index f1f58e9..3b0b6e8 100644 (file)
@@ -14,7 +14,7 @@ CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_PCSPKR_PLATFORM is not set
index d6457bc..55902d9 100644 (file)
@@ -13,7 +13,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index 29acfab..9cba856 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_EPOLL is not set
index 2b3e476..2c0230e 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 64840d7..5b0463e 100644 (file)
@@ -15,7 +15,7 @@ CONFIG_RELAY=y
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index d9be37f..30036b4 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 3d25dd0..81bfa1d 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index be697c9..c415c4f 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
index 7ec9287..ee4b2be 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index a231b73..44a451b 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_EPOLL is not set
 CONFIG_SLAB=y
index ab3a3dc..f72d305 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 8ed41cf..243bfa2 100644 (file)
@@ -1,6 +1,7 @@
 config MN10300
        def_bool y
        select HAVE_OPROFILE
+       select GENERIC_HARDIRQS
 
 config AM33_2
        def_bool n
@@ -34,9 +35,6 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config GENERIC_CALIBRATE_DELAY
        def_bool y
 
@@ -79,10 +77,6 @@ config QUICKLIST
 config ARCH_HAS_ILOG2_U32
        def_bool y
 
-# Use the generic interrupt handling code in kernel/irq/
-config GENERIC_HARDIRQS
-       def_bool y
-
 config HOTPLUG_CPU
        def_bool n
 
index 3f749b6..1fd41ec 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
index 83ce2f2..31d7626 100644 (file)
@@ -15,7 +15,7 @@ CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_RELAY=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
index 0888675..fed2946 100644 (file)
@@ -12,7 +12,10 @@ config PARISC
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
-       select GENERIC_HARDIRQS_NO__DO_IRQ
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select IRQ_PER_CPU
+
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
@@ -66,22 +69,9 @@ config TIME_LOW_RES
        depends on SMP
        default y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       def_bool y
-
 config HAVE_LATENCYTOP_SUPPORT
         def_bool y
 
-config IRQ_PER_CPU
-       bool
-       default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
index f9305f3..b647b18 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
index 628d3e0..311ca36 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
index 11bdd68..fc770be 100644 (file)
@@ -169,11 +169,11 @@ static int __init pdc_console_tty_driver_init(void)
 
        struct console *tmp;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(tmp)
                if (tmp == &pdc_cons)
                        break;
-       release_console_sem();
+       console_unlock();
 
        if (!tmp) {
                printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
index 959f38c..7d69e9b 100644 (file)
@@ -36,24 +36,12 @@ config GENERIC_TIME_VSYSCALL
 config GENERIC_CLOCKEVENTS
        def_bool y
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       default y
-
 config HAVE_SETUP_PER_CPU_AREA
        def_bool PPC64
 
 config NEED_PER_CPU_EMBED_FIRST_CHUNK
        def_bool PPC64
 
-config IRQ_PER_CPU
-       bool
-       default y
-
 config NR_IRQS
        int "Number of virtual interrupt numbers"
        range 32 32768
@@ -143,6 +131,9 @@ config PPC
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
+       select HAVE_GENERIC_HARDIRQS
+       select HAVE_SPARSE_IRQ
+       select IRQ_PER_CPU
 
 config EARLY_PRINTK
        bool
@@ -392,19 +383,6 @@ config IRQ_ALL_CPUS
          CPU.  Generally saying Y is safe, although some problems have been
          reported with SMP Power Macintoshes with this option enabled.
 
-config SPARSE_IRQ
-       bool "Support sparse irq numbering"
-       default n
-       help
-         This enables support for sparse irqs. This is useful for distro
-         kernels that want to define a high CONFIG_NR_CPUS value but still
-         want to have low kernel memory footprint on smaller machines.
-
-         ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
-           out the irq_desc[] array in a more NUMA-friendly way. )
-
-         If you don't know what to do here, say N.
-
 config NUMA
        bool "NUMA support"
        depends on PPC64
index 96deec6..8917816 100644 (file)
@@ -368,7 +368,7 @@ INSTALL := install
 extra-installed                := $(patsubst $(obj)/%, $(DESTDIR)$(WRAPPER_OBJDIR)/%, $(extra-y))
 hostprogs-installed    := $(patsubst %, $(DESTDIR)$(WRAPPER_BINDIR)/%, $(hostprogs-y))
 wrapper-installed      := $(DESTDIR)$(WRAPPER_BINDIR)/wrapper
-dts-installed          := $(patsubst $(obj)/dts/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(obj)/dts/*.dts))
+dts-installed          := $(patsubst $(dtstree)/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(dtstree)/*.dts))
 
 all-installed          := $(extra-installed) $(hostprogs-installed) $(wrapper-installed) $(dts-installed)
 
index d3db02f..a0bd188 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                device_type = "soc";
-               compatible = "fsl,mpc8315-immr", "simple-bus";
+               compatible = "fsl,mpc8308-immr", "simple-bus";
                ranges = <0 0xe0000000 0x00100000>;
                reg = <0xe0000000 0x00000200>;
                bus-frequency = <0>;
index 2bbecbb..69422eb 100644 (file)
                        ranges = <0x0 0xc100 0x200>;
                        cell-index = <1>;
                        dma00: dma-channel@0 {
-                               compatible = "fsl,eloplus-dma-channel";
+                               compatible = "fsl,ssi-dma-channel";
                                reg = <0x0 0x80>;
                                cell-index = <0>;
                                interrupts = <76 2>;
                        };
                        dma01: dma-channel@80 {
-                               compatible = "fsl,eloplus-dma-channel";
+                               compatible = "fsl,ssi-dma-channel";
                                reg = <0x80 0x80>;
                                cell-index = <1>;
                                interrupts = <77 2>;
index 97fedce..4182c77 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 33b3c24..2dbb293 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 4613079..ebeb4ac 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 34b8c1a..532ea9d 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 651be09..3c142ac 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index ded455e..ff57d48 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 63746a0..3ed16d5 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index f5f2a4e..b1b7d2c 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index ac65b48..30a0a8e 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_PCI_QUIRKS is not set
 # CONFIG_COMPAT_BRK is not set
index 17e4dd9..a46942a 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index fedd03f..07d77e5 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index ebff701..2ce7e9a 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 865e93f..18730ff 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 8ece4c7..92f863a 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_PROFILING=y
index 4ca9b48..34c0914 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index e3b65d2..21c33fa 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 64cd0f3..01cc2b1 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 01d0336..dfcffed 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 89b2f96..47e399f 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index e3386cf..a6a002e 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index 9c13b9d..6cf9d66 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index f234c4d..69b57da 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_EPOLL is not set
index a4a795c..f3638ae 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_EPOLL is not set
index 20d53a1..6828eda 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_EPOLL is not set
index 6bd5833..7f7e4a8 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
index 3a1f702..959cd2c 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_EPOLL is not set
index eed42d8..d2762d9 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index e43ecb2..7a7b731 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index c2e6ab5..c683bce 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 1d3b200..a721cd3 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 91fe73b..a5699a1 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 6d300f2..b4da1a7 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index b236a67..291f822 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 001dead..f8b228a 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 9dccefc..99660c0 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index d4b165d..10b5c4c 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 89ba672..45925d7 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 2ea6b40..f367985 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index bffe3c7..414eda3 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index fa5c9ee..6d6463f 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
index 385b1af..8f7c106 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_KSI8560=y
 CONFIG_CPM2=y
index 222b704..55e0725 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_MPC8540_ADS=y
 CONFIG_NO_HZ=y
index 619702d..d724095 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_MPC8560_ADS=y
 CONFIG_BINFMT_MISC=y
index 6bf56e8..4b44bea 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_MPC85xx_CDS=y
 CONFIG_NO_HZ=y
index a9a17d0..5b2b651 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_SBC8548=y
index 820e32d..f7fdb03 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_SBC8560=y
index b6db3f4..77506b5 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index 333a41b..5d4db15 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
index 33db352..ddcb9f3 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index f0c20df..981abd6 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index a883450..37b3d72 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
index ff95f90..3593b32 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index 8d6c90e..de413ac 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
index f53efe4..5ea3124 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 432ebc2..4b24412 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index ce5e919..a360ba4 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 589e71e..be2829d 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 321fb47..036bfb2 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_ELF_CORE is not set
 CONFIG_MODULES=y
index b5e4639..0c9c7ed 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 71145c3..0a92ca0 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index ca84c7f..6912874 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
index 94d120e..06f9549 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 2677b08..fceffb3 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
 # CONFIG_IOSCHED_CFQ is not set
index f9a3112..219fd47 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
index fcf0a39..e74d3a4 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
 CONFIG_PERF_COUNTERS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index b9b63a6..94ebfee 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_PPC_CHRP is not set
index c4ed255..39518e9 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_SLAB=y
 # CONFIG_IOSCHED_CFQ is not set
index f276c7c..2a49062 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_BUG is not set
index 3b94708..75f0bbf 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_PPC_CHRP is not set
 # CONFIG_PPC_PMAC is not set
index c7d68ff..6a22400 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_PPC_CHRP is not set
 # CONFIG_PPC_PMAC is not set
index 5b1b10f..5aac9a8 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index 3aeb594..99a19d1 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index d62c801..c636f23 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 668215c..5c25882 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_BUG is not set
index 63b90d4..55b5431 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index f9b8348..9e146cd 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
index 93d7425..bfd634b 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index 2fa05f7..4713320 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_MODULES=y
index a4353be..baad8db 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_PPC_CHRP is not set
 # CONFIG_PPC_PMAC is not set
index 49cffe0..caba919 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_PERF_EVENTS is not set
 # CONFIG_COMPAT_BRK is not set
index f87f0e1..9c3f22c 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_PPC64=y
 CONFIG_ALTIVEC=y
 CONFIG_VSX=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=128
+CONFIG_NR_CPUS=1024
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -45,6 +45,8 @@ CONFIG_KEXEC=y
 CONFIG_IRQ_ALL_CPUS=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_PPC_64K_PAGES=y
+CONFIG_PPC_SUBPAGE_PROT=y
 CONFIG_SCHED_SMT=y
 CONFIG_HOTPLUG_PCI=m
 CONFIG_HOTPLUG_PCI_RPA=m
@@ -184,6 +186,7 @@ CONFIG_ACENIC_OMIT_TIGON_I=y
 CONFIG_E1000=y
 CONFIG_E1000E=y
 CONFIG_TIGON3=y
+CONFIG_BNX2=m
 CONFIG_CHELSIO_T1=m
 CONFIG_CHELSIO_T3=m
 CONFIG_EHEA=y
@@ -311,9 +314,7 @@ CONFIG_DEBUG_KERNEL=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_LATENCYTOP=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_IRQSOFF_TRACER=y
 CONFIG_SCHED_TRACER=y
-CONFIG_STACK_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DEBUG_STACK_USAGE=y
index 4f0c10a..ebb2a66 100644 (file)
@@ -1,7 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
index d0a5b67..8616fde 100644 (file)
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
index bb8ba75..175295f 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
 CONFIG_PERF_COUNTERS=y
 # CONFIG_VM_EVENT_COUNTERS is not set
index 96a7d06..921a847 100644 (file)
@@ -37,18 +37,21 @@ label##2:                                           \
        .align 2;                                       \
 label##3:
 
-#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect)  \
-label##4:                                              \
-       .popsection;                                    \
-       .pushsection sect,"a";                          \
-       .align 3;                                       \
-label##5:                                              \
-       FTR_ENTRY_LONG msk;                             \
-       FTR_ENTRY_LONG val;                             \
-       FTR_ENTRY_OFFSET label##1b-label##5b;           \
-       FTR_ENTRY_OFFSET label##2b-label##5b;           \
-       FTR_ENTRY_OFFSET label##3b-label##5b;           \
-       FTR_ENTRY_OFFSET label##4b-label##5b;           \
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect)          \
+label##4:                                                      \
+       .popsection;                                            \
+       .pushsection sect,"a";                                  \
+       .align 3;                                               \
+label##5:                                                      \
+       FTR_ENTRY_LONG msk;                                     \
+       FTR_ENTRY_LONG val;                                     \
+       FTR_ENTRY_OFFSET label##1b-label##5b;                   \
+       FTR_ENTRY_OFFSET label##2b-label##5b;                   \
+       FTR_ENTRY_OFFSET label##3b-label##5b;                   \
+       FTR_ENTRY_OFFSET label##4b-label##5b;                   \
+       .ifgt (label##4b-label##3b)-(label##2b-label##1b);      \
+       .error "Feature section else case larger than body";    \
+       .endif;                                                 \
        .popsection;
 
 
index 4e10f50..0edb684 100644 (file)
@@ -467,13 +467,22 @@ struct qe_immap {
 extern struct qe_immap __iomem *qe_immr;
 extern phys_addr_t get_qe_base(void);
 
-static inline unsigned long immrbar_virt_to_phys(void *address)
+/*
+ * Returns the offset within the QE address space of the given pointer.
+ *
+ * Note that the QE does not support 36-bit physical addresses, so if
+ * get_qe_base() returns a number above 4GB, the caller will probably fail.
+ */
+static inline phys_addr_t immrbar_virt_to_phys(void *address)
 {
-       if ( ((u32)address >= (u32)qe_immr) &&
-                       ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) )
-               return (unsigned long)(address - (u32)qe_immr +
-                               (u32)get_qe_base());
-       return (unsigned long)virt_to_phys(address);
+       void *q = (void *)qe_immr;
+
+       /* Is it a MURAM address? */
+       if ((address >= q) && (address < (q + QE_IMMAP_SIZE)))
+               return get_qe_base() + (address - q);
+
+       /* It's an address returned by kmalloc */
+       return virt_to_phys(address);
 }
 
 #endif /* __KERNEL__ */
index b85d8dd..b0b06d8 100644 (file)
 
 #else
 #ifdef CONFIG_TRACE_IRQFLAGS
+#ifdef CONFIG_IRQSOFF_TRACER
+/*
+ * Since the ftrace irqsoff latency trace checks CALLER_ADDR1,
+ * which is the stack frame here, we need to force a stack frame
+ * in case we came from user space.
+ */
+#define TRACE_WITH_FRAME_BUFFER(func)          \
+       mflr    r0;                             \
+       stdu    r1, -32(r1);                    \
+       std     r0, 16(r1);                     \
+       stdu    r1, -32(r1);                    \
+       bl func;                                \
+       ld      r1, 0(r1);                      \
+       ld      r1, 0(r1);
+#else
+#define TRACE_WITH_FRAME_BUFFER(func)          \
+       bl func;
+#endif
+
 /*
  * Most of the CPU's IRQ-state tracing is done from assembly code; we
  * have to call a C function so call a wrapper that saves all the
  * C-clobbered registers.
  */
-#define TRACE_ENABLE_INTS      bl .trace_hardirqs_on
-#define TRACE_DISABLE_INTS     bl .trace_hardirqs_off
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \
-       cmpdi   en,0;                           \
-       bne     95f;                            \
-       stb     en,PACASOFTIRQEN(r13);          \
-       bl      .trace_hardirqs_off;            \
-       b       skip;                           \
-95:    bl      .trace_hardirqs_on;             \
+#define TRACE_ENABLE_INTS      TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
+#define TRACE_DISABLE_INTS     TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
+
+#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)         \
+       cmpdi   en,0;                                   \
+       bne     95f;                                    \
+       stb     en,PACASOFTIRQEN(r13);                  \
+       TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)    \
+       b       skip;                                   \
+95:    TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)     \
        li      en,1;
 #define TRACE_AND_RESTORE_IRQ(en)              \
        TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f);  \
-       stb     en,PACASOFTIRQEN(r13);          \
+       stb     en,PACASOFTIRQEN(r13);          \
 96:
 #else
 #define TRACE_ENABLE_INTS
index 8433d36..fe56a23 100644 (file)
@@ -116,9 +116,6 @@ struct machdep_calls {
         * If for some reason there is no irq, but the interrupt
         * shouldn't be counted as spurious, return NO_IRQ_IGNORE. */
        unsigned int    (*get_irq)(void);
-#ifdef CONFIG_KEXEC
-       void            (*kexec_cpu_down)(int crash_shutdown, int secondary);
-#endif
 
        /* PCI stuff */
        /* Called after scanning the bus, before allocating resources */
@@ -235,11 +232,7 @@ struct machdep_calls {
        void (*machine_shutdown)(void);
 
 #ifdef CONFIG_KEXEC
-       /* Called to do the minimal shutdown needed to run a kexec'd kernel
-        * to run successfully.
-        * XXX Should we move this one out of kexec scope?
-        */
-       void (*machine_crash_shutdown)(struct pt_regs *regs);
+       void (*kexec_cpu_down)(int crash_shutdown, int secondary);
 
        /* Called to do what every setup is needed on image and the
         * reboot code buffer. Returns 0 on success.
@@ -248,9 +241,6 @@ struct machdep_calls {
         */
        int (*machine_kexec_prepare)(struct kimage *image);
 
-       /* Called to handle any machine specific cleanup on image */
-       void (*machine_kexec_cleanup)(struct kimage *image);
-
        /* Called to perform the _real_ kexec.
         * Do NOT allocate memory or fail here. We are past the point of
         * no return.
index 8eaed81..17194fc 100644 (file)
@@ -40,8 +40,8 @@
 
 /* MAS registers bit definitions */
 
-#define MAS0_TLBSEL(x)         ((x << 28) & 0x30000000)
-#define MAS0_ESEL(x)           ((x << 16) & 0x0FFF0000)
+#define MAS0_TLBSEL(x)         (((x) << 28) & 0x30000000)
+#define MAS0_ESEL(x)           (((x) << 16) & 0x0FFF0000)
 #define MAS0_NV(x)             ((x) & 0x00000FFF)
 #define MAS0_HES               0x00004000
 #define MAS0_WQ_ALLWAYS                0x00000000
 
 #define MAS1_VALID             0x80000000
 #define MAS1_IPROT             0x40000000
-#define MAS1_TID(x)            ((x << 16) & 0x3FFF0000)
+#define MAS1_TID(x)            (((x) << 16) & 0x3FFF0000)
 #define MAS1_IND               0x00002000
 #define MAS1_TS                        0x00001000
 #define MAS1_TSIZE_MASK                0x00000f80
 #define MAS1_TSIZE_SHIFT       7
-#define MAS1_TSIZE(x)          ((x << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+#define MAS1_TSIZE(x)          (((x) << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
 
 #define MAS2_EPN               0xFFFFF000
 #define MAS2_X0                        0x00000040
index 53b64be..da4b200 100644 (file)
@@ -101,7 +101,7 @@ extern phys_addr_t kernstart_addr;
 
 #ifdef CONFIG_FLATMEM
 #define ARCH_PFN_OFFSET                (MEMORY_START >> PAGE_SHIFT)
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < (ARCH_PFN_OFFSET + max_mapnr))
+#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
 #endif
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
index ff0005e..125fc1a 100644 (file)
 #define HID0_NOPTI     (1<<0)          /* No-op dcbt and dcbst instr. */
 
 #define SPRN_HID1      0x3F1           /* Hardware Implementation Register 1 */
+#ifdef CONFIG_6xx
 #define HID1_EMCP      (1<<31)         /* 7450 Machine Check Pin Enable */
 #define HID1_DFS       (1<<22)         /* 7447A Dynamic Frequency Scaling */
 #define HID1_PC0       (1<<16)         /* 7450 PLL_CFG[0] */
 #define HID1_SYNCBE    (1<<11)         /* 7450 ABE for sync, eieio */
 #define HID1_ABE       (1<<10)         /* 7450 Address Broadcast Enable */
 #define HID1_PS                (1<<16)         /* 750FX PLL selection */
+#endif
 #define SPRN_HID2      0x3F8           /* Hardware Implementation Register 2 */
 #define SPRN_HID2_GEKKO        0x398           /* Gekko HID2 Register */
 #define SPRN_IABR      0x3F2   /* Instruction Address Breakpoint Register */
index 667a498..e68c69b 100644 (file)
                                        store or cache line push */
 #endif
 
+/* Bit definitions for the HID1 */
+#ifdef CONFIG_E500
+/* e500v1/v2 */
+#define HID1_PLL_CFG_MASK 0xfc000000   /* PLL_CFG input pins */
+#define HID1_RFXE      0x00020000      /* Read fault exception enable */
+#define HID1_R1DPE     0x00008000      /* R1 data bus parity enable */
+#define HID1_R2DPE     0x00004000      /* R2 data bus parity enable */
+#define HID1_ASTME     0x00002000      /* Address bus streaming mode enable */
+#define HID1_ABE       0x00001000      /* Address broadcast enable */
+#define HID1_MPXTT     0x00000400      /* MPX re-map transfer type */
+#define HID1_ATS       0x00000080      /* Atomic status */
+#define HID1_MID_MASK  0x0000000f      /* MID input pins */
+#endif
+
 /* Bit definitions for the DBSR. */
 /*
  * DBSR bits which have conflicting definitions on true Book E versus IBM 40x.
index 0ab8d86..0c8b35d 100644 (file)
@@ -203,14 +203,6 @@ void spu_irq_setaffinity(struct spu *spu, int cpu);
 void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
                void *code, int code_size);
 
-#ifdef CONFIG_KEXEC
-void crash_register_spus(struct list_head *list);
-#else
-static inline void crash_register_spus(struct list_head *list)
-{
-}
-#endif
-
 extern void spu_invalidate_slbs(struct spu *spu);
 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 int spu_64k_pages_available(void);
index 55cba4a..f8cd9fb 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/mmu.h>
 
 _GLOBAL(__setup_cpu_603)
-       mflr    r4
+       mflr    r5
 BEGIN_MMU_FTR_SECTION
        li      r10,0
        mtspr   SPRN_SPRG_603_LRU,r10           /* init SW LRU tracking */
@@ -27,60 +27,60 @@ BEGIN_FTR_SECTION
        bl      __init_fpu_registers
 END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
        bl      setup_common_caches
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_604)
-       mflr    r4
+       mflr    r5
        bl      setup_common_caches
        bl      setup_604_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750cx)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        bl      setup_750cx
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750fx)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        bl      setup_750fx
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_7400)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_7400_workarounds
        bl      setup_common_caches
        bl      setup_750_7400_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_7410)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_7410_workarounds
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        li      r3,0
        mtspr   SPRN_L2CR2,r3
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_745x)
-       mflr    r4
+       mflr    r5
        bl      setup_common_caches
        bl      setup_745x_specifics
-       mtlr    r4
+       mtlr    r5
        blr
 
 /* Enable caches for 603's, 604, 750 & 7400 */
@@ -194,10 +194,10 @@ setup_750cx:
        cror    4*cr0+eq,4*cr0+eq,4*cr1+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr2+eq
        bnelr
-       lwz     r6,CPU_SPEC_FEATURES(r5)
+       lwz     r6,CPU_SPEC_FEATURES(r4)
        li      r7,CPU_FTR_CAN_NAP
        andc    r6,r6,r7
-       stw     r6,CPU_SPEC_FEATURES(r5)
+       stw     r6,CPU_SPEC_FEATURES(r4)
        blr
 
 /* 750fx specific
@@ -225,12 +225,12 @@ BEGIN_FTR_SECTION
        andis.  r11,r11,L3CR_L3E@h
        beq     1f
 END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
-       lwz     r6,CPU_SPEC_FEATURES(r5)
+       lwz     r6,CPU_SPEC_FEATURES(r4)
        andi.   r0,r6,CPU_FTR_L3_DISABLE_NAP
        beq     1f
        li      r7,CPU_FTR_CAN_NAP
        andc    r6,r6,r7
-       stw     r6,CPU_SPEC_FEATURES(r5)
+       stw     r6,CPU_SPEC_FEATURES(r4)
 1:
        mfspr   r11,SPRN_HID0
 
index 894e64f..5c518ad 100644 (file)
@@ -64,6 +64,12 @@ _GLOBAL(__setup_cpu_e500v2)
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
        bl      __setup_e500_ivors
+#ifdef CONFIG_RAPIDIO
+       /* Ensure that RFXE is set */
+       mfspr   r3,SPRN_HID1
+       oris    r3,r3,HID1_RFXE@h
+       mtspr   SPRN_HID1,r3
+#endif
        mtlr    r4
        blr
 _GLOBAL(__setup_cpu_e500mc)
index be5ab18..e8e915c 100644 (file)
@@ -116,7 +116,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/power3",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "power3",
        },
        {       /* Power3+ */
@@ -132,7 +131,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/power3",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "power3",
        },
        {       /* Northstar */
@@ -148,7 +146,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/rs64",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "rs64",
        },
        {       /* Pulsar */
@@ -164,7 +161,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/rs64",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "rs64",
        },
        {       /* I-star */
@@ -180,7 +176,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/rs64",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "rs64",
        },
        {       /* S-star */
@@ -196,7 +191,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/rs64",
                .oprofile_type          = PPC_OPROFILE_RS64,
-               .machine_check          = machine_check_generic,
                .platform               = "rs64",
        },
        {       /* Power4 */
@@ -212,7 +206,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/power4",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "power4",
        },
        {       /* Power4+ */
@@ -228,7 +221,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/power4",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "power4",
        },
        {       /* PPC970 */
@@ -247,7 +239,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc970",
        },
        {       /* PPC970FX */
@@ -266,7 +257,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc970",
        },
        {       /* PPC970MP DD1.0 - no DEEPNAP, use regular 970 init */
@@ -285,7 +275,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970MP",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc970",
        },
        {       /* PPC970MP */
@@ -304,7 +293,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970MP",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc970",
        },
        {       /* PPC970GX */
@@ -322,7 +310,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
                .oprofile_type          = PPC_OPROFILE_POWER4,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc970",
        },
        {       /* Power5 GR */
@@ -343,7 +330,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                 */
                .oprofile_mmcra_sihv    = MMCRA_SIHV,
                .oprofile_mmcra_sipr    = MMCRA_SIPR,
-               .machine_check          = machine_check_generic,
                .platform               = "power5",
        },
        {       /* Power5++ */
@@ -360,7 +346,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .oprofile_mmcra_sihv    = MMCRA_SIHV,
                .oprofile_mmcra_sipr    = MMCRA_SIPR,
-               .machine_check          = machine_check_generic,
                .platform               = "power5+",
        },
        {       /* Power5 GS */
@@ -378,7 +363,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .oprofile_mmcra_sihv    = MMCRA_SIHV,
                .oprofile_mmcra_sipr    = MMCRA_SIPR,
-               .machine_check          = machine_check_generic,
                .platform               = "power5+",
        },
        {       /* POWER6 in P5+ mode; 2.04-compliant processor */
@@ -390,7 +374,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .mmu_features           = MMU_FTR_HPTE_TABLE,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
-               .machine_check          = machine_check_generic,
                .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .platform               = "power5+",
@@ -413,7 +396,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_mmcra_sipr    = POWER6_MMCRA_SIPR,
                .oprofile_mmcra_clear   = POWER6_MMCRA_THRM |
                        POWER6_MMCRA_OTHER,
-               .machine_check          = machine_check_generic,
                .platform               = "power6x",
        },
        {       /* 2.05-compliant processor, i.e. Power6 "architected" mode */
@@ -425,7 +407,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .mmu_features           = MMU_FTR_HPTE_TABLE,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
-               .machine_check          = machine_check_generic,
                .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .platform               = "power6",
@@ -440,7 +421,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                        MMU_FTR_TLBIE_206,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
-               .machine_check          = machine_check_generic,
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
                .platform               = "power7",
@@ -492,7 +472,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pmc_type               = PPC_PMC_IBM,
                .oprofile_cpu_type      = "ppc64/cell-be",
                .oprofile_type          = PPC_OPROFILE_CELL,
-               .machine_check          = machine_check_generic,
                .platform               = "ppc-cell-be",
        },
        {       /* PA Semi PA6T */
@@ -510,7 +489,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_pa6t,
                .oprofile_cpu_type      = "ppc64/pa6t",
                .oprofile_type          = PPC_OPROFILE_PA6T,
-               .machine_check          = machine_check_generic,
                .platform               = "pa6t",
        },
        {       /* default match */
@@ -524,7 +502,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 6,
                .pmc_type               = PPC_PMC_IBM,
-               .machine_check          = machine_check_generic,
                .platform               = "power4",
        }
 #endif /* CONFIG_PPC_BOOK3S_64 */
@@ -2099,8 +2076,8 @@ static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
         * pointer on ppc64 and booke as we are running at 0 in real mode
         * on ppc64 and reloc_offset is always 0 on booke.
         */
-       if (s->cpu_setup) {
-               s->cpu_setup(offset, s);
+       if (t->cpu_setup) {
+               t->cpu_setup(offset, t);
        }
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
 }
index 832c8c4..3d569e2 100644 (file)
@@ -48,7 +48,7 @@ int crashing_cpu = -1;
 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 cpumask_t cpus_in_sr = CPU_MASK_NONE;
 
-#define CRASH_HANDLER_MAX 2
+#define CRASH_HANDLER_MAX 3
 /* NULL terminated list of shutdown handles */
 static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1];
 static DEFINE_SPINLOCK(crash_handlers_lock);
@@ -125,7 +125,7 @@ static void crash_kexec_prepare_cpus(int cpu)
        smp_wmb();
 
        /*
-        * FIXME: Until we will have the way to stop other CPUSs reliabally,
+        * FIXME: Until we will have the way to stop other CPUs reliably,
         * the crash CPU will send an IPI and wait for other CPUs to
         * respond.
         * Delay of at least 10 seconds.
@@ -254,72 +254,6 @@ void crash_kexec_secondary(struct pt_regs *regs)
        cpus_in_sr = CPU_MASK_NONE;
 }
 #endif
-#ifdef CONFIG_SPU_BASE
-
-#include <asm/spu.h>
-#include <asm/spu_priv1.h>
-
-struct crash_spu_info {
-       struct spu *spu;
-       u32 saved_spu_runcntl_RW;
-       u32 saved_spu_status_R;
-       u32 saved_spu_npc_RW;
-       u64 saved_mfc_sr1_RW;
-       u64 saved_mfc_dar;
-       u64 saved_mfc_dsisr;
-};
-
-#define CRASH_NUM_SPUS 16      /* Enough for current hardware */
-static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
-
-static void crash_kexec_stop_spus(void)
-{
-       struct spu *spu;
-       int i;
-       u64 tmp;
-
-       for (i = 0; i < CRASH_NUM_SPUS; i++) {
-               if (!crash_spu_info[i].spu)
-                       continue;
-
-               spu = crash_spu_info[i].spu;
-
-               crash_spu_info[i].saved_spu_runcntl_RW =
-                       in_be32(&spu->problem->spu_runcntl_RW);
-               crash_spu_info[i].saved_spu_status_R =
-                       in_be32(&spu->problem->spu_status_R);
-               crash_spu_info[i].saved_spu_npc_RW =
-                       in_be32(&spu->problem->spu_npc_RW);
-
-               crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
-               crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
-               tmp = spu_mfc_sr1_get(spu);
-               crash_spu_info[i].saved_mfc_sr1_RW = tmp;
-
-               tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
-               spu_mfc_sr1_set(spu, tmp);
-
-               __delay(200);
-       }
-}
-
-void crash_register_spus(struct list_head *list)
-{
-       struct spu *spu;
-
-       list_for_each_entry(spu, list, full_list) {
-               if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
-                       continue;
-
-               crash_spu_info[spu->number].spu = spu;
-       }
-}
-
-#else
-static inline void crash_kexec_stop_spus(void)
-{
-}
-#endif /* CONFIG_SPU_BASE */
 
 /*
  * Register a function to be called on shutdown.  Only use this if you
@@ -439,8 +373,6 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        crash_shutdown_cpu = -1;
        __debugger_fault_handler = old_handler;
 
-       crash_kexec_stop_spus();
-
        if (ppc_md.kexec_cpu_down)
                ppc_md.kexec_cpu_down(1, 0);
 }
index c22dc1e..56212bc 100644 (file)
@@ -880,7 +880,18 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
         */
        andi.   r10,r9,MSR_EE
        beq     1f
+       /*
+        * Since the ftrace irqsoff latency trace checks CALLER_ADDR1,
+        * which is the stack frame here, we need to force a stack frame
+        * in case we came from user space.
+        */
+       stwu    r1,-32(r1)
+       mflr    r0
+       stw     r0,4(r1)
+       stwu    r1,-32(r1)
        bl      trace_hardirqs_on
+       lwz     r1,0(r1)
+       lwz     r1,0(r1)
        lwz     r9,_MSR(r1)
 1:
 #endif /* CONFIG_TRACE_IRQFLAGS */
index df7e20c..a5f8672 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/memblock.h>
 #include <linux/of.h>
 #include <linux/irq.h>
+#include <linux/ftrace.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -44,10 +45,7 @@ void machine_kexec_mask_interrupts(void) {
 
 void machine_crash_shutdown(struct pt_regs *regs)
 {
-       if (ppc_md.machine_crash_shutdown)
-               ppc_md.machine_crash_shutdown(regs);
-       else
-               default_machine_crash_shutdown(regs);
+       default_machine_crash_shutdown(regs);
 }
 
 /*
@@ -65,8 +63,6 @@ int machine_kexec_prepare(struct kimage *image)
 
 void machine_kexec_cleanup(struct kimage *image)
 {
-       if (ppc_md.machine_kexec_cleanup)
-               ppc_md.machine_kexec_cleanup(image);
 }
 
 void arch_crash_save_vmcoreinfo(void)
@@ -87,11 +83,17 @@ void arch_crash_save_vmcoreinfo(void)
  */
 void machine_kexec(struct kimage *image)
 {
+       int save_ftrace_enabled;
+
+       save_ftrace_enabled = __ftrace_enabled_save();
+
        if (ppc_md.machine_kexec)
                ppc_md.machine_kexec(image);
        else
                default_machine_kexec(image);
 
+       __ftrace_enabled_restore(save_ftrace_enabled);
+
        /* Fall back to normal restart if we're still alive. */
        machine_restart(NULL);
        for(;;);
index 4dcf5f8..b0dc8f7 100644 (file)
@@ -596,6 +596,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                        if (left <= 0)
                                left = period;
                        record = 1;
+                       event->hw.last_period = event->hw.sample_period;
                }
                if (left < 0x80000000LL)
                        val = 0x80000000LL - left;
index 84906d3..8303a6c 100644 (file)
@@ -353,6 +353,7 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread)
                        prime_debug_regs(new_thread);
 }
 #else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
+#ifndef CONFIG_HAVE_HW_BREAKPOINT
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
        if (thread->dabr) {
@@ -360,6 +361,7 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
                set_dabr(0);
        }
 }
+#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
 int set_dabr(unsigned long dabr)
@@ -631,7 +633,7 @@ void show_regs(struct pt_regs * regs)
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
                printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr);
 #else
-               printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
+               printk("DAR: "REG", DSISR: %08lx\n", regs->dar, regs->dsisr);
 #endif
        printk("TASK = %p[%d] '%s' THREAD: %p",
               current, task_pid_nr(current), current->comm, task_thread_info(current));
@@ -670,11 +672,11 @@ void flush_thread(void)
 {
        discard_lazy_cpu_state();
 
-#ifdef CONFIG_HAVE_HW_BREAKPOINTS
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
        flush_ptrace_hw_breakpoint(current);
-#else /* CONFIG_HAVE_HW_BREAKPOINTS */
+#else /* CONFIG_HAVE_HW_BREAKPOINT */
        set_debug_reg_defaults(&current->thread);
-#endif /* CONFIG_HAVE_HW_BREAKPOINTS */
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 }
 
 void
index 2b442e6..bf5f5ce 100644 (file)
@@ -256,31 +256,16 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf,
        struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
        struct rtas_update_flash_t *uf;
        char msg[RTAS_MSG_MAXLEN];
-       int msglen;
 
-       uf = (struct rtas_update_flash_t *) dp->data;
+       uf = dp->data;
 
        if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) {
                get_flash_status_msg(uf->status, msg);
        } else {           /* FIRMWARE_UPDATE_NAME */
                sprintf(msg, "%d\n", uf->status);
        }
-       msglen = strlen(msg);
-       if (msglen > count)
-               msglen = count;
-
-       if (ppos && *ppos != 0)
-               return 0;       /* be cheap */
-
-       if (!access_ok(VERIFY_WRITE, buf, msglen))
-               return -EINVAL;
 
-       if (copy_to_user(buf, msg, msglen))
-               return -EFAULT;
-
-       if (ppos)
-               *ppos = msglen;
-       return msglen;
+       return simple_read_from_buffer(buf, count, ppos, msg, strlen(msg));
 }
 
 /* constructor for flash_block_cache */
@@ -394,26 +379,13 @@ static ssize_t manage_flash_read(struct file *file, char __user *buf,
        char msg[RTAS_MSG_MAXLEN];
        int msglen;
 
-       args_buf = (struct rtas_manage_flash_t *) dp->data;
+       args_buf = dp->data;
        if (args_buf == NULL)
                return 0;
 
        msglen = sprintf(msg, "%d\n", args_buf->status);
-       if (msglen > count)
-               msglen = count;
 
-       if (ppos && *ppos != 0)
-               return 0;       /* be cheap */
-
-       if (!access_ok(VERIFY_WRITE, buf, msglen))
-               return -EINVAL;
-
-       if (copy_to_user(buf, msg, msglen))
-               return -EFAULT;
-
-       if (ppos)
-               *ppos = msglen;
-       return msglen;
+       return simple_read_from_buffer(buf, count, ppos, msg, msglen);
 }
 
 static ssize_t manage_flash_write(struct file *file, const char __user *buf,
@@ -495,24 +467,11 @@ static ssize_t validate_flash_read(struct file *file, char __user *buf,
        char msg[RTAS_MSG_MAXLEN];
        int msglen;
 
-       args_buf = (struct rtas_validate_flash_t *) dp->data;
+       args_buf = dp->data;
 
-       if (ppos && *ppos != 0)
-               return 0;       /* be cheap */
-       
        msglen = get_validate_flash_msg(args_buf, msg);
-       if (msglen > count)
-               msglen = count;
-
-       if (!access_ok(VERIFY_WRITE, buf, msglen))
-               return -EINVAL;
-
-       if (copy_to_user(buf, msg, msglen))
-               return -EFAULT;
 
-       if (ppos)
-               *ppos = msglen;
-       return msglen;
+       return simple_read_from_buffer(buf, count, ppos, msg, msglen);
 }
 
 static ssize_t validate_flash_write(struct file *file, const char __user *buf,
index 0438f81..049dbec 100644 (file)
@@ -160,7 +160,7 @@ static int log_rtas_len(char * buf)
        /* rtas fixed header */
        len = 8;
        err = (struct rtas_error_log *)buf;
-       if (err->extended_log_length) {
+       if (err->extended && err->extended_log_length) {
 
                /* extended header */
                len += err->extended_log_length;
index 09e4dea..09d31db 100644 (file)
@@ -265,11 +265,26 @@ void accumulate_stolen_time(void)
 {
        u64 sst, ust;
 
-       sst = scan_dispatch_log(get_paca()->starttime_user);
-       ust = scan_dispatch_log(get_paca()->starttime);
-       get_paca()->system_time -= sst;
-       get_paca()->user_time -= ust;
-       get_paca()->stolen_time += ust + sst;
+       u8 save_soft_enabled = local_paca->soft_enabled;
+       u8 save_hard_enabled = local_paca->hard_enabled;
+
+       /* We are called early in the exception entry, before
+        * soft/hard_enabled are sync'ed to the expected state
+        * for the exception. We are hard disabled but the PACA
+        * needs to reflect that so various debug stuff doesn't
+        * complain
+        */
+       local_paca->soft_enabled = 0;
+       local_paca->hard_enabled = 0;
+
+       sst = scan_dispatch_log(local_paca->starttime_user);
+       ust = scan_dispatch_log(local_paca->starttime);
+       local_paca->system_time -= sst;
+       local_paca->user_time -= ust;
+       local_paca->stolen_time += ust + sst;
+
+       local_paca->soft_enabled = save_soft_enabled;
+       local_paca->hard_enabled = save_hard_enabled;
 }
 
 static inline u64 calculate_stolen_time(u64 stop_tb)
index 1b2cdc8..bd74fac 100644 (file)
@@ -626,12 +626,6 @@ void machine_check_exception(struct pt_regs *regs)
        if (recover > 0)
                return;
 
-       if (user_mode(regs)) {
-               regs->msr |= MSR_RI;
-               _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
-               return;
-       }
-
 #if defined(CONFIG_8xx) && defined(CONFIG_PCI)
        /* the qspan pci read routines can cause machine checks -- Cort
         *
@@ -643,16 +637,12 @@ void machine_check_exception(struct pt_regs *regs)
        return;
 #endif
 
-       if (debugger_fault_handler(regs)) {
-               regs->msr |= MSR_RI;
+       if (debugger_fault_handler(regs))
                return;
-       }
 
        if (check_io_access(regs))
                return;
 
-       if (debugger_fault_handler(regs))
-               return;
        die("Machine check", regs, SIGBUS);
 
        /* Must die if the interrupt is not recoverable */
index cb73748..f461311 100644 (file)
@@ -172,6 +172,25 @@ globl(ftr_fixup_test6_expected)
 3:     or      3,3,3
 
 
+#if 0
+/* Test that if we have a larger else case the assembler spots it and
+ * reports an error. #if 0'ed so as not to break the build normally.
+ */
+ftr_fixup_test7:
+       or      1,1,1
+BEGIN_FTR_SECTION
+       or      2,2,2
+       or      2,2,2
+       or      2,2,2
+FTR_SECTION_ELSE
+       or      3,3,3
+       or      3,3,3
+       or      3,3,3
+       or      3,3,3
+ALT_FTR_SECTION_END(0, 1)
+       or      1,1,1
+#endif
+
 #define        MAKE_MACRO_TEST(TYPE)                                           \
 globl(ftr_fixup_test_ ##TYPE##_macros)                                 \
        or      1,1,1;                                                  \
index bf5cb91..fd48123 100644 (file)
@@ -186,7 +186,7 @@ static void unmap_cpu_from_node(unsigned long cpu)
        dbg("removing cpu %lu from node %d\n", cpu, node);
 
        if (cpumask_test_cpu(cpu, node_to_cpumask_map[node])) {
-               cpumask_set_cpu(cpu, node_to_cpumask_map[node]);
+               cpumask_clear_cpu(cpu, node_to_cpumask_map[node]);
        } else {
                printk(KERN_ERR "WARNING: cpu %lu not found in node %d\n",
                       cpu, node);
@@ -1289,10 +1289,9 @@ u64 memory_hotplug_max(void)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-/* Vrtual Processor Home Node (VPHN) support */
+/* Virtual Processor Home Node (VPHN) support */
 #ifdef CONFIG_PPC_SPLPAR
-#define VPHN_NR_CHANGE_CTRS (8)
-static u8 vphn_cpu_change_counts[NR_CPUS][VPHN_NR_CHANGE_CTRS];
+static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];
 static cpumask_t cpu_associativity_changes_mask;
 static int vphn_enabled;
 static void set_topology_timer(void);
@@ -1303,16 +1302,18 @@ static void set_topology_timer(void);
  */
 static void setup_cpu_associativity_change_counters(void)
 {
-       int cpu = 0;
+       int cpu;
+
+       /* The VPHN feature supports a maximum of 8 reference points */
+       BUILD_BUG_ON(MAX_DISTANCE_REF_POINTS > 8);
 
        for_each_possible_cpu(cpu) {
-               int i = 0;
+               int i;
                u8 *counts = vphn_cpu_change_counts[cpu];
                volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
 
-               for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
+               for (i = 0; i < distance_ref_points_depth; i++)
                        counts[i] = hypervisor_counts[i];
-               }
        }
 }
 
@@ -1329,7 +1330,7 @@ static void setup_cpu_associativity_change_counters(void)
  */
 static int update_cpu_associativity_changes_mask(void)
 {
-       int cpu = 0, nr_cpus = 0;
+       int cpu, nr_cpus = 0;
        cpumask_t *changes = &cpu_associativity_changes_mask;
 
        cpumask_clear(changes);
@@ -1339,8 +1340,8 @@ static int update_cpu_associativity_changes_mask(void)
                u8 *counts = vphn_cpu_change_counts[cpu];
                volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
 
-               for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
-                       if (hypervisor_counts[i] > counts[i]) {
+               for (i = 0; i < distance_ref_points_depth; i++) {
+                       if (hypervisor_counts[i] != counts[i]) {
                                counts[i] = hypervisor_counts[i];
                                changed = 1;
                        }
@@ -1354,8 +1355,11 @@ static int update_cpu_associativity_changes_mask(void)
        return nr_cpus;
 }
 
-/* 6 64-bit registers unpacked into 12 32-bit associativity values */
-#define VPHN_ASSOC_BUFSIZE (6*sizeof(u64)/sizeof(u32))
+/*
+ * 6 64-bit registers unpacked into 12 32-bit associativity values. To form
+ * the complete property we have to add the length in the first cell.
+ */
+#define VPHN_ASSOC_BUFSIZE (6*sizeof(u64)/sizeof(u32) + 1)
 
 /*
  * Convert the associativity domain numbers returned from the hypervisor
@@ -1363,15 +1367,14 @@ static int update_cpu_associativity_changes_mask(void)
  */
 static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
 {
-       int i = 0;
-       int nr_assoc_doms = 0;
+       int i, nr_assoc_doms = 0;
        const u16 *field = (const u16*) packed;
 
 #define VPHN_FIELD_UNUSED      (0xffff)
 #define VPHN_FIELD_MSB         (0x8000)
 #define VPHN_FIELD_MASK                (~VPHN_FIELD_MSB)
 
-       for (i = 0; i < VPHN_ASSOC_BUFSIZE; i++) {
+       for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) {
                if (*field == VPHN_FIELD_UNUSED) {
                        /* All significant fields processed, and remaining
                         * fields contain the reserved value of all 1's.
@@ -1379,14 +1382,12 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
                         */
                        unpacked[i] = *((u32*)field);
                        field += 2;
-               }
-               else if (*field & VPHN_FIELD_MSB) {
+               } else if (*field & VPHN_FIELD_MSB) {
                        /* Data is in the lower 15 bits of this field */
                        unpacked[i] = *field & VPHN_FIELD_MASK;
                        field++;
                        nr_assoc_doms++;
-               }
-               else {
+               } else {
                        /* Data is in the lower 15 bits of this field
                         * concatenated with the next 16 bit field
                         */
@@ -1396,6 +1397,9 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
                }
        }
 
+       /* The first cell contains the length of the property */
+       unpacked[0] = nr_assoc_doms;
+
        return nr_assoc_doms;
 }
 
@@ -1405,7 +1409,7 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
  */
 static long hcall_vphn(unsigned long cpu, unsigned int *associativity)
 {
-       long rc = 0;
+       long rc;
        long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
        u64 flags = 1;
        int hwcpu = get_hard_smp_processor_id(cpu);
@@ -1419,7 +1423,7 @@ static long hcall_vphn(unsigned long cpu, unsigned int *associativity)
 static long vphn_get_associativity(unsigned long cpu,
                                        unsigned int *associativity)
 {
-       long rc = 0;
+       long rc;
 
        rc = hcall_vphn(cpu, associativity);
 
@@ -1445,9 +1449,9 @@ static long vphn_get_associativity(unsigned long cpu,
  */
 int arch_update_cpu_topology(void)
 {
-       int cpu = 0, nid = 0, old_nid = 0;
+       int cpu, nid, old_nid;
        unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
-       struct sys_device *sysdev = NULL;
+       struct sys_device *sysdev;
 
        for_each_cpu_mask(cpu, cpu_associativity_changes_mask) {
                vphn_get_associativity(cpu, associativity);
@@ -1512,7 +1516,8 @@ int start_topology_update(void)
 {
        int rc = 0;
 
-       if (firmware_has_feature(FW_FEATURE_VPHN)) {
+       if (firmware_has_feature(FW_FEATURE_VPHN) &&
+           get_lppaca()->shared_proc) {
                vphn_enabled = 1;
                setup_cpu_associativity_change_counters();
                init_timer_deferrable(&topology_timer);
index 1ec0657..c14d09f 100644 (file)
@@ -38,13 +38,11 @@ DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
  * neesd to be flushed. This function will either perform the flush
  * immediately or will batch it up if the current CPU has an active
  * batch on it.
- *
- * Must be called from within some kind of spinlock/non-preempt region...
  */
 void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, unsigned long pte, int huge)
 {
-       struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+       struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
        unsigned long vsid, vaddr;
        unsigned int psize;
        int ssize;
@@ -99,6 +97,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
         */
        if (!batch->active) {
                flush_hash_page(vaddr, rpte, psize, ssize, 0);
+               put_cpu_var(ppc64_tlb_batch);
                return;
        }
 
@@ -127,6 +126,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
        batch->index = ++i;
        if (i >= PPC64_TLB_BATCH_NR)
                __flush_tlb_pending(batch);
+       put_cpu_var(ppc64_tlb_batch);
 }
 
 /*
index 661d354..d0c4e15 100644 (file)
@@ -57,12 +57,12 @@ static void __init mpc830x_rdb_init_IRQ(void)
        ipic_set_default_priority();
 }
 
-struct const char *board[] __initdata = {
+static const char *board[] __initdata = {
        "MPC8308RDB",
        "fsl,mpc8308rdb",
        "denx,mpc8308_p1m",
        NULL
-}
+};
 
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
index b54cd73..f859ead 100644 (file)
@@ -60,11 +60,11 @@ static void __init mpc831x_rdb_init_IRQ(void)
        ipic_set_default_priority();
 }
 
-struct const char *board[] __initdata = {
+static const char *board[] __initdata = {
        "MPC8313ERDB",
        "fsl,mpc8315erdb",
        NULL
-}
+};
 
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
index 0fea881..82a4345 100644 (file)
@@ -35,6 +35,8 @@
 
 /* system i/o configuration register high */
 #define MPC83XX_SICRH_OFFS         0x118
+#define MPC8308_SICRH_USB_MASK     0x000c0000
+#define MPC8308_SICRH_USB_ULPI     0x00040000
 #define MPC834X_SICRH_USB_UTMI     0x00020000
 #define MPC831X_SICRH_USB_MASK     0x000000e0
 #define MPC831X_SICRH_USB_ULPI     0x000000a0
index 3ba4bb7..2c64164 100644 (file)
@@ -127,7 +127,8 @@ int mpc831x_usb_cfg(void)
 
        /* Configure clock */
        immr_node = of_get_parent(np);
-       if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
+       if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
+                       of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
                clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
                                MPC8315_SCCR_USB_MASK,
                                MPC8315_SCCR_USB_DRCM_01);
@@ -138,7 +139,11 @@ int mpc831x_usb_cfg(void)
 
        /* Configure pin mux for ULPI.  There is no pin mux for UTMI */
        if (prop && !strcmp(prop, "ulpi")) {
-               if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
+               if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+                       clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
+                                       MPC8308_SICRH_USB_MASK,
+                                       MPC8308_SICRH_USB_ULPI);
+               } else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
                        clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
                                        MPC8315_SICRL_USB_MASK,
                                        MPC8315_SICRL_USB_ULPI);
@@ -173,6 +178,9 @@ int mpc831x_usb_cfg(void)
                     !strcmp(prop, "utmi"))) {
                u32 refsel;
 
+               if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
+                       goto out;
+
                if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
                        refsel = CONTROL_REFSEL_24MHZ;
                else
@@ -186,9 +194,11 @@ int mpc831x_usb_cfg(void)
                temp = CONTROL_PHY_CLK_SEL_ULPI;
 #ifdef CONFIG_USB_OTG
                /* Set OTG_PORT */
-               dr_mode = of_get_property(np, "dr_mode", NULL);
-               if (dr_mode && !strcmp(dr_mode, "otg"))
-                       temp |= CONTROL_OTG_PORT;
+               if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+                       dr_mode = of_get_property(np, "dr_mode", NULL);
+                       if (dr_mode && !strcmp(dr_mode, "otg"))
+                               temp |= CONTROL_OTG_PORT;
+               }
 #endif /* CONFIG_USB_OTG */
                out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
        } else {
@@ -196,6 +206,7 @@ int mpc831x_usb_cfg(void)
                ret = -EINVAL;
        }
 
+out:
        iounmap(usb_regs);
        of_node_put(np);
        return ret;
index 968c1c0..d809836 100644 (file)
@@ -39,8 +39,6 @@ struct spu_gov_info_struct {
 };
 static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info);
 
-static struct workqueue_struct *kspugov_wq;
-
 static int calc_freq(struct spu_gov_info_struct *info)
 {
        int cpu;
@@ -71,14 +69,14 @@ static void spu_gov_work(struct work_struct *work)
        __cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H);
 
        delay = usecs_to_jiffies(info->poll_int);
-       queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay);
+       schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
 }
 
 static void spu_gov_init_work(struct spu_gov_info_struct *info)
 {
        int delay = usecs_to_jiffies(info->poll_int);
        INIT_DELAYED_WORK_DEFERRABLE(&info->work, spu_gov_work);
-       queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay);
+       schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
 }
 
 static void spu_gov_cancel_work(struct spu_gov_info_struct *info)
@@ -152,27 +150,15 @@ static int __init spu_gov_init(void)
 {
        int ret;
 
-       kspugov_wq = create_workqueue("kspugov");
-       if (!kspugov_wq) {
-               printk(KERN_ERR "creation of kspugov failed\n");
-               ret = -EFAULT;
-               goto out;
-       }
-
        ret = cpufreq_register_governor(&spu_governor);
-       if (ret) {
+       if (ret)
                printk(KERN_ERR "registration of governor failed\n");
-               destroy_workqueue(kspugov_wq);
-               goto out;
-       }
-out:
        return ret;
 }
 
 static void __exit spu_gov_exit(void)
 {
        cpufreq_unregister_governor(&spu_governor);
-       destroy_workqueue(kspugov_wq);
 }
 
 
index 1b57490..d31c594 100644 (file)
@@ -145,9 +145,4 @@ define_machine(qpace) {
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = qpace_progress,
        .init_IRQ               = iic_init_IRQ,
-#ifdef CONFIG_KEXEC
-       .machine_kexec          = default_machine_kexec,
-       .machine_kexec_prepare  = default_machine_kexec_prepare,
-       .machine_crash_shutdown = default_machine_crash_shutdown,
-#endif
 };
index 8547e86..acfacce 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/spu_csa.h>
 #include <asm/xmon.h>
 #include <asm/prom.h>
+#include <asm/kexec.h>
 
 const struct spu_management_ops *spu_management_ops;
 EXPORT_SYMBOL_GPL(spu_management_ops);
@@ -727,6 +728,75 @@ static ssize_t spu_stat_show(struct sys_device *sysdev,
 
 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
 
+#ifdef CONFIG_KEXEC
+
+struct crash_spu_info {
+       struct spu *spu;
+       u32 saved_spu_runcntl_RW;
+       u32 saved_spu_status_R;
+       u32 saved_spu_npc_RW;
+       u64 saved_mfc_sr1_RW;
+       u64 saved_mfc_dar;
+       u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS 16      /* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+       struct spu *spu;
+       int i;
+       u64 tmp;
+
+       for (i = 0; i < CRASH_NUM_SPUS; i++) {
+               if (!crash_spu_info[i].spu)
+                       continue;
+
+               spu = crash_spu_info[i].spu;
+
+               crash_spu_info[i].saved_spu_runcntl_RW =
+                       in_be32(&spu->problem->spu_runcntl_RW);
+               crash_spu_info[i].saved_spu_status_R =
+                       in_be32(&spu->problem->spu_status_R);
+               crash_spu_info[i].saved_spu_npc_RW =
+                       in_be32(&spu->problem->spu_npc_RW);
+
+               crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
+               crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
+               tmp = spu_mfc_sr1_get(spu);
+               crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+               tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+               spu_mfc_sr1_set(spu, tmp);
+
+               __delay(200);
+       }
+}
+
+static void crash_register_spus(struct list_head *list)
+{
+       struct spu *spu;
+       int ret;
+
+       list_for_each_entry(spu, list, full_list) {
+               if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+                       continue;
+
+               crash_spu_info[spu->number].spu = spu;
+       }
+
+       ret = crash_shutdown_register(&crash_kexec_stop_spus);
+       if (ret)
+               printk(KERN_ERR "Could not register SPU crash handler");
+}
+
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
 static int __init init_spu_base(void)
 {
        int i, ret = 0;
index 02f7b11..3c7c3f8 100644 (file)
@@ -219,24 +219,17 @@ spufs_mem_write(struct file *file, const char __user *buffer,
        loff_t pos = *ppos;
        int ret;
 
-       if (pos < 0)
-               return -EINVAL;
        if (pos > LS_SIZE)
                return -EFBIG;
-       if (size > LS_SIZE - pos)
-               size = LS_SIZE - pos;
 
        ret = spu_acquire(ctx);
        if (ret)
                return ret;
 
        local_store = ctx->ops->get_ls(ctx);
-       ret = copy_from_user(local_store + pos, buffer, size);
+       size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size);
        spu_release(ctx);
 
-       if (ret)
-               return -EFAULT;
-       *ppos = pos + size;
        return size;
 }
 
@@ -574,18 +567,15 @@ spufs_regs_write(struct file *file, const char __user *buffer,
        if (*pos >= sizeof(lscsa->gprs))
                return -EFBIG;
 
-       size = min_t(ssize_t, sizeof(lscsa->gprs) - *pos, size);
-       *pos += size;
-
        ret = spu_acquire_saved(ctx);
        if (ret)
                return ret;
 
-       ret = copy_from_user((char *)lscsa->gprs + *pos - size,
-                            buffer, size) ? -EFAULT : size;
+       size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos,
+                                       buffer, size);
 
        spu_release_saved(ctx);
-       return ret;
+       return size;
 }
 
 static const struct file_operations spufs_regs_fops = {
@@ -630,18 +620,15 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
        if (*pos >= sizeof(lscsa->fpcr))
                return -EFBIG;
 
-       size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
-
        ret = spu_acquire_saved(ctx);
        if (ret)
                return ret;
 
-       *pos += size;
-       ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
-                            buffer, size) ? -EFAULT : size;
+       size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos,
+                                       buffer, size);
 
        spu_release_saved(ctx);
-       return ret;
+       return size;
 }
 
 static const struct file_operations spufs_fpcr_fops = {
index 1106fd9..a138e14 100644 (file)
@@ -75,14 +75,6 @@ static void gamecube_shutdown(void)
        flipper_quiesce();
 }
 
-#ifdef CONFIG_KEXEC
-static int gamecube_kexec_prepare(struct kimage *image)
-{
-       return 0;
-}
-#endif /* CONFIG_KEXEC */
-
-
 define_machine(gamecube) {
        .name                   = "gamecube",
        .probe                  = gamecube_probe,
@@ -95,9 +87,6 @@ define_machine(gamecube) {
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = udbg_progress,
        .machine_shutdown       = gamecube_shutdown,
-#ifdef CONFIG_KEXEC
-       .machine_kexec_prepare  = gamecube_kexec_prepare,
-#endif
 };
 
 
index 649473a..1b5dc1a 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/seq_file.h>
-#include <linux/kexec.h>
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
 #include <mm/mmu_decl.h>
@@ -226,13 +225,6 @@ static void wii_shutdown(void)
        flipper_quiesce();
 }
 
-#ifdef CONFIG_KEXEC
-static int wii_machine_kexec_prepare(struct kimage *image)
-{
-       return 0;
-}
-#endif /* CONFIG_KEXEC */
-
 define_machine(wii) {
        .name                   = "wii",
        .probe                  = wii_probe,
@@ -246,9 +238,6 @@ define_machine(wii) {
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = udbg_progress,
        .machine_shutdown       = wii_shutdown,
-#ifdef CONFIG_KEXEC
-       .machine_kexec_prepare  = wii_machine_kexec_prepare,
-#endif
 };
 
 static struct of_device_id wii_of_bus[] = {
index 47a20cf..e5bc9f7 100644 (file)
@@ -2,7 +2,7 @@ config PPC_ISERIES
        bool "IBM Legacy iSeries"
        depends on PPC64 && PPC_BOOK3S
        select PPC_INDIRECT_IO
-       select PPC_PCI_CHOICE if EMBEDDED
+       select PPC_PCI_CHOICE if EXPERT
 
 menu "iSeries device drivers"
        depends on PPC_ISERIES
index 5d1b743..5b3da4b 100644 (file)
@@ -10,7 +10,7 @@ config PPC_PSERIES
        select RTAS_ERROR_LOGGING
        select PPC_UDBG_16550
        select PPC_NATIVE
-       select PPC_PCI_CHOICE if EMBEDDED
+       select PPC_PCI_CHOICE if EXPERT
        default y
 
 config PPC_SPLPAR
@@ -24,9 +24,9 @@ config PPC_SPLPAR
          two or more partitions.
 
 config EEH
-       bool "PCI Extended Error Handling (EEH)" if EMBEDDED
+       bool "PCI Extended Error Handling (EEH)" if EXPERT
        depends on PPC_PSERIES && PCI
-       default y if !EMBEDDED
+       default y if !EXPERT
 
 config PSERIES_MSI
        bool
index 53cbd53..77d38a5 100644 (file)
@@ -61,13 +61,3 @@ void __init setup_kexec_cpu_down_xics(void)
 {
        ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
 }
-
-static int __init pseries_kexec_setup(void)
-{
-       ppc_md.machine_kexec = default_machine_kexec;
-       ppc_md.machine_kexec_prepare = default_machine_kexec_prepare;
-       ppc_md.machine_crash_shutdown = default_machine_crash_shutdown;
-
-       return 0;
-}
-machine_device_initcall(pseries, pseries_kexec_setup);
index 5d3ea9f..ca5d589 100644 (file)
@@ -713,6 +713,13 @@ EXPORT_SYMBOL(arch_free_page);
 /* NB: reg/unreg are called while guarded with the tracepoints_mutex */
 extern long hcall_tracepoint_refcount;
 
+/* 
+ * Since the tracing code might execute hcalls we need to guard against
+ * recursion. One example of this are spinlocks calling H_YIELD on
+ * shared processor partitions.
+ */
+static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
+
 void hcall_tracepoint_regfunc(void)
 {
        hcall_tracepoint_refcount++;
@@ -725,12 +732,42 @@ void hcall_tracepoint_unregfunc(void)
 
 void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
 {
+       unsigned long flags;
+       unsigned int *depth;
+
+       local_irq_save(flags);
+
+       depth = &__get_cpu_var(hcall_trace_depth);
+
+       if (*depth)
+               goto out;
+
+       (*depth)++;
        trace_hcall_entry(opcode, args);
+       (*depth)--;
+
+out:
+       local_irq_restore(flags);
 }
 
 void __trace_hcall_exit(long opcode, unsigned long retval,
                        unsigned long *retbuf)
 {
+       unsigned long flags;
+       unsigned int *depth;
+
+       local_irq_save(flags);
+
+       depth = &__get_cpu_var(hcall_trace_depth);
+
+       if (*depth)
+               goto out;
+
+       (*depth)++;
        trace_hcall_exit(opcode, retval, retbuf);
+       (*depth)--;
+
+out:
+       local_irq_restore(flags);
 }
 #endif
index a4fc6da..c55d7ad 100644 (file)
@@ -54,7 +54,8 @@
 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(ras_log_buf_lock);
 
-static char mce_data_buf[RTAS_ERROR_LOG_MAX];
+static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
+static DEFINE_PER_CPU(__u64, mce_data_buf);
 
 static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
@@ -196,12 +197,24 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Get the error information for errors coming through the
+/*
+ * Some versions of FWNMI place the buffer inside the 4kB page starting at
+ * 0x7000. Other versions place it inside the rtas buffer. We check both.
+ */
+#define VALID_FWNMI_BUFFER(A) \
+       ((((A) >= 0x7000) && ((A) < 0x7ff0)) || \
+       (((A) >= rtas.base) && ((A) < (rtas.base + rtas.size - 16))))
+
+/*
+ * Get the error information for errors coming through the
  * FWNMI vectors.  The pt_regs' r3 will be updated to reflect
  * the actual r3 if possible, and a ptr to the error log entry
  * will be returned if found.
  *
- * The mce_data_buf does not have any locks or protection around it,
+ * If the RTAS error is not of the extended type, then we put it in a per
+ * cpu 64bit buffer. If it is the extended type we use global_mce_data_buf.
+ *
+ * The global_mce_data_buf does not have any locks or protection around it,
  * if a second machine check comes in, or a system reset is done
  * before we have logged the error, then we will get corruption in the
  * error log.  This is preferable over holding off on calling
@@ -210,20 +223,31 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
  */
 static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
 {
-       unsigned long errdata = regs->gpr[3];
-       struct rtas_error_log *errhdr = NULL;
        unsigned long *savep;
+       struct rtas_error_log *h, *errhdr = NULL;
+
+       if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
+               printk(KERN_ERR "FWNMI: corrupt r3\n");
+               return NULL;
+       }
 
-       if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
-           (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
-               savep = __va(errdata);
-               regs->gpr[3] = savep[0];        /* restore original r3 */
-               memset(mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
-               memcpy(mce_data_buf, (char *)(savep + 1), RTAS_ERROR_LOG_MAX);
-               errhdr = (struct rtas_error_log *)mce_data_buf;
+       savep = __va(regs->gpr[3]);
+       regs->gpr[3] = savep[0];        /* restore original r3 */
+
+       /* If it isn't an extended log we can use the per cpu 64bit buffer */
+       h = (struct rtas_error_log *)&savep[1];
+       if (!h->extended) {
+               memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64));
+               errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf);
        } else {
-               printk("FWNMI: corrupt r3\n");
+               int len;
+
+               len = max_t(int, 8+h->extended_log_length, RTAS_ERROR_LOG_MAX);
+               memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
+               memcpy(global_mce_data_buf, h, len);
+               errhdr = (struct rtas_error_log *)global_mce_data_buf;
        }
+
        return errhdr;
 }
 
@@ -235,7 +259,7 @@ static void fwnmi_release_errinfo(void)
 {
        int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
        if (ret != 0)
-               printk("FWNMI: nmi-interlock failed: %d\n", ret);
+               printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret);
 }
 
 int pSeries_system_reset_exception(struct pt_regs *regs)
@@ -259,31 +283,43 @@ int pSeries_system_reset_exception(struct pt_regs *regs)
  * Return 1 if corrected (or delivered a signal).
  * Return 0 if there is nothing we can do.
  */
-static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err)
+static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)
 {
-       int nonfatal = 0;
+       int recovered = 0;
 
-       if (err->disposition == RTAS_DISP_FULLY_RECOVERED) {
+       if (!(regs->msr & MSR_RI)) {
+               /* If MSR_RI isn't set, we cannot recover */
+               recovered = 0;
+
+       } else if (err->disposition == RTAS_DISP_FULLY_RECOVERED) {
                /* Platform corrected itself */
-               nonfatal = 1;
-       } else if ((regs->msr & MSR_RI) &&
-                  user_mode(regs) &&
-                  err->severity == RTAS_SEVERITY_ERROR_SYNC &&
-                  err->disposition == RTAS_DISP_NOT_RECOVERED &&
-                  err->target == RTAS_TARGET_MEMORY &&
-                  err->type == RTAS_TYPE_ECC_UNCORR &&
-                  !(current->pid == 0 || is_global_init(current))) {
-               /* Kill off a user process with an ECC error */
-               printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
-                      current->pid);
-               /* XXX something better for ECC error? */
-               _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
-               nonfatal = 1;
+               recovered = 1;
+
+       } else if (err->disposition == RTAS_DISP_LIMITED_RECOVERY) {
+               /* Platform corrected itself but could be degraded */
+               printk(KERN_ERR "MCE: limited recovery, system may "
+                      "be degraded\n");
+               recovered = 1;
+
+       } else if (user_mode(regs) && !is_global_init(current) &&
+                  err->severity == RTAS_SEVERITY_ERROR_SYNC) {
+
+               /*
+                * If we received a synchronous error when in userspace
+                * kill the task. Firmware may report details of the fail
+                * asynchronously, so we can't rely on the target and type
+                * fields being valid here.
+                */
+               printk(KERN_ERR "MCE: uncorrectable error, killing task "
+                      "%s:%d\n", current->comm, current->pid);
+
+               _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+               recovered = 1;
        }
 
-       log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal);
+       log_error((char *)err, ERR_TYPE_RTAS_LOG, 0);
 
-       return nonfatal;
+       return recovered;
 }
 
 /*
index 9f99bef..8c6cab0 100644 (file)
@@ -1555,8 +1555,6 @@ int fsl_rio_setup(struct platform_device *dev)
        saved_mcheck_exception = ppc_md.machine_check_exception;
        ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
 #endif
-       /* Ensure that RFXE is set */
-       mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000));
 
        return 0;
 err:
index 7c13426..b0c8469 100644 (file)
@@ -674,7 +674,8 @@ void mpic_unmask_irq(unsigned int irq)
        /* make sure mask gets to controller before we return to user */
        do {
                if (!loops--) {
-                       printk(KERN_ERR "mpic_enable_irq timeout\n");
+                       printk(KERN_ERR "%s: timeout on hwirq %u\n",
+                              __func__, src);
                        break;
                }
        } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
@@ -695,7 +696,8 @@ void mpic_mask_irq(unsigned int irq)
        /* make sure mask gets to controller before we return to user */
        do {
                if (!loops--) {
-                       printk(KERN_ERR "mpic_enable_irq timeout\n");
+                       printk(KERN_ERR "%s: timeout on hwirq %u\n",
+                              __func__, src);
                        break;
                }
        } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
index ff19efd..636bcb8 100644 (file)
@@ -406,7 +406,7 @@ config QDIO
          If unsure, say Y.
 
 config CHSC_SCH
-       def_tristate y
+       def_tristate m
        prompt "Support for CHSC subchannels"
        help
          This driver allows usage of CHSC subchannels. A CHSC subchannel
index 0851eb1..2751b3a 100644 (file)
@@ -133,11 +133,12 @@ unsigned long decompress_kernel(void)
        unsigned long output_addr;
        unsigned char *output;
 
-       check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start);
+       output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
+       check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
        memset(&_bss, 0, &_ebss - &_bss);
        free_mem_ptr = (unsigned long)&_end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-       output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL);
+       output = (unsigned char *) output_addr;
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
index f42dbab..48884f8 100644 (file)
@@ -38,6 +38,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
                BUG_ON(ret != bsize);
                data += bsize - index;
                len -= bsize - index;
+               index = 0;
        }
 
        /* process as many blocks as possible */
index 76daea1..5c5ba10 100644 (file)
 
 static inline int atomic_read(const atomic_t *v)
 {
-       barrier();
-       return v->counter;
+       int c;
+
+       asm volatile(
+               "       l       %0,%1\n"
+               : "=d" (c) : "Q" (v->counter));
+       return c;
 }
 
 static inline void atomic_set(atomic_t *v, int i)
 {
-       v->counter = i;
-       barrier();
+       asm volatile(
+               "       st      %1,%0\n"
+               : "=Q" (v->counter) : "d" (i));
 }
 
 static inline int atomic_add_return(int i, atomic_t *v)
@@ -128,14 +133,19 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 
 static inline long long atomic64_read(const atomic64_t *v)
 {
-       barrier();
-       return v->counter;
+       long long c;
+
+       asm volatile(
+               "       lg      %0,%1\n"
+               : "=d" (c) : "Q" (v->counter));
+       return c;
 }
 
 static inline void atomic64_set(atomic64_t *v, long long i)
 {
-       v->counter = i;
-       barrier();
+       asm volatile(
+               "       stg     %1,%0\n"
+               : "=Q" (v->counter) : "d" (i));
 }
 
 static inline long long atomic64_add_return(long long i, atomic64_t *v)
index 24aafa6..2a30d5a 100644 (file)
@@ -13,6 +13,7 @@
 
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
+#define NET_SKB_PAD       32
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
index 405cc97..7e1f776 100644 (file)
@@ -1,29 +1,8 @@
 #ifndef _S390_CACHEFLUSH_H
 #define _S390_CACHEFLUSH_H
 
-/* Keep includes the same across arches.  */
-#include <linux/mm.h>
-
 /* Caches aren't brain-dead on the s390. */
-#define flush_cache_all()                      do { } while (0)
-#define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_dup_mm(mm)                 do { } while (0)
-#define flush_cache_range(vma, start, end)     do { } while (0)
-#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page)                        do { } while (0)
-#define flush_dcache_mmap_lock(mapping)                do { } while (0)
-#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
-#define flush_icache_range(start, end)         do { } while (0)
-#define flush_icache_page(vma,pg)              do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
-#define flush_cache_vmap(start, end)           do { } while (0)
-#define flush_cache_vunmap(start, end)         do { } while (0)
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
+#include <asm-generic/cacheflush.h>
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 void kernel_map_pages(struct page *page, int numpages, int enable);
index bf3de04..2c79b64 100644 (file)
@@ -148,11 +148,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
  */
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
-/*
- * Print register of task into buffer. Used in fs/proc/array.c.
- */
-extern void task_show_regs(struct seq_file *m, struct task_struct *task);
-
 extern void show_code(struct pt_regs *regs);
 
 unsigned long get_wchan(struct task_struct *p);
index f1f644f..9074a54 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <asm/processor.h>
 #include <asm/pgalloc.h>
index 5eb78dd..b5a4a73 100644 (file)
@@ -237,43 +237,6 @@ void show_regs(struct pt_regs *regs)
        show_last_breaking_event(regs);
 }
 
-/* This is called from fs/proc/array.c */
-void task_show_regs(struct seq_file *m, struct task_struct *task)
-{
-       struct pt_regs *regs;
-
-       regs = task_pt_regs(task);
-       seq_printf(m, "task: %p, ksp: %p\n",
-                      task, (void *)task->thread.ksp);
-       seq_printf(m, "User PSW : %p %p\n",
-                      (void *) regs->psw.mask, (void *)regs->psw.addr);
-
-       seq_printf(m, "User GPRS: " FOURLONG,
-                         regs->gprs[0], regs->gprs[1],
-                         regs->gprs[2], regs->gprs[3]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[4], regs->gprs[5],
-                         regs->gprs[6], regs->gprs[7]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[8], regs->gprs[9],
-                         regs->gprs[10], regs->gprs[11]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[12], regs->gprs[13],
-                         regs->gprs[14], regs->gprs[15]);
-       seq_printf(m, "User ACRS: %08x %08x %08x %08x\n",
-                         task->thread.acrs[0], task->thread.acrs[1],
-                         task->thread.acrs[2], task->thread.acrs[3]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[4], task->thread.acrs[5],
-                         task->thread.acrs[6], task->thread.acrs[7]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[8], task->thread.acrs[9],
-                         task->thread.acrs[10], task->thread.acrs[11]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[12], task->thread.acrs[13],
-                         task->thread.acrs[14], task->thread.acrs[15]);
-}
-
 static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
index 07deaee..a6c4f7e 100644 (file)
@@ -125,9 +125,9 @@ static size_t copy_in_user_std(size_t size, void __user *to,
        unsigned long tmp1;
 
        asm volatile(
+               "   sacf  256\n"
                "  "AHI"  %0,-1\n"
                "   jo    5f\n"
-               "   sacf  256\n"
                "   bras  %3,3f\n"
                "0:"AHI"  %0,257\n"
                "1: mvc   0(1,%1),0(%2)\n"
@@ -142,9 +142,8 @@ static size_t copy_in_user_std(size_t size, void __user *to,
                "3:"AHI"  %0,-256\n"
                "   jnm   2b\n"
                "4: ex    %0,1b-0b(%3)\n"
-               "   sacf  0\n"
                "5: "SLR"  %0,%0\n"
-               "6:\n"
+               "6: sacf  0\n"
                EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
                : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
                : : "cc", "memory");
@@ -156,9 +155,9 @@ static size_t clear_user_std(size_t size, void __user *to)
        unsigned long tmp1, tmp2;
 
        asm volatile(
+               "   sacf  256\n"
                "  "AHI"  %0,-1\n"
                "   jo    5f\n"
-               "   sacf  256\n"
                "   bras  %3,3f\n"
                "   xc    0(1,%1),0(%1)\n"
                "0:"AHI"  %0,257\n"
@@ -178,9 +177,8 @@ static size_t clear_user_std(size_t size, void __user *to)
                "3:"AHI"  %0,-256\n"
                "   jnm   2b\n"
                "4: ex    %0,0(%3)\n"
-               "   sacf  0\n"
                "5: "SLR"  %0,%0\n"
-               "6:\n"
+               "6: sacf  0\n"
                EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
                : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
                : : "cc", "memory");
index 0c719c6..e1850c2 100644 (file)
@@ -336,7 +336,8 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        page->flags ^= bits;
        if (page->flags & FRAG_MASK) {
                /* Page now has some free pgtable fragments. */
-               list_move(&page->lru, &mm->context.pgtable_list);
+               if (!list_empty(&page->lru))
+                       list_move(&page->lru, &mm->context.pgtable_list);
                page = NULL;
        } else
                /* All fragments of the 4K page have been freed. */
index 4293fdc..27b2295 100644 (file)
@@ -1,5 +1,9 @@
 menu "Machine selection"
 
+config SCORE
+       def_bool y
+       select HAVE_GENERIC_HARDIRQS
+
 choice
        prompt "System type"
        default MACH_SPCT6600
@@ -53,9 +57,6 @@ config GENERIC_CLOCKEVENTS
 config SCHED_NO_NO_OMIT_FRAME_POINTER
        def_bool y
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config GENERIC_SYSCALL_TABLE
        def_bool y
 
@@ -68,9 +69,6 @@ menu "Kernel type"
 config 32BIT
        def_bool y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
 config ARCH_FLATMEM_ENABLE
        def_bool y
 
index 9883c50..df1edbf 100644 (file)
@@ -9,7 +9,7 @@ CONFIG_LOG_BUF_SHIFT=12
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_SLAB=y
index fff2522..8a9011d 100644 (file)
@@ -1,6 +1,6 @@
 config SUPERH
        def_bool y
-       select EMBEDDED
+       select EXPERT
        select CLKDEV_LOOKUP
        select HAVE_IDE if HAS_IOPORT
        select HAVE_MEMBLOCK
@@ -15,6 +15,7 @@ config SUPERH
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_KERNEL_XZ
        select HAVE_KERNEL_LZO
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_REGS_AND_STACK_ACCESS_API
index 9c8c6e1..e3d8170 100644 (file)
@@ -200,7 +200,7 @@ endif
 libs-$(CONFIG_SUPERH32)                := arch/sh/lib/ $(libs-y)
 libs-$(CONFIG_SUPERH64)                := arch/sh/lib64/ $(libs-y)
 
-BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.lzo \
+BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.xz uImage.lzo \
               uImage.srec uImage.bin zImage vmlinux.bin vmlinux.srec \
               romImage
 PHONY += $(BOOT_TARGETS)
@@ -230,5 +230,6 @@ define archhelp
        @echo '* uImage.gz                 - Kernel-only image for U-Boot (gzip)'
        @echo '  uImage.bz2                - Kernel-only image for U-Boot (bzip2)'
        @echo '  uImage.lzma               - Kernel-only image for U-Boot (lzma)'
+       @echo '  uImage.xz                 - Kernel-only image for U-Boot (xz)'
        @echo '  uImage.lzo                - Kernel-only image for U-Boot (lzo)'
 endef
index 33b6629..701667a 100644 (file)
@@ -1294,6 +1294,7 @@ static int __init arch_setup(void)
        i2c_register_board_info(1, i2c1_devices,
                                ARRAY_SIZE(i2c1_devices));
 
+#if defined(CONFIG_VIDEO_SH_VOU) || defined(CONFIG_VIDEO_SH_VOU_MODULE)
        /* VOU */
        gpio_request(GPIO_FN_DV_D15, NULL);
        gpio_request(GPIO_FN_DV_D14, NULL);
@@ -1325,6 +1326,7 @@ static int __init arch_setup(void)
 
        /* Remove reset */
        gpio_set_value(GPIO_PTG4, 1);
+#endif
 
        return platform_add_devices(ecovec_devices,
                                    ARRAY_SIZE(ecovec_devices));
index 1ce6362..ba515d8 100644 (file)
@@ -24,12 +24,13 @@ suffix-y := bin
 suffix-$(CONFIG_KERNEL_GZIP)   := gz
 suffix-$(CONFIG_KERNEL_BZIP2)  := bz2
 suffix-$(CONFIG_KERNEL_LZMA)   := lzma
+suffix-$(CONFIG_KERNEL_XZ)     := xz
 suffix-$(CONFIG_KERNEL_LZO)    := lzo
 
 targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \
-          uImage.bz2 uImage.lzma uImage.lzo uImage.bin
+          uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin
 extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
-          vmlinux.bin.lzo
+          vmlinux.bin.xz vmlinux.bin.lzo
 subdir- := compressed romimage
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
@@ -76,6 +77,9 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
 $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
        $(call if_changed,lzma)
 
+$(obj)/vmlinux.bin.xz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,xzkern)
+
 $(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.bin FORCE
        $(call if_changed,lzo)
 
@@ -88,6 +92,9 @@ $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
 $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
        $(call if_changed,uimage,lzma)
 
+$(obj)/uImage.xz: $(obj)/vmlinux.bin.xz
+       $(call if_changed,uimage,xz)
+
 $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo
        $(call if_changed,uimage,lzo)
 
index cfa5a08..e0b0293 100644 (file)
@@ -6,7 +6,7 @@
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
                   vmlinux.bin.bz2 vmlinux.bin.lzma \
-                  vmlinux.bin.lzo \
+                  vmlinux.bin.xz vmlinux.bin.lzo \
                   head_$(BITS).o misc.o piggy.o
 
 OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o
@@ -50,6 +50,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,bzip2)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzma)
+$(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,xzkern)
 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzo)
 
index 27140a6..95470a4 100644 (file)
@@ -61,6 +61,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_unlzma.c"
 #endif
 
+#ifdef CONFIG_KERNEL_XZ
+#include "../../../../lib/decompress_unxz.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZO
 #include "../../../../lib/decompress_unlzo.c"
 #endif
index 083ea06..db85916 100644 (file)
@@ -134,6 +134,7 @@ typedef pte_t *pte_addr_t;
 extern void pgtable_cache_init(void);
 
 struct vm_area_struct;
+struct mm_struct;
 
 extern void __update_cache(struct vm_area_struct *vma,
                           unsigned long address, pte_t pte);
index a78701d..4a53500 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm-generic/sections.h>
 
-extern void __nosave_begin, __nosave_end;
+extern long __nosave_begin, __nosave_end;
 extern long __machvec_start, __machvec_end;
 extern char __uncached_start, __uncached_end;
 extern char _ebss[];
index c2b0aaa..e53b4b3 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/io.h>
 #include <linux/sh_timer.h>
 #include <linux/serial_sci.h>
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -230,10 +230,10 @@ static struct platform_device *sh7750_devices[] __initdata = {
 static int __init sh7750_devices_setup(void)
 {
        if (mach_is_rts7751r2d()) {
-               platform_register_device(&scif_device);
+               platform_device_register(&scif_device);
        } else {
-               platform_register_device(&sci_device);
-               platform_register_device(&scif_device);
+               platform_device_register(&sci_device);
+               platform_device_register(&scif_device);
        }
 
        return platform_add_devices(sh7750_devices,
@@ -255,12 +255,17 @@ static struct platform_device *sh7750_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
+       struct platform_device *dev[1];
+
        if (mach_is_rts7751r2d()) {
                scif_platform_data.scscr |= SCSCR_CKE1;
-               early_platform_add_devices(&scif_device, 1);
+               dev[0] = &scif_device;
+               early_platform_add_devices(dev, 1);
        } else {
-               early_platform_add_devices(&sci_device, 1);
-               early_platform_add_devices(&scif_device, 1);
+               dev[0] = &sci_device;
+               early_platform_add_devices(dev, 1);
+               dev[0] = &scif_device;
+               early_platform_add_devices(dev, 1);
        }
 
        early_platform_add_devices(sh7750_early_devices,
index 948fdb6..38e8628 100644 (file)
@@ -17,6 +17,7 @@
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 cpumask_t cpu_core_map[NR_CPUS];
+EXPORT_SYMBOL(cpu_core_map);
 
 static cpumask_t cpu_coregroup_map(unsigned int cpu)
 {
index faa8f86..0901b2f 100644 (file)
 void __delay(unsigned long loops)
 {
        __asm__ __volatile__(
+               /*
+                * ST40-300 appears to have an issue with this code,
+                * normally taking two cycles each loop, as with all
+                * other SH variants. If however the branch and the
+                * delay slot straddle an 8 byte boundary, this increases
+                * to 3 cycles.
+                * This align directive ensures this doesn't occur.
+                */
+               ".balign 8\n\t"
+
                "tst    %0, %0\n\t"
                "1:\t"
                "bf/s   1b\n\t"
index 88d3dc3..5a580ea 100644 (file)
@@ -108,7 +108,8 @@ void copy_user_highpage(struct page *to, struct page *from,
                kunmap_atomic(vfrom, KM_USER0);
        }
 
-       if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+       if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) ||
+           (vma->vm_flags & VM_EXEC))
                __flush_purge_region(vto, PAGE_SIZE);
 
        kunmap_atomic(vto, KM_USER1);
index 45d9c87..95695e9 100644 (file)
@@ -50,6 +50,7 @@ config SPARC64
        select RTC_DRV_STARFIRE
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
+       select HAVE_GENERIC_HARDIRQS
 
 config ARCH_DEFCONFIG
        string
@@ -107,10 +108,6 @@ config NEED_PER_CPU_EMBED_FIRST_CHUNK
 config NEED_PER_CPU_PAGE_FIRST_CHUNK
        def_bool y if SPARC64
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       def_bool y if SPARC64
-
 config MMU
        bool
        default y
@@ -276,10 +273,6 @@ config HOTPLUG_CPU
          can be controlled through /sys/devices/system/cpu/cpu#.
          Say N if you want to disable CPU hotplug.
 
-config GENERIC_HARDIRQS
-       bool
-       default y if SPARC64
-
 source "kernel/time/Kconfig"
 
 if SPARC64
index a2f5c61..843e4fa 100644 (file)
@@ -43,4 +43,6 @@ static inline u64 picl_value(unsigned int nmi_hz)
 
 extern u64 pcr_enable;
 
+extern int pcr_arch_init(void);
+
 #endif /* __PCR_H */
index 47977a7..72509d0 100644 (file)
@@ -255,10 +255,9 @@ static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu,
 static int iommu_alloc_ctx(struct iommu *iommu)
 {
        int lowest = iommu->ctx_lowest_free;
-       int sz = IOMMU_NUM_CTXS - lowest;
-       int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
+       int n = find_next_zero_bit(iommu->ctx_bitmap, IOMMU_NUM_CTXS, lowest);
 
-       if (unlikely(n == sz)) {
+       if (unlikely(n == IOMMU_NUM_CTXS)) {
                n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
                if (unlikely(n == lowest)) {
                        printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
index ae96cf5..7c2ced6 100644 (file)
@@ -167,5 +167,3 @@ out_unregister:
        unregister_perf_hsvc();
        return err;
 }
-
-early_initcall(pcr_arch_init);
index b6a2b8f..555a76d 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/mdesc.h>
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
+#include <asm/pcr.h>
 
 #include "cpumap.h"
 
@@ -1358,6 +1359,7 @@ void __cpu_die(unsigned int cpu)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+       pcr_arch_init();
 }
 
 void smp_send_reschedule(int cpu)
index 8cc0345..8f096e8 100644 (file)
@@ -24,9 +24,9 @@ retl_efault:
        .globl  __do_int_store
 __do_int_store:
        ld      [%o2], %g1
-       cmp     %1, 2
+       cmp     %o1, 2
        be      2f
-        cmp    %1, 4
+        cmp    %o1, 4
        be      1f
         srl    %g1, 24, %g2
        srl     %g1, 16, %g7
index 764b3eb..48d00e7 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/string.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 
 #include <asm/bitext.h>
 
@@ -80,8 +80,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
                while (test_bit(offset + i, t->map) == 0) {
                        i++;
                        if (i == len) {
-                               for (i = 0; i < len; i++)
-                                       __set_bit(offset + i, t->map);
+                               bitmap_set(t->map, offset, len);
                                if (offset == t->first_free)
                                        t->first_free = find_next_zero_bit
                                                        (t->map, t->size,
index e11b5fc..08948e4 100644 (file)
@@ -1,24 +1,33 @@
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 
-config MMU
-       def_bool y
-
-config GENERIC_CSUM
-       def_bool y
-
-config GENERIC_HARDIRQS
+config TILE
        def_bool y
+       select HAVE_KVM if !TILEGX
+       select GENERIC_FIND_FIRST_BIT
+       select GENERIC_FIND_NEXT_BIT
+       select USE_GENERIC_SMP_HELPERS
+       select CC_OPTIMIZE_FOR_SIZE
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select GENERIC_PENDING_IRQ if SMP
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
+# FIXME: investigate whether we need/want these options.
+#      select HAVE_IOREMAP_PROT
+#       select HAVE_OPTPROBES
+#       select HAVE_REGS_AND_STACK_ACCESS_API
+#       select HAVE_HW_BREAKPOINT
+#       select PERF_EVENTS
+#       select HAVE_USER_RETURN_NOTIFIER
+#       config NO_BOOTMEM
+#       config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+#       config HUGETLB_PAGE_SIZE_VARIABLE
 
-config GENERIC_IRQ_PROBE
+config MMU
        def_bool y
 
-config GENERIC_PENDING_IRQ
+config GENERIC_CSUM
        def_bool y
-       depends on GENERIC_HARDIRQS && SMP
 
 config SEMAPHORE_SLEEPERS
        def_bool y
@@ -97,26 +106,6 @@ config HVC_TILE
        select HVC_DRIVER
        def_bool y
 
-config TILE
-       def_bool y
-       select HAVE_KVM if !TILEGX
-       select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
-       select USE_GENERIC_SMP_HELPERS
-       select CC_OPTIMIZE_FOR_SIZE
-
-# FIXME: investigate whether we need/want these options.
-#      select HAVE_IOREMAP_PROT
-#       select HAVE_OPTPROBES
-#       select HAVE_REGS_AND_STACK_ACCESS_API
-#       select HAVE_HW_BREAKPOINT
-#       select PERF_EVENTS
-#       select HAVE_USER_RETURN_NOTIFIER
-#       config NO_BOOTMEM
-#       config ARCH_SUPPORTS_DEBUG_PAGEALLOC
-#       config HUGETLB_PAGE_SIZE_VARIABLE
-
-
 # Please note: TILE-Gx support is not yet finalized; this is
 # the preliminary support.  TILE-Gx drivers are only provided
 # with the alpha or beta test versions for Tilera customers.
@@ -220,7 +209,7 @@ config FORCE_MAX_ZONEORDER
 
 choice
        depends on !TILEGX
-       prompt "Memory split" if EMBEDDED
+       prompt "Memory split" if EXPERT
        default VMSPLIT_3G
        ---help---
          Select the desired split between kernel and user memory.
index a81f0fb..9bc161a 100644 (file)
@@ -3,7 +3,7 @@ menu "Kernel hacking"
 source "lib/Kconfig.debug"
 
 config EARLY_PRINTK
-       bool "Early printk" if EMBEDDED && DEBUG_KERNEL
+       bool "Early printk" if EXPERT && DEBUG_KERNEL
        default y
        help
          Write kernel log output directly via the hypervisor console.
index 919c54a..0fe5444 100644 (file)
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
index 049d048..e351e14 100644 (file)
@@ -3,14 +3,10 @@ config DEFCONFIG_LIST
        option defconfig_list
        default "arch/$ARCH/defconfig"
 
-# UML uses the generic IRQ subsystem
-config GENERIC_HARDIRQS
-       bool
-       default y
-
 config UML
        bool
        default y
+       select HAVE_GENERIC_HARDIRQS
 
 config MMU
        bool
index f8d1d0d..90a438a 100644 (file)
@@ -120,9 +120,6 @@ config SMP
 
          If you don't know what to do, say N.
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 config NR_CPUS
        int "Maximum number of CPUs (2-32)"
        range 2 32
index 564f3de..9f7634f 100644 (file)
@@ -133,7 +133,7 @@ CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
+# CONFIG_EXPERT is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
index 3ed5ad9..d5ed94d 100644 (file)
@@ -627,11 +627,11 @@ config APB_TIMER
          as it is off-chip. APB timers are always running regardless of CPU
          C states, they are used as per CPU clockevent device when possible.
 
-# Mark as embedded because too many people got it wrong.
+# Mark as expert because too many people got it wrong.
 # The code disables itself when not needed.
 config DMI
        default y
-       bool "Enable DMI scanning" if EMBEDDED
+       bool "Enable DMI scanning" if EXPERT
        ---help---
          Enabled scanning of DMI to identify machine quirks. Say Y
          here unless you have verified that your setup is not
@@ -639,7 +639,7 @@ config DMI
          BIOS code.
 
 config GART_IOMMU
-       bool "GART IOMMU support" if EMBEDDED
+       bool "GART IOMMU support" if EXPERT
        default y
        select SWIOTLB
        depends on X86_64 && PCI && AMD_NB
@@ -889,7 +889,7 @@ config X86_THERMAL_VECTOR
        depends on X86_MCE_INTEL
 
 config VM86
-       bool "Enable VM86 support" if EMBEDDED
+       bool "Enable VM86 support" if EXPERT
        default y
        depends on X86_32
        ---help---
@@ -1073,7 +1073,7 @@ endchoice
 
 choice
        depends on EXPERIMENTAL
-       prompt "Memory split" if EMBEDDED
+       prompt "Memory split" if EXPERT
        default VMSPLIT_3G
        depends on X86_32
        ---help---
@@ -1135,7 +1135,7 @@ config ARCH_DMA_ADDR_T_64BIT
        def_bool X86_64 || HIGHMEM64G
 
 config DIRECT_GBPAGES
-       bool "Enable 1GB pages for kernel pagetables" if EMBEDDED
+       bool "Enable 1GB pages for kernel pagetables" if EXPERT
        default y
        depends on X86_64
        ---help---
@@ -1369,7 +1369,7 @@ config MATH_EMULATION
 
 config MTRR
        def_bool y
-       prompt "MTRR (Memory Type Range Register) support" if EMBEDDED
+       prompt "MTRR (Memory Type Range Register) support" if EXPERT
        ---help---
          On Intel P6 family processors (Pentium Pro, Pentium II and later)
          the Memory Type Range Registers (MTRRs) may be used to control
@@ -1435,7 +1435,7 @@ config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
 
 config X86_PAT
        def_bool y
-       prompt "x86 PAT support" if EMBEDDED
+       prompt "x86 PAT support" if EXPERT
        depends on MTRR
        ---help---
          Use PAT attributes to setup page level cache control.
@@ -1539,7 +1539,7 @@ config KEXEC_JUMP
          code in physical address mode via KEXEC
 
 config PHYSICAL_START
-       hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+       hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP)
        default "0x1000000"
        ---help---
          This gives the physical address where the kernel is loaded.
@@ -1934,7 +1934,7 @@ config PCI_MMCONFIG
        depends on X86_64 && PCI && ACPI
 
 config PCI_CNB20LE_QUIRK
-       bool "Read CNB20LE Host Bridge Windows" if EMBEDDED
+       bool "Read CNB20LE Host Bridge Windows" if EXPERT
        default n
        depends on PCI && EXPERIMENTAL
        help
index 15588a0..283c5a6 100644 (file)
@@ -424,7 +424,7 @@ config X86_DEBUGCTLMSR
        depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) && !UML
 
 menuconfig PROCESSOR_SELECT
-       bool "Supported processor vendors" if EMBEDDED
+       bool "Supported processor vendors" if EXPERT
        ---help---
          This lets you choose what x86 vendor support code your kernel
          will include.
index 45143bb..615e188 100644 (file)
@@ -31,7 +31,7 @@ config X86_VERBOSE_BOOTUP
          see errors. Disable this if you want silent bootup.
 
 config EARLY_PRINTK
-       bool "Early printk" if EMBEDDED
+       bool "Early printk" if EXPERT
        default y
        ---help---
          Write kernel log output directly into the VGA buffer or to a serial
@@ -138,7 +138,7 @@ config DEBUG_NX_TEST
 
 config DOUBLEFAULT
        default y
-       bool "Enable doublefault exception handler" if EMBEDDED
+       bool "Enable doublefault exception handler" if EXPERT
        depends on X86_32
        ---help---
          This option allows trapping of rare doublefault exceptions that
index 211ca3f..4ea15ca 100644 (file)
@@ -88,6 +88,7 @@ extern int acpi_disabled;
 extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
+extern int acpi_fix_pin2_polarity;
 
 extern u8 acpi_sci_flags;
 extern int acpi_sci_override_gsi;
index 5e3969c..3c89694 100644 (file)
@@ -233,6 +233,7 @@ extern void sync_Arb_IDs(void);
 extern void init_bsp_APIC(void);
 extern void setup_local_APIC(void);
 extern void end_local_APIC_setup(void);
+extern void bsp_end_local_APIC_setup(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
index 63e35ec..62f0844 100644 (file)
@@ -1,48 +1,8 @@
 #ifndef _ASM_X86_CACHEFLUSH_H
 #define _ASM_X86_CACHEFLUSH_H
 
-/* Keep includes the same across arches.  */
-#include <linux/mm.h>
-
 /* Caches aren't brain-dead on the intel. */
-static inline void flush_cache_all(void) { }
-static inline void flush_cache_mm(struct mm_struct *mm) { }
-static inline void flush_cache_dup_mm(struct mm_struct *mm) { }
-static inline void flush_cache_range(struct vm_area_struct *vma,
-                                    unsigned long start, unsigned long end) { }
-static inline void flush_cache_page(struct vm_area_struct *vma,
-                                   unsigned long vmaddr, unsigned long pfn) { }
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-static inline void flush_dcache_page(struct page *page) { }
-static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
-static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
-static inline void flush_icache_range(unsigned long start,
-                                     unsigned long end) { }
-static inline void flush_icache_page(struct vm_area_struct *vma,
-                                    struct page *page) { }
-static inline void flush_icache_user_range(struct vm_area_struct *vma,
-                                          struct page *page,
-                                          unsigned long addr,
-                                          unsigned long len) { }
-static inline void flush_cache_vmap(unsigned long start, unsigned long end) { }
-static inline void flush_cache_vunmap(unsigned long start,
-                                     unsigned long end) { }
-
-static inline void copy_to_user_page(struct vm_area_struct *vma,
-                                    struct page *page, unsigned long vaddr,
-                                    void *dst, const void *src,
-                                    unsigned long len)
-{
-       memcpy(dst, src, len);
-}
-
-static inline void copy_from_user_page(struct vm_area_struct *vma,
-                                      struct page *page, unsigned long vaddr,
-                                      void *dst, const void *src,
-                                      unsigned long len)
-{
-       memcpy(dst, src, len);
-}
+#include <asm-generic/cacheflush.h>
 
 #ifdef CONFIG_X86_PAT
 /*
index 4fab24d..4564c8e 100644 (file)
@@ -32,5 +32,6 @@ extern void arch_unregister_cpu(int);
 
 DECLARE_PER_CPU(int, cpu_state);
 
+int mwait_usable(const struct cpuinfo_x86 *);
 
 #endif /* _ASM_X86_CPU_H */
index f52d42e..574dbc2 100644 (file)
@@ -14,7 +14,7 @@
        do {                                                    \
                asm goto("1:"                                   \
                        JUMP_LABEL_INITIAL_NOP                  \
-                       ".pushsection __jump_table,  \"a\" \n\t"\
+                       ".pushsection __jump_table,  \"aw\" \n\t"\
                        _ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
                        ".popsection \n\t"                      \
                        : :  "i" (key) :  : label);             \
index 4a2d4e0..8b5393e 100644 (file)
@@ -36,8 +36,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        unsigned cpu = smp_processor_id();
 
        if (likely(prev != next)) {
-               /* stop flush ipis for the previous mm */
-               cpumask_clear_cpu(cpu, mm_cpumask(prev));
 #ifdef CONFIG_SMP
                percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
                percpu_write(cpu_tlbstate.active_mm, next);
@@ -47,6 +45,9 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                /* Re-load page tables */
                load_cr3(next->pgd);
 
+               /* stop flush ipis for the previous mm */
+               cpumask_clear_cpu(cpu, mm_cpumask(prev));
+
                /*
                 * load the LDT, if the LDT is different:
                 */
index 4d0dfa0..43a18c7 100644 (file)
 #define MSR_IA32_PERFCTR1              0x000000c2
 #define MSR_FSB_FREQ                   0x000000cd
 
+#define MSR_NHM_SNB_PKG_CST_CFG_CTL    0x000000e2
+#define NHM_C3_AUTO_DEMOTE             (1UL << 25)
+#define NHM_C1_AUTO_DEMOTE             (1UL << 26)
+#define ATM_LNC_C6_AUTO_DEMOTE         (1UL << 25)
+
 #define MSR_MTRRcap                    0x000000fe
 #define MSR_IA32_BBL_CR_CTL            0x00000119
 
index a372290..b0ef2b4 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_NUMA_32_H
 #define _ASM_X86_NUMA_32_H
 
+extern int numa_off;
+
 extern int pxm_to_nid(int pxm);
 extern void numa_remove_cpu(int cpu);
 
index 5ae8728..0493be3 100644 (file)
@@ -40,6 +40,7 @@ extern void __cpuinit numa_remove_cpu(int cpu);
 #ifdef CONFIG_NUMA_EMU
 #define FAKE_NODE_MIN_SIZE     ((u64)32 << 20)
 #define FAKE_NODE_MIN_HASH_MASK        (~(FAKE_NODE_MIN_SIZE - 1UL))
+void numa_emu_cmdline(char *);
 #endif /* CONFIG_NUMA_EMU */
 #else
 static inline void init_cpu_to_node(void)              { }
index 2071a8b..ebbc4d8 100644 (file)
@@ -558,13 +558,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                              pmd_t *pmdp, pmd_t pmd)
 {
-#if PAGETABLE_LEVELS >= 3
        if (sizeof(pmdval_t) > sizeof(long))
                /* 5 arg words */
                pv_mmu_ops.set_pmd_at(mm, addr, pmdp, pmd);
        else
-               PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp, pmd.pmd);
-#endif
+               PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp,
+                           native_pmd_val(pmd));
 }
 #endif
 
index 8ee4516..7e17295 100644 (file)
@@ -273,34 +273,34 @@ do {                                                                      \
        typeof(var) pxo_new__ = (nval);                                 \
        switch (sizeof(var)) {                                          \
        case 1:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%al"                    \
-                   "\n\tcmpxchgb %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%al"                    \
+                   "\n1:\tcmpxchgb %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "q" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 2:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%ax"                    \
-                   "\n\tcmpxchgw %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%ax"                    \
+                   "\n1:\tcmpxchgw %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 4:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%eax"                   \
-                   "\n\tcmpxchgl %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%eax"                   \
+                   "\n1:\tcmpxchgl %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 8:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%rax"                   \
-                   "\n\tcmpxchgq %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%rax"                   \
+                   "\n1:\tcmpxchgq %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
@@ -414,8 +414,6 @@ do {                                                                        \
 #define this_cpu_xchg_1(pcp, nval)     percpu_xchg_op(pcp, nval)
 #define this_cpu_xchg_2(pcp, nval)     percpu_xchg_op(pcp, nval)
 #define this_cpu_xchg_4(pcp, nval)     percpu_xchg_op(pcp, nval)
-#define this_cpu_xchg_8(pcp, nval)     percpu_xchg_op(pcp, nval)
-#define this_cpu_cmpxchg_8(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 
 #define irqsafe_cpu_add_1(pcp, val)    percpu_add_op((pcp), val)
 #define irqsafe_cpu_add_2(pcp, val)    percpu_add_op((pcp), val)
@@ -432,8 +430,6 @@ do {                                                                        \
 #define irqsafe_cpu_xchg_1(pcp, nval)  percpu_xchg_op(pcp, nval)
 #define irqsafe_cpu_xchg_2(pcp, nval)  percpu_xchg_op(pcp, nval)
 #define irqsafe_cpu_xchg_4(pcp, nval)  percpu_xchg_op(pcp, nval)
-#define irqsafe_cpu_xchg_8(pcp, nval)  percpu_xchg_op(pcp, nval)
-#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
 
 #ifndef CONFIG_M386
 #define __this_cpu_add_return_1(pcp, val) percpu_add_return_op(pcp, val)
@@ -475,11 +471,15 @@ do {                                                                      \
 #define this_cpu_or_8(pcp, val)                percpu_to_op("or", (pcp), val)
 #define this_cpu_xor_8(pcp, val)       percpu_to_op("xor", (pcp), val)
 #define this_cpu_add_return_8(pcp, val)        percpu_add_return_op(pcp, val)
+#define this_cpu_xchg_8(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define this_cpu_cmpxchg_8(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 
 #define irqsafe_cpu_add_8(pcp, val)    percpu_add_op((pcp), val)
 #define irqsafe_cpu_and_8(pcp, val)    percpu_to_op("and", (pcp), val)
 #define irqsafe_cpu_or_8(pcp, val)     percpu_to_op("or", (pcp), val)
 #define irqsafe_cpu_xor_8(pcp, val)    percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xchg_8(pcp, nval)  percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
 #endif
 
 /* This is not atomic against other CPUs -- CPU preemption needs to be off */
index e2f6a99..cc29086 100644 (file)
@@ -22,6 +22,7 @@
 
 #define ARCH_P4_CNTRVAL_BITS   (40)
 #define ARCH_P4_CNTRVAL_MASK   ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1)
+#define ARCH_P4_UNFLAGGED_BIT  ((1ULL) << (ARCH_P4_CNTRVAL_BITS - 1))
 
 #define P4_ESCR_EVENT_MASK     0x7e000000U
 #define P4_ESCR_EVENT_SHIFT    25
index 4c2f63c..1f46951 100644 (file)
@@ -40,10 +40,7 @@ DECLARE_EARLY_PER_CPU(u16, x86_cpu_to_apicid);
 DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
 
 /* Static state in head.S used to set up a CPU */
-extern struct {
-       void *sp;
-       unsigned short ss;
-} stack_start;
+extern unsigned long stack_start; /* Initial stack pointer address */
 
 struct smp_ops {
        void (*smp_prepare_boot_cpu)(void);
index 6c22bf3..725b778 100644 (file)
@@ -34,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
         */
        CMOS_WRITE(0, 0xf);
 
-       *((volatile long *)phys_to_virt(apic->trampoline_phys_low)) = 0;
+       *((volatile u32 *)phys_to_virt(apic->trampoline_phys_low)) = 0;
 }
 
 static inline void __init smpboot_setup_io_apic(void)
diff --git a/arch/x86/include/asm/system_64.h b/arch/x86/include/asm/system_64.h
deleted file mode 100644 (file)
index 1159e09..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _ASM_X86_SYSTEM_64_H
-#define _ASM_X86_SYSTEM_64_H
-
-#include <asm/segment.h>
-#include <asm/cmpxchg.h>
-
-
-static inline unsigned long read_cr8(void)
-{
-       unsigned long cr8;
-       asm volatile("movq %%cr8,%0" : "=r" (cr8));
-       return cr8;
-}
-
-static inline void write_cr8(unsigned long val)
-{
-       asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
-}
-
-#include <linux/irqflags.h>
-
-#endif /* _ASM_X86_SYSTEM_64_H */
index b3a7113..3e6e2d6 100644 (file)
@@ -72,6 +72,7 @@ u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
 int acpi_skip_timer_override __initdata;
 int acpi_use_timer_override __initdata;
+int acpi_fix_pin2_polarity __initdata;
 
 #ifdef CONFIG_X86_LOCAL_APIC
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
@@ -415,10 +416,15 @@ acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
                return 0;
        }
 
-       if (acpi_skip_timer_override &&
-           intsrc->source_irq == 0 && intsrc->global_irq == 2) {
-               printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
-               return 0;
+       if (intsrc->source_irq == 0 && intsrc->global_irq == 2) {
+               if (acpi_skip_timer_override) {
+                       printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
+                       return 0;
+               }
+               if (acpi_fix_pin2_polarity && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) {
+                       intsrc->inti_flags &= ~ACPI_MADT_POLARITY_MASK;
+                       printk(PREFIX "BIOS IRQ0 pin2 override: forcing polarity to high active.\n");
+               }
        }
 
        mp_override_legacy_irq(intsrc->source_irq,
index 69fd72a..68d1537 100644 (file)
 #include <linux/cpumask.h>
 #include <asm/segment.h>
 #include <asm/desc.h>
-
-#ifdef CONFIG_X86_32
 #include <asm/pgtable.h>
-#endif
+#include <asm/cacheflush.h>
 
 #include "realmode/wakeup.h"
 #include "sleep.h"
@@ -100,7 +98,7 @@ int acpi_save_state_mem(void)
 #else /* CONFIG_64BIT */
        header->trampoline_segment = setup_trampoline() >> 4;
 #ifdef CONFIG_SMP
-       stack_start.sp = temp_stack + sizeof(temp_stack);
+       stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
        early_gdt_descr.address =
                        (unsigned long)get_cpu_gdt_table(smp_processor_id());
        initial_gs = per_cpu_offset(smp_processor_id());
@@ -149,6 +147,15 @@ void __init acpi_reserve_wakeup_memory(void)
        memblock_x86_reserve_range(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
 }
 
+int __init acpi_configure_wakeup_memory(void)
+{
+       if (acpi_realmode)
+               set_memory_x(acpi_realmode, WAKEUP_SIZE >> PAGE_SHIFT);
+
+       return 0;
+}
+arch_initcall(acpi_configure_wakeup_memory);
+
 
 static int __init acpi_sleep_setup(char *str)
 {
index 1236085..7038b95 100644 (file)
@@ -671,7 +671,7 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
 
        atomic_set(&stop_machine_first, 1);
        wrote_text = 0;
-       stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
+       __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
 }
 
 #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
index 51ef31a..51d4e16 100644 (file)
@@ -284,7 +284,7 @@ static int __init apbt_clockevent_register(void)
        memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device));
 
        if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
-               apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100;
+               adev->evt.rating = APBT_CLOCKEVENT_RATING - 100;
                global_clock_event = &adev->evt;
                printk(KERN_DEBUG "%s clockevent registered as global\n",
                       global_clock_event->name);
index 06c196d..76b96d7 100644 (file)
@@ -1381,12 +1381,17 @@ void __cpuinit end_local_APIC_setup(void)
 #endif
 
        apic_pm_activate();
+}
+
+void __init bsp_end_local_APIC_setup(void)
+{
+       end_local_APIC_setup();
 
        /*
         * Now that local APIC setup is completed for BP, configure the fault
         * handling for interrupt remapping.
         */
-       if (!smp_processor_id() && intr_remapping_enabled)
+       if (intr_remapping_enabled)
                enable_drhd_fault_handling();
 
 }
@@ -1756,7 +1761,7 @@ int __init APIC_init_uniprocessor(void)
                enable_IO_APIC();
 #endif
 
-       end_local_APIC_setup();
+       bsp_end_local_APIC_setup();
 
 #ifdef CONFIG_X86_IO_APIC
        if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
index 697dc34..ca9e2a3 100644 (file)
@@ -4002,6 +4002,9 @@ int mp_find_ioapic(u32 gsi)
 {
        int i = 0;
 
+       if (nr_ioapics == 0)
+               return -1;
+
        /* Find the IOAPIC that manages this GSI. */
        for (i = 0; i < nr_ioapics; i++) {
                if ((gsi >= mp_gsi_routing[i].gsi_base)
index bd1cac7..52c9364 100644 (file)
@@ -158,9 +158,9 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
 {
        if (c->x86 == 0x06) {
                if (cpu_has(c, X86_FEATURE_EST))
-                       printk(KERN_WARNING PFX "Warning: EST-capable CPU "
-                              "detected. The acpi-cpufreq module offers "
-                              "voltage scaling in addition of frequency "
+                       printk_once(KERN_WARNING PFX "Warning: EST-capable "
+                              "CPU detected. The acpi-cpufreq module offers "
+                              "voltage scaling in addition to frequency "
                               "scaling. You should use that instead of "
                               "p4-clockmod, if possible.\n");
                switch (c->x86_model) {
index 35c7e65..c567dec 100644 (file)
@@ -1537,6 +1537,7 @@ static struct notifier_block cpb_nb = {
 static int __cpuinit powernowk8_init(void)
 {
        unsigned int i, supported_cpus = 0, cpu;
+       int rv;
 
        for_each_online_cpu(i) {
                int rc;
@@ -1555,14 +1556,14 @@ static int __cpuinit powernowk8_init(void)
 
                cpb_capable = true;
 
-               register_cpu_notifier(&cpb_nb);
-
                msrs = msrs_alloc();
                if (!msrs) {
                        printk(KERN_ERR "%s: Error allocating msrs!\n", __func__);
                        return -ENOMEM;
                }
 
+               register_cpu_notifier(&cpb_nb);
+
                rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
 
                for_each_cpu(cpu, cpu_online_mask) {
@@ -1574,7 +1575,13 @@ static int __cpuinit powernowk8_init(void)
                        (cpb_enabled ? "on" : "off"));
        }
 
-       return cpufreq_register_driver(&cpufreq_amd64_driver);
+       rv = cpufreq_register_driver(&cpufreq_amd64_driver);
+       if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) {
+               unregister_cpu_notifier(&cpb_nb);
+               msrs_free(msrs);
+               msrs = NULL;
+       }
+       return rv;
 }
 
 /* driver entry point for term */
index 7283e98..ec2c19a 100644 (file)
@@ -45,6 +45,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
        { 0x0a, LVL_1_DATA, 8 },        /* 2 way set assoc, 32 byte line size */
        { 0x0c, LVL_1_DATA, 16 },       /* 4-way set assoc, 32 byte line size */
        { 0x0d, LVL_1_DATA, 16 },       /* 4-way set assoc, 64 byte line size */
+       { 0x0e, LVL_1_DATA, 24 },       /* 6-way set assoc, 64 byte line size */
        { 0x21, LVL_2,      256 },      /* 8-way set assoc, 64 byte line size */
        { 0x22, LVL_3,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
        { 0x23, LVL_3,      MB(1) },    /* 8-way set assoc, sectored cache, 64 byte line size */
@@ -66,6 +67,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
        { 0x45, LVL_2,      MB(2) },    /* 4-way set assoc, 32 byte line size */
        { 0x46, LVL_3,      MB(4) },    /* 4-way set assoc, 64 byte line size */
        { 0x47, LVL_3,      MB(8) },    /* 8-way set assoc, 64 byte line size */
+       { 0x48, LVL_2,      MB(3) },    /* 12-way set assoc, 64 byte line size */
        { 0x49, LVL_3,      MB(4) },    /* 16-way set assoc, 64 byte line size */
        { 0x4a, LVL_3,      MB(6) },    /* 12-way set assoc, 64 byte line size */
        { 0x4b, LVL_3,      MB(8) },    /* 16-way set assoc, 64 byte line size */
@@ -87,6 +89,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
        { 0x7c, LVL_2,      MB(1) },    /* 8-way set assoc, sectored cache, 64 byte line size */
        { 0x7d, LVL_2,      MB(2) },    /* 8-way set assoc, 64 byte line size */
        { 0x7f, LVL_2,      512 },      /* 2-way set assoc, 64 byte line size */
+       { 0x80, LVL_2,      512 },      /* 8-way set assoc, 64 byte line size */
        { 0x82, LVL_2,      256 },      /* 8-way set assoc, 32 byte line size */
        { 0x83, LVL_2,      512 },      /* 8-way set assoc, 32 byte line size */
        { 0x84, LVL_2,      MB(1) },    /* 8-way set assoc, 32 byte line size */
index e12246f..6f8c5e9 100644 (file)
@@ -59,6 +59,7 @@ struct thermal_state {
 
 /* Callback to handle core threshold interrupts */
 int (*platform_thermal_notify)(__u64 msr_val);
+EXPORT_SYMBOL(platform_thermal_notify);
 
 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 
index 01c0f3e..bebabec 100644 (file)
@@ -793,13 +793,21 @@ void set_mtrr_aps_delayed_init(void)
 }
 
 /*
- * MTRR initialization for all AP's
+ * Delayed MTRR initialization for all AP's
  */
 void mtrr_aps_init(void)
 {
        if (!use_intel())
                return;
 
+       /*
+        * Check if someone has requested the delay of AP MTRR initialization,
+        * by doing set_mtrr_aps_delayed_init(), prior to this point. If not,
+        * then we are done.
+        */
+       if (!mtrr_aps_delayed_init)
+               return;
+
        set_mtrr(~0U, 0, 0, 0);
        mtrr_aps_delayed_init = false;
 }
index e56b9bf..ff751a9 100644 (file)
@@ -682,7 +682,7 @@ static int p4_validate_raw_event(struct perf_event *event)
         * if an event is shared accross the logical threads
         * the user needs special permissions to be able to use it
         */
-       if (p4_event_bind_map[v].shared) {
+       if (p4_ht_active() && p4_event_bind_map[v].shared) {
                if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
                        return -EACCES;
        }
@@ -727,7 +727,8 @@ static int p4_hw_config(struct perf_event *event)
                event->hw.config = p4_set_ht_bit(event->hw.config);
 
        if (event->attr.type == PERF_TYPE_RAW) {
-
+               struct p4_event_bind *bind;
+               unsigned int esel;
                /*
                 * Clear bits we reserve to be managed by kernel itself
                 * and never allowed from a user space
@@ -743,6 +744,13 @@ static int p4_hw_config(struct perf_event *event)
                 * bits since we keep additional info here (for cache events and etc)
                 */
                event->hw.config |= event->attr.config;
+               bind = p4_config_get_bind(event->attr.config);
+               if (!bind) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+               esel = P4_OPCODE_ESEL(bind->opcode);
+               event->hw.config |= p4_config_pack_cccr(P4_CCCR_ESEL(esel));
        }
 
        rc = x86_setup_perfctr(event);
@@ -762,9 +770,14 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
                return 1;
        }
 
-       /* it might be unflagged overflow */
-       rdmsrl(hwc->event_base + hwc->idx, v);
-       if (!(v & ARCH_P4_CNTRVAL_MASK))
+       /*
+        * In some circumstances the overflow might issue an NMI but did
+        * not set P4_CCCR_OVF bit. Because a counter holds a negative value
+        * we simply check for high bit being set, if it's cleared it means
+        * the counter has reached zero value and continued counting before
+        * real NMI signal was received:
+        */
+       if (!(v & ARCH_P4_UNFLAGGED_BIT))
                return 1;
 
        return 0;
index 6410133..a6b6fcf 100644 (file)
@@ -149,13 +149,13 @@ void dump_trace(struct task_struct *task,
        unsigned used = 0;
        struct thread_info *tinfo;
        int graph = 0;
+       unsigned long dummy;
        unsigned long bp;
 
        if (!task)
                task = current;
 
        if (!stack) {
-               unsigned long dummy;
                stack = &dummy;
                if (task && task != current)
                        stack = (unsigned long *)task->thread.sp;
index 76b8cd9..9efbdcc 100644 (file)
@@ -143,15 +143,10 @@ static void __init ati_bugs(int num, int slot, int func)
 
 static u32 __init ati_sbx00_rev(int num, int slot, int func)
 {
-       u32 old, d;
+       u32 d;
 
-       d = read_pci_config(num, slot, func, 0x70);
-       old = d;
-       d &= ~(1<<8);
-       write_pci_config(num, slot, func, 0x70, d);
        d = read_pci_config(num, slot, func, 0x8);
        d &= 0xff;
-       write_pci_config(num, slot, func, 0x70, old);
 
        return d;
 }
@@ -160,13 +155,16 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 {
        u32 d, rev;
 
-       if (acpi_use_timer_override)
-               return;
-
        rev = ati_sbx00_rev(num, slot, func);
+       if (rev >= 0x40)
+               acpi_fix_pin2_polarity = 1;
+
        if (rev > 0x13)
                return;
 
+       if (acpi_use_timer_override)
+               return;
+
        /* check for IRQ0 interrupt swap */
        d = read_pci_config(num, slot, func, 0x64);
        if (!(d & (1<<14)))
index fc293dc..767d6c4 100644 (file)
@@ -85,6 +85,8 @@ RESERVE_BRK(pagetables, INIT_MAP_SIZE)
  */
 __HEAD
 ENTRY(startup_32)
+       movl pa(stack_start),%ecx
+       
        /* test KEEP_SEGMENTS flag to see if the bootloader is asking
                us to not reload segments */
        testb $(1<<6), BP_loadflags(%esi)
@@ -99,7 +101,9 @@ ENTRY(startup_32)
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+       movl %eax,%ss
 2:
+       leal -__PAGE_OFFSET(%ecx),%esp
 
 /*
  * Clear BSS first so that there are no surprises...
@@ -145,8 +149,6 @@ ENTRY(startup_32)
  * _brk_end is set up to point to the first "safe" location.
  * Mappings are created both at virtual address 0 (identity mapping)
  * and PAGE_OFFSET for up to _end.
- *
- * Note that the stack is not yet set up!
  */
 #ifdef CONFIG_X86_PAE
 
@@ -282,6 +284,9 @@ ENTRY(startup_32_smp)
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+       movl pa(stack_start),%ecx
+       movl %eax,%ss
+       leal -__PAGE_OFFSET(%ecx),%esp
 #endif /* CONFIG_SMP */
 default_entry:
 
@@ -347,8 +352,8 @@ default_entry:
        movl %eax,%cr0          /* ..and set paging (PG) bit */
        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
 1:
-       /* Set up the stack pointer */
-       lss stack_start,%esp
+       /* Shift the stack pointer to a virtual address */
+       addl $__PAGE_OFFSET, %esp
 
 /*
  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
@@ -360,9 +365,7 @@ default_entry:
 
 #ifdef CONFIG_SMP
        cmpb $0, ready
-       jz  1f                          /* Initial CPU cleans BSS */
-       jmp checkCPUtype
-1:
+       jnz checkCPUtype
 #endif /* CONFIG_SMP */
 
 /*
@@ -470,14 +473,7 @@ is386:     movl $2,%ecx            # set MP
 
        cld                     # gcc2 wants the direction flag cleared at all times
        pushl $0                # fake return address for unwinder
-#ifdef CONFIG_SMP
-       movb ready, %cl
        movb $1, ready
-       cmpb $0,%cl             # the first CPU calls start_kernel
-       je   1f
-       movl (stack_start), %esp
-1:
-#endif /* CONFIG_SMP */
        jmp *(initial_code)
 
 /*
@@ -670,15 +666,15 @@ ENTRY(initial_page_table)
 #endif
 
 .data
+.balign 4
 ENTRY(stack_start)
        .long init_thread_union+THREAD_SIZE
-       .long __BOOT_DS
-
-ready: .byte 0
 
 early_recursion_flag:
        .long 0
 
+ready: .byte 0
+
 int_msg:
        .asciz "Unknown interrupt or fault at: %p %p %p\n"
 
index 52945da..387b6a0 100644 (file)
@@ -367,7 +367,8 @@ void fixup_irqs(void)
                if (irr  & (1 << (vector % 32))) {
                        irq = __this_cpu_read(vector_irq[vector]);
 
-                       data = irq_get_irq_data(irq);
+                       desc = irq_to_desc(irq);
+                       data = &desc->irq_data;
                        raw_spin_lock(&desc->lock);
                        if (data->chip->irq_retrigger)
                                data->chip->irq_retrigger(data);
index d8286ed..ff45541 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/utsname.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
+#include <asm/cpu.h>
 #include <asm/system.h>
 #include <asm/apic.h>
 #include <asm/syscalls.h>
@@ -91,21 +92,31 @@ void show_regs(struct pt_regs *regs)
 
 void show_regs_common(void)
 {
-       const char *board, *product;
+       const char *vendor, *product, *board;
 
-       board = dmi_get_system_info(DMI_BOARD_NAME);
-       if (!board)
-               board = "";
+       vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+       if (!vendor)
+               vendor = "";
        product = dmi_get_system_info(DMI_PRODUCT_NAME);
        if (!product)
                product = "";
 
+       /* Board Name is optional */
+       board = dmi_get_system_info(DMI_BOARD_NAME);
+
        printk(KERN_CONT "\n");
-       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s/%s\n",
+       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s",
                current->pid, current->comm, print_tainted(),
                init_utsname()->release,
                (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version, board, product);
+               init_utsname()->version);
+       printk(KERN_CONT " ");
+       printk(KERN_CONT "%s %s", vendor, product);
+       if (board) {
+               printk(KERN_CONT "/");
+               printk(KERN_CONT "%s", board);
+       }
+       printk(KERN_CONT "\n");
 }
 
 void flush_thread(void)
@@ -505,7 +516,7 @@ static void poll_idle(void)
 #define MWAIT_ECX_EXTENDED_INFO                0x01
 #define MWAIT_EDX_C1                   0xf0
 
-static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
+int mwait_usable(const struct cpuinfo_x86 *c)
 {
        u32 eax, ebx, ecx, edx;
 
index fc7aae1..715037c 100644 (file)
@@ -285,6 +285,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
                },
        },
+       {       /* Handle problems with rebooting on VersaLogic Menlow boards */
+               .callback = set_bios_reboot,
+               .ident = "VersaLogic Menlow based board",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "VersaLogic Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"),
+               },
+       },
        { }
 };
 
index 763df77..08776a9 100644 (file)
@@ -638,7 +638,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
         * target processor state.
         */
        startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
-                        (unsigned long)stack_start.sp);
+                        stack_start);
 
        /*
         * Run STARTUP IPI loop.
@@ -785,7 +785,7 @@ do_rest:
 #endif
        early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
        initial_code = (unsigned long)start_secondary;
-       stack_start.sp = (void *) c_idle.idle->thread.sp;
+       stack_start  = c_idle.idle->thread.sp;
 
        /* start_ip had better be page-aligned! */
        start_ip = setup_trampoline();
@@ -1060,7 +1060,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 
                connect_bsp_APIC();
                setup_local_APIC();
-               end_local_APIC_setup();
+               bsp_end_local_APIC_setup();
                return -1;
        }
 
@@ -1137,7 +1137,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        if (!skip_ioapic_setup && nr_ioapics)
                enable_IO_APIC();
 
-       end_local_APIC_setup();
+       bsp_end_local_APIC_setup();
 
        map_cpu_to_logical_apicid();
 
@@ -1402,8 +1402,9 @@ static inline void mwait_play_dead(void)
        unsigned int highest_subcstate = 0;
        int i;
        void *mwait_ptr;
+       struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
 
-       if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_MWAIT))
+       if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)))
                return;
        if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH))
                return;
index b34ab80..bf47007 100644 (file)
@@ -34,9 +34,11 @@ OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT)
 #ifdef CONFIG_X86_32
 OUTPUT_ARCH(i386)
 ENTRY(phys_startup_32)
+jiffies = jiffies_64;
 #else
 OUTPUT_ARCH(i386:x86-64)
 ENTRY(phys_startup_64)
+jiffies_64 = jiffies;
 #endif
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
@@ -140,15 +142,6 @@ SECTIONS
                CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
 
                DATA_DATA
-               /*
-                * Workaround a binutils (2.20.51.0.12 to 2.21.51.0.3) bug.
-                * This makes jiffies relocatable in such binutils
-                */
-#ifdef CONFIG_X86_32
-               jiffies = jiffies_64;
-#else
-               jiffies_64 = jiffies;
-#endif
                CONSTRUCTORS
 
                /* rarely changed data like cpu maps */
index 25bd1bc..63fec15 100644 (file)
@@ -1150,8 +1150,8 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
        kvm_load_ldt(svm->host.ldt);
 #ifdef CONFIG_X86_64
        loadsegment(fs, svm->host.fs);
-       load_gs_index(svm->host.gs);
        wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+       load_gs_index(svm->host.gs);
 #else
        loadsegment(gs, svm->host.gs);
 #endif
@@ -2777,6 +2777,8 @@ static int dr_interception(struct vcpu_svm *svm)
                        kvm_register_write(&svm->vcpu, reg, val);
        }
 
+       skip_emulated_instruction(&svm->vcpu);
+
        return 1;
 }
 
index 3871804..6e121a2 100644 (file)
@@ -2,6 +2,7 @@ config LGUEST_GUEST
        bool "Lguest guest support"
        select PARAVIRT
        depends on X86_32
+       select VIRTUALIZATION
        select VIRTIO
        select VIRTIO_RING
        select VIRTIO_CONSOLE
index 4996cf5..eba687f 100644 (file)
@@ -824,7 +824,7 @@ static void __init lguest_init_IRQ(void)
 
        for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
                /* Some systems map "vectors" to interrupts weirdly.  Not us! */
-               __get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR;
+               __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR);
                if (i != SYSCALL_VECTOR)
                        set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
        }
index 787c52c..ebf6d78 100644 (file)
@@ -2,6 +2,28 @@
 #include <linux/topology.h>
 #include <linux/module.h>
 #include <linux/bootmem.h>
+#include <asm/numa.h>
+#include <asm/acpi.h>
+
+int __initdata numa_off;
+
+static __init int numa_setup(char *opt)
+{
+       if (!opt)
+               return -EINVAL;
+       if (!strncmp(opt, "off", 3))
+               numa_off = 1;
+#ifdef CONFIG_NUMA_EMU
+       if (!strncmp(opt, "fake=", 5))
+               numa_emu_cmdline(opt + 5);
+#endif
+#ifdef CONFIG_ACPI_NUMA
+       if (!strncmp(opt, "noacpi", 6))
+               acpi_numa = -1;
+#endif
+       return 0;
+}
+early_param("numa", numa_setup);
 
 /*
  * Which logical CPUs are on which nodes
index 1e72102..95ea155 100644 (file)
@@ -30,7 +30,6 @@ s16 apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
        [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
 };
 
-int numa_off __initdata;
 static unsigned long __initdata nodemap_addr;
 static unsigned long __initdata nodemap_size;
 
@@ -263,6 +262,11 @@ static struct bootnode nodes[MAX_NUMNODES] __initdata;
 static struct bootnode physnodes[MAX_NUMNODES] __cpuinitdata;
 static char *cmdline __initdata;
 
+void __init numa_emu_cmdline(char *str)
+{
+       cmdline = str;
+}
+
 static int __init setup_physnodes(unsigned long start, unsigned long end,
                                        int acpi, int amd)
 {
@@ -670,24 +674,6 @@ unsigned long __init numa_free_all_bootmem(void)
        return pages;
 }
 
-static __init int numa_setup(char *opt)
-{
-       if (!opt)
-               return -EINVAL;
-       if (!strncmp(opt, "off", 3))
-               numa_off = 1;
-#ifdef CONFIG_NUMA_EMU
-       if (!strncmp(opt, "fake=", 5))
-               cmdline = opt + 5;
-#endif
-#ifdef CONFIG_ACPI_NUMA
-       if (!strncmp(opt, "noacpi", 6))
-               acpi_numa = -1;
-#endif
-       return 0;
-}
-early_param("numa", numa_setup);
-
 #ifdef CONFIG_NUMA
 
 static __init int find_near_online_node(int node)
index 8b830ca..d343b3c 100644 (file)
@@ -256,7 +256,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
                                   unsigned long pfn)
 {
        pgprot_t forbidden = __pgprot(0);
-       pgprot_t required = __pgprot(0);
 
        /*
         * The BIOS area between 640k and 1Mb needs to be executable for
@@ -282,12 +281,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
        if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
                   __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_RW;
-       /*
-        * .data and .bss should always be writable.
-        */
-       if (within(address, (unsigned long)_sdata, (unsigned long)_edata) ||
-           within(address, (unsigned long)__bss_start, (unsigned long)__bss_stop))
-               pgprot_val(required) |= _PAGE_RW;
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
        /*
@@ -327,7 +320,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
 #endif
 
        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
-       prot = __pgprot(pgprot_val(prot) | pgprot_val(required));
 
        return prot;
 }
index f164345..ae96e7b 100644 (file)
@@ -59,7 +59,6 @@ static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS];
 static int __initdata num_memory_chunks; /* total number of memory chunks */
 static u8 __initdata apicid_to_pxm[MAX_APICID];
 
-int numa_off __initdata;
 int acpi_numa __initdata;
 
 static __init void bad_srat(void)
index dab8746..044bda5 100644 (file)
@@ -140,8 +140,7 @@ void * __init prom_early_alloc(unsigned long size)
                 * wasted bootmem) and hand off chunks of it to callers.
                 */
                res = alloc_bootmem(chunk_size);
-               if (!res)
-                       return NULL;
+               BUG_ON(!res);
                prom_early_allocated += chunk_size;
                memset(res, 0, chunk_size);
                free_mem = chunk_size;
index 7e8d3bc..50542ef 100644 (file)
@@ -1194,7 +1194,7 @@ asmlinkage void __init xen_start_kernel(void)
        per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
 
        local_irq_disable();
-       early_boot_irqs_off();
+       early_boot_irqs_disabled = true;
 
        memblock_init();
 
index 9d30105..6a6fe89 100644 (file)
@@ -126,7 +126,7 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
 #endif
 };
 
-void __init xen_init_irq_ops()
+void __init xen_init_irq_ops(void)
 {
        pv_irq_ops = xen_irq_ops;
        x86_init.irqs.intr_init = xen_init_IRQ;
index 8f2251d..fd12d7c 100644 (file)
@@ -237,6 +237,18 @@ void __init xen_build_dynamic_phys_to_machine(void)
                        p2m_top[topidx] = mid;
                }
 
+               /*
+                * As long as the mfn_list has enough entries to completely
+                * fill a p2m page, pointing into the array is ok. But if
+                * not the entries beyond the last pfn will be undefined.
+                */
+               if (unlikely(pfn + P2M_PER_PAGE > max_pfn)) {
+                       unsigned long p2midx;
+
+                       p2midx = max_pfn % P2M_PER_PAGE;
+                       for ( ; p2midx < P2M_PER_PAGE; p2midx++)
+                               mfn_list[pfn + p2midx] = INVALID_P2M_ENTRY;
+               }
                p2m_top[topidx][mididx] = &mfn_list[pfn];
        }
 
index b5a7f92..a8a66a5 100644 (file)
@@ -179,8 +179,13 @@ char * __init xen_memory_setup(void)
        e820.nr_map = 0;
        xen_extra_mem_start = mem_end;
        for (i = 0; i < memmap.nr_entries; i++) {
-               unsigned long long end = map[i].addr + map[i].size;
+               unsigned long long end;
 
+               /* Guard against non-page aligned E820 entries. */
+               if (map[i].type == E820_RAM)
+                       map[i].size -= (map[i].size + map[i].addr) % PAGE_SIZE;
+
+               end = map[i].addr + map[i].size;
                if (map[i].type == E820_RAM && end > mem_end) {
                        /* RAM off the end - may be partially included */
                        u64 delta = min(map[i].size, end - mem_end);
@@ -350,6 +355,7 @@ void __init xen_arch_setup(void)
        boot_cpu_data.hlt_works_ok = 1;
 #endif
        pm_idle = default_idle;
+       boot_option_idle_override = IDLE_HALT;
 
        fiddle_vdso();
 }
index 1d230ee..b90038e 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
+# CONFIG_EXPERT is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
index 7368164..0234cd1 100644 (file)
@@ -55,7 +55,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
index bb84fbc..095cd80 100644 (file)
@@ -55,7 +55,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
index 6c9213e..60be1e0 100644 (file)
@@ -2,7 +2,7 @@
 # Block layer core configuration
 #
 menuconfig BLOCK
-       bool "Enable the block layer" if EMBEDDED
+       bool "Enable the block layer" if EXPERT
        default y
        help
         Provide block layer support for the kernel.
index 2f4002f..518dd42 100644 (file)
@@ -352,7 +352,7 @@ void blk_start_queue(struct request_queue *q)
        WARN_ON(!irqs_disabled());
 
        queue_flag_clear(QUEUE_FLAG_STOPPED, q);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
 }
 EXPORT_SYMBOL(blk_start_queue);
 
@@ -403,13 +403,14 @@ EXPORT_SYMBOL(blk_sync_queue);
 /**
  * __blk_run_queue - run a single device queue
  * @q: The queue to run
+ * @force_kblockd: Don't run @q->request_fn directly.  Use kblockd.
  *
  * Description:
  *    See @blk_run_queue. This variant must be called with the queue lock
  *    held and interrupts disabled.
  *
  */
-void __blk_run_queue(struct request_queue *q)
+void __blk_run_queue(struct request_queue *q, bool force_kblockd)
 {
        blk_remove_plug(q);
 
@@ -423,7 +424,7 @@ void __blk_run_queue(struct request_queue *q)
         * Only recurse once to avoid overrunning the stack, let the unplug
         * handling reinvoke the handler shortly if we already got there.
         */
-       if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
+       if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
                q->request_fn(q);
                queue_flag_clear(QUEUE_FLAG_REENTER, q);
        } else {
@@ -446,7 +447,7 @@ void blk_run_queue(struct request_queue *q)
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_run_queue);
@@ -1053,7 +1054,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
 
        drive_stat_acct(rq, 1);
        __elv_add_request(q, rq, where, 0);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_insert_request);
@@ -2610,13 +2611,6 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-int kblockd_schedule_delayed_work(struct request_queue *q,
-                       struct delayed_work *dwork, unsigned long delay)
-{
-       return queue_delayed_work(kblockd_workqueue, dwork, delay);
-}
-EXPORT_SYMBOL(kblockd_schedule_delayed_work);
-
 int __init blk_dev_init(void)
 {
        BUILD_BUG_ON(__REQ_NR_BITS > 8 *
index 54b123d..b27d020 100644 (file)
@@ -66,10 +66,12 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q,
 
        /*
         * Moving a request silently to empty queue_head may stall the
-        * queue.  Kick the queue in those cases.
+        * queue.  Kick the queue in those cases.  This function is called
+        * from request completion path and calling directly into
+        * request_fn may confuse the driver.  Always use kblockd.
         */
        if (was_empty && next_rq)
-               __blk_run_queue(q);
+               __blk_run_queue(q, true);
 }
 
 static void pre_flush_end_io(struct request *rq, int error)
@@ -130,7 +132,7 @@ static struct request *queue_next_fseq(struct request_queue *q)
                BUG();
        }
 
-       elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
+       elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
        return rq;
 }
 
index 1a320d2..eec78be 100644 (file)
@@ -132,7 +132,7 @@ static void bio_batch_end_io(struct bio *bio, int err)
 }
 
 /**
- * blkdev_issue_zeroout generate number of zero filed write bios
+ * blkdev_issue_zeroout - generate number of zero filed write bios
  * @bdev:      blockdev to issue
  * @sector:    start sector
  * @nr_sects:  number of sectors to write
index 381b09b..e36cc10 100644 (file)
@@ -20,6 +20,11 @@ static int throtl_quantum = 32;
 /* Throttling is performed over 100ms slice and after that slice is renewed */
 static unsigned long throtl_slice = HZ/10;     /* 100 ms */
 
+/* A workqueue to queue throttle related work */
+static struct workqueue_struct *kthrotld_workqueue;
+static void throtl_schedule_delayed_work(struct throtl_data *td,
+                               unsigned long delay);
+
 struct throtl_rb_root {
        struct rb_root rb;
        struct rb_node *left;
@@ -168,7 +173,15 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
         * tree of blkg (instead of traversing through hash list all
         * the time.
         */
-       tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+       /*
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
+        */
+       if (blkcg == &blkio_root_cgroup)
+               tg = &td->root_tg;
+       else
+               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
 
        /* Fill in device details for root group */
        if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
@@ -337,10 +350,9 @@ static void throtl_schedule_next_dispatch(struct throtl_data *td)
        update_min_dispatch_time(st);
 
        if (time_before_eq(st->min_disptime, jiffies))
-               throtl_schedule_delayed_work(td->queue, 0);
+               throtl_schedule_delayed_work(td, 0);
        else
-               throtl_schedule_delayed_work(td->queue,
-                               (st->min_disptime - jiffies));
+               throtl_schedule_delayed_work(td, (st->min_disptime - jiffies));
 }
 
 static inline void
@@ -807,10 +819,10 @@ void blk_throtl_work(struct work_struct *work)
 }
 
 /* Call with queue lock held */
-void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay)
+static void
+throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay)
 {
 
-       struct throtl_data *td = q->td;
        struct delayed_work *dwork = &td->throtl_work;
 
        if (total_nr_queued(td) > 0) {
@@ -819,12 +831,11 @@ void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay)
                 * Cancel that and schedule a new one.
                 */
                __cancel_delayed_work(dwork);
-               kblockd_schedule_delayed_work(q, dwork, delay);
+               queue_delayed_work(kthrotld_workqueue, dwork, delay);
                throtl_log(td, "schedule work. delay=%lu jiffies=%lu",
                                delay, jiffies);
        }
 }
-EXPORT_SYMBOL(throtl_schedule_delayed_work);
 
 static void
 throtl_destroy_tg(struct throtl_data *td, struct throtl_grp *tg)
@@ -912,7 +923,7 @@ static void throtl_update_blkio_group_read_bps(void *key,
        smp_mb__after_atomic_inc();
 
        /* Schedule a work now to process the limit change */
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_write_bps(void *key,
@@ -926,7 +937,7 @@ static void throtl_update_blkio_group_write_bps(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_read_iops(void *key,
@@ -940,7 +951,7 @@ static void throtl_update_blkio_group_read_iops(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_write_iops(void *key,
@@ -954,7 +965,7 @@ static void throtl_update_blkio_group_write_iops(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 void throtl_shutdown_timer_wq(struct request_queue *q)
@@ -1127,6 +1138,10 @@ void blk_throtl_exit(struct request_queue *q)
 
 static int __init throtl_init(void)
 {
+       kthrotld_workqueue = alloc_workqueue("kthrotld", WQ_MEM_RECLAIM, 0);
+       if (!kthrotld_workqueue)
+               panic("Failed to create kthrotld\n");
+
        blkio_policy_register(&blkio_policy_throtl);
        return 0;
 }
index 501ffdf..ea83a4f 100644 (file)
@@ -599,7 +599,7 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
 }
 
 static inline unsigned
-cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_scaled_cfqq_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
        if (cfqd->cfq_latency) {
@@ -631,7 +631,7 @@ cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       unsigned slice = cfq_scaled_group_slice(cfqd, cfqq);
+       unsigned slice = cfq_scaled_cfqq_slice(cfqd, cfqq);
 
        cfqq->slice_start = jiffies;
        cfqq->slice_end = jiffies + slice;
@@ -1671,7 +1671,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
         */
        if (timed_out) {
                if (cfq_cfqq_slice_new(cfqq))
-                       cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq);
+                       cfqq->slice_resid = cfq_scaled_cfqq_slice(cfqd, cfqq);
                else
                        cfqq->slice_resid = cfqq->slice_end - jiffies;
                cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
@@ -3355,7 +3355,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                            cfqd->busy_queues > 1) {
                                cfq_del_timer(cfqd, cfqq);
                                cfq_clear_cfqq_wait_request(cfqq);
-                               __blk_run_queue(cfqd->queue);
+                               __blk_run_queue(cfqd->queue, false);
                        } else {
                                cfq_blkiocg_update_idle_time_stats(
                                                &cfqq->cfqg->blkg);
@@ -3370,7 +3370,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 * this new queue is RT and the current one is BE
                 */
                cfq_preempt_queue(cfqd, cfqq);
-               __blk_run_queue(cfqd->queue);
+               __blk_run_queue(cfqd->queue, false);
        }
 }
 
@@ -3432,6 +3432,10 @@ static bool cfq_should_wait_busy(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        struct cfq_io_context *cic = cfqd->active_cic;
 
+       /* If the queue already has requests, don't wait */
+       if (!RB_EMPTY_ROOT(&cfqq->sort_list))
+               return false;
+
        /* If there are other queues in the group, don't wait */
        if (cfqq->cfqg->nr_cfqq > 1)
                return false;
@@ -3727,7 +3731,7 @@ static void cfq_kick_queue(struct work_struct *work)
        struct request_queue *q = cfqd->queue;
 
        spin_lock_irq(q->queue_lock);
-       __blk_run_queue(cfqd->queue);
+       __blk_run_queue(cfqd->queue, false);
        spin_unlock_irq(q->queue_lock);
 }
 
index 2569512..236e93c 100644 (file)
@@ -602,7 +602,7 @@ void elv_quiesce_start(struct request_queue *q)
         */
        elv_drain_elevator(q);
        while (q->rq.elvpriv) {
-               __blk_run_queue(q);
+               __blk_run_queue(q, false);
                spin_unlock_irq(q->queue_lock);
                msleep(10);
                spin_lock_irq(q->queue_lock);
@@ -651,7 +651,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
                 *   with anything.  There's no point in delaying queue
                 *   processing.
                 */
-               __blk_run_queue(q);
+               __blk_run_queue(q, false);
                break;
 
        case ELEVATOR_INSERT_SORT:
index 6a5b772..cbf1112 100644 (file)
@@ -1355,7 +1355,7 @@ int invalidate_partition(struct gendisk *disk, int partno)
        struct block_device *bdev = bdget_disk(disk, partno);
        if (bdev) {
                fsync_bdev(bdev);
-               res = __invalidate_device(bdev);
+               res = __invalidate_device(bdev, true);
                bdput(bdev);
        }
        return res;
index 9049d46..1124cd2 100644 (file)
@@ -294,9 +294,11 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                        return -EINVAL;
                if (get_user(n, (int __user *) arg))
                        return -EFAULT;
-               if (!(mode & FMODE_EXCL) &&
-                   blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
-                       return -EBUSY;
+               if (!(mode & FMODE_EXCL)) {
+                       bdgrab(bdev);
+                       if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
+                               return -EBUSY;
+               }
                ret = set_blocksize(bdev, n);
                if (!(mode & FMODE_EXCL))
                        blkdev_put(bdev, mode | FMODE_EXCL);
index 7eb35f4..b423bb1 100644 (file)
@@ -24,7 +24,7 @@ obj-$(CONFIG_XEN)             += xen/
 # regulators early, since some subsystems rely on them to initialize
 obj-$(CONFIG_REGULATOR)                += regulator/
 
-# char/ comes before serial/ etc so that the VT console is the boot-time
+# tty/ comes before char/ so that the VT console is the boot-time
 # default.
 obj-y                          += tty/
 obj-y                          += char/
@@ -38,7 +38,6 @@ obj-$(CONFIG_CONNECTOR)               += connector/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
-obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
 obj-y                          += base/ block/ misc/ mfd/ nfc/
 obj-$(CONFIG_NUBUS)            += nubus/
index 10c7ad5..2aa042a 100644 (file)
@@ -318,7 +318,7 @@ config ACPI_PCI_SLOT
          the module will be called pci_slot.
 
 config X86_PM_TIMER
-       bool "Power Management Timer Support" if EMBEDDED
+       bool "Power Management Timer Support" if EXPERT
        depends on X86
        default y
        help
index 3e50c74..e0ba17f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b17d8de..ab87396 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 72e9d5e..eb0b1f8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 894a0ff..666271b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 70e0b28..41d247d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0e4dba0..82a1bd2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 258d628..e7213be 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 049e203..3731e1c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 74000f5..edc2586 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -416,10 +416,15 @@ struct acpi_gpe_handler_info {
        u8 originally_enabled;  /* True if GPE was originally enabled */
 };
 
+struct acpi_gpe_notify_object {
+       struct acpi_namespace_node *node;
+       struct acpi_gpe_notify_object *next;
+};
+
 union acpi_gpe_dispatch_info {
        struct acpi_namespace_node *method_node;        /* Method node for this GPE level */
        struct acpi_gpe_handler_info *handler;  /* Installed GPE handler */
-       struct acpi_namespace_node *device_node;        /* Parent _PRW device for implicit notify */
+       struct acpi_gpe_notify_object device;   /* List of _PRW devices for implicit notify */
 };
 
 /*
index 8d5c9e0..b7491ee 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d44d3bc..79a598c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 962a3cc..1055769 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,8 +97,6 @@
 #define AOPOBJ_OBJECT_INITIALIZED   0x08       /* Region is initialized, _REG was run */
 #define AOPOBJ_SETUP_COMPLETE       0x10       /* Region setup is complete */
 #define AOPOBJ_INVALID              0x20       /* Host OS won't allow a Region address */
-#define AOPOBJ_MODULE_LEVEL         0x40       /* Method is actually module-level code */
-#define AOPOBJ_MODIFIED_NAMESPACE   0x80       /* Method modified the namespace */
 
 /******************************************************************************
  *
@@ -175,7 +173,7 @@ struct acpi_object_region {
 };
 
 struct acpi_object_method {
-       ACPI_OBJECT_COMMON_HEADER u8 method_flags;
+       ACPI_OBJECT_COMMON_HEADER u8 info_flags;
        u8 param_count;
        u8 sync_level;
        union acpi_operand_object *mutex;
@@ -183,13 +181,21 @@ struct acpi_object_method {
        union {
                ACPI_INTERNAL_METHOD implementation;
                union acpi_operand_object *handler;
-       } extra;
+       } dispatch;
 
        u32 aml_length;
        u8 thread_count;
        acpi_owner_id owner_id;
 };
 
+/* Flags for info_flags field above */
+
+#define ACPI_METHOD_MODULE_LEVEL        0x01   /* Method is actually module-level code */
+#define ACPI_METHOD_INTERNAL_ONLY       0x02   /* Method is implemented internally (_OSI) */
+#define ACPI_METHOD_SERIALIZED          0x04   /* Method is serialized */
+#define ACPI_METHOD_SERIALIZED_PENDING  0x08   /* Method is to be marked serialized */
+#define ACPI_METHOD_MODIFIED_NAMESPACE  0x10   /* Method modified the namespace */
+
 /******************************************************************************
  *
  * Objects that can be notified.  All share a common notify_info area.
index 8c15ff4..bb2ccfa 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d0bb0fd..5ea1e06 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 10998d3..94e73c9 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 528bcba..f08b55b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6e5dd97..1623b24 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 62a576e..967f081 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 72e4183..99c140d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1f484ba..f4f0998 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -480,16 +480,10 @@ typedef enum {
        AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D
 } AML_ACCESS_ATTRIBUTE;
 
-/* Bit fields in method_flags byte */
+/* Bit fields in the AML method_flags byte */
 
 #define AML_METHOD_ARG_COUNT        0x07
 #define AML_METHOD_SERIALIZED       0x08
 #define AML_METHOD_SYNC_LEVEL       0xF0
 
-/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
-
-#define AML_METHOD_INTERNAL_ONLY    0x01
-#define AML_METHOD_RESERVED1        0x02
-#define AML_METHOD_RESERVED2        0x04
-
 #endif                         /* __AMLCODE_H__ */
index 0e5798f..59122cd 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 347bee1..34be60c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cc4a38c..a7718bf 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d94dd89..5d79775 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,6 @@
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "amlcode.h"
 #include "acdispat.h"
 #include "acinterp.h"
 #include "acnamesp.h"
@@ -201,7 +200,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
        /*
         * If this method is serialized, we need to acquire the method mutex.
         */
-       if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
+       if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
                /*
                 * Create a mutex for the method if it is defined to be Serialized
                 * and a mutex has not already been created. We defer the mutex creation
@@ -413,8 +412,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
 
        /* Invoke an internal method if necessary */
 
-       if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
-               status = obj_desc->method.extra.implementation(next_walk_state);
+       if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
+               status =
+                   obj_desc->method.dispatch.implementation(next_walk_state);
                if (status == AE_OK) {
                        status = AE_CTRL_TERMINATE;
                }
@@ -579,11 +579,14 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
 
                /*
                 * Delete any namespace objects created anywhere within the
-                * namespace by the execution of this method. Unless this method
-                * is a module-level executable code method, in which case we
-                * want make the objects permanent.
+                * namespace by the execution of this method. Unless:
+                * 1) This method is a module-level executable code method, in which
+                *    case we want make the objects permanent.
+                * 2) There are other threads executing the method, in which case we
+                *    will wait until the last thread has completed.
                 */
-               if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+               if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
+                   && (method_desc->method.thread_count == 1)) {
 
                        /* Delete any direct children of (created by) this method */
 
@@ -593,12 +596,17 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
                        /*
                         * Delete any objects that were created by this method
                         * elsewhere in the namespace (if any were created).
+                        * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
+                        * deletion such that we don't have to perform an entire
+                        * namespace walk for every control method execution.
                         */
                        if (method_desc->method.
-                           flags & AOPOBJ_MODIFIED_NAMESPACE) {
+                           info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
                                acpi_ns_delete_namespace_by_owner(method_desc->
                                                                  method.
                                                                  owner_id);
+                               method_desc->method.info_flags &=
+                                   ~ACPI_METHOD_MODIFIED_NAMESPACE;
                        }
                }
        }
@@ -629,19 +637,43 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
                 * Serialized if it appears that the method is incorrectly written and
                 * does not support multiple thread execution. The best example of this
                 * is if such a method creates namespace objects and blocks. A second
-                * thread will fail with an AE_ALREADY_EXISTS exception
+                * thread will fail with an AE_ALREADY_EXISTS exception.
                 *
                 * This code is here because we must wait until the last thread exits
-                * before creating the synchronization semaphore.
+                * before marking the method as serialized.
                 */
-               if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
-                   && (!method_desc->method.mutex)) {
-                       (void)acpi_ds_create_method_mutex(method_desc);
+               if (method_desc->method.
+                   info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
+                       if (walk_state) {
+                               ACPI_INFO((AE_INFO,
+                                          "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
+                                          walk_state->method_node->name.
+                                          ascii));
+                       }
+
+                       /*
+                        * Method tried to create an object twice and was marked as
+                        * "pending serialized". The probable cause is that the method
+                        * cannot handle reentrancy.
+                        *
+                        * The method was created as not_serialized, but it tried to create
+                        * a named object and then blocked, causing the second thread
+                        * entrance to begin and then fail. Workaround this problem by
+                        * marking the method permanently as Serialized when the last
+                        * thread exits here.
+                        */
+                       method_desc->method.info_flags &=
+                           ~ACPI_METHOD_SERIALIZED_PENDING;
+                       method_desc->method.info_flags |=
+                           ACPI_METHOD_SERIALIZED;
+                       method_desc->method.sync_level = 0;
                }
 
                /* No more threads, we can free the owner_id */
 
-               if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+               if (!
+                   (method_desc->method.
+                    info_flags & ACPI_METHOD_MODULE_LEVEL)) {
                        acpi_ut_release_owner_id(&method_desc->method.owner_id);
                }
        }
index 8095306..905ce29 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8e85f54..f42e17e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7c0e742..bbecf29 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 15135c2..2c477ce 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6b0b5d0..fe40e4c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 140a9d0..52566ff 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d1e7017..76a661f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 83155dd..a6c374e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e5e313c..d458b04 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7c339d3..f472521 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
        acpi_status status;
        struct acpi_gpe_event_info *local_gpe_event_info;
        struct acpi_evaluate_info *info;
+       struct acpi_gpe_notify_object *notify_object;
 
        ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
 
@@ -471,6 +472,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
        if (ACPI_FAILURE(status)) {
+               ACPI_FREE(local_gpe_event_info);
                return_VOID;
        }
 
@@ -478,6 +480,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 
        if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
                status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+               ACPI_FREE(local_gpe_event_info);
                return_VOID;
        }
 
@@ -506,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                 * from this thread -- because handlers may in turn run other
                 * control methods.
                 */
-               status =
-                   acpi_ev_queue_notify_request(local_gpe_event_info->dispatch.
-                                                device_node,
-                                                ACPI_NOTIFY_DEVICE_WAKE);
+               status = acpi_ev_queue_notify_request(
+                               local_gpe_event_info->dispatch.device.node,
+                               ACPI_NOTIFY_DEVICE_WAKE);
+
+               notify_object = local_gpe_event_info->dispatch.device.next;
+               while (ACPI_SUCCESS(status) && notify_object) {
+                       status = acpi_ev_queue_notify_request(
+                                       notify_object->node,
+                                       ACPI_NOTIFY_DEVICE_WAKE);
+                       notify_object = notify_object->next;
+               }
+
                break;
 
        case ACPI_GPE_DISPATCH_METHOD:
index 9acb869..ca2c41a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c59dc23..ce9aa9f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 10e4774..80a81d0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 38bba66..7dc8094 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 98fd210..785a5ee 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0b47a6d..9659cee 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -590,9 +590,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
                                 * See acpi_ns_exec_module_code
                                 */
                                if (obj_desc->method.
-                                   flags & AOPOBJ_MODULE_LEVEL) {
+                                   info_flags & ACPI_METHOD_MODULE_LEVEL) {
                                        handler_obj =
-                                           obj_desc->method.extra.handler;
+                                           obj_desc->method.dispatch.handler;
                                }
                                break;
 
index 8dfbaa9..2ebd40e 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1226689..e114140 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 90488c1..c57b5c7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 416845b..52aaff3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
        acpi_status status = AE_BAD_PARAMETER;
        struct acpi_gpe_event_info *gpe_event_info;
        struct acpi_namespace_node *device_node;
+       struct acpi_gpe_notify_object *notify_object;
        acpi_cpu_flags flags;
+       u8 gpe_dispatch_mask;
 
        ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
 
@@ -212,37 +214,62 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       /* Ensure that we have a valid GPE number */
+
+       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+       if (!gpe_event_info) {
+               goto unlock_and_exit;
+       }
+
+       if (wake_device == ACPI_ROOT_OBJECT) {
+               goto out;
+       }
+
+       /*
+        * If there is no method or handler for this GPE, then the
+        * wake_device will be notified whenever this GPE fires (aka
+        * "implicit notify") Note: The GPE is assumed to be
+        * level-triggered (for windows compatibility).
+        */
+       gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK;
+       if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE
+           && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) {
+               goto out;
+       }
+
        /* Validate wake_device is of type Device */
 
        device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
        if (device_node->type != ACPI_TYPE_DEVICE) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               goto unlock_and_exit;
        }
 
-       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+       if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) {
+               gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |
+                                        ACPI_GPE_LEVEL_TRIGGERED);
+               gpe_event_info->dispatch.device.node = device_node;
+               gpe_event_info->dispatch.device.next = NULL;
+       } else {
+               /* There are multiple devices to notify implicitly. */
 
-       /* Ensure that we have a valid GPE number */
-
-       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (gpe_event_info) {
-               /*
-                * If there is no method or handler for this GPE, then the
-                * wake_device will be notified whenever this GPE fires (aka
-                * "implicit notify") Note: The GPE is assumed to be
-                * level-triggered (for windows compatibility).
-                */
-               if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
-                   ACPI_GPE_DISPATCH_NONE) {
-                       gpe_event_info->flags =
-                           (ACPI_GPE_DISPATCH_NOTIFY |
-                            ACPI_GPE_LEVEL_TRIGGERED);
-                       gpe_event_info->dispatch.device_node = device_node;
+               notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object));
+               if (!notify_object) {
+                       status = AE_NO_MEMORY;
+                       goto unlock_and_exit;
                }
 
-               gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
-               status = AE_OK;
+               notify_object->node = device_node;
+               notify_object->next = gpe_event_info->dispatch.device.next;
+               gpe_event_info->dispatch.device.next = notify_object;
        }
 
+ out:
+       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       status = AE_OK;
+
+ unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
index ce9314f..eb73867 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1883220..745a42b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b73bc50..74162a1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3c61b48..e7b372d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -482,13 +482,11 @@ acpi_ex_create_method(u8 * aml_start,
        obj_desc->method.aml_length = aml_length;
 
        /*
-        * Disassemble the method flags. Split off the Arg Count
-        * for efficiency
+        * Disassemble the method flags. Split off the arg_count, Serialized
+        * flag, and sync_level for efficiency.
         */
        method_flags = (u8) operand[1]->integer.value;
 
-       obj_desc->method.method_flags =
-           (u8) (method_flags & ~AML_METHOD_ARG_COUNT);
        obj_desc->method.param_count =
            (u8) (method_flags & AML_METHOD_ARG_COUNT);
 
@@ -497,6 +495,8 @@ acpi_ex_create_method(u8 * aml_start,
         * created for this method when it is parsed.
         */
        if (method_flags & AML_METHOD_SERIALIZED) {
+               obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED;
+
                /*
                 * ACPI 1.0: sync_level = 0
                 * ACPI 2.0: sync_level = sync_level in method declaration
index be8c98b..c7a2f1e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f067bbb..61b8c0e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -122,7 +122,7 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
 
 static struct acpi_exdump_info acpi_ex_dump_method[9] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
-       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.info_flags), "Info Flags"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count),
         "Parameter Count"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
index f17d2ff..0bde223 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 38293fd..6c79c29 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 95db4be..703d88e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6af14e4..be1c56e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d11e539..49ec049 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 84e4d18..236ead1 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 10e104c..2571b4a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7a08d23..1b48d9d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4b50730..f4a2787 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7aae29f..cc95e20 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index de17e10..f0d5e14 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1fa4289..55997e4 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7ca35ea..db502cd 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8c97cfd..e3bb00c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1624436..c0c8842 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d4af684..a979017 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e972b66..dc665cc 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 675aaa9..df66e7b 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4093522..8ad9314 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b44274a..fc380d3 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 85c3cbd..f610d88 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ad21c7d..050fd22 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5d1273b..55accb7 100644 (file)
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3796811..2ac28bb 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1ef8e0b..9c8eb71 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e1d9c77..5f16058 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 50cc3be..6f98d21 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0cd925b..d93172f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -163,9 +163,9 @@ acpi_status acpi_ns_root_initialize(void)
 #else
                                /* Mark this as a very SPECIAL method */
 
-                               obj_desc->method.method_flags =
-                                   AML_METHOD_INTERNAL_ONLY;
-                               obj_desc->method.extra.implementation =
+                               obj_desc->method.info_flags =
+                                   ACPI_METHOD_INTERNAL_ONLY;
+                               obj_desc->method.dispatch.implementation =
                                    acpi_ut_osi_implementation;
 #endif
                                break;
index 1e5ff80..1d0ef15 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -234,8 +234,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
                         * modified the namespace. This is used for cleanup when the
                         * method exits.
                         */
-                       walk_state->method_desc->method.flags |=
-                           AOPOBJ_MODIFIED_NAMESPACE;
+                       walk_state->method_desc->method.info_flags |=
+                           ACPI_METHOD_MODIFIED_NAMESPACE;
                }
        }
 
@@ -341,6 +341,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
 {
        struct acpi_namespace_node *child_node = NULL;
        u32 level = 1;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
 
@@ -348,6 +349,13 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
                return_VOID;
        }
 
+       /* Lock namespace for possible update */
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               return_VOID;
+       }
+
        /*
         * Traverse the tree of objects until we bubble back up
         * to where we started.
@@ -397,6 +405,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
                }
        }
 
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_VOID;
 }
 
index a54dc39..b683cc2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -624,9 +624,22 @@ acpi_ns_dump_objects(acpi_object_type type,
                     acpi_owner_id owner_id, acpi_handle start_handle)
 {
        struct acpi_walk_info info;
+       acpi_status status;
 
        ACPI_FUNCTION_ENTRY();
 
+       /*
+        * Just lock the entire namespace for the duration of the dump.
+        * We don't want any changes to the namespace during this time,
+        * especially the temporary nodes since we are going to display
+        * them also.
+        */
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not acquire namespace mutex\n");
+               return;
+       }
+
        info.debug_level = ACPI_LV_TABLES;
        info.owner_id = owner_id;
        info.display_type = display_type;
@@ -636,6 +649,8 @@ acpi_ns_dump_objects(acpi_object_type type,
                                     ACPI_NS_WALK_TEMP_NODES,
                                     acpi_ns_dump_one_object, NULL,
                                     (void *)&info, NULL);
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
 #endif                         /* ACPI_FUTURE_USAGE */
 
index d2a9792..2ed294b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f52829c..c1bd02b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -389,7 +389,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
         * acpi_gbl_root_node->Object is NULL at PASS1.
         */
        if ((type == ACPI_TYPE_DEVICE) && parent_node->object) {
-               method_obj->method.extra.handler =
+               method_obj->method.dispatch.handler =
                    parent_node->object->device.handler;
        }
 
index 0cac7ec..fd7c638 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index df18be9..5f7dc69 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d3104af..d5fa520 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 41a9213..3bb8bf1 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5808c89..b3234fa 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7096bcd..9fb03fa 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d1c1366..1d76ac8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ef9f43..973883b 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 41102a8..28b0d7a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a7d6ad9..cb1b104 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2cd5be8..345f0c3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebef8a7..c53f004 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b01e45a..3fd4526 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -603,10 +603,9 @@ acpi_status acpi_install_method(u8 *buffer)
        method_obj->method.param_count = (u8)
            (method_flags & AML_METHOD_ARG_COUNT);
 
-       method_obj->method.method_flags = (u8)
-           (method_flags & ~AML_METHOD_ARG_COUNT);
-
        if (method_flags & AML_METHOD_SERIALIZED) {
+               method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
+
                method_obj->method.sync_level = (u8)
                    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
        }
index a1f04e9..db7660f 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7df1a4c..e1fad0e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2f2e776..01dd70d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -655,7 +655,7 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op,
                method_obj->method.aml_start = aml_start;
                method_obj->method.aml_length = aml_length;
                method_obj->method.owner_id = owner_id;
-               method_obj->method.flags |= AOPOBJ_MODULE_LEVEL;
+               method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
 
                /*
                 * Save the parent node in next_object. This is cheating, but we
index 2b0c3be..bed08de 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8d81542..9bb0cbd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,6 @@
 #include "acparser.h"
 #include "acdispat.h"
 #include "amlcode.h"
-#include "acnamesp.h"
 #include "acinterp.h"
 
 #define _COMPONENT          ACPI_PARSER
@@ -539,24 +538,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
                        /* Check for possible multi-thread reentrancy problem */
 
                        if ((status == AE_ALREADY_EXISTS) &&
-                           (!walk_state->method_desc->method.mutex)) {
-                               ACPI_INFO((AE_INFO,
-                                          "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
-                                          walk_state->method_node->name.
-                                          ascii));
-
+                           (!(walk_state->method_desc->method.
+                              info_flags & ACPI_METHOD_SERIALIZED))) {
                                /*
-                                * Method tried to create an object twice. The probable cause is
-                                * that the method cannot handle reentrancy.
-                                *
-                                * The method is marked not_serialized, but it tried to create
-                                * a named object, causing the second thread entrance to fail.
-                                * Workaround this problem by marking the method permanently
-                                * as Serialized.
+                                * Method is not serialized and tried to create an object
+                                * twice. The probable cause is that the method cannot
+                                * handle reentrancy. Mark as "pending serialized" now, and
+                                * then mark "serialized" when the last thread exits.
                                 */
-                               walk_state->method_desc->method.method_flags |=
-                                   AML_METHOD_SERIALIZED;
-                               walk_state->method_desc->method.sync_level = 0;
+                               walk_state->method_desc->method.info_flags |=
+                                   ACPI_METHOD_SERIALIZED_PENDING;
                        }
                }
 
index 40e2b27..a5faa13 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d4b970c..f1464c0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fe29eee..7eda785 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8abb962..3312d63 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c42f067..8086805 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,6 @@
 #include "acdispat.h"
 #include "acinterp.h"
 #include "actables.h"
-#include "amlcode.h"
 
 #define _COMPONENT          ACPI_PARSER
 ACPI_MODULE_NAME("psxface")
@@ -285,15 +284,15 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
                goto cleanup;
        }
 
-       if (info->obj_desc->method.flags & AOPOBJ_MODULE_LEVEL) {
+       if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) {
                walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL;
        }
 
        /* Invoke an internal method if necessary */
 
-       if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+       if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
                status =
-                   info->obj_desc->method.extra.implementation(walk_state);
+                   info->obj_desc->method.dispatch.implementation(walk_state);
                info->return_object = walk_state->return_desc;
 
                /* Cleanup states */
index 226c806..9e66f90 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d6ebf7e..3a8a89e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c80a2ee..4ce6e11 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f859b03..33db752 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1fd868b..f9ea608 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 33bff17..0c7efef 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 545da40..50b8ad2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7335f22..1bfcef7 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 887b8ba..7cc6d86 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f8cd9e8..410264b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 491191e..231811e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9f6a6e7..2ff657a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d2ff432..428d44e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 989d5c8..a55cb2b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 83d7af8..48db094 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 34f9c2b..0f2d395 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4a8b9e6..4b7085d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fd2c07d..7eb6c6c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8f08962..0a69735 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6fef83f..aded299 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f21c486..a9bcd81 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ed794cd..31f5a78 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 22f59ef..18f73c9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 508537f..97dd9bb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d290632..b679ea6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c1b1c80..191b682 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b081cd4..f6bb75c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 49cf7b7..ce481da 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c7d0e05..c33a852 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 199528f..a946c68 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fd1fa27..188340a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 18c59a8..1fb10cb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7965919..84e0518 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d35d109..30c21e1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1f484c9..98ad125 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6f12e31..916ae09 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 68bc227..ac1a599 100644 (file)
@@ -998,7 +998,6 @@ static int acpi_battery_resume(struct acpi_device *device)
        if (!device)
                return -EINVAL;
        battery = acpi_driver_data(device);
-       acpi_battery_refresh(battery);
        battery->update_time = 0;
        acpi_battery_update(battery);
        return 0;
index 5df67f1..384f7ab 100644 (file)
@@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
                        size_t count, loff_t *ppos)
 {
        static char *buf;
-       static int uncopied_bytes;
+       static u32 max_size;
+       static u32 uncopied_bytes;
+
        struct acpi_table_header table;
        acpi_status status;
 
@@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
                if (copy_from_user(&table, user_buf,
                                   sizeof(struct acpi_table_header)))
                        return -EFAULT;
-               uncopied_bytes = table.length;
-               buf = kzalloc(uncopied_bytes, GFP_KERNEL);
+               uncopied_bytes = max_size = table.length;
+               buf = kzalloc(max_size, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
        }
 
-       if (uncopied_bytes < count) {
-               kfree(buf);
+       if (buf == NULL)
+               return -EINVAL;
+
+       if ((*ppos > max_size) ||
+           (*ppos + count > max_size) ||
+           (*ppos + count < count) ||
+           (count > uncopied_bytes))
                return -EINVAL;
-       }
 
        if (copy_from_user(buf + (*ppos), user_buf, count)) {
                kfree(buf);
+               buf = NULL;
                return -EFAULT;
        }
 
@@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
        if (!uncopied_bytes) {
                status = acpi_install_method(buf);
                kfree(buf);
+               buf = NULL;
                if (ACPI_FAILURE(status))
                        return -EINVAL;
                add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
index 54b6ab8..fa5a1df 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <acpi/acpiosxf.h>
 
 /*
@@ -80,7 +81,7 @@ void suspend_nvs_free(void)
                        free_page((unsigned long)entry->data);
                        entry->data = NULL;
                        if (entry->kaddr) {
-                               acpi_os_unmap_memory(entry->kaddr, entry->size);
+                               iounmap(entry->kaddr);
                                entry->kaddr = NULL;
                        }
                }
@@ -114,8 +115,8 @@ int suspend_nvs_save(void)
 
        list_for_each_entry(entry, &nvs_list, node)
                if (entry->data) {
-                       entry->kaddr = acpi_os_map_memory(entry->phys_start,
-                                                         entry->size);
+                       entry->kaddr = acpi_os_ioremap(entry->phys_start,
+                                                   entry->size);
                        if (!entry->kaddr) {
                                suspend_nvs_free();
                                return -ENOMEM;
index e2dd6de..c90c76a 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/workqueue.h>
 #include <linux/nmi.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <linux/efi.h>
 #include <linux/ioport.h>
 #include <linux/list.h>
@@ -302,9 +303,10 @@ void __iomem *__init_refok
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        struct acpi_ioremap *map, *tmp_map;
-       unsigned long flags, pg_sz;
+       unsigned long flags;
        void __iomem *virt;
-       phys_addr_t pg_off;
+       acpi_physical_address pg_off;
+       acpi_size pg_sz;
 
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -320,7 +322,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 
        pg_off = round_down(phys, PAGE_SIZE);
        pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
-       virt = ioremap_cache(pg_off, pg_sz);
+       virt = acpi_os_ioremap(pg_off, pg_sz);
        if (!virt) {
                kfree(map);
                return NULL;
@@ -634,17 +636,21 @@ EXPORT_SYMBOL(acpi_os_write_port);
 acpi_status
 acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
 {
-       u32 dummy;
        void __iomem *virt_addr;
-       int size = width / 8, unmap = 0;
+       unsigned int size = width / 8;
+       bool unmap = false;
+       u32 dummy;
 
        rcu_read_lock();
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-       rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
-               unmap = 1;
+               rcu_read_unlock();
+               virt_addr = acpi_os_ioremap(phys_addr, size);
+               if (!virt_addr)
+                       return AE_BAD_ADDRESS;
+               unmap = true;
        }
+
        if (!value)
                value = &dummy;
 
@@ -664,6 +670,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
 
        if (unmap)
                iounmap(virt_addr);
+       else
+               rcu_read_unlock();
 
        return AE_OK;
 }
@@ -672,14 +680,17 @@ acpi_status
 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 {
        void __iomem *virt_addr;
-       int size = width / 8, unmap = 0;
+       unsigned int size = width / 8;
+       bool unmap = false;
 
        rcu_read_lock();
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-       rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
-               unmap = 1;
+               rcu_read_unlock();
+               virt_addr = acpi_os_ioremap(phys_addr, size);
+               if (!virt_addr)
+                       return AE_BAD_ADDRESS;
+               unmap = true;
        }
 
        switch (width) {
@@ -698,6 +709,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 
        if (unmap)
                iounmap(virt_addr);
+       else
+               rcu_read_unlock();
 
        return AE_OK;
 }
index fdd3aee..d6a8cd1 100644 (file)
@@ -166,6 +166,7 @@ static void acpi_pm_finish(void)
        u32 acpi_state = acpi_target_sleep_state;
 
        acpi_ec_unblock_transactions();
+       suspend_nvs_free();
 
        if (acpi_state == ACPI_STATE_S0)
                return;
@@ -186,7 +187,6 @@ static void acpi_pm_finish(void)
  */
 static void acpi_pm_end(void)
 {
-       suspend_nvs_free();
        /*
         * This is necessary in case acpi_pm_finish() is not called during a
         * failing transition to a sleep state.
index 42d3d72..5af3479 100644 (file)
@@ -82,6 +82,11 @@ long acpi_is_video_device(struct acpi_device *device)
        if (!device)
                return 0;
 
+       /* Is this device able to support video switching ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
+               video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
+
        /* Is this device able to retrieve a video ROM ? */
        if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
                video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
index ed65014..7bfbe40 100644 (file)
@@ -86,8 +86,12 @@ int __init acpi_wakeup_device_init(void)
                struct acpi_device *dev = container_of(node,
                                                       struct acpi_device,
                                                       wakeup_list);
-               if (device_can_wakeup(&dev->dev))
+               if (device_can_wakeup(&dev->dev)) {
+                       /* Button GPEs are supposed to be always enabled. */
+                       acpi_enable_gpe(dev->wakeup.gpe_device,
+                                       dev->wakeup.gpe_number);
                        device_set_wakeup_enable(&dev->dev, true);
+               }
        }
        mutex_unlock(&acpi_device_lock);
        return 0;
index c6b298d..c2328ae 100644 (file)
@@ -783,7 +783,7 @@ config PATA_PCMCIA
 
 config PATA_PLATFORM
        tristate "Generic platform device PATA support"
-       depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
+       depends on EXPERT || PPC || HAVE_PATA_PLATFORM
        help
          This option enables support for generic directly connected ATA
          devices commonly found on embedded systems.
index 3288263..b8d96ce 100644 (file)
@@ -260,6 +260,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
        { PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
        { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
+       { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -379,6 +380,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },        /* 6145 */
        { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },        /* 6121 */
        { PCI_DEVICE(0x1b4b, 0x9123),
+         .class = PCI_CLASS_STORAGE_SATA_AHCI,
+         .class_mask = 0xffffff,
          .driver_data = board_ahci_yes_fbs },                  /* 88se9128 */
 
        /* Promise */
index a31fe96..d4e52e2 100644 (file)
@@ -4138,6 +4138,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         * device and controller are SATA.
         */
        { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-212D",   "1.28", ATA_HORKAGE_NOSETXFER },
 
        /* End Marker */
        { }
index 5defc74..600f635 100644 (file)
@@ -1099,9 +1099,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                struct request_queue *q = sdev->request_queue;
                void *buf;
 
-               /* set the min alignment and padding */
-               blk_queue_update_dma_alignment(sdev->request_queue,
-                                              ATA_DMA_PAD_SZ - 1);
+               sdev->sector_size = ATA_SECT_SIZE;
+
+               /* set DMA padding */
                blk_queue_update_dma_pad(sdev->request_queue,
                                         ATA_DMA_PAD_SZ - 1);
 
@@ -1115,13 +1115,25 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
 
                blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
        } else {
-               /* ATA devices must be sector aligned */
                sdev->sector_size = ata_id_logical_sector_size(dev->id);
-               blk_queue_update_dma_alignment(sdev->request_queue,
-                                              sdev->sector_size - 1);
                sdev->manage_start_stop = 1;
        }
 
+       /*
+        * ata_pio_sectors() expects buffer for each sector to not cross
+        * page boundary.  Enforce it by requiring buffers to be sector
+        * aligned, which works iff sector_size is not larger than
+        * PAGE_SIZE.  ATAPI devices also need the alignment as
+        * IDENTIFY_PACKET is executed as ATA_PROT_PIO.
+        */
+       if (sdev->sector_size > PAGE_SIZE)
+               ata_dev_printk(dev, KERN_WARNING,
+                       "sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
+                       sdev->sector_size);
+
+       blk_queue_update_dma_alignment(sdev->request_queue,
+                                      sdev->sector_size - 1);
+
        if (dev->flags & ATA_DFLAG_AN)
                set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
 
index d7e57db..538ec38 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.9"
+#define DRV_VERSION    "0.6.10"
 
 struct hpt_clock {
        u8      xfer_mode;
@@ -160,8 +160,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
 
        while (list[i] != NULL) {
                if (!strcmp(list[i], model_num)) {
-                       printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
-                               modestr, list[i]);
+                       pr_warning(DRV_NAME ": %s is not supported for %s.\n",
+                                  modestr, list[i]);
                        return 1;
                }
                i++;
index efdd18b..4c5b518 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.18"
+#define DRV_VERSION    "0.6.22"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -229,8 +229,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
 
        while (list[i] != NULL) {
                if (!strcmp(list[i], model_num)) {
-                       printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
-                               modestr, list[i]);
+                       pr_warning(DRV_NAME ": %s is not supported for %s.\n",
+                                  modestr, list[i]);
                        return 1;
                }
                i++;
@@ -642,7 +642,6 @@ static struct ata_port_operations hpt372_port_ops = {
 static struct ata_port_operations hpt374_fn1_port_ops = {
        .inherits       = &hpt372_port_ops,
        .cable_detect   = hpt374_fn1_cable_detect,
-       .prereset       = hpt37x_pre_reset,
 };
 
 /**
@@ -803,7 +802,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .udma_mask = ATA_UDMA6,
                .port_ops = &hpt302_port_ops
        };
-       /* HPT374 - UDMA100, function 1 uses different prereset method */
+       /* HPT374 - UDMA100, function 1 uses different cable_detect method */
        static const struct ata_port_info info_hpt374_fn0 = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
@@ -838,7 +837,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
+       switch (dev->device) {
+       case PCI_DEVICE_ID_TTI_HPT366:
                /* May be a later chip in disguise. Check */
                /* Older chips are in the HPT366 driver. Ignore them */
                if (rev < 3)
@@ -863,54 +863,50 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        chip_table = &hpt372;
                        break;
                default:
-                       printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, "
+                       pr_err(DRV_NAME ": Unknown HPT366 subtype, "
                               "please report (%d).\n", rev);
                        return -ENODEV;
                }
-       } else {
-               switch (dev->device) {
-               case PCI_DEVICE_ID_TTI_HPT372:
-                       /* 372N if rev >= 2 */
-                       if (rev >= 2)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt372;
-                       chip_table = &hpt372a;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT302:
-                       /* 302N if rev > 1 */
-                       if (rev > 1)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt302;
-                       /* Check this */
-                       chip_table = &hpt302;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT371:
-                       if (rev > 1)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt302;
-                       chip_table = &hpt371;
-                       /*
-                        * Single channel device, master is not present
-                        * but the BIOS (or us for non x86) must mark it
-                        * absent
-                        */
-                       pci_read_config_byte(dev, 0x50, &mcr1);
-                       mcr1 &= ~0x04;
-                       pci_write_config_byte(dev, 0x50, mcr1);
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT374:
-                       chip_table = &hpt374;
-                       if (!(PCI_FUNC(dev->devfn) & 1))
-                               *ppi = &info_hpt374_fn0;
-                       else
-                               *ppi = &info_hpt374_fn1;
-                       break;
-               default:
-                       printk(KERN_ERR
-                              "pata_hpt37x: PCI table is bogus, please report (%d).\n",
-                              dev->device);
-                               return -ENODEV;
-               }
+               break;
+       case PCI_DEVICE_ID_TTI_HPT372:
+               /* 372N if rev >= 2 */
+               if (rev >= 2)
+                       return -ENODEV;
+               ppi[0] = &info_hpt372;
+               chip_table = &hpt372a;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT302:
+               /* 302N if rev > 1 */
+               if (rev > 1)
+                       return -ENODEV;
+               ppi[0] = &info_hpt302;
+               /* Check this */
+               chip_table = &hpt302;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT371:
+               if (rev > 1)
+                       return -ENODEV;
+               ppi[0] = &info_hpt302;
+               chip_table = &hpt371;
+               /*
+                * Single channel device, master is not present but the BIOS
+                * (or us for non x86) must mark it absent
+                */
+               pci_read_config_byte(dev, 0x50, &mcr1);
+               mcr1 &= ~0x04;
+               pci_write_config_byte(dev, 0x50, mcr1);
+               break;
+       case PCI_DEVICE_ID_TTI_HPT374:
+               chip_table = &hpt374;
+               if (!(PCI_FUNC(dev->devfn) & 1))
+                       *ppi = &info_hpt374_fn0;
+               else
+                       *ppi = &info_hpt374_fn1;
+               break;
+       default:
+               pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n",
+                      dev->device);
+               return -ENODEV;
        }
        /* Ok so this is a chip we support */
 
@@ -957,8 +953,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                u8 sr;
                u32 total = 0;
 
-               printk(KERN_WARNING
-                      "pata_hpt37x: BIOS has not set timing clocks.\n");
+               pr_warning(DRV_NAME ": BIOS has not set timing clocks.\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
                for (i = 0; i < 128; i++) {
@@ -1014,7 +1009,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                                               (f_high << 16) | f_low | 0x100);
                }
                if (adjust == 8) {
-                       printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
+                       pr_err(DRV_NAME ": DPLL did not stabilize!\n");
                        return -ENODEV;
                }
                if (dpll == 3)
@@ -1022,8 +1017,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                else
                        private_data = (void *)hpt37x_timings_50;
 
-               printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n",
-                      MHz[clock_slot], MHz[dpll]);
+               pr_info(DRV_NAME ": bus clock %dMHz, using %dMHz DPLL.\n",
+                       MHz[clock_slot], MHz[dpll]);
        } else {
                private_data = (void *)chip_table->clocks[clock_slot];
                /*
@@ -1036,8 +1031,9 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        ppi[0] = &info_hpt370_33;
                if (clock_slot < 2 && ppi[0] == &info_hpt370a)
                        ppi[0] = &info_hpt370a_33;
-               printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n",
-                      chip_table->name, MHz[clock_slot]);
+
+               pr_info(DRV_NAME ": %s using %dMHz bus clock.\n",
+                       chip_table->name, MHz[clock_slot]);
        }
 
        /* Now kick off ATA set up */
index d2239bb..eca68ca 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.13"
+#define DRV_VERSION    "0.3.14"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -418,7 +418,7 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
                u16 sr;
                u32 total = 0;
 
-               printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n");
+               pr_warning(DRV_NAME ": BIOS clock data not set.\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
                for (i = 0; i < 128; i++) {
@@ -528,8 +528,7 @@ hpt372n:
                ppi[0] = &info_hpt372n;
                break;
        default:
-               printk(KERN_ERR
-                      "pata_hpt3x2n: PCI table is bogus please report (%d).\n",
+               pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n",
                       dev->device);
                return -ENODEV;
        }
@@ -579,12 +578,11 @@ hpt372n:
                pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
        }
        if (adjust == 8) {
-               printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n");
+               pr_err(DRV_NAME ": DPLL did not stabilize!\n");
                return -ENODEV;
        }
 
-       printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
-              pci_mhz);
+       pr_info(DRV_NAME ": bus clock %dMHz, using 66MHz DPLL.\n", pci_mhz);
 
        /*
         * Set our private data up. We only need a few flags
index 8cc536e..d7d8026 100644 (file)
@@ -610,7 +610,7 @@ static struct scsi_host_template mpc52xx_ata_sht = {
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
-       .inherits               = &ata_sff_port_ops,
+       .inherits               = &ata_bmdma_port_ops,
        .sff_dev_select         = mpc52xx_ata_dev_select,
        .set_piomode            = mpc52xx_ata_set_piomode,
        .set_dmamode            = mpc52xx_ata_set_dmamode,
index bca9cb8..487a547 100644 (file)
@@ -151,7 +151,7 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int
        spin_unlock_irqrestore(&idt77105_priv_lock, flags);
        if (arg == NULL)
                return 0;
-       return copy_to_user(arg, &PRIV(dev)->stats,
+       return copy_to_user(arg, &stats,
                    sizeof(struct idt77105_stats)) ? -EFAULT : 0;
 }
 
index 73fb1c4..25ef1a4 100644 (file)
@@ -866,8 +866,9 @@ static int popen(struct atm_vcc *vcc)
        }
 
        skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
-       if (!skb && net_ratelimit()) {
-               dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
+       if (!skb) {
+               if (net_ratelimit())
+                       dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
                return -ENOMEM;
        }
        header = (void *)skb_put(skb, sizeof(*header));
index fd96345..d57e8d0 100644 (file)
@@ -70,7 +70,7 @@ config PREVENT_FIRMWARE_BUILD
          If unsure say Y here.
 
 config FW_LOADER
-       tristate "Userspace firmware loading support" if EMBEDDED
+       tristate "Userspace firmware loading support" if EXPERT
        default y
        ---help---
          This option is provided for the case where no in-kernel-tree modules
index 656493a..42615b4 100644 (file)
@@ -407,12 +407,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
+       /* Maybe the parent is now able to suspend. */
        if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
-               spin_unlock_irq(&dev->power.lock);
+               spin_unlock(&dev->power.lock);
 
-               pm_request_idle(parent);
+               spin_lock(&parent->power.lock);
+               rpm_idle(parent, RPM_ASYNC);
+               spin_unlock(&parent->power.lock);
 
-               spin_lock_irq(&dev->power.lock);
+               spin_lock(&dev->power.lock);
        }
 
  out:
index d7f463d..40528ba 100644 (file)
@@ -39,4 +39,4 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     += xen-blkfront.o
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
-swim_mod-objs  := swim.o swim_asm.o
+swim_mod-y     := swim.o swim_asm.o
index e76d997..06ea82c 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 obj-$(CONFIG_ATA_OVER_ETH)     += aoe.o
-aoe-objs := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
+aoe-y := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
index 516d5bb..9279272 100644 (file)
@@ -2833,7 +2833,7 @@ static int cciss_revalidate(struct gendisk *disk)
        sector_t total_size;
        InquiryData_struct *inq_buff = NULL;
 
-       for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+       for (logvol = 0; logvol <= h->highest_lun; logvol++) {
                if (!h->drv[logvol])
                        continue;
                if (memcmp(h->drv[logvol]->LunID, drv->LunID,
index b9ba04f..77fc76f 100644 (file)
@@ -3281,7 +3281,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
                        struct block_device *bdev = opened_bdev[cnt];
                        if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
                                continue;
-                       __invalidate_device(bdev);
+                       __invalidate_device(bdev, true);
                }
                mutex_unlock(&open_lock);
        } else {
index 44e18c0..dbf31ec 100644 (file)
@@ -78,7 +78,6 @@
 
 #include <asm/uaccess.h>
 
-static DEFINE_MUTEX(loop_mutex);
 static LIST_HEAD(loop_devices);
 static DEFINE_MUTEX(loop_devices_mutex);
 
@@ -1501,11 +1500,9 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
 {
        struct loop_device *lo = bdev->bd_disk->private_data;
 
-       mutex_lock(&loop_mutex);
        mutex_lock(&lo->lo_ctl_mutex);
        lo->lo_refcnt++;
        mutex_unlock(&lo->lo_ctl_mutex);
-       mutex_unlock(&loop_mutex);
 
        return 0;
 }
@@ -1515,7 +1512,6 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
        struct loop_device *lo = disk->private_data;
        int err;
 
-       mutex_lock(&loop_mutex);
        mutex_lock(&lo->lo_ctl_mutex);
 
        if (--lo->lo_refcnt)
@@ -1540,7 +1536,6 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
 out:
        mutex_unlock(&lo->lo_ctl_mutex);
 out_unlocked:
-       mutex_unlock(&loop_mutex);
        return 0;
 }
 
@@ -1641,6 +1636,9 @@ out:
 
 static void loop_free(struct loop_device *lo)
 {
+       if (!lo->lo_queue->queue_lock)
+               lo->lo_queue->queue_lock = &lo->lo_queue->__queue_lock;
+
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
        list_del(&lo->lo_list);
index a32fb41..e6fc716 100644 (file)
@@ -53,7 +53,6 @@
 #define DBG_BLKDEV      0x0100
 #define DBG_RX          0x0200
 #define DBG_TX          0x0400
-static DEFINE_MUTEX(nbd_mutex);
 static unsigned int debugflags;
 #endif /* NDEBUG */
 
@@ -718,11 +717,9 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
        dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
                        lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
 
-       mutex_lock(&nbd_mutex);
        mutex_lock(&lo->tx_lock);
        error = __nbd_ioctl(bdev, lo, cmd, arg);
        mutex_unlock(&lo->tx_lock);
-       mutex_unlock(&nbd_mutex);
 
        return error;
 }
index 949ed09..6dcd55a 100644 (file)
@@ -39,6 +39,11 @@ static struct usb_device_id ath3k_table[] = {
        /* Atheros AR3011 with sflash firmware*/
        { USB_DEVICE(0x0CF3, 0x3002) },
 
+       /* Atheros AR9285 Malbec with sflash firmware */
+       { USB_DEVICE(0x03F0, 0x311D) },
+
+       /* Atheros AR5BBU12 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xE02C) },
        { }     /* Terminating entry */
 };
 
@@ -47,46 +52,40 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
 #define USB_REQ_DFU_DNLOAD     1
 #define BULK_SIZE              4096
 
-struct ath3k_data {
-       struct usb_device *udev;
-       u8 *fw_data;
-       u32 fw_size;
-       u32 fw_sent;
-};
-
-static int ath3k_load_firmware(struct ath3k_data *data,
-                               unsigned char *firmware,
-                               int count)
+static int ath3k_load_firmware(struct usb_device *udev,
+                               const struct firmware *firmware)
 {
        u8 *send_buf;
        int err, pipe, len, size, sent = 0;
+       int count = firmware->size;
 
-       BT_DBG("ath3k %p udev %p", data, data->udev);
+       BT_DBG("udev %p", udev);
 
-       pipe = usb_sndctrlpipe(data->udev, 0);
+       pipe = usb_sndctrlpipe(udev, 0);
 
-       if ((usb_control_msg(data->udev, pipe,
+       send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
+       if (!send_buf) {
+               BT_ERR("Can't allocate memory chunk for firmware");
+               return -ENOMEM;
+       }
+
+       memcpy(send_buf, firmware->data, 20);
+       if ((err = usb_control_msg(udev, pipe,
                                USB_REQ_DFU_DNLOAD,
                                USB_TYPE_VENDOR, 0, 0,
-                               firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
+                               send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
                BT_ERR("Can't change to loading configuration err");
-               return -EBUSY;
+               goto error;
        }
        sent += 20;
        count -= 20;
 
-       send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
-       if (!send_buf) {
-               BT_ERR("Can't allocate memory chunk for firmware");
-               return -ENOMEM;
-       }
-
        while (count) {
                size = min_t(uint, count, BULK_SIZE);
-               pipe = usb_sndbulkpipe(data->udev, 0x02);
-               memcpy(send_buf, firmware + sent, size);
+               pipe = usb_sndbulkpipe(udev, 0x02);
+               memcpy(send_buf, firmware->data + sent, size);
 
-               err = usb_bulk_msg(data->udev, pipe, send_buf, size,
+               err = usb_bulk_msg(udev, pipe, send_buf, size,
                                        &len, 3000);
 
                if (err || (len != size)) {
@@ -112,57 +111,28 @@ static int ath3k_probe(struct usb_interface *intf,
 {
        const struct firmware *firmware;
        struct usb_device *udev = interface_to_usbdev(intf);
-       struct ath3k_data *data;
-       int size;
 
        BT_DBG("intf %p id %p", intf, id);
 
        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->udev = udev;
-
        if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
-               kfree(data);
                return -EIO;
        }
 
-       size = max_t(uint, firmware->size, 4096);
-       data->fw_data = kmalloc(size, GFP_KERNEL);
-       if (!data->fw_data) {
+       if (ath3k_load_firmware(udev, firmware)) {
                release_firmware(firmware);
-               kfree(data);
-               return -ENOMEM;
-       }
-
-       memcpy(data->fw_data, firmware->data, firmware->size);
-       data->fw_size = firmware->size;
-       data->fw_sent = 0;
-       release_firmware(firmware);
-
-       usb_set_intfdata(intf, data);
-       if (ath3k_load_firmware(data, data->fw_data, data->fw_size)) {
-               usb_set_intfdata(intf, NULL);
-               kfree(data->fw_data);
-               kfree(data);
                return -EIO;
        }
+       release_firmware(firmware);
 
        return 0;
 }
 
 static void ath3k_disconnect(struct usb_interface *intf)
 {
-       struct ath3k_data *data = usb_get_intfdata(intf);
-
        BT_DBG("ath3k_disconnect intf %p", intf);
-
-       kfree(data->fw_data);
-       kfree(data);
 }
 
 static struct usb_driver ath3k_driver = {
index 1da773f..700a384 100644 (file)
@@ -102,6 +102,12 @@ static struct usb_device_id blacklist_table[] = {
        /* Atheros 3011 with sflash firmware */
        { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
 
+       /* Atheros AR9285 Malbec with sflash firmware */
+       { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
+
+       /* Atheros AR5BBU12 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
+
        /* Broadcom BCM2035 */
        { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -826,7 +832,7 @@ static void btusb_work(struct work_struct *work)
 
        if (hdev->conn_hash.sco_num > 0) {
                if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
-                       err = usb_autopm_get_interface(data->isoc);
+                       err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf);
                        if (err < 0) {
                                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                                usb_kill_anchored_urbs(&data->isoc_anchor);
@@ -855,7 +861,7 @@ static void btusb_work(struct work_struct *work)
 
                __set_isoc_interface(hdev, 0);
                if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
-                       usb_autopm_put_interface(data->isoc);
+                       usb_autopm_put_interface(data->isoc ? data->isoc : data->intf);
        }
 }
 
@@ -1038,8 +1044,6 @@ static int btusb_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, data);
 
-       usb_enable_autosuspend(interface_to_usbdev(intf));
-
        return 0;
 }
 
index 14033a3..e2c48a7 100644 (file)
@@ -409,7 +409,8 @@ int register_cdrom(struct cdrom_device_info *cdi)
        }
 
        ENSURE(drive_status, CDC_DRIVE_STATUS );
-       ENSURE(media_changed, CDC_MEDIA_CHANGED);
+       if (cdo->check_events == NULL && cdo->media_changed == NULL)
+               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
        ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
        ENSURE(lock_door, CDC_LOCK);
        ENSURE(select_speed, CDC_SELECT_SPEED);
index 0f175a8..b7980a8 100644 (file)
@@ -5,7 +5,7 @@
 menu "Character devices"
 
 config VT
-       bool "Virtual terminal" if EMBEDDED
+       bool "Virtual terminal" if EXPERT
        depends on !S390
        select INPUT
        default y
@@ -39,13 +39,13 @@ config VT
 config CONSOLE_TRANSLATIONS
        depends on VT
        default y
-       bool "Enable character translations in console" if EMBEDDED
+       bool "Enable character translations in console" if EXPERT
        ---help---
          This enables support for font mapping and Unicode translation
          on virtual consoles.
 
 config VT_CONSOLE
-       bool "Support for console on virtual terminal" if EMBEDDED
+       bool "Support for console on virtual terminal" if EXPERT
        depends on VT
        default y
        ---help---
@@ -426,10 +426,10 @@ config SGI_MBCS
          If you have an SGI Altix with an attached SABrick
          say Y or M here, otherwise say N.
 
-source "drivers/serial/Kconfig"
+source "drivers/tty/serial/Kconfig"
 
 config UNIX98_PTYS
-       bool "Unix98 PTY support" if EMBEDDED
+       bool "Unix98 PTY support" if EXPERT
        default y
        ---help---
          A pseudo terminal (PTY) is a software device consisting of two
@@ -495,7 +495,7 @@ config LEGACY_PTY_COUNT
 
 config TTY_PRINTK
        bool "TTY driver to output user messages via printk"
-       depends on EMBEDDED
+       depends on EXPERT
        default n
        ---help---
          If you say Y here, the support for writing user messages (i.e.
index 1e9dffb..8238f89 100644 (file)
@@ -30,17 +30,6 @@ obj-$(CONFIG_SYNCLINK_GT)    += synclink_gt.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
-obj-$(CONFIG_HVC_CONSOLE)      += hvc_vio.o hvsi.o
-obj-$(CONFIG_HVC_ISERIES)      += hvc_iseries.o
-obj-$(CONFIG_HVC_RTAS)         += hvc_rtas.o
-obj-$(CONFIG_HVC_TILE)         += hvc_tile.o
-obj-$(CONFIG_HVC_DCC)          += hvc_dcc.o
-obj-$(CONFIG_HVC_BEAT)         += hvc_beat.o
-obj-$(CONFIG_HVC_DRIVER)       += hvc_console.o
-obj-$(CONFIG_HVC_IRQ)          += hvc_irq.o
-obj-$(CONFIG_HVC_XEN)          += hvc_xen.o
-obj-$(CONFIG_HVC_IUCV)         += hvc_iucv.o
-obj-$(CONFIG_HVC_UDBG)         += hvc_udbg.o
 obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
@@ -48,7 +37,6 @@ obj-$(CONFIG_MSPEC)           += mspec.o
 obj-$(CONFIG_MMTIMER)          += mmtimer.o
 obj-$(CONFIG_UV_MMTIMER)       += uv_mmtimer.o
 obj-$(CONFIG_VIOTAPE)          += viotape.o
-obj-$(CONFIG_HVCS)             += hvcs.o
 obj-$(CONFIG_IBM_BSR)          += bsr.o
 obj-$(CONFIG_SGI_MBCS)         += mbcs.o
 obj-$(CONFIG_BRIQ_PANEL)       += briq_panel.o
index fcd867d..d8b1b57 100644 (file)
@@ -50,7 +50,7 @@ config AGP_ATI
 
 config AGP_AMD
        tristate "AMD Irongate, 761, and 762 chipset support"
-       depends on AGP && (X86_32 || ALPHA)
+       depends on AGP && X86_32
        help
          This option gives you AGP support for the GLX component of
          X on AMD Irongate, 761, and 762 chipsets.
index b1b4362..45681c0 100644 (file)
@@ -41,22 +41,8 @@ static int amd_create_page_map(struct amd_page_map *page_map)
        if (page_map->real == NULL)
                return -ENOMEM;
 
-#ifndef CONFIG_X86
-       SetPageReserved(virt_to_page(page_map->real));
-       global_cache_flush();
-       page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
-                                           PAGE_SIZE);
-       if (page_map->remapped == NULL) {
-               ClearPageReserved(virt_to_page(page_map->real));
-               free_page((unsigned long) page_map->real);
-               page_map->real = NULL;
-               return -ENOMEM;
-       }
-       global_cache_flush();
-#else
        set_memory_uc((unsigned long)page_map->real, 1);
        page_map->remapped = page_map->real;
-#endif
 
        for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
                writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -68,12 +54,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
 
 static void amd_free_page_map(struct amd_page_map *page_map)
 {
-#ifndef CONFIG_X86
-       iounmap(page_map->remapped);
-       ClearPageReserved(virt_to_page(page_map->real));
-#else
        set_memory_wb((unsigned long)page_map->real, 1);
-#endif
        free_page((unsigned long) page_map->real);
 }
 
index 9252e85..780498d 100644 (file)
@@ -773,18 +773,23 @@ int __init agp_amd64_init(void)
 #else
                        printk(KERN_INFO PFX "You can boot with agp=try_unsupported\n");
 #endif
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        return -ENODEV;
                }
 
                /* First check that we have at least one AMD64 NB */
-               if (!pci_dev_present(amd_nb_misc_ids))
+               if (!pci_dev_present(amd_nb_misc_ids)) {
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        return -ENODEV;
+               }
 
                /* Look for any AGP bridge */
                agp_amd64_pci_driver.id_table = agp_amd64_pci_promisc_table;
                err = driver_attach(&agp_amd64_pci_driver.driver);
-               if (err == 0 && agp_bridges_found == 0)
+               if (err == 0 && agp_bridges_found == 0) {
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        err = -ENODEV;
+               }
        }
        return err;
 }
index 857df10..b0a0dcc 100644 (file)
@@ -774,20 +774,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
        dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
 
        /*
-       * If the device has not been properly setup, the following will catch
-       * the problem and should stop the system from crashing.
-       * 20030610 - hamish@zot.org
-       */
-       if (pci_enable_device(pdev)) {
-               dev_err(&pdev->dev, "can't enable PCI device\n");
-               agp_put_bridge(bridge);
-               return -ENODEV;
-       }
-
-       /*
        * The following fixes the case where the BIOS has "forgotten" to
        * provide an address range for the GART.
        * 20030610 - hamish@zot.org
+       * This happens before pci_enable_device() intentionally;
+       * calling pci_enable_device() before assigning the resource
+       * will result in the GART being disabled on machines with such
+       * BIOSs (the GART ends up with a BAR starting at 0, which
+       * conflicts a lot of other devices).
        */
        r = &pdev->resource[0];
        if (!r->start && r->end) {
@@ -798,6 +792,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                }
        }
 
+       /*
+       * If the device has not been properly setup, the following will catch
+       * the problem and should stop the system from crashing.
+       * 20030610 - hamish@zot.org
+       */
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev, "can't enable PCI device\n");
+               agp_put_bridge(bridge);
+               return -ENODEV;
+       }
+
        /* Fill in the mode register */
        if (cap_ptr) {
                pci_read_config_dword(pdev,
index c195bfe..5feebe2 100644 (file)
 #define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
 
 #define I915_IFPADDR    0x60
+#define I830_HIC        0x70
 
 /* Intel 965G registers */
 #define I965_MSAC 0x62
index 826ab09..0d09b53 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
+#include <linux/delay.h>
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
@@ -68,13 +69,10 @@ static struct _intel_private {
        phys_addr_t gma_bus_addr;
        u32 PGETBL_save;
        u32 __iomem *gtt;               /* I915G */
+       bool clear_fake_agp; /* on first access via agp, fill with scratch */
        int num_dcache_entries;
-       union {
-               void __iomem *i9xx_flush_page;
-               void *i8xx_flush_page;
-       };
+       void __iomem *i9xx_flush_page;
        char *i81x_gtt_table;
-       struct page *i8xx_page;
        struct resource ifp_resource;
        int resource_valid;
        struct page *scratch_page;
@@ -721,28 +719,6 @@ static int intel_fake_agp_fetch_size(void)
 
 static void i830_cleanup(void)
 {
-       if (intel_private.i8xx_flush_page) {
-               kunmap(intel_private.i8xx_flush_page);
-               intel_private.i8xx_flush_page = NULL;
-       }
-
-       __free_page(intel_private.i8xx_page);
-       intel_private.i8xx_page = NULL;
-}
-
-static void intel_i830_setup_flush(void)
-{
-       /* return if we've already set the flush mechanism up */
-       if (intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL);
-       if (!intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
-       if (!intel_private.i8xx_flush_page)
-               i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -757,14 +733,27 @@ static void intel_i830_setup_flush(void)
  */
 static void i830_chipset_flush(void)
 {
-       unsigned int *pg = intel_private.i8xx_flush_page;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       /* Forcibly evict everything from the CPU write buffers.
+        * clflush appears to be insufficient.
+        */
+       wbinvd_on_all_cpus();
 
-       memset(pg, 0, 1024);
+       /* Now we've only seen documents for this magic bit on 855GM,
+        * we hope it exists for the other gen2 chipsets...
+        *
+        * Also works as advertised on my 845G.
+        */
+       writel(readl(intel_private.registers+I830_HIC) | (1<<31),
+              intel_private.registers+I830_HIC);
 
-       if (cpu_has_clflush)
-               clflush_cache_range(pg, 1024);
-       else if (wbinvd_on_all_cpus() != 0)
-               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+       while (readl(intel_private.registers+I830_HIC) & (1<<31)) {
+               if (time_after(jiffies, timeout))
+                       break;
+
+               udelay(50);
+       }
 }
 
 static void i830_write_entry(dma_addr_t addr, unsigned int entry,
@@ -848,8 +837,6 @@ static int i830_setup(void)
 
        intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
 
-       intel_i830_setup_flush();
-
        return 0;
 }
 
@@ -869,21 +856,12 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
 
 static int intel_fake_agp_configure(void)
 {
-       int i;
-
        if (!intel_enable_gtt())
            return -EIO;
 
+       intel_private.clear_fake_agp = true;
        agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
-       for (i = 0; i < intel_private.base.gtt_total_entries; i++) {
-               intel_private.driver->write_entry(intel_private.scratch_page_dma,
-                                                 i, 0);
-       }
-       readl(intel_private.gtt+i-1);   /* PCI Posting. */
-
-       global_cache_flush();
-
        return 0;
 }
 
@@ -945,6 +923,13 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
 {
        int ret = -EINVAL;
 
+       if (intel_private.clear_fake_agp) {
+               int start = intel_private.base.stolen_size / PAGE_SIZE;
+               int end = intel_private.base.gtt_mappable_entries;
+               intel_gtt_clear_range(start, end - start);
+               intel_private.clear_fake_agp = false;
+       }
+
        if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY)
                return i810_insert_dcache_entries(mem, pg_start, type);
 
index e397df3..1640244 100644 (file)
@@ -183,16 +183,16 @@ bfin_jc_circ_write(const unsigned char *buf, int count)
 }
 
 #ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
-# define acquire_console_sem()
-# define release_console_sem()
+# define console_lock()
+# define console_unlock()
 #endif
 static int
 bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        int i;
-       acquire_console_sem();
+       console_lock();
        i = bfin_jc_circ_write(buf, count);
-       release_console_sem();
+       console_unlock();
        wake_up_process(bfin_jc_kthread);
        return i;
 }
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
deleted file mode 100644 (file)
index 5fe4631..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Beat hypervisor console driver
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on drivers/char/hvc_rtas.c:
- * (C) Copyright IBM Corporation 2001-2005
- * (C) Copyright Red Hat, Inc. 2005
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/console.h>
-#include <asm/prom.h>
-#include <asm/hvconsole.h>
-#include <asm/firmware.h>
-
-#include "hvc_console.h"
-
-extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
-extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
-
-struct hvc_struct *hvc_beat_dev = NULL;
-
-/* bug: only one queue is available regardless of vtermno */
-static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
-{
-       static unsigned char q[sizeof(unsigned long) * 2]
-               __attribute__((aligned(sizeof(unsigned long))));
-       static int qlen = 0;
-       u64 got;
-
-again:
-       if (qlen) {
-               if (qlen > cnt) {
-                       memcpy(buf, q, cnt);
-                       qlen -= cnt;
-                       memmove(q + cnt, q, qlen);
-                       return cnt;
-               } else {        /* qlen <= cnt */
-                       int     r;
-
-                       memcpy(buf, q, qlen);
-                       r = qlen;
-                       qlen = 0;
-                       return r;
-               }
-       }
-       if (beat_get_term_char(vtermno, &got,
-               ((u64 *)q), ((u64 *)q) + 1) == 0) {
-               qlen = got;
-               goto again;
-       }
-       return 0;
-}
-
-static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
-{
-       unsigned long kb[2];
-       int rest, nlen;
-
-       for (rest = cnt; rest > 0; rest -= nlen) {
-               nlen = (rest > 16) ? 16 : rest;
-               memcpy(kb, buf, nlen);
-               beat_put_term_char(vtermno, nlen, kb[0], kb[1]);
-               buf += nlen;
-       }
-       return cnt;
-}
-
-static const struct hv_ops hvc_beat_get_put_ops = {
-       .get_chars = hvc_beat_get_chars,
-       .put_chars = hvc_beat_put_chars,
-};
-
-static int hvc_beat_useit = 1;
-
-static int hvc_beat_config(char *p)
-{
-       hvc_beat_useit = simple_strtoul(p, NULL, 0);
-       return 0;
-}
-
-static int __init hvc_beat_console_init(void)
-{
-       if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
-               hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
-       }
-       return 0;
-}
-
-/* temp */
-static int __init hvc_beat_init(void)
-{
-       struct hvc_struct *hp;
-
-       if (!firmware_has_feature(FW_FEATURE_BEAT))
-               return -ENODEV;
-
-       hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-       hvc_beat_dev = hp;
-       return 0;
-}
-
-static void __exit hvc_beat_exit(void)
-{
-       if (hvc_beat_dev)
-               hvc_remove(hvc_beat_dev);
-}
-
-module_init(hvc_beat_init);
-module_exit(hvc_beat_exit);
-
-__setup("hvc_beat=", hvc_beat_config);
-
-console_initcall(hvc_beat_console_init);
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
deleted file mode 100644 (file)
index e9cba13..0000000
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
- * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
- * Copyright (C) 2004 IBM Corporation
- *
- * Additional Author(s):
- *  Ryan S. Arnold <rsa@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/console.h>
-#include <linux/cpumask.h>
-#include <linux/init.h>
-#include <linux/kbd_kern.h>
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/major.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/freezer.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-
-#include "hvc_console.h"
-
-#define HVC_MAJOR      229
-#define HVC_MINOR      0
-
-/*
- * Wait this long per iteration while trying to push buffered data to the
- * hypervisor before allowing the tty to complete a close operation.
- */
-#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
-
-/*
- * These sizes are most efficient for vio, because they are the
- * native transfer size. We could make them selectable in the
- * future to better deal with backends that want other buffer sizes.
- */
-#define N_OUTBUF       16
-#define N_INBUF                16
-
-#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
-
-static struct tty_driver *hvc_driver;
-static struct task_struct *hvc_task;
-
-/* Picks up late kicks after list walk but before schedule() */
-static int hvc_kicked;
-
-static int hvc_init(void);
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
-#endif
-
-/* dynamic list of hvc_struct instances */
-static LIST_HEAD(hvc_structs);
-
-/*
- * Protect the list of hvc_struct instances from inserts and removals during
- * list traversal.
- */
-static DEFINE_SPINLOCK(hvc_structs_lock);
-
-/*
- * This value is used to assign a tty->index value to a hvc_struct based
- * upon order of exposure via hvc_probe(), when we can not match it to
- * a console candidate registered with hvc_instantiate().
- */
-static int last_hvc = -1;
-
-/*
- * Do not call this function with either the hvc_structs_lock or the hvc_struct
- * lock held.  If successful, this function increments the kref reference
- * count against the target hvc_struct so it should be released when finished.
- */
-static struct hvc_struct *hvc_get_by_index(int index)
-{
-       struct hvc_struct *hp;
-       unsigned long flags;
-
-       spin_lock(&hvc_structs_lock);
-
-       list_for_each_entry(hp, &hvc_structs, next) {
-               spin_lock_irqsave(&hp->lock, flags);
-               if (hp->index == index) {
-                       kref_get(&hp->kref);
-                       spin_unlock_irqrestore(&hp->lock, flags);
-                       spin_unlock(&hvc_structs_lock);
-                       return hp;
-               }
-               spin_unlock_irqrestore(&hp->lock, flags);
-       }
-       hp = NULL;
-
-       spin_unlock(&hvc_structs_lock);
-       return hp;
-}
-
-
-/*
- * Initial console vtermnos for console API usage prior to full console
- * initialization.  Any vty adapter outside this range will not have usable
- * console interfaces but can still be used as a tty device.  This has to be
- * static because kmalloc will not work during early console init.
- */
-static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
-static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
-       {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
-
-/*
- * Console APIs, NOT TTY.  These APIs are available immediately when
- * hvc_console_setup() finds adapters.
- */
-
-static void hvc_console_print(struct console *co, const char *b,
-                             unsigned count)
-{
-       char c[N_OUTBUF] __ALIGNED__;
-       unsigned i = 0, n = 0;
-       int r, donecr = 0, index = co->index;
-
-       /* Console access attempt outside of acceptable console range. */
-       if (index >= MAX_NR_HVC_CONSOLES)
-               return;
-
-       /* This console adapter was removed so it is not usable. */
-       if (vtermnos[index] == -1)
-               return;
-
-       while (count > 0 || i > 0) {
-               if (count > 0 && i < sizeof(c)) {
-                       if (b[n] == '\n' && !donecr) {
-                               c[i++] = '\r';
-                               donecr = 1;
-                       } else {
-                               c[i++] = b[n++];
-                               donecr = 0;
-                               --count;
-                       }
-               } else {
-                       r = cons_ops[index]->put_chars(vtermnos[index], c, i);
-                       if (r <= 0) {
-                               /* throw away chars on error */
-                               i = 0;
-                       } else if (r > 0) {
-                               i -= r;
-                               if (i > 0)
-                                       memmove(c, c+r, i);
-                       }
-               }
-       }
-}
-
-static struct tty_driver *hvc_console_device(struct console *c, int *index)
-{
-       if (vtermnos[c->index] == -1)
-               return NULL;
-
-       *index = c->index;
-       return hvc_driver;
-}
-
-static int __init hvc_console_setup(struct console *co, char *options)
-{
-       if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
-               return -ENODEV;
-
-       if (vtermnos[co->index] == -1)
-               return -ENODEV;
-
-       return 0;
-}
-
-static struct console hvc_console = {
-       .name           = "hvc",
-       .write          = hvc_console_print,
-       .device         = hvc_console_device,
-       .setup          = hvc_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-/*
- * Early console initialization.  Precedes driver initialization.
- *
- * (1) we are first, and the user specified another driver
- * -- index will remain -1
- * (2) we are first and the user specified no driver
- * -- index will be set to 0, then we will fail setup.
- * (3)  we are first and the user specified our driver
- * -- index will be set to user specified driver, and we will fail
- * (4) we are after driver, and this initcall will register us
- * -- if the user didn't specify a driver then the console will match
- *
- * Note that for cases 2 and 3, we will match later when the io driver
- * calls hvc_instantiate() and call register again.
- */
-static int __init hvc_console_init(void)
-{
-       register_console(&hvc_console);
-       return 0;
-}
-console_initcall(hvc_console_init);
-
-/* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kref *kref)
-{
-       struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
-       unsigned long flags;
-
-       spin_lock(&hvc_structs_lock);
-
-       spin_lock_irqsave(&hp->lock, flags);
-       list_del(&(hp->next));
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       spin_unlock(&hvc_structs_lock);
-
-       kfree(hp);
-}
-
-/*
- * hvc_instantiate() is an early console discovery method which locates
- * consoles * prior to the vio subsystem discovering them.  Hotplugged
- * vty adapters do NOT get an hvc_instantiate() callback since they
- * appear after early console init.
- */
-int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
-{
-       struct hvc_struct *hp;
-
-       if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
-               return -1;
-
-       if (vtermnos[index] != -1)
-               return -1;
-
-       /* make sure no no tty has been registered in this index */
-       hp = hvc_get_by_index(index);
-       if (hp) {
-               kref_put(&hp->kref, destroy_hvc_struct);
-               return -1;
-       }
-
-       vtermnos[index] = vtermno;
-       cons_ops[index] = ops;
-
-       /* reserve all indices up to and including this index */
-       if (last_hvc < index)
-               last_hvc = index;
-
-       /* if this index is what the user requested, then register
-        * now (setup won't fail at this point).  It's ok to just
-        * call register again if previously .setup failed.
-        */
-       if (index == hvc_console.index)
-               register_console(&hvc_console);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(hvc_instantiate);
-
-/* Wake the sleeping khvcd */
-void hvc_kick(void)
-{
-       hvc_kicked = 1;
-       wake_up_process(hvc_task);
-}
-EXPORT_SYMBOL_GPL(hvc_kick);
-
-static void hvc_unthrottle(struct tty_struct *tty)
-{
-       hvc_kick();
-}
-
-/*
- * The TTY interface won't be used until after the vio layer has exposed the vty
- * adapter to the kernel.
- */
-static int hvc_open(struct tty_struct *tty, struct file * filp)
-{
-       struct hvc_struct *hp;
-       unsigned long flags;
-       int rc = 0;
-
-       /* Auto increments kref reference if found. */
-       if (!(hp = hvc_get_by_index(tty->index)))
-               return -ENODEV;
-
-       spin_lock_irqsave(&hp->lock, flags);
-       /* Check and then increment for fast path open. */
-       if (hp->count++ > 0) {
-               tty_kref_get(tty);
-               spin_unlock_irqrestore(&hp->lock, flags);
-               hvc_kick();
-               return 0;
-       } /* else count == 0 */
-
-       tty->driver_data = hp;
-
-       hp->tty = tty_kref_get(tty);
-
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (hp->ops->notifier_add)
-               rc = hp->ops->notifier_add(hp, hp->data);
-
-       /*
-        * If the notifier fails we return an error.  The tty layer
-        * will call hvc_close() after a failed open but we don't want to clean
-        * up there so we'll clean up here and clear out the previously set
-        * tty fields and return the kref reference.
-        */
-       if (rc) {
-               spin_lock_irqsave(&hp->lock, flags);
-               hp->tty = NULL;
-               spin_unlock_irqrestore(&hp->lock, flags);
-               tty_kref_put(tty);
-               tty->driver_data = NULL;
-               kref_put(&hp->kref, destroy_hvc_struct);
-               printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
-       }
-       /* Force wakeup of the polling thread */
-       hvc_kick();
-
-       return rc;
-}
-
-static void hvc_close(struct tty_struct *tty, struct file * filp)
-{
-       struct hvc_struct *hp;
-       unsigned long flags;
-
-       if (tty_hung_up_p(filp))
-               return;
-
-       /*
-        * No driver_data means that this close was issued after a failed
-        * hvc_open by the tty layer's release_dev() function and we can just
-        * exit cleanly because the kref reference wasn't made.
-        */
-       if (!tty->driver_data)
-               return;
-
-       hp = tty->driver_data;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       if (--hp->count == 0) {
-               /* We are done with the tty pointer now. */
-               hp->tty = NULL;
-               spin_unlock_irqrestore(&hp->lock, flags);
-
-               if (hp->ops->notifier_del)
-                       hp->ops->notifier_del(hp, hp->data);
-
-               /* cancel pending tty resize work */
-               cancel_work_sync(&hp->tty_resize);
-
-               /*
-                * Chain calls chars_in_buffer() and returns immediately if
-                * there is no buffered data otherwise sleeps on a wait queue
-                * waking periodically to check chars_in_buffer().
-                */
-               tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
-       } else {
-               if (hp->count < 0)
-                       printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
-                               hp->vtermno, hp->count);
-               spin_unlock_irqrestore(&hp->lock, flags);
-       }
-
-       tty_kref_put(tty);
-       kref_put(&hp->kref, destroy_hvc_struct);
-}
-
-static void hvc_hangup(struct tty_struct *tty)
-{
-       struct hvc_struct *hp = tty->driver_data;
-       unsigned long flags;
-       int temp_open_count;
-
-       if (!hp)
-               return;
-
-       /* cancel pending tty resize work */
-       cancel_work_sync(&hp->tty_resize);
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       /*
-        * The N_TTY line discipline has problems such that in a close vs
-        * open->hangup case this can be called after the final close so prevent
-        * that from happening for now.
-        */
-       if (hp->count <= 0) {
-               spin_unlock_irqrestore(&hp->lock, flags);
-               return;
-       }
-
-       temp_open_count = hp->count;
-       hp->count = 0;
-       hp->n_outbuf = 0;
-       hp->tty = NULL;
-
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (hp->ops->notifier_hangup)
-               hp->ops->notifier_hangup(hp, hp->data);
-
-       while(temp_open_count) {
-               --temp_open_count;
-               tty_kref_put(tty);
-               kref_put(&hp->kref, destroy_hvc_struct);
-       }
-}
-
-/*
- * Push buffered characters whether they were just recently buffered or waiting
- * on a blocked hypervisor.  Call this function with hp->lock held.
- */
-static int hvc_push(struct hvc_struct *hp)
-{
-       int n;
-
-       n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
-       if (n <= 0) {
-               if (n == 0) {
-                       hp->do_wakeup = 1;
-                       return 0;
-               }
-               /* throw away output on error; this happens when
-                  there is no session connected to the vterm. */
-               hp->n_outbuf = 0;
-       } else
-               hp->n_outbuf -= n;
-       if (hp->n_outbuf > 0)
-               memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
-       else
-               hp->do_wakeup = 1;
-
-       return n;
-}
-
-static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       struct hvc_struct *hp = tty->driver_data;
-       unsigned long flags;
-       int rsize, written = 0;
-
-       /* This write was probably executed during a tty close. */
-       if (!hp)
-               return -EPIPE;
-
-       if (hp->count <= 0)
-               return -EIO;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       /* Push pending writes */
-       if (hp->n_outbuf > 0)
-               hvc_push(hp);
-
-       while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
-               if (rsize > count)
-                       rsize = count;
-               memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
-               count -= rsize;
-               buf += rsize;
-               hp->n_outbuf += rsize;
-               written += rsize;
-               hvc_push(hp);
-       }
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       /*
-        * Racy, but harmless, kick thread if there is still pending data.
-        */
-       if (hp->n_outbuf)
-               hvc_kick();
-
-       return written;
-}
-
-/**
- * hvc_set_winsz() - Resize the hvc tty terminal window.
- * @work:      work structure.
- *
- * The routine shall not be called within an atomic context because it
- * might sleep.
- *
- * Locking:    hp->lock
- */
-static void hvc_set_winsz(struct work_struct *work)
-{
-       struct hvc_struct *hp;
-       unsigned long hvc_flags;
-       struct tty_struct *tty;
-       struct winsize ws;
-
-       hp = container_of(work, struct hvc_struct, tty_resize);
-
-       spin_lock_irqsave(&hp->lock, hvc_flags);
-       if (!hp->tty) {
-               spin_unlock_irqrestore(&hp->lock, hvc_flags);
-               return;
-       }
-       ws  = hp->ws;
-       tty = tty_kref_get(hp->tty);
-       spin_unlock_irqrestore(&hp->lock, hvc_flags);
-
-       tty_do_resize(tty, &ws);
-       tty_kref_put(tty);
-}
-
-/*
- * This is actually a contract between the driver and the tty layer outlining
- * how much write room the driver can guarantee will be sent OR BUFFERED.  This
- * driver MUST honor the return value.
- */
-static int hvc_write_room(struct tty_struct *tty)
-{
-       struct hvc_struct *hp = tty->driver_data;
-
-       if (!hp)
-               return -1;
-
-       return hp->outbuf_size - hp->n_outbuf;
-}
-
-static int hvc_chars_in_buffer(struct tty_struct *tty)
-{
-       struct hvc_struct *hp = tty->driver_data;
-
-       if (!hp)
-               return 0;
-       return hp->n_outbuf;
-}
-
-/*
- * timeout will vary between the MIN and MAX values defined here.  By default
- * and during console activity we will use a default MIN_TIMEOUT of 10.  When
- * the console is idle, we increase the timeout value on each pass through
- * msleep until we reach the max.  This may be noticeable as a brief (average
- * one second) delay on the console before the console responds to input when
- * there has been no input for some time.
- */
-#define MIN_TIMEOUT            (10)
-#define MAX_TIMEOUT            (2000)
-static u32 timeout = MIN_TIMEOUT;
-
-#define HVC_POLL_READ  0x00000001
-#define HVC_POLL_WRITE 0x00000002
-
-int hvc_poll(struct hvc_struct *hp)
-{
-       struct tty_struct *tty;
-       int i, n, poll_mask = 0;
-       char buf[N_INBUF] __ALIGNED__;
-       unsigned long flags;
-       int read_total = 0;
-       int written_total = 0;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       /* Push pending writes */
-       if (hp->n_outbuf > 0)
-               written_total = hvc_push(hp);
-
-       /* Reschedule us if still some write pending */
-       if (hp->n_outbuf > 0) {
-               poll_mask |= HVC_POLL_WRITE;
-               /* If hvc_push() was not able to write, sleep a few msecs */
-               timeout = (written_total) ? 0 : MIN_TIMEOUT;
-       }
-
-       /* No tty attached, just skip */
-       tty = tty_kref_get(hp->tty);
-       if (tty == NULL)
-               goto bail;
-
-       /* Now check if we can get data (are we throttled ?) */
-       if (test_bit(TTY_THROTTLED, &tty->flags))
-               goto throttled;
-
-       /* If we aren't notifier driven and aren't throttled, we always
-        * request a reschedule
-        */
-       if (!hp->irq_requested)
-               poll_mask |= HVC_POLL_READ;
-
-       /* Read data if any */
-       for (;;) {
-               int count = tty_buffer_request_room(tty, N_INBUF);
-
-               /* If flip is full, just reschedule a later read */
-               if (count == 0) {
-                       poll_mask |= HVC_POLL_READ;
-                       break;
-               }
-
-               n = hp->ops->get_chars(hp->vtermno, buf, count);
-               if (n <= 0) {
-                       /* Hangup the tty when disconnected from host */
-                       if (n == -EPIPE) {
-                               spin_unlock_irqrestore(&hp->lock, flags);
-                               tty_hangup(tty);
-                               spin_lock_irqsave(&hp->lock, flags);
-                       } else if ( n == -EAGAIN ) {
-                               /*
-                                * Some back-ends can only ensure a certain min
-                                * num of bytes read, which may be > 'count'.
-                                * Let the tty clear the flip buff to make room.
-                                */
-                               poll_mask |= HVC_POLL_READ;
-                       }
-                       break;
-               }
-               for (i = 0; i < n; ++i) {
-#ifdef CONFIG_MAGIC_SYSRQ
-                       if (hp->index == hvc_console.index) {
-                               /* Handle the SysRq Hack */
-                               /* XXX should support a sequence */
-                               if (buf[i] == '\x0f') { /* ^O */
-                                       /* if ^O is pressed again, reset
-                                        * sysrq_pressed and flip ^O char */
-                                       sysrq_pressed = !sysrq_pressed;
-                                       if (sysrq_pressed)
-                                               continue;
-                               } else if (sysrq_pressed) {
-                                       handle_sysrq(buf[i]);
-                                       sysrq_pressed = 0;
-                                       continue;
-                               }
-                       }
-#endif /* CONFIG_MAGIC_SYSRQ */
-                       tty_insert_flip_char(tty, buf[i], 0);
-               }
-
-               read_total += n;
-       }
- throttled:
-       /* Wakeup write queue if necessary */
-       if (hp->do_wakeup) {
-               hp->do_wakeup = 0;
-               tty_wakeup(tty);
-       }
- bail:
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (read_total) {
-               /* Activity is occurring, so reset the polling backoff value to
-                  a minimum for performance. */
-               timeout = MIN_TIMEOUT;
-
-               tty_flip_buffer_push(tty);
-       }
-       if (tty)
-               tty_kref_put(tty);
-
-       return poll_mask;
-}
-EXPORT_SYMBOL_GPL(hvc_poll);
-
-/**
- * __hvc_resize() - Update terminal window size information.
- * @hp:                HVC console pointer
- * @ws:                Terminal window size structure
- *
- * Stores the specified window size information in the hvc structure of @hp.
- * The function schedule the tty resize update.
- *
- * Locking:    Locking free; the function MUST be called holding hp->lock
- */
-void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
-{
-       hp->ws = ws;
-       schedule_work(&hp->tty_resize);
-}
-EXPORT_SYMBOL_GPL(__hvc_resize);
-
-/*
- * This kthread is either polling or interrupt driven.  This is determined by
- * calling hvc_poll() who determines whether a console adapter support
- * interrupts.
- */
-static int khvcd(void *unused)
-{
-       int poll_mask;
-       struct hvc_struct *hp;
-
-       set_freezable();
-       do {
-               poll_mask = 0;
-               hvc_kicked = 0;
-               try_to_freeze();
-               wmb();
-               if (!cpus_are_in_xmon()) {
-                       spin_lock(&hvc_structs_lock);
-                       list_for_each_entry(hp, &hvc_structs, next) {
-                               poll_mask |= hvc_poll(hp);
-                       }
-                       spin_unlock(&hvc_structs_lock);
-               } else
-                       poll_mask |= HVC_POLL_READ;
-               if (hvc_kicked)
-                       continue;
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!hvc_kicked) {
-                       if (poll_mask == 0)
-                               schedule();
-                       else {
-                               if (timeout < MAX_TIMEOUT)
-                                       timeout += (timeout >> 6) + 1;
-
-                               msleep_interruptible(timeout);
-                       }
-               }
-               __set_current_state(TASK_RUNNING);
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-static const struct tty_operations hvc_ops = {
-       .open = hvc_open,
-       .close = hvc_close,
-       .write = hvc_write,
-       .hangup = hvc_hangup,
-       .unthrottle = hvc_unthrottle,
-       .write_room = hvc_write_room,
-       .chars_in_buffer = hvc_chars_in_buffer,
-};
-
-struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
-                            const struct hv_ops *ops,
-                            int outbuf_size)
-{
-       struct hvc_struct *hp;
-       int i;
-
-       /* We wait until a driver actually comes along */
-       if (!hvc_driver) {
-               int err = hvc_init();
-               if (err)
-                       return ERR_PTR(err);
-       }
-
-       hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
-                       GFP_KERNEL);
-       if (!hp)
-               return ERR_PTR(-ENOMEM);
-
-       hp->vtermno = vtermno;
-       hp->data = data;
-       hp->ops = ops;
-       hp->outbuf_size = outbuf_size;
-       hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
-
-       kref_init(&hp->kref);
-
-       INIT_WORK(&hp->tty_resize, hvc_set_winsz);
-       spin_lock_init(&hp->lock);
-       spin_lock(&hvc_structs_lock);
-
-       /*
-        * find index to use:
-        * see if this vterm id matches one registered for console.
-        */
-       for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
-               if (vtermnos[i] == hp->vtermno &&
-                   cons_ops[i] == hp->ops)
-                       break;
-
-       /* no matching slot, just use a counter */
-       if (i >= MAX_NR_HVC_CONSOLES)
-               i = ++last_hvc;
-
-       hp->index = i;
-
-       list_add_tail(&(hp->next), &hvc_structs);
-       spin_unlock(&hvc_structs_lock);
-
-       return hp;
-}
-EXPORT_SYMBOL_GPL(hvc_alloc);
-
-int hvc_remove(struct hvc_struct *hp)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-
-       spin_lock_irqsave(&hp->lock, flags);
-       tty = tty_kref_get(hp->tty);
-
-       if (hp->index < MAX_NR_HVC_CONSOLES)
-               vtermnos[hp->index] = -1;
-
-       /* Don't whack hp->irq because tty_hangup() will need to free the irq. */
-
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       /*
-        * We 'put' the instance that was grabbed when the kref instance
-        * was initialized using kref_init().  Let the last holder of this
-        * kref cause it to be removed, which will probably be the tty_vhangup
-        * below.
-        */
-       kref_put(&hp->kref, destroy_hvc_struct);
-
-       /*
-        * This function call will auto chain call hvc_hangup.
-        */
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(hvc_remove);
-
-/* Driver initialization: called as soon as someone uses hvc_alloc(). */
-static int hvc_init(void)
-{
-       struct tty_driver *drv;
-       int err;
-
-       /* We need more than hvc_count adapters due to hotplug additions. */
-       drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
-       if (!drv) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       drv->owner = THIS_MODULE;
-       drv->driver_name = "hvc";
-       drv->name = "hvc";
-       drv->major = HVC_MAJOR;
-       drv->minor_start = HVC_MINOR;
-       drv->type = TTY_DRIVER_TYPE_SYSTEM;
-       drv->init_termios = tty_std_termios;
-       drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-       tty_set_operations(drv, &hvc_ops);
-
-       /* Always start the kthread because there can be hotplug vty adapters
-        * added later. */
-       hvc_task = kthread_run(khvcd, NULL, "khvcd");
-       if (IS_ERR(hvc_task)) {
-               printk(KERN_ERR "Couldn't create kthread for console.\n");
-               err = PTR_ERR(hvc_task);
-               goto put_tty;
-       }
-
-       err = tty_register_driver(drv);
-       if (err) {
-               printk(KERN_ERR "Couldn't register hvc console driver\n");
-               goto stop_thread;
-       }
-
-       /*
-        * Make sure tty is fully registered before allowing it to be
-        * found by hvc_console_device.
-        */
-       smp_mb();
-       hvc_driver = drv;
-       return 0;
-
-stop_thread:
-       kthread_stop(hvc_task);
-       hvc_task = NULL;
-put_tty:
-       put_tty_driver(drv);
-out:
-       return err;
-}
-
-/* This isn't particularly necessary due to this being a console driver
- * but it is nice to be thorough.
- */
-static void __exit hvc_exit(void)
-{
-       if (hvc_driver) {
-               kthread_stop(hvc_task);
-
-               tty_unregister_driver(hvc_driver);
-               /* return tty_struct instances allocated in hvc_init(). */
-               put_tty_driver(hvc_driver);
-               unregister_console(&hvc_console);
-       }
-}
-module_exit(hvc_exit);
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
deleted file mode 100644 (file)
index 54381eb..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * hvc_console.h
- * Copyright (C) 2005 IBM Corporation
- *
- * Author(s):
- *     Ryan S. Arnold <rsa@us.ibm.com>
- *
- * hvc_console header information:
- *      moved here from arch/powerpc/include/asm/hvconsole.h
- *      and drivers/char/hvc_console.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#ifndef HVC_CONSOLE_H
-#define HVC_CONSOLE_H
-#include <linux/kref.h>
-#include <linux/tty.h>
-#include <linux/spinlock.h>
-
-/*
- * This is the max number of console adapters that can/will be found as
- * console devices on first stage console init.  Any number beyond this range
- * can't be used as a console device but is still a valid tty device.
- */
-#define MAX_NR_HVC_CONSOLES    16
-
-/*
- * The Linux TTY code does not support dynamic addition of tty derived devices
- * so we need to know how many tty devices we might need when space is allocated
- * for the tty device.  Since this driver supports hotplug of vty adapters we
- * need to make sure we have enough allocated.
- */
-#define HVC_ALLOC_TTY_ADAPTERS 8
-
-struct hvc_struct {
-       spinlock_t lock;
-       int index;
-       struct tty_struct *tty;
-       int count;
-       int do_wakeup;
-       char *outbuf;
-       int outbuf_size;
-       int n_outbuf;
-       uint32_t vtermno;
-       const struct hv_ops *ops;
-       int irq_requested;
-       int data;
-       struct winsize ws;
-       struct work_struct tty_resize;
-       struct list_head next;
-       struct kref kref; /* ref count & hvc_struct lifetime */
-};
-
-/* implemented by a low level driver */
-struct hv_ops {
-       int (*get_chars)(uint32_t vtermno, char *buf, int count);
-       int (*put_chars)(uint32_t vtermno, const char *buf, int count);
-
-       /* Callbacks for notification. Called in open, close and hangup */
-       int (*notifier_add)(struct hvc_struct *hp, int irq);
-       void (*notifier_del)(struct hvc_struct *hp, int irq);
-       void (*notifier_hangup)(struct hvc_struct *hp, int irq);
-};
-
-/* Register a vterm and a slot index for use as a console (console_init) */
-extern int hvc_instantiate(uint32_t vtermno, int index,
-                          const struct hv_ops *ops);
-
-/* register a vterm for hvc tty operation (module_init or hotplug add) */
-extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data,
-                                    const struct hv_ops *ops, int outbuf_size);
-/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
-extern int hvc_remove(struct hvc_struct *hp);
-
-/* data available */
-int hvc_poll(struct hvc_struct *hp);
-void hvc_kick(void);
-
-/* Resize hvc tty terminal window */
-extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws);
-
-static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hp->lock, flags);
-       __hvc_resize(hp, ws);
-       spin_unlock_irqrestore(&hp->lock, flags);
-}
-
-/* default notifier for irq based notification */
-extern int notifier_add_irq(struct hvc_struct *hp, int data);
-extern void notifier_del_irq(struct hvc_struct *hp, int data);
-extern void notifier_hangup_irq(struct hvc_struct *hp, int data);
-
-
-#if defined(CONFIG_XMON) && defined(CONFIG_SMP)
-#include <asm/xmon.h>
-#else
-static inline int cpus_are_in_xmon(void)
-{
-       return 0;
-}
-#endif
-
-#endif // HVC_CONSOLE_H
diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c
deleted file mode 100644 (file)
index 6470f63..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-
-#include <asm/processor.h>
-
-#include "hvc_console.h"
-
-/* DCC Status Bits */
-#define DCC_STATUS_RX          (1 << 30)
-#define DCC_STATUS_TX          (1 << 29)
-
-static inline u32 __dcc_getstatus(void)
-{
-       u32 __ret;
-
-       asm("mrc p14, 0, %0, c0, c1, 0  @ read comms ctrl reg"
-               : "=r" (__ret) : : "cc");
-
-       return __ret;
-}
-
-
-#if defined(CONFIG_CPU_V7)
-static inline char __dcc_getchar(void)
-{
-       char __c;
-
-       asm("get_wait:  mrc p14, 0, pc, c0, c1, 0                          \n\
-                       bne get_wait                                       \n\
-                       mrc p14, 0, %0, c0, c5, 0       @ read comms data reg"
-               : "=r" (__c) : : "cc");
-
-       return __c;
-}
-#else
-static inline char __dcc_getchar(void)
-{
-       char __c;
-
-       asm("mrc p14, 0, %0, c0, c5, 0  @ read comms data reg"
-               : "=r" (__c));
-
-       return __c;
-}
-#endif
-
-#if defined(CONFIG_CPU_V7)
-static inline void __dcc_putchar(char c)
-{
-       asm("put_wait:  mrc p14, 0, pc, c0, c1, 0                 \n\
-                       bcs put_wait                              \n\
-                       mcr p14, 0, %0, c0, c5, 0                   "
-       : : "r" (c) : "cc");
-}
-#else
-static inline void __dcc_putchar(char c)
-{
-       asm("mcr p14, 0, %0, c0, c5, 0  @ write a char"
-               : /* no output register */
-               : "r" (c));
-}
-#endif
-
-static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++) {
-               while (__dcc_getstatus() & DCC_STATUS_TX)
-                       cpu_relax();
-
-               __dcc_putchar((char)(buf[i] & 0xFF));
-       }
-
-       return count;
-}
-
-static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
-{
-       int i;
-
-       for (i = 0; i < count; ++i) {
-               int c = -1;
-
-               if (__dcc_getstatus() & DCC_STATUS_RX)
-                       c = __dcc_getchar();
-               if (c < 0)
-                       break;
-               buf[i] = c;
-       }
-
-       return i;
-}
-
-static const struct hv_ops hvc_dcc_get_put_ops = {
-       .get_chars = hvc_dcc_get_chars,
-       .put_chars = hvc_dcc_put_chars,
-};
-
-static int __init hvc_dcc_console_init(void)
-{
-       hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
-       return 0;
-}
-console_initcall(hvc_dcc_console_init);
-
-static int __init hvc_dcc_init(void)
-{
-       hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
-       return 0;
-}
-device_initcall(hvc_dcc_init);
diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c
deleted file mode 100644 (file)
index 2623e17..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright IBM Corp. 2001,2008
- *
- * This file contains the IRQ specific code for hvc_console
- *
- */
-
-#include <linux/interrupt.h>
-
-#include "hvc_console.h"
-
-static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
-{
-       /* if hvc_poll request a repoll, then kick the hvcd thread */
-       if (hvc_poll(dev_instance))
-               hvc_kick();
-       return IRQ_HANDLED;
-}
-
-/*
- * For IRQ based systems these callbacks can be used
- */
-int notifier_add_irq(struct hvc_struct *hp, int irq)
-{
-       int rc;
-
-       if (!irq) {
-               hp->irq_requested = 0;
-               return 0;
-       }
-       rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
-                          "hvc_console", hp);
-       if (!rc)
-               hp->irq_requested = 1;
-       return rc;
-}
-
-void notifier_del_irq(struct hvc_struct *hp, int irq)
-{
-       if (!hp->irq_requested)
-               return;
-       free_irq(irq, hp);
-       hp->irq_requested = 0;
-}
-
-void notifier_hangup_irq(struct hvc_struct *hp, int irq)
-{
-       notifier_del_irq(hp, irq);
-}
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
deleted file mode 100644 (file)
index 21c5495..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * iSeries vio driver interface to hvc_console.c
- *
- * This code is based heavily on hvc_vio.c and viocons.c
- *
- * Copyright (C) 2006 Stephen Rothwell, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/console.h>
-
-#include <asm/hvconsole.h>
-#include <asm/vio.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_lp_event.h>
-
-#include "hvc_console.h"
-
-#define VTTY_PORTS 10
-
-static DEFINE_SPINLOCK(consolelock);
-static DEFINE_SPINLOCK(consoleloglock);
-
-static const char hvc_driver_name[] = "hvc_console";
-
-#define IN_BUF_SIZE    200
-
-/*
- * Our port information.
- */
-static struct port_info {
-       HvLpIndex lp;
-       u64 seq;        /* sequence number of last HV send */
-       u64 ack;        /* last ack from HV */
-       struct hvc_struct *hp;
-       int in_start;
-       int in_end;
-       unsigned char in_buf[IN_BUF_SIZE];
-} port_info[VTTY_PORTS] = {
-       [ 0 ... VTTY_PORTS - 1 ] = {
-               .lp = HvLpIndexInvalid
-       }
-};
-
-#define viochar_is_console(pi) ((pi) == &port_info[0])
-
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
-       {"serial", "IBM,iSeries-vty"},
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
-static void hvlog(char *fmt, ...)
-{
-       int i;
-       unsigned long flags;
-       va_list args;
-       static char buf[256];
-
-       spin_lock_irqsave(&consoleloglock, flags);
-       va_start(args, fmt);
-       i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
-       va_end(args);
-       buf[i++] = '\r';
-       HvCall_writeLogBuffer(buf, i);
-       spin_unlock_irqrestore(&consoleloglock, flags);
-}
-
-/*
- * Initialize the common fields in a charLpEvent
- */
-static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
-{
-       struct HvLpEvent *hev = &viochar->event;
-
-       memset(viochar, 0, sizeof(struct viocharlpevent));
-
-       hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
-               HV_LP_EVENT_INT;
-       hev->xType = HvLpEvent_Type_VirtualIo;
-       hev->xSubtype = viomajorsubtype_chario | viochardata;
-       hev->xSourceLp = HvLpConfig_getLpIndex();
-       hev->xTargetLp = lp;
-       hev->xSizeMinus1 = sizeof(struct viocharlpevent);
-       hev->xSourceInstanceId = viopath_sourceinst(lp);
-       hev->xTargetInstanceId = viopath_targetinst(lp);
-}
-
-static int get_chars(uint32_t vtermno, char *buf, int count)
-{
-       struct port_info *pi;
-       int n = 0;
-       unsigned long flags;
-
-       if (vtermno >= VTTY_PORTS)
-               return -EINVAL;
-       if (count == 0)
-               return 0;
-
-       pi = &port_info[vtermno];
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (pi->in_end == 0)
-               goto done;
-
-       n = pi->in_end - pi->in_start;
-       if (n > count)
-               n = count;
-       memcpy(buf, &pi->in_buf[pi->in_start], n);
-       pi->in_start += n;
-       if (pi->in_start == pi->in_end) {
-               pi->in_start = 0;
-               pi->in_end = 0;
-       }
-done:
-       spin_unlock_irqrestore(&consolelock, flags);
-       return n;
-}
-
-static int put_chars(uint32_t vtermno, const char *buf, int count)
-{
-       struct viocharlpevent *viochar;
-       struct port_info *pi;
-       HvLpEvent_Rc hvrc;
-       unsigned long flags;
-       int sent = 0;
-
-       if (vtermno >= VTTY_PORTS)
-               return -EINVAL;
-
-       pi = &port_info[vtermno];
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
-               HvCall_writeLogBuffer(buf, count);
-               sent = count;
-               goto done;
-       }
-
-       viochar = vio_get_event_buffer(viomajorsubtype_chario);
-       if (viochar == NULL) {
-               hvlog("\n\rviocons: Can't get viochar buffer.");
-               goto done;
-       }
-
-       while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
-               int len;
-
-               len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
-
-               if (viochar_is_console(pi))
-                       HvCall_writeLogBuffer(buf, len);
-
-               init_data_event(viochar, pi->lp);
-
-               viochar->len = len;
-               viochar->event.xCorrelationToken = pi->seq++;
-               viochar->event.xSizeMinus1 =
-                       offsetof(struct viocharlpevent, data) + len;
-
-               memcpy(viochar->data, buf, len);
-
-               hvrc = HvCallEvent_signalLpEvent(&viochar->event);
-               if (hvrc)
-                       hvlog("\n\rerror sending event! return code %d\n\r",
-                               (int)hvrc);
-               sent += len;
-               count -= len;
-               buf += len;
-       }
-
-       vio_free_event_buffer(viomajorsubtype_chario, viochar);
-done:
-       spin_unlock_irqrestore(&consolelock, flags);
-       return sent;
-}
-
-static const struct hv_ops hvc_get_put_ops = {
-       .get_chars = get_chars,
-       .put_chars = put_chars,
-       .notifier_add = notifier_add_irq,
-       .notifier_del = notifier_del_irq,
-       .notifier_hangup = notifier_hangup_irq,
-};
-
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
-                       const struct vio_device_id *id)
-{
-       struct hvc_struct *hp;
-       struct port_info *pi;
-
-       /* probed with invalid parameters. */
-       if (!vdev || !id)
-               return -EPERM;
-
-       if (vdev->unit_address >= VTTY_PORTS)
-               return -ENODEV;
-
-       pi = &port_info[vdev->unit_address];
-
-       hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
-                       VIOCHAR_MAX_DATA);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-       pi->hp = hp;
-       dev_set_drvdata(&vdev->dev, pi);
-
-       return 0;
-}
-
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
-{
-       struct port_info *pi = dev_get_drvdata(&vdev->dev);
-       struct hvc_struct *hp = pi->hp;
-
-       return hvc_remove(hp);
-}
-
-static struct vio_driver hvc_vio_driver = {
-       .id_table       = hvc_driver_table,
-       .probe          = hvc_vio_probe,
-       .remove         = __devexit_p(hvc_vio_remove),
-       .driver         = {
-               .name   = hvc_driver_name,
-               .owner  = THIS_MODULE,
-       }
-};
-
-static void hvc_open_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       u8 port = cevent->virtual_device;
-       struct port_info *pi;
-       int reject = 0;
-
-       if (hvlpevent_is_ack(event)) {
-               if (port >= VTTY_PORTS)
-                       return;
-
-               spin_lock_irqsave(&consolelock, flags);
-
-               pi = &port_info[port];
-               if (event->xRc == HvLpEvent_Rc_Good) {
-                       pi->seq = pi->ack = 0;
-                       /*
-                        * This line allows connections from the primary
-                        * partition but once one is connected from the
-                        * primary partition nothing short of a reboot
-                        * of linux will allow access from the hosting
-                        * partition again without a required iSeries fix.
-                        */
-                       pi->lp = event->xTargetLp;
-               }
-
-               spin_unlock_irqrestore(&consolelock, flags);
-               if (event->xRc != HvLpEvent_Rc_Good)
-                       printk(KERN_WARNING
-                              "hvc: handle_open_event: event->xRc == (%d).\n",
-                              event->xRc);
-
-               if (event->xCorrelationToken != 0) {
-                       atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
-                       atomic_set(aptr, 1);
-               } else
-                       printk(KERN_WARNING
-                              "hvc: weird...got open ack without atomic\n");
-               return;
-       }
-
-       /* This had better require an ack, otherwise complain */
-       if (!hvlpevent_need_ack(event)) {
-               printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
-               return;
-       }
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       /* Make sure this is a good virtual tty */
-       if (port >= VTTY_PORTS) {
-               event->xRc = HvLpEvent_Rc_SubtypeError;
-               cevent->subtype_result_code = viorc_openRejected;
-               /*
-                * Flag state here since we can't printk while holding
-                * the consolelock spinlock.
-                */
-               reject = 1;
-       } else {
-               pi = &port_info[port];
-               if ((pi->lp != HvLpIndexInvalid) &&
-                               (pi->lp != event->xSourceLp)) {
-                       /*
-                        * If this is tty is already connected to a different
-                        * partition, fail.
-                        */
-                       event->xRc = HvLpEvent_Rc_SubtypeError;
-                       cevent->subtype_result_code = viorc_openRejected;
-                       reject = 2;
-               } else {
-                       pi->lp = event->xSourceLp;
-                       event->xRc = HvLpEvent_Rc_Good;
-                       cevent->subtype_result_code = viorc_good;
-                       pi->seq = pi->ack = 0;
-               }
-       }
-
-       spin_unlock_irqrestore(&consolelock, flags);
-
-       if (reject == 1)
-               printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
-       else if (reject == 2)
-               printk(KERN_WARNING "hvc: open rejected: console in exclusive "
-                               "use by another partition.\n");
-
-       /* Return the acknowledgement */
-       HvCallEvent_ackLpEvent(event);
-}
-
-/*
- * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
- * virtual console should never actually issue a close event to the hypervisor
- * because the virtual console never goes away.  A close event coming from the
- * hypervisor simply means that there are no client consoles connected to the
- * virtual console.
- */
-static void hvc_close_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       u8 port = cevent->virtual_device;
-
-       if (!hvlpevent_is_int(event)) {
-               printk(KERN_WARNING
-                       "hvc: got unexpected close acknowledgement\n");
-               return;
-       }
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING
-                       "hvc: close message from invalid virtual device.\n");
-               return;
-       }
-
-       /* For closes, just mark the console partition invalid */
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (port_info[port].lp == event->xSourceLp)
-               port_info[port].lp = HvLpIndexInvalid;
-
-       spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_data_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       struct port_info *pi;
-       int n;
-       u8 port = cevent->virtual_device;
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
-                               port);
-               return;
-       }
-       if (cevent->len == 0)
-               return;
-
-       /*
-        * Change 05/01/2003 - Ryan Arnold: If a partition other than
-        * the current exclusive partition tries to send us data
-        * events then just drop them on the floor because we don't
-        * want his stinking data.  He isn't authorized to receive
-        * data because he wasn't the first one to get the console,
-        * therefore he shouldn't be allowed to send data either.
-        * This will work without an iSeries fix.
-        */
-       pi = &port_info[port];
-       if (pi->lp != event->xSourceLp)
-               return;
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       n = IN_BUF_SIZE - pi->in_end;
-       if (n > cevent->len)
-               n = cevent->len;
-       if (n > 0) {
-               memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
-               pi->in_end += n;
-       }
-       spin_unlock_irqrestore(&consolelock, flags);
-       if (n == 0)
-               printk(KERN_WARNING "hvc: input buffer overflow\n");
-}
-
-static void hvc_ack_event(struct HvLpEvent *event)
-{
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       unsigned long flags;
-       u8 port = cevent->virtual_device;
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING "hvc: data on invalid virtual device\n");
-               return;
-       }
-
-       spin_lock_irqsave(&consolelock, flags);
-       port_info[port].ack = event->xCorrelationToken;
-       spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_config_event(struct HvLpEvent *event)
-{
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-
-       if (cevent->data[0] == 0x01)
-               printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
-                      cevent->data[1], cevent->data[2],
-                      cevent->data[3], cevent->data[4]);
-       else
-               printk(KERN_WARNING "hvc: unknown config event\n");
-}
-
-static void hvc_handle_event(struct HvLpEvent *event)
-{
-       int charminor;
-
-       if (event == NULL)
-               return;
-
-       charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
-       switch (charminor) {
-       case viocharopen:
-               hvc_open_event(event);
-               break;
-       case viocharclose:
-               hvc_close_event(event);
-               break;
-       case viochardata:
-               hvc_data_event(event);
-               break;
-       case viocharack:
-               hvc_ack_event(event);
-               break;
-       case viocharconfig:
-               hvc_config_event(event);
-               break;
-       default:
-               if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-static int __init send_open(HvLpIndex remoteLp, void *sem)
-{
-       return HvCallEvent_signalLpEventFast(remoteLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_chario | viocharopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(remoteLp),
-                       viopath_targetinst(remoteLp),
-                       (u64)(unsigned long)sem, VIOVERSION << 16,
-                       0, 0, 0, 0);
-}
-
-static int __init hvc_vio_init(void)
-{
-       atomic_t wait_flag;
-       int rc;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return -EIO;
-
-       /* +2 for fudge */
-       rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
-                       viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
-       if (rc)
-               printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
-
-       if (viopath_hostLp == HvLpIndexInvalid)
-               vio_set_hostlp();
-
-       /*
-        * And if the primary is not the same as the hosting LP, open to the
-        * hosting lp
-        */
-       if ((viopath_hostLp != HvLpIndexInvalid) &&
-           (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
-               printk(KERN_INFO "hvc: open path to hosting (%d)\n",
-                               viopath_hostLp);
-               rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
-                               VIOCHAR_WINDOW + 2);    /* +2 for fudge */
-               if (rc)
-                       printk(KERN_WARNING
-                               "error opening to partition %d: %d\n",
-                               viopath_hostLp, rc);
-       }
-
-       if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
-               printk(KERN_WARNING
-                       "hvc: error seting handler for console events!\n");
-
-       /*
-        * First, try to open the console to the hosting lp.
-        * Wait on a semaphore for the response.
-        */
-       atomic_set(&wait_flag, 0);
-       if ((viopath_isactive(viopath_hostLp)) &&
-           (send_open(viopath_hostLp, &wait_flag) == 0)) {
-               printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
-               while (atomic_read(&wait_flag) == 0)
-                       mb();
-               atomic_set(&wait_flag, 0);
-       }
-
-       /*
-        * If we don't have an active console, try the primary
-        */
-       if ((!viopath_isactive(port_info[0].lp)) &&
-           (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
-           (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
-               printk(KERN_INFO "hvc: opening console to primary partition\n");
-               while (atomic_read(&wait_flag) == 0)
-                       mb();
-       }
-
-       /* Register as a vio device to receive callbacks */
-       rc = vio_register_driver(&hvc_vio_driver);
-
-       return rc;
-}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
-       vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
-
-/* the device tree order defines our numbering */
-static int __init hvc_find_vtys(void)
-{
-       struct device_node *vty;
-       int num_found = 0;
-
-       for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
-                       vty = of_find_node_by_name(vty, "vty")) {
-               const uint32_t *vtermno;
-
-               /* We have statically defined space for only a certain number
-                * of console adapters.
-                */
-               if ((num_found >= MAX_NR_HVC_CONSOLES) ||
-                               (num_found >= VTTY_PORTS)) {
-                       of_node_put(vty);
-                       break;
-               }
-
-               vtermno = of_get_property(vty, "reg", NULL);
-               if (!vtermno)
-                       continue;
-
-               if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
-                       continue;
-
-               if (num_found == 0)
-                       add_preferred_console("hvc", 0, NULL);
-               hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
-               ++num_found;
-       }
-
-       return num_found;
-}
-console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
deleted file mode 100644 (file)
index c3425bb..0000000
+++ /dev/null
@@ -1,1337 +0,0 @@
-/*
- * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
- *
- * This HVC device driver provides terminal access using
- * z/VM IUCV communication paths.
- *
- * Copyright IBM Corp. 2008, 2009
- *
- * Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-#define KMSG_COMPONENT         "hvc_iucv"
-#define pr_fmt(fmt)            KMSG_COMPONENT ": " fmt
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/ebcdic.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/mempool.h>
-#include <linux/moduleparam.h>
-#include <linux/tty.h>
-#include <linux/wait.h>
-#include <net/iucv/iucv.h>
-
-#include "hvc_console.h"
-
-
-/* General device driver settings */
-#define HVC_IUCV_MAGIC         0xc9e4c3e5
-#define MAX_HVC_IUCV_LINES     HVC_ALLOC_TTY_ADAPTERS
-#define MEMPOOL_MIN_NR         (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4)
-
-/* IUCV TTY message  */
-#define MSG_VERSION            0x02    /* Message version */
-#define MSG_TYPE_ERROR         0x01    /* Error message */
-#define MSG_TYPE_TERMENV       0x02    /* Terminal environment variable */
-#define MSG_TYPE_TERMIOS       0x04    /* Terminal IO struct update */
-#define MSG_TYPE_WINSIZE       0x08    /* Terminal window size update */
-#define MSG_TYPE_DATA          0x10    /* Terminal data */
-
-struct iucv_tty_msg {
-       u8      version;                /* Message version */
-       u8      type;                   /* Message type */
-#define MSG_MAX_DATALEN                ((u16)(~0))
-       u16     datalen;                /* Payload length */
-       u8      data[];                 /* Payload buffer */
-} __attribute__((packed));
-#define MSG_SIZE(s)            ((s) + offsetof(struct iucv_tty_msg, data))
-
-enum iucv_state_t {
-       IUCV_DISCONN    = 0,
-       IUCV_CONNECTED  = 1,
-       IUCV_SEVERED    = 2,
-};
-
-enum tty_state_t {
-       TTY_CLOSED      = 0,
-       TTY_OPENED      = 1,
-};
-
-struct hvc_iucv_private {
-       struct hvc_struct       *hvc;           /* HVC struct reference */
-       u8                      srv_name[8];    /* IUCV service name (ebcdic) */
-       unsigned char           is_console;     /* Linux console usage flag */
-       enum iucv_state_t       iucv_state;     /* IUCV connection status */
-       enum tty_state_t        tty_state;      /* TTY status */
-       struct iucv_path        *path;          /* IUCV path pointer */
-       spinlock_t              lock;           /* hvc_iucv_private lock */
-#define SNDBUF_SIZE            (PAGE_SIZE)     /* must be < MSG_MAX_DATALEN */
-       void                    *sndbuf;        /* send buffer            */
-       size_t                  sndbuf_len;     /* length of send buffer  */
-#define QUEUE_SNDBUF_DELAY     (HZ / 25)
-       struct delayed_work     sndbuf_work;    /* work: send iucv msg(s) */
-       wait_queue_head_t       sndbuf_waitq;   /* wait for send completion */
-       struct list_head        tty_outqueue;   /* outgoing IUCV messages */
-       struct list_head        tty_inqueue;    /* incoming IUCV messages */
-       struct device           *dev;           /* device structure */
-};
-
-struct iucv_tty_buffer {
-       struct list_head        list;   /* list pointer */
-       struct iucv_message     msg;    /* store an IUCV message */
-       size_t                  offset; /* data buffer offset */
-       struct iucv_tty_msg     *mbuf;  /* buffer to store input/output data */
-};
-
-/* IUCV callback handler */
-static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]);
-static void hvc_iucv_path_severed(struct iucv_path *, u8[16]);
-static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *);
-static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *);
-
-
-/* Kernel module parameter: use one terminal device as default */
-static unsigned long hvc_iucv_devices = 1;
-
-/* Array of allocated hvc iucv tty lines... */
-static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
-#define IUCV_HVC_CON_IDX       (0)
-/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
-#define MAX_VMID_FILTER                (500)
-static size_t hvc_iucv_filter_size;
-static void *hvc_iucv_filter;
-static const char *hvc_iucv_filter_string;
-static DEFINE_RWLOCK(hvc_iucv_filter_lock);
-
-/* Kmem cache and mempool for iucv_tty_buffer elements */
-static struct kmem_cache *hvc_iucv_buffer_cache;
-static mempool_t *hvc_iucv_mempool;
-
-/* IUCV handler callback functions */
-static struct iucv_handler hvc_iucv_handler = {
-       .path_pending  = hvc_iucv_path_pending,
-       .path_severed  = hvc_iucv_path_severed,
-       .message_complete = hvc_iucv_msg_complete,
-       .message_pending  = hvc_iucv_msg_pending,
-};
-
-
-/**
- * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance.
- * @num:       The HVC virtual terminal number (vtermno)
- *
- * This function returns the struct hvc_iucv_private instance that corresponds
- * to the HVC virtual terminal number specified as parameter @num.
- */
-struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
-{
-       if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))
-               return NULL;
-       return hvc_iucv_table[num - HVC_IUCV_MAGIC];
-}
-
-/**
- * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element.
- * @size:      Size of the internal buffer used to store data.
- * @flags:     Memory allocation flags passed to mempool.
- *
- * This function allocates a new struct iucv_tty_buffer element and, optionally,
- * allocates an internal data buffer with the specified size @size.
- * The internal data buffer is always allocated with GFP_DMA which is
- * required for receiving and sending data with IUCV.
- * Note: The total message size arises from the internal buffer size and the
- *      members of the iucv_tty_msg structure.
- * The function returns NULL if memory allocation has failed.
- */
-static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
-{
-       struct iucv_tty_buffer *bufp;
-
-       bufp = mempool_alloc(hvc_iucv_mempool, flags);
-       if (!bufp)
-               return NULL;
-       memset(bufp, 0, sizeof(*bufp));
-
-       if (size > 0) {
-               bufp->msg.length = MSG_SIZE(size);
-               bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA);
-               if (!bufp->mbuf) {
-                       mempool_free(bufp, hvc_iucv_mempool);
-                       return NULL;
-               }
-               bufp->mbuf->version = MSG_VERSION;
-               bufp->mbuf->type    = MSG_TYPE_DATA;
-               bufp->mbuf->datalen = (u16) size;
-       }
-       return bufp;
-}
-
-/**
- * destroy_tty_buffer() - destroy struct iucv_tty_buffer element.
- * @bufp:      Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL.
- */
-static void destroy_tty_buffer(struct iucv_tty_buffer *bufp)
-{
-       kfree(bufp->mbuf);
-       mempool_free(bufp, hvc_iucv_mempool);
-}
-
-/**
- * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element.
- * @list:      List containing struct iucv_tty_buffer elements.
- */
-static void destroy_tty_buffer_list(struct list_head *list)
-{
-       struct iucv_tty_buffer *ent, *next;
-
-       list_for_each_entry_safe(ent, next, list, list) {
-               list_del(&ent->list);
-               destroy_tty_buffer(ent);
-       }
-}
-
-/**
- * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer.
- * @priv:              Pointer to struct hvc_iucv_private
- * @buf:               HVC buffer for writing received terminal data.
- * @count:             HVC buffer size.
- * @has_more_data:     Pointer to an int variable.
- *
- * The function picks up pending messages from the input queue and receives
- * the message data that is then written to the specified buffer @buf.
- * If the buffer size @count is less than the data message size, the
- * message is kept on the input queue and @has_more_data is set to 1.
- * If all message data has been written, the message is removed from
- * the input queue.
- *
- * The function returns the number of bytes written to the terminal, zero if
- * there are no pending data messages available or if there is no established
- * IUCV path.
- * If the IUCV path has been severed, then -EPIPE is returned to cause a
- * hang up (that is issued by the HVC layer).
- */
-static int hvc_iucv_write(struct hvc_iucv_private *priv,
-                         char *buf, int count, int *has_more_data)
-{
-       struct iucv_tty_buffer *rb;
-       int written;
-       int rc;
-
-       /* immediately return if there is no IUCV connection */
-       if (priv->iucv_state == IUCV_DISCONN)
-               return 0;
-
-       /* if the IUCV path has been severed, return -EPIPE to inform the
-        * HVC layer to hang up the tty device. */
-       if (priv->iucv_state == IUCV_SEVERED)
-               return -EPIPE;
-
-       /* check if there are pending messages */
-       if (list_empty(&priv->tty_inqueue))
-               return 0;
-
-       /* receive an iucv message and flip data to the tty (ldisc) */
-       rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list);
-
-       written = 0;
-       if (!rb->mbuf) { /* message not yet received ... */
-               /* allocate mem to store msg data; if no memory is available
-                * then leave the buffer on the list and re-try later */
-               rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA);
-               if (!rb->mbuf)
-                       return -ENOMEM;
-
-               rc = __iucv_message_receive(priv->path, &rb->msg, 0,
-                                           rb->mbuf, rb->msg.length, NULL);
-               switch (rc) {
-               case 0: /* Successful       */
-                       break;
-               case 2: /* No message found */
-               case 9: /* Message purged   */
-                       break;
-               default:
-                       written = -EIO;
-               }
-               /* remove buffer if an error has occured or received data
-                * is not correct */
-               if (rc || (rb->mbuf->version != MSG_VERSION) ||
-                         (rb->msg.length    != MSG_SIZE(rb->mbuf->datalen)))
-                       goto out_remove_buffer;
-       }
-
-       switch (rb->mbuf->type) {
-       case MSG_TYPE_DATA:
-               written = min_t(int, rb->mbuf->datalen - rb->offset, count);
-               memcpy(buf, rb->mbuf->data + rb->offset, written);
-               if (written < (rb->mbuf->datalen - rb->offset)) {
-                       rb->offset += written;
-                       *has_more_data = 1;
-                       goto out_written;
-               }
-               break;
-
-       case MSG_TYPE_WINSIZE:
-               if (rb->mbuf->datalen != sizeof(struct winsize))
-                       break;
-               /* The caller must ensure that the hvc is locked, which
-                * is the case when called from hvc_iucv_get_chars() */
-               __hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
-               break;
-
-       case MSG_TYPE_ERROR:    /* ignored ... */
-       case MSG_TYPE_TERMENV:  /* ignored ... */
-       case MSG_TYPE_TERMIOS:  /* ignored ... */
-               break;
-       }
-
-out_remove_buffer:
-       list_del(&rb->list);
-       destroy_tty_buffer(rb);
-       *has_more_data = !list_empty(&priv->tty_inqueue);
-
-out_written:
-       return written;
-}
-
-/**
- * hvc_iucv_get_chars() - HVC get_chars operation.
- * @vtermno:   HVC virtual terminal number.
- * @buf:       Pointer to a buffer to store data
- * @count:     Size of buffer available for writing
- *
- * The HVC thread calls this method to read characters from the back-end.
- * If an IUCV communication path has been established, pending IUCV messages
- * are received and data is copied into buffer @buf up to @count bytes.
- *
- * Locking:    The routine gets called under an irqsave() spinlock; and
- *             the routine locks the struct hvc_iucv_private->lock to call
- *             helper functions.
- */
-static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
-{
-       struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
-       int written;
-       int has_more_data;
-
-       if (count <= 0)
-               return 0;
-
-       if (!priv)
-               return -ENODEV;
-
-       spin_lock(&priv->lock);
-       has_more_data = 0;
-       written = hvc_iucv_write(priv, buf, count, &has_more_data);
-       spin_unlock(&priv->lock);
-
-       /* if there are still messages on the queue... schedule another run */
-       if (has_more_data)
-               hvc_kick();
-
-       return written;
-}
-
-/**
- * hvc_iucv_queue() - Buffer terminal data for sending.
- * @priv:      Pointer to struct hvc_iucv_private instance.
- * @buf:       Buffer containing data to send.
- * @count:     Size of buffer and amount of data to send.
- *
- * The function queues data for sending. To actually send the buffered data,
- * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY).
- * The function returns the number of data bytes that has been buffered.
- *
- * If the device is not connected, data is ignored and the function returns
- * @count.
- * If the buffer is full, the function returns 0.
- * If an existing IUCV communicaton path has been severed, -EPIPE is returned
- * (that can be passed to HVC layer to cause a tty hangup).
- */
-static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf,
-                         int count)
-{
-       size_t len;
-
-       if (priv->iucv_state == IUCV_DISCONN)
-               return count;                   /* ignore data */
-
-       if (priv->iucv_state == IUCV_SEVERED)
-               return -EPIPE;
-
-       len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len);
-       if (!len)
-               return 0;
-
-       memcpy(priv->sndbuf + priv->sndbuf_len, buf, len);
-       priv->sndbuf_len += len;
-
-       if (priv->iucv_state == IUCV_CONNECTED)
-               schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY);
-
-       return len;
-}
-
-/**
- * hvc_iucv_send() - Send an IUCV message containing terminal data.
- * @priv:      Pointer to struct hvc_iucv_private instance.
- *
- * If an IUCV communication path has been established, the buffered output data
- * is sent via an IUCV message and the number of bytes sent is returned.
- * Returns 0 if there is no established IUCV communication path or
- * -EPIPE if an existing IUCV communicaton path has been severed.
- */
-static int hvc_iucv_send(struct hvc_iucv_private *priv)
-{
-       struct iucv_tty_buffer *sb;
-       int rc, len;
-
-       if (priv->iucv_state == IUCV_SEVERED)
-               return -EPIPE;
-
-       if (priv->iucv_state == IUCV_DISCONN)
-               return -EIO;
-
-       if (!priv->sndbuf_len)
-               return 0;
-
-       /* allocate internal buffer to store msg data and also compute total
-        * message length */
-       sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC);
-       if (!sb)
-               return -ENOMEM;
-
-       memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len);
-       sb->mbuf->datalen = (u16) priv->sndbuf_len;
-       sb->msg.length = MSG_SIZE(sb->mbuf->datalen);
-
-       list_add_tail(&sb->list, &priv->tty_outqueue);
-
-       rc = __iucv_message_send(priv->path, &sb->msg, 0, 0,
-                                (void *) sb->mbuf, sb->msg.length);
-       if (rc) {
-               /* drop the message here; however we might want to handle
-                * 0x03 (msg limit reached) by trying again... */
-               list_del(&sb->list);
-               destroy_tty_buffer(sb);
-       }
-       len = priv->sndbuf_len;
-       priv->sndbuf_len = 0;
-
-       return len;
-}
-
-/**
- * hvc_iucv_sndbuf_work() - Send buffered data over IUCV
- * @work:      Work structure.
- *
- * This work queue function sends buffered output data over IUCV and,
- * if not all buffered data could be sent, reschedules itself.
- */
-static void hvc_iucv_sndbuf_work(struct work_struct *work)
-{
-       struct hvc_iucv_private *priv;
-
-       priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work);
-       if (!priv)
-               return;
-
-       spin_lock_bh(&priv->lock);
-       hvc_iucv_send(priv);
-       spin_unlock_bh(&priv->lock);
-}
-
-/**
- * hvc_iucv_put_chars() - HVC put_chars operation.
- * @vtermno:   HVC virtual terminal number.
- * @buf:       Pointer to an buffer to read data from
- * @count:     Size of buffer available for reading
- *
- * The HVC thread calls this method to write characters to the back-end.
- * The function calls hvc_iucv_queue() to queue terminal data for sending.
- *
- * Locking:    The method gets called under an irqsave() spinlock; and
- *             locks struct hvc_iucv_private->lock.
- */
-static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
-{
-       struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
-       int queued;
-
-       if (count <= 0)
-               return 0;
-
-       if (!priv)
-               return -ENODEV;
-
-       spin_lock(&priv->lock);
-       queued = hvc_iucv_queue(priv, buf, count);
-       spin_unlock(&priv->lock);
-
-       return queued;
-}
-
-/**
- * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time.
- * @hp:        Pointer to the HVC device (struct hvc_struct)
- * @id:        Additional data (originally passed to hvc_alloc): the index of an struct
- *     hvc_iucv_private instance.
- *
- * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private
- * instance that is derived from @id. Always returns 0.
- *
- * Locking:    struct hvc_iucv_private->lock, spin_lock_bh
- */
-static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id)
-{
-       struct hvc_iucv_private *priv;
-
-       priv = hvc_iucv_get_private(id);
-       if (!priv)
-               return 0;
-
-       spin_lock_bh(&priv->lock);
-       priv->tty_state = TTY_OPENED;
-       spin_unlock_bh(&priv->lock);
-
-       return 0;
-}
-
-/**
- * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance.
- * @priv:      Pointer to the struct hvc_iucv_private instance.
- */
-static void hvc_iucv_cleanup(struct hvc_iucv_private *priv)
-{
-       destroy_tty_buffer_list(&priv->tty_outqueue);
-       destroy_tty_buffer_list(&priv->tty_inqueue);
-
-       priv->tty_state = TTY_CLOSED;
-       priv->iucv_state = IUCV_DISCONN;
-
-       priv->sndbuf_len = 0;
-}
-
-/**
- * tty_outqueue_empty() - Test if the tty outq is empty
- * @priv:      Pointer to struct hvc_iucv_private instance.
- */
-static inline int tty_outqueue_empty(struct hvc_iucv_private *priv)
-{
-       int rc;
-
-       spin_lock_bh(&priv->lock);
-       rc = list_empty(&priv->tty_outqueue);
-       spin_unlock_bh(&priv->lock);
-
-       return rc;
-}
-
-/**
- * flush_sndbuf_sync() - Flush send buffer and wait for completion
- * @priv:      Pointer to struct hvc_iucv_private instance.
- *
- * The routine cancels a pending sndbuf work, calls hvc_iucv_send()
- * to flush any buffered terminal output data and waits for completion.
- */
-static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
-{
-       int sync_wait;
-
-       cancel_delayed_work_sync(&priv->sndbuf_work);
-
-       spin_lock_bh(&priv->lock);
-       hvc_iucv_send(priv);            /* force sending buffered data */
-       sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */
-       spin_unlock_bh(&priv->lock);
-
-       if (sync_wait)
-               wait_event_timeout(priv->sndbuf_waitq,
-                                  tty_outqueue_empty(priv), HZ/10);
-}
-
-/**
- * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up
- * @priv:      Pointer to hvc_iucv_private structure
- *
- * This routine severs an existing IUCV communication path and hangs
- * up the underlying HVC terminal device.
- * The hang-up occurs only if an IUCV communication path is established;
- * otherwise there is no need to hang up the terminal device.
- *
- * The IUCV HVC hang-up is separated into two steps:
- * 1. After the IUCV path has been severed, the iucv_state is set to
- *    IUCV_SEVERED.
- * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the
- *    IUCV_SEVERED state causes the tty hang-up in the HVC layer.
- *
- * If the tty has not yet been opened, clean up the hvc_iucv_private
- * structure to allow re-connects.
- * If the tty has been opened, let get_chars() return -EPIPE to signal
- * the HVC layer to hang up the tty and, if so, wake up the HVC thread
- * to call get_chars()...
- *
- * Special notes on hanging up a HVC terminal instantiated as console:
- * Hang-up:    1. do_tty_hangup() replaces file ops (= hung_up_tty_fops)
- *             2. do_tty_hangup() calls tty->ops->close() for console_filp
- *                     => no hangup notifier is called by HVC (default)
- *             2. hvc_close() returns because of tty_hung_up_p(filp)
- *                     => no delete notifier is called!
- * Finally, the back-end is not being notified, thus, the tty session is
- * kept active (TTY_OPEN) to be ready for re-connects.
- *
- * Locking:    spin_lock(&priv->lock) w/o disabling bh
- */
-static void hvc_iucv_hangup(struct hvc_iucv_private *priv)
-{
-       struct iucv_path *path;
-
-       path = NULL;
-       spin_lock(&priv->lock);
-       if (priv->iucv_state == IUCV_CONNECTED) {
-               path = priv->path;
-               priv->path = NULL;
-               priv->iucv_state = IUCV_SEVERED;
-               if (priv->tty_state == TTY_CLOSED)
-                       hvc_iucv_cleanup(priv);
-               else
-                       /* console is special (see above) */
-                       if (priv->is_console) {
-                               hvc_iucv_cleanup(priv);
-                               priv->tty_state = TTY_OPENED;
-                       } else
-                               hvc_kick();
-       }
-       spin_unlock(&priv->lock);
-
-       /* finally sever path (outside of priv->lock due to lock ordering) */
-       if (path) {
-               iucv_path_sever(path, NULL);
-               iucv_path_free(path);
-       }
-}
-
-/**
- * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups.
- * @hp:                Pointer to the HVC device (struct hvc_struct)
- * @id:                Additional data (originally passed to hvc_alloc):
- *             the index of an struct hvc_iucv_private instance.
- *
- * This routine notifies the HVC back-end that a tty hangup (carrier loss,
- * virtual or otherwise) has occured.
- * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup())
- * to keep an existing IUCV communication path established.
- * (Background: vhangup() is called from user space (by getty or login) to
- *             disable writing to the tty by other applications).
- * If the tty has been opened and an established IUCV path has been severed
- * (we caused the tty hangup), the function calls hvc_iucv_cleanup().
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
-{
-       struct hvc_iucv_private *priv;
-
-       priv = hvc_iucv_get_private(id);
-       if (!priv)
-               return;
-
-       flush_sndbuf_sync(priv);
-
-       spin_lock_bh(&priv->lock);
-       /* NOTE: If the hangup was scheduled by ourself (from the iucv
-        *       path_servered callback [IUCV_SEVERED]), we have to clean up
-        *       our structure and to set state to TTY_CLOSED.
-        *       If the tty was hung up otherwise (e.g. vhangup()), then we
-        *       ignore this hangup and keep an established IUCV path open...
-        *       (...the reason is that we are not able to connect back to the
-        *       client if we disconnect on hang up) */
-       priv->tty_state = TTY_CLOSED;
-
-       if (priv->iucv_state == IUCV_SEVERED)
-               hvc_iucv_cleanup(priv);
-       spin_unlock_bh(&priv->lock);
-}
-
-/**
- * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
- * @hp:                Pointer to the HVC device (struct hvc_struct)
- * @id:                Additional data (originally passed to hvc_alloc):
- *             the index of an struct hvc_iucv_private instance.
- *
- * This routine notifies the HVC back-end that the last tty device fd has been
- * closed.  The function calls hvc_iucv_cleanup() to clean up the struct
- * hvc_iucv_private instance.
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
-{
-       struct hvc_iucv_private *priv;
-       struct iucv_path        *path;
-
-       priv = hvc_iucv_get_private(id);
-       if (!priv)
-               return;
-
-       flush_sndbuf_sync(priv);
-
-       spin_lock_bh(&priv->lock);
-       path = priv->path;              /* save reference to IUCV path */
-       priv->path = NULL;
-       hvc_iucv_cleanup(priv);
-       spin_unlock_bh(&priv->lock);
-
-       /* sever IUCV path outside of priv->lock due to lock ordering of:
-        * priv->lock <--> iucv_table_lock */
-       if (path) {
-               iucv_path_sever(path, NULL);
-               iucv_path_free(path);
-       }
-}
-
-/**
- * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID
- * @ipvmid:    Originating z/VM user ID (right padded with blanks)
- *
- * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise
- * non-zero.
- */
-static int hvc_iucv_filter_connreq(u8 ipvmid[8])
-{
-       size_t i;
-
-       /* Note: default policy is ACCEPT if no filter is set */
-       if (!hvc_iucv_filter_size)
-               return 0;
-
-       for (i = 0; i < hvc_iucv_filter_size; i++)
-               if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8))
-                       return 0;
-       return 1;
-}
-
-/**
- * hvc_iucv_path_pending() - IUCV handler to process a connection request.
- * @path:      Pending path (struct iucv_path)
- * @ipvmid:    z/VM system identifier of originator
- * @ipuser:    User specified data for this path
- *             (AF_IUCV: port/service name and originator port)
- *
- * The function uses the @ipuser data to determine if the pending path belongs
- * to a terminal managed by this device driver.
- * If the path belongs to this driver, ensure that the terminal is not accessed
- * multiple times (only one connection to a terminal is allowed).
- * If the terminal is not yet connected, the pending path is accepted and is
- * associated to the appropriate struct hvc_iucv_private instance.
- *
- * Returns 0 if @path belongs to a terminal managed by the this device driver;
- * otherwise returns -ENODEV in order to dispatch this path to other handlers.
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static int hvc_iucv_path_pending(struct iucv_path *path,
-                                 u8 ipvmid[8], u8 ipuser[16])
-{
-       struct hvc_iucv_private *priv;
-       u8 nuser_data[16];
-       u8 vm_user_id[9];
-       int i, rc;
-
-       priv = NULL;
-       for (i = 0; i < hvc_iucv_devices; i++)
-               if (hvc_iucv_table[i] &&
-                   (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) {
-                       priv = hvc_iucv_table[i];
-                       break;
-               }
-       if (!priv)
-               return -ENODEV;
-
-       /* Enforce that ipvmid is allowed to connect to us */
-       read_lock(&hvc_iucv_filter_lock);
-       rc = hvc_iucv_filter_connreq(ipvmid);
-       read_unlock(&hvc_iucv_filter_lock);
-       if (rc) {
-               iucv_path_sever(path, ipuser);
-               iucv_path_free(path);
-               memcpy(vm_user_id, ipvmid, 8);
-               vm_user_id[8] = 0;
-               pr_info("A connection request from z/VM user ID %s "
-                       "was refused\n", vm_user_id);
-               return 0;
-       }
-
-       spin_lock(&priv->lock);
-
-       /* If the terminal is already connected or being severed, then sever
-        * this path to enforce that there is only ONE established communication
-        * path per terminal. */
-       if (priv->iucv_state != IUCV_DISCONN) {
-               iucv_path_sever(path, ipuser);
-               iucv_path_free(path);
-               goto out_path_handled;
-       }
-
-       /* accept path */
-       memcpy(nuser_data, ipuser + 8, 8);  /* remote service (for af_iucv) */
-       memcpy(nuser_data + 8, ipuser, 8);  /* local service  (for af_iucv) */
-       path->msglim = 0xffff;              /* IUCV MSGLIMIT */
-       path->flags &= ~IUCV_IPRMDATA;      /* TODO: use IUCV_IPRMDATA */
-       rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv);
-       if (rc) {
-               iucv_path_sever(path, ipuser);
-               iucv_path_free(path);
-               goto out_path_handled;
-       }
-       priv->path = path;
-       priv->iucv_state = IUCV_CONNECTED;
-
-       /* flush buffered output data... */
-       schedule_delayed_work(&priv->sndbuf_work, 5);
-
-out_path_handled:
-       spin_unlock(&priv->lock);
-       return 0;
-}
-
-/**
- * hvc_iucv_path_severed() - IUCV handler to process a path sever.
- * @path:      Pending path (struct iucv_path)
- * @ipuser:    User specified data for this path
- *             (AF_IUCV: port/service name and originator port)
- *
- * This function calls the hvc_iucv_hangup() function for the
- * respective IUCV HVC terminal.
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
-{
-       struct hvc_iucv_private *priv = path->private;
-
-       hvc_iucv_hangup(priv);
-}
-
-/**
- * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message.
- * @path:      Pending path (struct iucv_path)
- * @msg:       Pointer to the IUCV message
- *
- * The function puts an incoming message on the input queue for later
- * processing (by hvc_iucv_get_chars() / hvc_iucv_write()).
- * If the tty has not yet been opened, the message is rejected.
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static void hvc_iucv_msg_pending(struct iucv_path *path,
-                                struct iucv_message *msg)
-{
-       struct hvc_iucv_private *priv = path->private;
-       struct iucv_tty_buffer *rb;
-
-       /* reject messages that exceed max size of iucv_tty_msg->datalen */
-       if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) {
-               iucv_message_reject(path, msg);
-               return;
-       }
-
-       spin_lock(&priv->lock);
-
-       /* reject messages if tty has not yet been opened */
-       if (priv->tty_state == TTY_CLOSED) {
-               iucv_message_reject(path, msg);
-               goto unlock_return;
-       }
-
-       /* allocate tty buffer to save iucv msg only */
-       rb = alloc_tty_buffer(0, GFP_ATOMIC);
-       if (!rb) {
-               iucv_message_reject(path, msg);
-               goto unlock_return;     /* -ENOMEM */
-       }
-       rb->msg = *msg;
-
-       list_add_tail(&rb->list, &priv->tty_inqueue);
-
-       hvc_kick();     /* wake up hvc thread */
-
-unlock_return:
-       spin_unlock(&priv->lock);
-}
-
-/**
- * hvc_iucv_msg_complete() - IUCV handler to process message completion
- * @path:      Pending path (struct iucv_path)
- * @msg:       Pointer to the IUCV message
- *
- * The function is called upon completion of message delivery to remove the
- * message from the outqueue. Additional delivery information can be found
- * msg->audit: rejected messages (0x040000 (IPADRJCT)), and
- *            purged messages   (0x010000 (IPADPGNR)).
- *
- * Locking:    struct hvc_iucv_private->lock
- */
-static void hvc_iucv_msg_complete(struct iucv_path *path,
-                                 struct iucv_message *msg)
-{
-       struct hvc_iucv_private *priv = path->private;
-       struct iucv_tty_buffer  *ent, *next;
-       LIST_HEAD(list_remove);
-
-       spin_lock(&priv->lock);
-       list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list)
-               if (ent->msg.id == msg->id) {
-                       list_move(&ent->list, &list_remove);
-                       break;
-               }
-       wake_up(&priv->sndbuf_waitq);
-       spin_unlock(&priv->lock);
-       destroy_tty_buffer_list(&list_remove);
-}
-
-/**
- * hvc_iucv_pm_freeze() - Freeze PM callback
- * @dev:       IUVC HVC terminal device
- *
- * Sever an established IUCV communication path and
- * trigger a hang-up of the underlying HVC terminal.
- */
-static int hvc_iucv_pm_freeze(struct device *dev)
-{
-       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
-
-       local_bh_disable();
-       hvc_iucv_hangup(priv);
-       local_bh_enable();
-
-       return 0;
-}
-
-/**
- * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
- * @dev:       IUVC HVC terminal device
- *
- * Wake up the HVC thread to trigger hang-up and respective
- * HVC back-end notifier invocations.
- */
-static int hvc_iucv_pm_restore_thaw(struct device *dev)
-{
-       hvc_kick();
-       return 0;
-}
-
-
-/* HVC operations */
-static const struct hv_ops hvc_iucv_ops = {
-       .get_chars = hvc_iucv_get_chars,
-       .put_chars = hvc_iucv_put_chars,
-       .notifier_add = hvc_iucv_notifier_add,
-       .notifier_del = hvc_iucv_notifier_del,
-       .notifier_hangup = hvc_iucv_notifier_hangup,
-};
-
-/* Suspend / resume device operations */
-static const struct dev_pm_ops hvc_iucv_pm_ops = {
-       .freeze   = hvc_iucv_pm_freeze,
-       .thaw     = hvc_iucv_pm_restore_thaw,
-       .restore  = hvc_iucv_pm_restore_thaw,
-};
-
-/* IUCV HVC device driver */
-static struct device_driver hvc_iucv_driver = {
-       .name = KMSG_COMPONENT,
-       .bus  = &iucv_bus,
-       .pm   = &hvc_iucv_pm_ops,
-};
-
-/**
- * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
- * @id:                        hvc_iucv_table index
- * @is_console:                Flag if the instance is used as Linux console
- *
- * This function allocates a new hvc_iucv_private structure and stores
- * the instance in hvc_iucv_table at index @id.
- * Returns 0 on success; otherwise non-zero.
- */
-static int __init hvc_iucv_alloc(int id, unsigned int is_console)
-{
-       struct hvc_iucv_private *priv;
-       char name[9];
-       int rc;
-
-       priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       spin_lock_init(&priv->lock);
-       INIT_LIST_HEAD(&priv->tty_outqueue);
-       INIT_LIST_HEAD(&priv->tty_inqueue);
-       INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work);
-       init_waitqueue_head(&priv->sndbuf_waitq);
-
-       priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!priv->sndbuf) {
-               kfree(priv);
-               return -ENOMEM;
-       }
-
-       /* set console flag */
-       priv->is_console = is_console;
-
-       /* allocate hvc device */
-       priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /*             PAGE_SIZE */
-                             HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
-       if (IS_ERR(priv->hvc)) {
-               rc = PTR_ERR(priv->hvc);
-               goto out_error_hvc;
-       }
-
-       /* notify HVC thread instead of using polling */
-       priv->hvc->irq_requested = 1;
-
-       /* setup iucv related information */
-       snprintf(name, 9, "lnxhvc%-2d", id);
-       memcpy(priv->srv_name, name, 8);
-       ASCEBC(priv->srv_name, 8);
-
-       /* create and setup device */
-       priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
-       if (!priv->dev) {
-               rc = -ENOMEM;
-               goto out_error_dev;
-       }
-       dev_set_name(priv->dev, "hvc_iucv%d", id);
-       dev_set_drvdata(priv->dev, priv);
-       priv->dev->bus = &iucv_bus;
-       priv->dev->parent = iucv_root;
-       priv->dev->driver = &hvc_iucv_driver;
-       priv->dev->release = (void (*)(struct device *)) kfree;
-       rc = device_register(priv->dev);
-       if (rc) {
-               put_device(priv->dev);
-               goto out_error_dev;
-       }
-
-       hvc_iucv_table[id] = priv;
-       return 0;
-
-out_error_dev:
-       hvc_remove(priv->hvc);
-out_error_hvc:
-       free_page((unsigned long) priv->sndbuf);
-       kfree(priv);
-
-       return rc;
-}
-
-/**
- * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances
- */
-static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
-{
-       hvc_remove(priv->hvc);
-       device_unregister(priv->dev);
-       free_page((unsigned long) priv->sndbuf);
-       kfree(priv);
-}
-
-/**
- * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID
- * @filter:    String containing a comma-separated list of z/VM user IDs
- */
-static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
-{
-       const char *nextdelim, *residual;
-       size_t len;
-
-       nextdelim = strchr(filter, ',');
-       if (nextdelim) {
-               len = nextdelim - filter;
-               residual = nextdelim + 1;
-       } else {
-               len = strlen(filter);
-               residual = filter + len;
-       }
-
-       if (len == 0)
-               return ERR_PTR(-EINVAL);
-
-       /* check for '\n' (if called from sysfs) */
-       if (filter[len - 1] == '\n')
-               len--;
-
-       if (len > 8)
-               return ERR_PTR(-EINVAL);
-
-       /* pad with blanks and save upper case version of user ID */
-       memset(dest, ' ', 8);
-       while (len--)
-               dest[len] = toupper(filter[len]);
-       return residual;
-}
-
-/**
- * hvc_iucv_setup_filter() - Set up z/VM user ID filter
- * @filter:    String consisting of a comma-separated list of z/VM user IDs
- *
- * The function parses the @filter string and creates an array containing
- * the list of z/VM user ID filter entries.
- * Return code 0 means success, -EINVAL if the filter is syntactically
- * incorrect, -ENOMEM if there was not enough memory to allocate the
- * filter list array, or -ENOSPC if too many z/VM user IDs have been specified.
- */
-static int hvc_iucv_setup_filter(const char *val)
-{
-       const char *residual;
-       int err;
-       size_t size, count;
-       void *array, *old_filter;
-
-       count = strlen(val);
-       if (count == 0 || (count == 1 && val[0] == '\n')) {
-               size  = 0;
-               array = NULL;
-               goto out_replace_filter;        /* clear filter */
-       }
-
-       /* count user IDs in order to allocate sufficient memory */
-       size = 1;
-       residual = val;
-       while ((residual = strchr(residual, ',')) != NULL) {
-               residual++;
-               size++;
-       }
-
-       /* check if the specified list exceeds the filter limit */
-       if (size > MAX_VMID_FILTER)
-               return -ENOSPC;
-
-       array = kzalloc(size * 8, GFP_KERNEL);
-       if (!array)
-               return -ENOMEM;
-
-       count = size;
-       residual = val;
-       while (*residual && count) {
-               residual = hvc_iucv_parse_filter(residual,
-                                                array + ((size - count) * 8));
-               if (IS_ERR(residual)) {
-                       err = PTR_ERR(residual);
-                       kfree(array);
-                       goto out_err;
-               }
-               count--;
-       }
-
-out_replace_filter:
-       write_lock_bh(&hvc_iucv_filter_lock);
-       old_filter = hvc_iucv_filter;
-       hvc_iucv_filter_size = size;
-       hvc_iucv_filter = array;
-       write_unlock_bh(&hvc_iucv_filter_lock);
-       kfree(old_filter);
-
-       err = 0;
-out_err:
-       return err;
-}
-
-/**
- * param_set_vmidfilter() - Set z/VM user ID filter parameter
- * @val:       String consisting of a comma-separated list of z/VM user IDs
- * @kp:                Kernel parameter pointing to hvc_iucv_filter array
- *
- * The function sets up the z/VM user ID filter specified as comma-separated
- * list of user IDs in @val.
- * Note: If it is called early in the boot process, @val is stored and
- *      parsed later in hvc_iucv_init().
- */
-static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
-{
-       int rc;
-
-       if (!MACHINE_IS_VM || !hvc_iucv_devices)
-               return -ENODEV;
-
-       if (!val)
-               return -EINVAL;
-
-       rc = 0;
-       if (slab_is_available())
-               rc = hvc_iucv_setup_filter(val);
-       else
-               hvc_iucv_filter_string = val;   /* defer... */
-       return rc;
-}
-
-/**
- * param_get_vmidfilter() - Get z/VM user ID filter
- * @buffer:    Buffer to store z/VM user ID filter,
- *             (buffer size assumption PAGE_SIZE)
- * @kp:                Kernel parameter pointing to the hvc_iucv_filter array
- *
- * The function stores the filter as a comma-separated list of z/VM user IDs
- * in @buffer. Typically, sysfs routines call this function for attr show.
- */
-static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
-{
-       int rc;
-       size_t index, len;
-       void *start, *end;
-
-       if (!MACHINE_IS_VM || !hvc_iucv_devices)
-               return -ENODEV;
-
-       rc = 0;
-       read_lock_bh(&hvc_iucv_filter_lock);
-       for (index = 0; index < hvc_iucv_filter_size; index++) {
-               start = hvc_iucv_filter + (8 * index);
-               end   = memchr(start, ' ', 8);
-               len   = (end) ? end - start : 8;
-               memcpy(buffer + rc, start, len);
-               rc += len;
-               buffer[rc++] = ',';
-       }
-       read_unlock_bh(&hvc_iucv_filter_lock);
-       if (rc)
-               buffer[--rc] = '\0';    /* replace last comma and update rc */
-       return rc;
-}
-
-#define param_check_vmidfilter(name, p) __param_check(name, p, void)
-
-static struct kernel_param_ops param_ops_vmidfilter = {
-       .set = param_set_vmidfilter,
-       .get = param_get_vmidfilter,
-};
-
-/**
- * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
- */
-static int __init hvc_iucv_init(void)
-{
-       int rc;
-       unsigned int i;
-
-       if (!hvc_iucv_devices)
-               return -ENODEV;
-
-       if (!MACHINE_IS_VM) {
-               pr_notice("The z/VM IUCV HVC device driver cannot "
-                          "be used without z/VM\n");
-               rc = -ENODEV;
-               goto out_error;
-       }
-
-       if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) {
-               pr_err("%lu is not a valid value for the hvc_iucv= "
-                       "kernel parameter\n", hvc_iucv_devices);
-               rc = -EINVAL;
-               goto out_error;
-       }
-
-       /* register IUCV HVC device driver */
-       rc = driver_register(&hvc_iucv_driver);
-       if (rc)
-               goto out_error;
-
-       /* parse hvc_iucv_allow string and create z/VM user ID filter list */
-       if (hvc_iucv_filter_string) {
-               rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
-               switch (rc) {
-               case 0:
-                       break;
-               case -ENOMEM:
-                       pr_err("Allocating memory failed with "
-                               "reason code=%d\n", 3);
-                       goto out_error;
-               case -EINVAL:
-                       pr_err("hvc_iucv_allow= does not specify a valid "
-                               "z/VM user ID list\n");
-                       goto out_error;
-               case -ENOSPC:
-                       pr_err("hvc_iucv_allow= specifies too many "
-                               "z/VM user IDs\n");
-                       goto out_error;
-               default:
-                       goto out_error;
-               }
-       }
-
-       hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,
-                                          sizeof(struct iucv_tty_buffer),
-                                          0, 0, NULL);
-       if (!hvc_iucv_buffer_cache) {
-               pr_err("Allocating memory failed with reason code=%d\n", 1);
-               rc = -ENOMEM;
-               goto out_error;
-       }
-
-       hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR,
-                                                   hvc_iucv_buffer_cache);
-       if (!hvc_iucv_mempool) {
-               pr_err("Allocating memory failed with reason code=%d\n", 2);
-               kmem_cache_destroy(hvc_iucv_buffer_cache);
-               rc = -ENOMEM;
-               goto out_error;
-       }
-
-       /* register the first terminal device as console
-        * (must be done before allocating hvc terminal devices) */
-       rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops);
-       if (rc) {
-               pr_err("Registering HVC terminal device as "
-                      "Linux console failed\n");
-               goto out_error_memory;
-       }
-
-       /* allocate hvc_iucv_private structs */
-       for (i = 0; i < hvc_iucv_devices; i++) {
-               rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0);
-               if (rc) {
-                       pr_err("Creating a new HVC terminal device "
-                               "failed with error code=%d\n", rc);
-                       goto out_error_hvc;
-               }
-       }
-
-       /* register IUCV callback handler */
-       rc = iucv_register(&hvc_iucv_handler, 0);
-       if (rc) {
-               pr_err("Registering IUCV handlers failed with error code=%d\n",
-                       rc);
-               goto out_error_hvc;
-       }
-
-       return 0;
-
-out_error_hvc:
-       for (i = 0; i < hvc_iucv_devices; i++)
-               if (hvc_iucv_table[i])
-                       hvc_iucv_destroy(hvc_iucv_table[i]);
-out_error_memory:
-       mempool_destroy(hvc_iucv_mempool);
-       kmem_cache_destroy(hvc_iucv_buffer_cache);
-out_error:
-       if (hvc_iucv_filter)
-               kfree(hvc_iucv_filter);
-       hvc_iucv_devices = 0; /* ensure that we do not provide any device */
-       return rc;
-}
-
-/**
- * hvc_iucv_config() - Parsing of hvc_iucv=  kernel command line parameter
- * @val:       Parameter value (numeric)
- */
-static int __init hvc_iucv_config(char *val)
-{
-        return strict_strtoul(val, 10, &hvc_iucv_devices);
-}
-
-
-device_initcall(hvc_iucv_init);
-__setup("hvc_iucv=", hvc_iucv_config);
-core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
deleted file mode 100644 (file)
index 61c4a61..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * IBM RTAS driver interface to hvc_console.c
- *
- * (C) Copyright IBM Corporation 2001-2005
- * (C) Copyright Red Hat, Inc. 2005
- *
- * Author(s): Maximino Augilar <IBM STI Design Center>
- *         : Ryan S. Arnold <rsa@us.ibm.com>
- *         : Utz Bacher <utz.bacher@de.ibm.com>
- *         : David Woodhouse <dwmw2@infradead.org>
- *
- *    inspired by drivers/char/hvc_console.c
- *    written by Anton Blanchard and Paul Mackerras
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-
-#include <asm/irq.h>
-#include <asm/rtas.h>
-#include "hvc_console.h"
-
-#define hvc_rtas_cookie 0x67781e15
-struct hvc_struct *hvc_rtas_dev;
-
-static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
-static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
-
-static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
-               int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++) {
-               if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i]))
-                       break;
-       }
-
-       return i;
-}
-
-static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
-{
-       int i, c;
-
-       for (i = 0; i < count; i++) {
-               if (rtas_call(rtascons_get_char_token, 0, 2, &c))
-                       break;
-
-               buf[i] = c;
-       }
-
-       return i;
-}
-
-static const struct hv_ops hvc_rtas_get_put_ops = {
-       .get_chars = hvc_rtas_read_console,
-       .put_chars = hvc_rtas_write_console,
-};
-
-static int __init hvc_rtas_init(void)
-{
-       struct hvc_struct *hp;
-
-       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
-               rtascons_put_char_token = rtas_token("put-term-char");
-       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
-               return -EIO;
-
-       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
-               rtascons_get_char_token = rtas_token("get-term-char");
-       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
-               return -EIO;
-
-       BUG_ON(hvc_rtas_dev);
-
-       /* Allocate an hvc_struct for the console device we instantiated
-        * earlier.  Save off hp so that we can return it on exit */
-       hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-
-       hvc_rtas_dev = hp;
-
-       return 0;
-}
-module_init(hvc_rtas_init);
-
-/* This will tear down the tty portion of the driver */
-static void __exit hvc_rtas_exit(void)
-{
-       /* Really the fun isn't over until the worker thread breaks down and
-        * the tty cleans up */
-       if (hvc_rtas_dev)
-               hvc_remove(hvc_rtas_dev);
-}
-module_exit(hvc_rtas_exit);
-
-/* This will happen prior to module init.  There is no tty at this time? */
-static int __init hvc_rtas_console_init(void)
-{
-       rtascons_put_char_token = rtas_token("put-term-char");
-       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
-               return -EIO;
-
-       rtascons_get_char_token = rtas_token("get-term-char");
-       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
-               return -EIO;
-
-       hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops);
-       add_preferred_console("hvc", 0, NULL);
-
-       return 0;
-}
-console_initcall(hvc_rtas_console_init);
diff --git a/drivers/char/hvc_tile.c b/drivers/char/hvc_tile.c
deleted file mode 100644 (file)
index 7a84a05..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- *   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.
- *
- *   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, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- *
- * Tilera TILE Processor hypervisor console
- */
-
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-
-#include <hv/hypervisor.h>
-
-#include "hvc_console.h"
-
-static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
-{
-       return hv_console_write((HV_VirtAddr)buf, count);
-}
-
-static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
-{
-       int i, c;
-
-       for (i = 0; i < count; ++i) {
-               c = hv_console_read_if_ready();
-               if (c < 0)
-                       break;
-               buf[i] = c;
-       }
-
-       return i;
-}
-
-static const struct hv_ops hvc_tile_get_put_ops = {
-       .get_chars = hvc_tile_get_chars,
-       .put_chars = hvc_tile_put_chars,
-};
-
-static int __init hvc_tile_console_init(void)
-{
-       extern void disable_early_printk(void);
-       hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
-       add_preferred_console("hvc", 0, NULL);
-       disable_early_printk();
-       return 0;
-}
-console_initcall(hvc_tile_console_init);
-
-static int __init hvc_tile_init(void)
-{
-       struct hvc_struct *s;
-       s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
-       return IS_ERR(s) ? PTR_ERR(s) : 0;
-}
-device_initcall(hvc_tile_init);
diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c
deleted file mode 100644 (file)
index b0957e6..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * udbg interface to hvc_console.c
- *
- * (C) Copyright David Gibson, IBM Corporation 2008.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/irq.h>
-
-#include <asm/udbg.h>
-
-#include "hvc_console.h"
-
-struct hvc_struct *hvc_udbg_dev;
-
-static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++)
-               udbg_putc(buf[i]);
-
-       return i;
-}
-
-static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
-{
-       int i, c;
-
-       if (!udbg_getc_poll)
-               return 0;
-
-       for (i = 0; i < count; i++) {
-               if ((c = udbg_getc_poll()) == -1)
-                       break;
-               buf[i] = c;
-       }
-
-       return i;
-}
-
-static const struct hv_ops hvc_udbg_ops = {
-       .get_chars = hvc_udbg_get,
-       .put_chars = hvc_udbg_put,
-};
-
-static int __init hvc_udbg_init(void)
-{
-       struct hvc_struct *hp;
-
-       BUG_ON(hvc_udbg_dev);
-
-       hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-
-       hvc_udbg_dev = hp;
-
-       return 0;
-}
-module_init(hvc_udbg_init);
-
-static void __exit hvc_udbg_exit(void)
-{
-       if (hvc_udbg_dev)
-               hvc_remove(hvc_udbg_dev);
-}
-module_exit(hvc_udbg_exit);
-
-static int __init hvc_udbg_console_init(void)
-{
-       hvc_instantiate(0, 0, &hvc_udbg_ops);
-       add_preferred_console("hvc", 0, NULL);
-
-       return 0;
-}
-console_initcall(hvc_udbg_console_init);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
deleted file mode 100644 (file)
index 5e2f52b..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * vio driver interface to hvc_console.c
- *
- * This code was moved here to allow the remaing code to be reused as a
- * generic polling mode with semi-reliable transport driver core to the
- * console and tty subsystems.
- *
- *
- * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
- * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
- * Copyright (C) 2004 IBM Corporation
- *
- * Additional Author(s):
- *  Ryan S. Arnold <rsa@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <asm/hvconsole.h>
-#include <asm/vio.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-
-#include "hvc_console.h"
-
-static const char hvc_driver_name[] = "hvc_console";
-
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
-       {"serial", "hvterm1"},
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
-static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
-{
-       unsigned long got;
-       int i;
-
-       /*
-        * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion
-        * so we play safe and avoid the situation where got > count which could
-        * overload the flip buffer.
-        */
-       if (count < SIZE_VIO_GET_CHARS)
-               return -EAGAIN;
-
-       got = hvc_get_chars(vtermno, buf, count);
-
-       /*
-        * Work around a HV bug where it gives us a null
-        * after every \r.  -- paulus
-        */
-       for (i = 1; i < got; ++i) {
-               if (buf[i] == 0 && buf[i-1] == '\r') {
-                       --got;
-                       if (i < got)
-                               memmove(&buf[i], &buf[i+1],
-                                       got - i);
-               }
-       }
-       return got;
-}
-
-static const struct hv_ops hvc_get_put_ops = {
-       .get_chars = filtered_get_chars,
-       .put_chars = hvc_put_chars,
-       .notifier_add = notifier_add_irq,
-       .notifier_del = notifier_del_irq,
-       .notifier_hangup = notifier_hangup_irq,
-};
-
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
-                               const struct vio_device_id *id)
-{
-       struct hvc_struct *hp;
-
-       /* probed with invalid parameters. */
-       if (!vdev || !id)
-               return -EPERM;
-
-       hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
-                       MAX_VIO_PUT_CHARS);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-       dev_set_drvdata(&vdev->dev, hp);
-
-       return 0;
-}
-
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
-{
-       struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
-
-       return hvc_remove(hp);
-}
-
-static struct vio_driver hvc_vio_driver = {
-       .id_table       = hvc_driver_table,
-       .probe          = hvc_vio_probe,
-       .remove         = __devexit_p(hvc_vio_remove),
-       .driver         = {
-               .name   = hvc_driver_name,
-               .owner  = THIS_MODULE,
-       }
-};
-
-static int __init hvc_vio_init(void)
-{
-       int rc;
-
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return -EIO;
-
-       /* Register as a vio device to receive callbacks */
-       rc = vio_register_driver(&hvc_vio_driver);
-
-       return rc;
-}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
-       vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
-
-/* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
-{
-       struct device_node *vty;
-       int num_found = 0;
-
-       for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
-                       vty = of_find_node_by_name(vty, "vty")) {
-               const uint32_t *vtermno;
-
-               /* We have statically defined space for only a certain number
-                * of console adapters.
-                */
-               if (num_found >= MAX_NR_HVC_CONSOLES) {
-                       of_node_put(vty);
-                       break;
-               }
-
-               vtermno = of_get_property(vty, "reg", NULL);
-               if (!vtermno)
-                       continue;
-
-               if (of_device_is_compatible(vty, "hvterm1")) {
-                       hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
-                       ++num_found;
-               }
-       }
-
-       return num_found;
-}
-console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
deleted file mode 100644 (file)
index 3740e32..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * xen console driver interface to hvc_console.c
- *
- * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <asm/xen/hypervisor.h>
-
-#include <xen/xen.h>
-#include <xen/page.h>
-#include <xen/events.h>
-#include <xen/interface/io/console.h>
-#include <xen/hvc-console.h>
-
-#include "hvc_console.h"
-
-#define HVC_COOKIE   0x58656e /* "Xen" in hex */
-
-static struct hvc_struct *hvc;
-static int xencons_irq;
-
-/* ------------------------------------------------------------------ */
-
-static unsigned long console_pfn = ~0ul;
-
-static inline struct xencons_interface *xencons_interface(void)
-{
-       if (console_pfn == ~0ul)
-               return mfn_to_virt(xen_start_info->console.domU.mfn);
-       else
-               return __va(console_pfn << PAGE_SHIFT);
-}
-
-static inline void notify_daemon(void)
-{
-       /* Use evtchn: this is called early, before irq is set up. */
-       notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
-}
-
-static int __write_console(const char *data, int len)
-{
-       struct xencons_interface *intf = xencons_interface();
-       XENCONS_RING_IDX cons, prod;
-       int sent = 0;
-
-       cons = intf->out_cons;
-       prod = intf->out_prod;
-       mb();                   /* update queue values before going on */
-       BUG_ON((prod - cons) > sizeof(intf->out));
-
-       while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
-               intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
-
-       wmb();                  /* write ring before updating pointer */
-       intf->out_prod = prod;
-
-       if (sent)
-               notify_daemon();
-       return sent;
-}
-
-static int domU_write_console(uint32_t vtermno, const char *data, int len)
-{
-       int ret = len;
-
-       /*
-        * Make sure the whole buffer is emitted, polling if
-        * necessary.  We don't ever want to rely on the hvc daemon
-        * because the most interesting console output is when the
-        * kernel is crippled.
-        */
-       while (len) {
-               int sent = __write_console(data, len);
-               
-               data += sent;
-               len -= sent;
-
-               if (unlikely(len))
-                       HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
-       }
-
-       return ret;
-}
-
-static int domU_read_console(uint32_t vtermno, char *buf, int len)
-{
-       struct xencons_interface *intf = xencons_interface();
-       XENCONS_RING_IDX cons, prod;
-       int recv = 0;
-
-       cons = intf->in_cons;
-       prod = intf->in_prod;
-       mb();                   /* get pointers before reading ring */
-       BUG_ON((prod - cons) > sizeof(intf->in));
-
-       while (cons != prod && recv < len)
-               buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
-
-       mb();                   /* read ring before consuming */
-       intf->in_cons = cons;
-
-       notify_daemon();
-       return recv;
-}
-
-static struct hv_ops domU_hvc_ops = {
-       .get_chars = domU_read_console,
-       .put_chars = domU_write_console,
-       .notifier_add = notifier_add_irq,
-       .notifier_del = notifier_del_irq,
-       .notifier_hangup = notifier_hangup_irq,
-};
-
-static int dom0_read_console(uint32_t vtermno, char *buf, int len)
-{
-       return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
-}
-
-/*
- * Either for a dom0 to write to the system console, or a domU with a
- * debug version of Xen
- */
-static int dom0_write_console(uint32_t vtermno, const char *str, int len)
-{
-       int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
-       if (rc < 0)
-               return 0;
-
-       return len;
-}
-
-static struct hv_ops dom0_hvc_ops = {
-       .get_chars = dom0_read_console,
-       .put_chars = dom0_write_console,
-       .notifier_add = notifier_add_irq,
-       .notifier_del = notifier_del_irq,
-       .notifier_hangup = notifier_hangup_irq,
-};
-
-static int __init xen_hvc_init(void)
-{
-       struct hvc_struct *hp;
-       struct hv_ops *ops;
-
-       if (!xen_pv_domain())
-               return -ENODEV;
-
-       if (xen_initial_domain()) {
-               ops = &dom0_hvc_ops;
-               xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
-       } else {
-               if (!xen_start_info->console.domU.evtchn)
-                       return -ENODEV;
-
-               ops = &domU_hvc_ops;
-               xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
-       }
-       if (xencons_irq < 0)
-               xencons_irq = 0; /* NO_IRQ */
-
-       hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-
-       hvc = hp;
-
-       console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn);
-
-       return 0;
-}
-
-void xen_console_resume(void)
-{
-       if (xencons_irq)
-               rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
-}
-
-static void __exit xen_hvc_fini(void)
-{
-       if (hvc)
-               hvc_remove(hvc);
-}
-
-static int xen_cons_init(void)
-{
-       struct hv_ops *ops;
-
-       if (!xen_pv_domain())
-               return 0;
-
-       if (xen_initial_domain())
-               ops = &dom0_hvc_ops;
-       else
-               ops = &domU_hvc_ops;
-
-       hvc_instantiate(HVC_COOKIE, 0, ops);
-       return 0;
-}
-
-module_init(xen_hvc_init);
-module_exit(xen_hvc_fini);
-console_initcall(xen_cons_init);
-
-#ifdef CONFIG_EARLY_PRINTK
-static void xenboot_write_console(struct console *console, const char *string,
-                                 unsigned len)
-{
-       unsigned int linelen, off = 0;
-       const char *pos;
-
-       dom0_write_console(0, string, len);
-
-       if (xen_initial_domain())
-               return;
-
-       domU_write_console(0, "(early) ", 8);
-       while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
-               linelen = pos-string+off;
-               if (off + linelen > len)
-                       break;
-               domU_write_console(0, string+off, linelen);
-               domU_write_console(0, "\r\n", 2);
-               off += linelen + 1;
-       }
-       if (off < len)
-               domU_write_console(0, string+off, len-off);
-}
-
-struct console xenboot_console = {
-       .name           = "xenboot",
-       .write          = xenboot_write_console,
-       .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
-};
-#endif /* CONFIG_EARLY_PRINTK */
-
-void xen_raw_console_write(const char *str)
-{
-       dom0_write_console(0, str, strlen(str));
-}
-
-void xen_raw_printk(const char *fmt, ...)
-{
-       static char buf[512];
-       va_list ap;
-
-       va_start(ap, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, ap);
-       va_end(ap);
-
-       xen_raw_console_write(buf);
-}
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
deleted file mode 100644 (file)
index bedc6c1..0000000
+++ /dev/null
@@ -1,1604 +0,0 @@
-/*
- * IBM eServer Hypervisor Virtual Console Server Device Driver
- * Copyright (C) 2003, 2004 IBM Corp.
- *  Ryan S. Arnold (rsa@us.ibm.com)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- * Author(s) :  Ryan S. Arnold <rsa@us.ibm.com>
- *
- * This is the device driver for the IBM Hypervisor Virtual Console Server,
- * "hvcs".  The IBM hvcs provides a tty driver interface to allow Linux
- * user space applications access to the system consoles of logically
- * partitioned operating systems, e.g. Linux, running on the same partitioned
- * Power5 ppc64 system.  Physical hardware consoles per partition are not
- * practical on this hardware so system consoles are accessed by this driver
- * using inter-partition firmware interfaces to virtual terminal devices.
- *
- * A vty is known to the HMC as a "virtual serial server adapter".  It is a
- * virtual terminal device that is created by firmware upon partition creation
- * to act as a partitioned OS's console device.
- *
- * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64
- * Linux system upon their creation by the HMC or their exposure during boot.
- * The non-user interactive backend of this driver is implemented as a vio
- * device driver so that it can receive notification of vty-server lifetimes
- * after it registers with the vio bus to handle vty-server probe and remove
- * callbacks.
- *
- * Many vty-servers can be configured to connect to one vty, but a vty can
- * only be actively connected to by a single vty-server, in any manner, at one
- * time.  If the HMC is currently hosting the console for a target Linux
- * partition; attempts to open the tty device to the partition's console using
- * the hvcs on any partition will return -EBUSY with every open attempt until
- * the HMC frees the connection between its vty-server and the desired
- * partition's vty device.  Conversely, a vty-server may only be connected to
- * a single vty at one time even though it may have several configured vty
- * partner possibilities.
- *
- * Firmware does not provide notification of vty partner changes to this
- * driver.  This means that an HMC Super Admin may add or remove partner vtys
- * from a vty-server's partner list but the changes will not be signaled to
- * the vty-server.  Firmware only notifies the driver when a vty-server is
- * added or removed from the system.  To compensate for this deficiency, this
- * driver implements a sysfs update attribute which provides a method for
- * rescanning partner information upon a user's request.
- *
- * Each vty-server, prior to being exposed to this driver is reference counted
- * using the 2.6 Linux kernel kref construct.
- *
- * For direction on installation and usage of this driver please reference
- * Documentation/powerpc/hvcs.txt.
- */
-
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/kref.h>
-#include <linux/kthread.h>
-#include <linux/list.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <asm/hvconsole.h>
-#include <asm/hvcserver.h>
-#include <asm/uaccess.h>
-#include <asm/vio.h>
-
-/*
- * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00).
- * Removed braces around single statements following conditionals.  Removed '=
- * 0' after static int declarations since these default to zero.  Removed
- * list_for_each_safe() and replaced with list_for_each_entry() in
- * hvcs_get_by_index().  The 'safe' version is un-needed now that the driver is
- * using spinlocks.  Changed spin_lock_irqsave() to spin_lock() when locking
- * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int
- * handler.  Initialized hvcs_structs_lock and hvcs_pi_lock to
- * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init().
- * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the
- * list traversals from a deletion.  Removed '= NULL' from pointer declaration
- * statements since they are initialized NULL by default.  Removed wmb()
- * instances from hvcs_try_write().  They probably aren't needed with locking in
- * place.  Added check and cleanup for hvcs_pi_buff = kmalloc() in
- * hvcs_module_init().  Exposed hvcs_struct.index via a sysfs attribute so that
- * the coupling between /dev/hvcs* and a vty-server can be automatically
- * determined.  Moved kobject_put() in hvcs_open outside of the
- * spin_unlock_irqrestore().
- *
- * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it
- * align with how the tty layer always assigns the lowest index available.  This
- * change resulted in a list of ints that denotes which indexes are available.
- * Device additions and removals use the new hvcs_get_index() and
- * hvcs_return_index() helper functions.  The list is created with
- * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list().
- * Without these fixes hotplug vty-server adapter support goes crazy with this
- * driver if the user removes a vty-server adapter.  Moved free_irq() outside of
- * the hvcs_final_close() function in order to get it out of the spinlock.
- * Rearranged hvcs_close().  Cleaned up some printks and did some housekeeping
- * on the changelog.  Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from
- * arch/powerepc/include/asm/hvcserver.h
- *
- * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to
- * prevent possible lockup with realtime scheduling as similarily pointed out by
- * akpm in hvc_console.  Changed resulted in the removal of hvcs_final_close()
- * to reorder cleanup operations and prevent discarding of pending data during
- * an hvcs_close().  Removed spinlock protection of hvcs_struct data members in
- * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed.
- */
-
-#define HVCS_DRIVER_VERSION "1.3.3"
-
-MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
-MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(HVCS_DRIVER_VERSION);
-
-/*
- * Wait this long per iteration while trying to push buffered data to the
- * hypervisor before allowing the tty to complete a close operation.
- */
-#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
-
-/*
- * Since the Linux TTY code does not currently (2-04-2004) support dynamic
- * addition of tty derived devices and we shouldn't allocate thousands of
- * tty_device pointers when the number of vty-server & vty partner connections
- * will most often be much lower than this, we'll arbitrarily allocate
- * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we
- * register the tty_driver. This can be overridden using an insmod parameter.
- */
-#define HVCS_DEFAULT_SERVER_ADAPTERS   64
-
-/*
- * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device
- * nodes as a sanity check.  Theoretically there can be over 1 Billion
- * vty-server & vty partner connections.
- */
-#define HVCS_MAX_SERVER_ADAPTERS       1024
-
-/*
- * We let Linux assign us a major number and we start the minors at zero.  There
- * is no intuitive mapping between minor number and the target vty-server
- * adapter except that each new vty-server adapter is always assigned to the
- * smallest minor number available.
- */
-#define HVCS_MINOR_START       0
-
-/*
- * The hcall interface involves putting 8 chars into each of two registers.
- * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c)
- * by casting char[16] to long[2].  It would work without __ALIGNED__, but a 
- * little (tiny) bit slower because an unaligned load is slower than aligned 
- * load.
- */
-#define __ALIGNED__    __attribute__((__aligned__(8)))
-
-/*
- * How much data can firmware send with each hvc_put_chars()?  Maybe this
- * should be moved into an architecture specific area.
- */
-#define HVCS_BUFF_LEN  16
-
-/*
- * This is the maximum amount of data we'll let the user send us (hvcs_write) at
- * once in a chunk as a sanity check.
- */
-#define HVCS_MAX_FROM_USER     4096
-
-/*
- * Be careful when adding flags to this line discipline.  Don't add anything
- * that will cause echoing or we'll go into recursive loop echoing chars back
- * and forth with the console drivers.
- */
-static struct ktermios hvcs_tty_termios = {
-       .c_iflag = IGNBRK | IGNPAR,
-       .c_oflag = OPOST,
-       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
-       .c_cc = INIT_C_CC,
-       .c_ispeed = 38400,
-       .c_ospeed = 38400
-};
-
-/*
- * This value is used to take the place of a command line parameter when the
- * module is inserted.  It starts as -1 and stays as such if the user doesn't
- * specify a module insmod parameter.  If they DO specify one then it is set to
- * the value of the integer passed in.
- */
-static int hvcs_parm_num_devs = -1;
-module_param(hvcs_parm_num_devs, int, 0);
-
-static const char hvcs_driver_name[] = "hvcs";
-static const char hvcs_device_node[] = "hvcs";
-static const char hvcs_driver_string[]
-       = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
-
-/* Status of partner info rescan triggered via sysfs. */
-static int hvcs_rescan_status;
-
-static struct tty_driver *hvcs_tty_driver;
-
-/*
- * In order to be somewhat sane this driver always associates the hvcs_struct
- * index element with the numerically equal tty->index.  This means that a
- * hotplugged vty-server adapter will always map to the lowest index valued
- * device node.  If vty-servers were hotplug removed from the system and then
- * new ones added the new vty-server may have the largest slot number of all
- * the vty-server adapters in the partition but it may have the lowest dev node
- * index of all the adapters due to the hole left by the hotplug removed
- * adapter.  There are a set of functions provided to get the lowest index for
- * a new device as well as return the index to the list.  This list is allocated
- * with a number of elements equal to the number of device nodes requested when
- * the module was inserted.
- */
-static int *hvcs_index_list;
-
-/*
- * How large is the list?  This is kept for traversal since the list is
- * dynamically created.
- */
-static int hvcs_index_count;
-
-/*
- * Used by the khvcsd to pick up I/O operations when the kernel_thread is
- * already awake but potentially shifted to TASK_INTERRUPTIBLE state.
- */
-static int hvcs_kicked;
-
-/*
- * Use by the kthread construct for task operations like waking the sleeping
- * thread and stopping the kthread.
- */
-static struct task_struct *hvcs_task;
-
-/*
- * We allocate this for the use of all of the hvcs_structs when they fetch
- * partner info.
- */
-static unsigned long *hvcs_pi_buff;
-
-/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */
-static DEFINE_SPINLOCK(hvcs_pi_lock);
-
-/* One vty-server per hvcs_struct */
-struct hvcs_struct {
-       spinlock_t lock;
-
-       /*
-        * This index identifies this hvcs device as the complement to a
-        * specific tty index.
-        */
-       unsigned int index;
-
-       struct tty_struct *tty;
-       int open_count;
-
-       /*
-        * Used to tell the driver kernel_thread what operations need to take
-        * place upon this hvcs_struct instance.
-        */
-       int todo_mask;
-
-       /*
-        * This buffer is required so that when hvcs_write_room() reports that
-        * it can send HVCS_BUFF_LEN characters that it will buffer the full
-        * HVCS_BUFF_LEN characters if need be.  This is essential for opost
-        * writes since they do not do high level buffering and expect to be
-        * able to send what the driver commits to sending buffering
-        * [e.g. tab to space conversions in n_tty.c opost()].
-        */
-       char buffer[HVCS_BUFF_LEN];
-       int chars_in_buffer;
-
-       /*
-        * Any variable below the kref is valid before a tty is connected and
-        * stays valid after the tty is disconnected.  These shouldn't be
-        * whacked until the koject refcount reaches zero though some entries
-        * may be changed via sysfs initiatives.
-        */
-       struct kref kref; /* ref count & hvcs_struct lifetime */
-       int connected; /* is the vty-server currently connected to a vty? */
-       uint32_t p_unit_address; /* partner unit address */
-       uint32_t p_partition_ID; /* partner partition ID */
-       char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
-       struct list_head next; /* list management */
-       struct vio_dev *vdev;
-};
-
-/* Required to back map a kref to its containing object */
-#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-
-static LIST_HEAD(hvcs_structs);
-static DEFINE_SPINLOCK(hvcs_structs_lock);
-
-static void hvcs_unthrottle(struct tty_struct *tty);
-static void hvcs_throttle(struct tty_struct *tty);
-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
-
-static int hvcs_write(struct tty_struct *tty,
-               const unsigned char *buf, int count);
-static int hvcs_write_room(struct tty_struct *tty);
-static int hvcs_chars_in_buffer(struct tty_struct *tty);
-
-static int hvcs_has_pi(struct hvcs_struct *hvcsd);
-static void hvcs_set_pi(struct hvcs_partner_info *pi,
-               struct hvcs_struct *hvcsd);
-static int hvcs_get_pi(struct hvcs_struct *hvcsd);
-static int hvcs_rescan_devices_list(void);
-
-static int hvcs_partner_connect(struct hvcs_struct *hvcsd);
-static void hvcs_partner_free(struct hvcs_struct *hvcsd);
-
-static int hvcs_enable_device(struct hvcs_struct *hvcsd,
-               uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
-
-static int hvcs_open(struct tty_struct *tty, struct file *filp);
-static void hvcs_close(struct tty_struct *tty, struct file *filp);
-static void hvcs_hangup(struct tty_struct * tty);
-
-static int __devinit hvcs_probe(struct vio_dev *dev,
-               const struct vio_device_id *id);
-static int __devexit hvcs_remove(struct vio_dev *dev);
-static int __init hvcs_module_init(void);
-static void __exit hvcs_module_exit(void);
-
-#define HVCS_SCHED_READ        0x00000001
-#define HVCS_QUICK_READ        0x00000002
-#define HVCS_TRY_WRITE 0x00000004
-#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ)
-
-static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
-{
-       return dev_get_drvdata(&viod->dev);
-}
-/* The sysfs interface for the driver and devices */
-
-static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       retval = sprintf(buf, "%X\n", hvcsd->p_unit_address);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return retval;
-}
-static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);
-
-static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return retval;
-}
-static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);
-
-static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf,
-               size_t count)
-{
-       /*
-        * Don't need this feature at the present time because firmware doesn't
-        * yet support multiple partners.
-        */
-       printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n");
-       return -EPERM;
-}
-
-static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return retval;
-}
-
-static DEVICE_ATTR(current_vty,
-       S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);
-
-static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf,
-               size_t count)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-
-       /* writing a '0' to this sysfs entry will result in the disconnect. */
-       if (simple_strtol(buf, NULL, 0) != 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       if (hvcsd->open_count > 0) {
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-               printk(KERN_INFO "HVCS: vterm state unchanged.  "
-                               "The hvcs device node is still in use.\n");
-               return -EPERM;
-       }
-
-       if (hvcsd->connected == 0) {
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-               printk(KERN_INFO "HVCS: vterm state unchanged. The"
-                               " vty-server is not connected to a vty.\n");
-               return -EPERM;
-       }
-
-       hvcs_partner_free(hvcsd);
-       printk(KERN_INFO "HVCS: Closed vty-server@%X and"
-                       " partner vty@%X:%d connection.\n",
-                       hvcsd->vdev->unit_address,
-                       hvcsd->p_unit_address,
-                       (uint32_t)hvcsd->p_partition_ID);
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return count;
-}
-
-static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       retval = sprintf(buf, "%d\n", hvcsd->connected);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return retval;
-}
-static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR,
-               hvcs_vterm_state_show, hvcs_vterm_state_store);
-
-static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct vio_dev *viod = to_vio_dev(dev);
-       struct hvcs_struct *hvcsd = from_vio_dev(viod);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       retval = sprintf(buf, "%d\n", hvcsd->index);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return retval;
-}
-
-static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
-
-static struct attribute *hvcs_attrs[] = {
-       &dev_attr_partner_vtys.attr,
-       &dev_attr_partner_clcs.attr,
-       &dev_attr_current_vty.attr,
-       &dev_attr_vterm_state.attr,
-       &dev_attr_index.attr,
-       NULL,
-};
-
-static struct attribute_group hvcs_attr_group = {
-       .attrs = hvcs_attrs,
-};
-
-static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf)
-{
-       /* A 1 means it is updating, a 0 means it is done updating */
-       return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
-}
-
-static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf,
-               size_t count)
-{
-       if ((simple_strtol(buf, NULL, 0) != 1)
-               && (hvcs_rescan_status != 0))
-               return -EINVAL;
-
-       hvcs_rescan_status = 1;
-       printk(KERN_INFO "HVCS: rescanning partner info for all"
-               " vty-servers.\n");
-       hvcs_rescan_devices_list();
-       hvcs_rescan_status = 0;
-       return count;
-}
-
-static DRIVER_ATTR(rescan,
-       S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store);
-
-static void hvcs_kick(void)
-{
-       hvcs_kicked = 1;
-       wmb();
-       wake_up_process(hvcs_task);
-}
-
-static void hvcs_unthrottle(struct tty_struct *tty)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       hvcsd->todo_mask |= HVCS_SCHED_READ;
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       hvcs_kick();
-}
-
-static void hvcs_throttle(struct tty_struct *tty)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       vio_disable_interrupts(hvcsd->vdev);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-}
-
-/*
- * If the device is being removed we don't have to worry about this interrupt
- * handler taking any further interrupts because they are disabled which means
- * the hvcs_struct will always be valid in this handler.
- */
-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
-{
-       struct hvcs_struct *hvcsd = dev_instance;
-
-       spin_lock(&hvcsd->lock);
-       vio_disable_interrupts(hvcsd->vdev);
-       hvcsd->todo_mask |= HVCS_SCHED_READ;
-       spin_unlock(&hvcsd->lock);
-       hvcs_kick();
-
-       return IRQ_HANDLED;
-}
-
-/* This function must be called with the hvcsd->lock held */
-static void hvcs_try_write(struct hvcs_struct *hvcsd)
-{
-       uint32_t unit_address = hvcsd->vdev->unit_address;
-       struct tty_struct *tty = hvcsd->tty;
-       int sent;
-
-       if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
-               /* won't send partial writes */
-               sent = hvc_put_chars(unit_address,
-                               &hvcsd->buffer[0],
-                               hvcsd->chars_in_buffer );
-               if (sent > 0) {
-                       hvcsd->chars_in_buffer = 0;
-                       /* wmb(); */
-                       hvcsd->todo_mask &= ~(HVCS_TRY_WRITE);
-                       /* wmb(); */
-
-                       /*
-                        * We are still obligated to deliver the data to the
-                        * hypervisor even if the tty has been closed because
-                        * we commited to delivering it.  But don't try to wake
-                        * a non-existent tty.
-                        */
-                       if (tty) {
-                               tty_wakeup(tty);
-                       }
-               }
-       }
-}
-
-static int hvcs_io(struct hvcs_struct *hvcsd)
-{
-       uint32_t unit_address;
-       struct tty_struct *tty;
-       char buf[HVCS_BUFF_LEN] __ALIGNED__;
-       unsigned long flags;
-       int got = 0;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       unit_address = hvcsd->vdev->unit_address;
-       tty = hvcsd->tty;
-
-       hvcs_try_write(hvcsd);
-
-       if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
-               hvcsd->todo_mask &= ~(HVCS_READ_MASK);
-               goto bail;
-       } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
-               goto bail;
-
-       /* remove the read masks */
-       hvcsd->todo_mask &= ~(HVCS_READ_MASK);
-
-       if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
-               got = hvc_get_chars(unit_address,
-                               &buf[0],
-                               HVCS_BUFF_LEN);
-               tty_insert_flip_string(tty, buf, got);
-       }
-
-       /* Give the TTY time to process the data we just sent. */
-       if (got)
-               hvcsd->todo_mask |= HVCS_QUICK_READ;
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       /* This is synch because tty->low_latency == 1 */
-       if(got)
-               tty_flip_buffer_push(tty);
-
-       if (!got) {
-               /* Do this _after_ the flip_buffer_push */
-               spin_lock_irqsave(&hvcsd->lock, flags);
-               vio_enable_interrupts(hvcsd->vdev);
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-       }
-
-       return hvcsd->todo_mask;
-
- bail:
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       return hvcsd->todo_mask;
-}
-
-static int khvcsd(void *unused)
-{
-       struct hvcs_struct *hvcsd;
-       int hvcs_todo_mask;
-
-       __set_current_state(TASK_RUNNING);
-
-       do {
-               hvcs_todo_mask = 0;
-               hvcs_kicked = 0;
-               wmb();
-
-               spin_lock(&hvcs_structs_lock);
-               list_for_each_entry(hvcsd, &hvcs_structs, next) {
-                       hvcs_todo_mask |= hvcs_io(hvcsd);
-               }
-               spin_unlock(&hvcs_structs_lock);
-
-               /*
-                * If any of the hvcs adapters want to try a write or quick read
-                * don't schedule(), yield a smidgen then execute the hvcs_io
-                * thread again for those that want the write.
-                */
-                if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) {
-                       yield();
-                       continue;
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!hvcs_kicked)
-                       schedule();
-               __set_current_state(TASK_RUNNING);
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-static struct vio_device_id hvcs_driver_table[] __devinitdata= {
-       {"serial-server", "hvterm2"},
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
-
-static void hvcs_return_index(int index)
-{
-       /* Paranoia check */
-       if (!hvcs_index_list)
-               return;
-       if (index < 0 || index >= hvcs_index_count)
-               return;
-       if (hvcs_index_list[index] == -1)
-               return;
-       else
-               hvcs_index_list[index] = -1;
-}
-
-/* callback when the kref ref count reaches zero */
-static void destroy_hvcs_struct(struct kref *kref)
-{
-       struct hvcs_struct *hvcsd = from_kref(kref);
-       struct vio_dev *vdev;
-       unsigned long flags;
-
-       spin_lock(&hvcs_structs_lock);
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       /* the list_del poisons the pointers */
-       list_del(&(hvcsd->next));
-
-       if (hvcsd->connected == 1) {
-               hvcs_partner_free(hvcsd);
-               printk(KERN_INFO "HVCS: Closed vty-server@%X and"
-                               " partner vty@%X:%d connection.\n",
-                               hvcsd->vdev->unit_address,
-                               hvcsd->p_unit_address,
-                               (uint32_t)hvcsd->p_partition_ID);
-       }
-       printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n",
-                       hvcsd->vdev->unit_address);
-
-       vdev = hvcsd->vdev;
-       hvcsd->vdev = NULL;
-
-       hvcsd->p_unit_address = 0;
-       hvcsd->p_partition_ID = 0;
-       hvcs_return_index(hvcsd->index);
-       memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       spin_unlock(&hvcs_structs_lock);
-
-       sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
-
-       kfree(hvcsd);
-}
-
-static int hvcs_get_index(void)
-{
-       int i;
-       /* Paranoia check */
-       if (!hvcs_index_list) {
-               printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n");
-               return -EFAULT;
-       }
-       /* Find the numerically lowest first free index. */
-       for(i = 0; i < hvcs_index_count; i++) {
-               if (hvcs_index_list[i] == -1) {
-                       hvcs_index_list[i] = 0;
-                       return i;
-               }
-       }
-       return -1;
-}
-
-static int __devinit hvcs_probe(
-       struct vio_dev *dev,
-       const struct vio_device_id *id)
-{
-       struct hvcs_struct *hvcsd;
-       int index;
-       int retval;
-
-       if (!dev || !id) {
-               printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
-               return -EPERM;
-       }
-
-       /* early to avoid cleanup on failure */
-       index = hvcs_get_index();
-       if (index < 0) {
-               return -EFAULT;
-       }
-
-       hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
-       if (!hvcsd)
-               return -ENODEV;
-
-
-       spin_lock_init(&hvcsd->lock);
-       /* Automatically incs the refcount the first time */
-       kref_init(&hvcsd->kref);
-
-       hvcsd->vdev = dev;
-       dev_set_drvdata(&dev->dev, hvcsd);
-
-       hvcsd->index = index;
-
-       /* hvcsd->index = ++hvcs_struct_count; */
-       hvcsd->chars_in_buffer = 0;
-       hvcsd->todo_mask = 0;
-       hvcsd->connected = 0;
-
-       /*
-        * This will populate the hvcs_struct's partner info fields for the
-        * first time.
-        */
-       if (hvcs_get_pi(hvcsd)) {
-               printk(KERN_ERR "HVCS: Failed to fetch partner"
-                       " info for vty-server@%X on device probe.\n",
-                       hvcsd->vdev->unit_address);
-       }
-
-       /*
-        * If a user app opens a tty that corresponds to this vty-server before
-        * the hvcs_struct has been added to the devices list then the user app
-        * will get -ENODEV.
-        */
-       spin_lock(&hvcs_structs_lock);
-       list_add_tail(&(hvcsd->next), &hvcs_structs);
-       spin_unlock(&hvcs_structs_lock);
-
-       retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
-       if (retval) {
-               printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
-                      hvcsd->vdev->unit_address);
-               return retval;
-       }
-
-       printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
-
-       /*
-        * DON'T enable interrupts here because there is no user to receive the
-        * data.
-        */
-       return 0;
-}
-
-static int __devexit hvcs_remove(struct vio_dev *dev)
-{
-       struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
-       unsigned long flags;
-       struct tty_struct *tty;
-
-       if (!hvcsd)
-               return -ENODEV;
-
-       /* By this time the vty-server won't be getting any more interrupts */
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       tty = hvcsd->tty;
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-       /*
-        * Let the last holder of this object cause it to be removed, which
-        * would probably be tty_hangup below.
-        */
-       kref_put(&hvcsd->kref, destroy_hvcs_struct);
-
-       /*
-        * The hangup is a scheduled function which will auto chain call
-        * hvcs_hangup.  The tty should always be valid at this time unless a
-        * simultaneous tty close already cleaned up the hvcs_struct.
-        */
-       if (tty)
-               tty_hangup(tty);
-
-       printk(KERN_INFO "HVCS: vty-server@%X removed from the"
-                       " vio bus.\n", dev->unit_address);
-       return 0;
-};
-
-static struct vio_driver hvcs_vio_driver = {
-       .id_table       = hvcs_driver_table,
-       .probe          = hvcs_probe,
-       .remove         = __devexit_p(hvcs_remove),
-       .driver         = {
-               .name   = hvcs_driver_name,
-               .owner  = THIS_MODULE,
-       }
-};
-
-/* Only called from hvcs_get_pi please */
-static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd)
-{
-       int clclength;
-
-       hvcsd->p_unit_address = pi->unit_address;
-       hvcsd->p_partition_ID  = pi->partition_ID;
-       clclength = strlen(&pi->location_code[0]);
-       if (clclength > HVCS_CLC_LENGTH)
-               clclength = HVCS_CLC_LENGTH;
-
-       /* copy the null-term char too */
-       strncpy(&hvcsd->p_location_code[0],
-                       &pi->location_code[0], clclength + 1);
-}
-
-/*
- * Traverse the list and add the partner info that is found to the hvcs_struct
- * struct entry. NOTE: At this time I know that partner info will return a
- * single entry but in the future there may be multiple partner info entries per
- * vty-server and you'll want to zero out that list and reset it.  If for some
- * reason you have an old version of this driver but there IS more than one
- * partner info then hvcsd->p_* will hold the last partner info data from the
- * firmware query.  A good way to update this code would be to replace the three
- * partner info fields in hvcs_struct with a list of hvcs_partner_info
- * instances.
- *
- * This function must be called with the hvcsd->lock held.
- */
-static int hvcs_get_pi(struct hvcs_struct *hvcsd)
-{
-       struct hvcs_partner_info *pi;
-       uint32_t unit_address = hvcsd->vdev->unit_address;
-       struct list_head head;
-       int retval;
-
-       spin_lock(&hvcs_pi_lock);
-       if (!hvcs_pi_buff) {
-               spin_unlock(&hvcs_pi_lock);
-               return -EFAULT;
-       }
-       retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff);
-       spin_unlock(&hvcs_pi_lock);
-       if (retval) {
-               printk(KERN_ERR "HVCS: Failed to fetch partner"
-                       " info for vty-server@%x.\n", unit_address);
-               return retval;
-       }
-
-       /* nixes the values if the partner vty went away */
-       hvcsd->p_unit_address = 0;
-       hvcsd->p_partition_ID = 0;
-
-       list_for_each_entry(pi, &head, node)
-               hvcs_set_pi(pi, hvcsd);
-
-       hvcs_free_partner_info(&head);
-       return 0;
-}
-
-/*
- * This function is executed by the driver "rescan" sysfs entry.  It shouldn't
- * be executed elsewhere, in order to prevent deadlock issues.
- */
-static int hvcs_rescan_devices_list(void)
-{
-       struct hvcs_struct *hvcsd;
-       unsigned long flags;
-
-       spin_lock(&hvcs_structs_lock);
-
-       list_for_each_entry(hvcsd, &hvcs_structs, next) {
-               spin_lock_irqsave(&hvcsd->lock, flags);
-               hvcs_get_pi(hvcsd);
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-       }
-
-       spin_unlock(&hvcs_structs_lock);
-
-       return 0;
-}
-
-/*
- * Farm this off into its own function because it could be more complex once
- * multiple partners support is added. This function should be called with
- * the hvcsd->lock held.
- */
-static int hvcs_has_pi(struct hvcs_struct *hvcsd)
-{
-       if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID))
-               return 0;
-       return 1;
-}
-
-/*
- * NOTE: It is possible that the super admin removed a partner vty and then
- * added a different vty as the new partner.
- *
- * This function must be called with the hvcsd->lock held.
- */
-static int hvcs_partner_connect(struct hvcs_struct *hvcsd)
-{
-       int retval;
-       unsigned int unit_address = hvcsd->vdev->unit_address;
-
-       /*
-        * If there wasn't any pi when the device was added it doesn't meant
-        * there isn't any now.  This driver isn't notified when a new partner
-        * vty is added to a vty-server so we discover changes on our own.
-        * Please see comments in hvcs_register_connection() for justification
-        * of this bizarre code.
-        */
-       retval = hvcs_register_connection(unit_address,
-                       hvcsd->p_partition_ID,
-                       hvcsd->p_unit_address);
-       if (!retval) {
-               hvcsd->connected = 1;
-               return 0;
-       } else if (retval != -EINVAL)
-               return retval;
-
-       /*
-        * As per the spec re-get the pi and try again if -EINVAL after the
-        * first connection attempt.
-        */
-       if (hvcs_get_pi(hvcsd))
-               return -ENOMEM;
-
-       if (!hvcs_has_pi(hvcsd))
-               return -ENODEV;
-
-       retval = hvcs_register_connection(unit_address,
-                       hvcsd->p_partition_ID,
-                       hvcsd->p_unit_address);
-       if (retval != -EINVAL) {
-               hvcsd->connected = 1;
-               return retval;
-       }
-
-       /*
-        * EBUSY is the most likely scenario though the vty could have been
-        * removed or there really could be an hcall error due to the parameter
-        * data but thanks to ambiguous firmware return codes we can't really
-        * tell.
-        */
-       printk(KERN_INFO "HVCS: vty-server or partner"
-                       " vty is busy.  Try again later.\n");
-       return -EBUSY;
-}
-
-/* This function must be called with the hvcsd->lock held */
-static void hvcs_partner_free(struct hvcs_struct *hvcsd)
-{
-       int retval;
-       do {
-               retval = hvcs_free_connection(hvcsd->vdev->unit_address);
-       } while (retval == -EBUSY);
-       hvcsd->connected = 0;
-}
-
-/* This helper function must be called WITHOUT the hvcsd->lock held */
-static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
-               unsigned int irq, struct vio_dev *vdev)
-{
-       unsigned long flags;
-       int rc;
-
-       /*
-        * It is possible that the vty-server was removed between the time that
-        * the conn was registered and now.
-        */
-       if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
-                               IRQF_DISABLED, "ibmhvcs", hvcsd))) {
-               /*
-                * It is possible the vty-server was removed after the irq was
-                * requested but before we have time to enable interrupts.
-                */
-               if (vio_enable_interrupts(vdev) == H_SUCCESS)
-                       return 0;
-               else {
-                       printk(KERN_ERR "HVCS: int enable failed for"
-                                       " vty-server@%X.\n", unit_address);
-                       free_irq(irq, hvcsd);
-               }
-       } else
-               printk(KERN_ERR "HVCS: irq req failed for"
-                               " vty-server@%X.\n", unit_address);
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       hvcs_partner_free(hvcsd);
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-       return rc;
-
-}
-
-/*
- * This always increments the kref ref count if the call is successful.
- * Please remember to dec when you are done with the instance.
- *
- * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
- * calling this function or you will get deadlock.
- */
-static struct hvcs_struct *hvcs_get_by_index(int index)
-{
-       struct hvcs_struct *hvcsd = NULL;
-       unsigned long flags;
-
-       spin_lock(&hvcs_structs_lock);
-       /* We can immediately discard OOB requests */
-       if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
-               list_for_each_entry(hvcsd, &hvcs_structs, next) {
-                       spin_lock_irqsave(&hvcsd->lock, flags);
-                       if (hvcsd->index == index) {
-                               kref_get(&hvcsd->kref);
-                               spin_unlock_irqrestore(&hvcsd->lock, flags);
-                               spin_unlock(&hvcs_structs_lock);
-                               return hvcsd;
-                       }
-                       spin_unlock_irqrestore(&hvcsd->lock, flags);
-               }
-               hvcsd = NULL;
-       }
-
-       spin_unlock(&hvcs_structs_lock);
-       return hvcsd;
-}
-
-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
-{
-       struct hvcs_struct *hvcsd;
-       int rc, retval = 0;
-       unsigned long flags;
-       unsigned int irq;
-       struct vio_dev *vdev;
-       unsigned long unit_address;
-
-       if (tty->driver_data)
-               goto fast_open;
-
-       /*
-        * Is there a vty-server that shares the same index?
-        * This function increments the kref index.
-        */
-       if (!(hvcsd = hvcs_get_by_index(tty->index))) {
-               printk(KERN_WARNING "HVCS: open failed, no device associated"
-                               " with tty->index %d.\n", tty->index);
-               return -ENODEV;
-       }
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       if (hvcsd->connected == 0)
-               if ((retval = hvcs_partner_connect(hvcsd)))
-                       goto error_release;
-
-       hvcsd->open_count = 1;
-       hvcsd->tty = tty;
-       tty->driver_data = hvcsd;
-
-       memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
-
-       /*
-        * Save these in the spinlock for the enable operations that need them
-        * outside of the spinlock.
-        */
-       irq = hvcsd->vdev->irq;
-       vdev = hvcsd->vdev;
-       unit_address = hvcsd->vdev->unit_address;
-
-       hvcsd->todo_mask |= HVCS_SCHED_READ;
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-       /*
-        * This must be done outside of the spinlock because it requests irqs
-        * and will grab the spinlock and free the connection if it fails.
-        */
-       if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-               kref_put(&hvcsd->kref, destroy_hvcs_struct);
-               printk(KERN_WARNING "HVCS: enable device failed.\n");
-               return rc;
-       }
-
-       goto open_success;
-
-fast_open:
-       hvcsd = tty->driver_data;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       kref_get(&hvcsd->kref);
-       hvcsd->open_count++;
-       hvcsd->todo_mask |= HVCS_SCHED_READ;
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-open_success:
-       hvcs_kick();
-
-       printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
-               hvcsd->vdev->unit_address );
-
-       return 0;
-
-error_release:
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       kref_put(&hvcsd->kref, destroy_hvcs_struct);
-
-       printk(KERN_WARNING "HVCS: partner connect failed.\n");
-       return retval;
-}
-
-static void hvcs_close(struct tty_struct *tty, struct file *filp)
-{
-       struct hvcs_struct *hvcsd;
-       unsigned long flags;
-       int irq = NO_IRQ;
-
-       /*
-        * Is someone trying to close the file associated with this device after
-        * we have hung up?  If so tty->driver_data wouldn't be valid.
-        */
-       if (tty_hung_up_p(filp))
-               return;
-
-       /*
-        * No driver_data means that this close was probably issued after a
-        * failed hvcs_open by the tty layer's release_dev() api and we can just
-        * exit cleanly.
-        */
-       if (!tty->driver_data)
-               return;
-
-       hvcsd = tty->driver_data;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       if (--hvcsd->open_count == 0) {
-
-               vio_disable_interrupts(hvcsd->vdev);
-
-               /*
-                * NULL this early so that the kernel_thread doesn't try to
-                * execute any operations on the TTY even though it is obligated
-                * to deliver any pending I/O to the hypervisor.
-                */
-               hvcsd->tty = NULL;
-
-               irq = hvcsd->vdev->irq;
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-               tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
-
-               /*
-                * This line is important because it tells hvcs_open that this
-                * device needs to be re-configured the next time hvcs_open is
-                * called.
-                */
-               tty->driver_data = NULL;
-
-               free_irq(irq, hvcsd);
-               kref_put(&hvcsd->kref, destroy_hvcs_struct);
-               return;
-       } else if (hvcsd->open_count < 0) {
-               printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
-                               " is missmanaged.\n",
-               hvcsd->vdev->unit_address, hvcsd->open_count);
-       }
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       kref_put(&hvcsd->kref, destroy_hvcs_struct);
-}
-
-static void hvcs_hangup(struct tty_struct * tty)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-       unsigned long flags;
-       int temp_open_count;
-       int irq = NO_IRQ;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-       /* Preserve this so that we know how many kref refs to put */
-       temp_open_count = hvcsd->open_count;
-
-       /*
-        * Don't kref put inside the spinlock because the destruction
-        * callback may use the spinlock and it may get called before the
-        * spinlock has been released.
-        */
-       vio_disable_interrupts(hvcsd->vdev);
-
-       hvcsd->todo_mask = 0;
-
-       /* I don't think the tty needs the hvcs_struct pointer after a hangup */
-       hvcsd->tty->driver_data = NULL;
-       hvcsd->tty = NULL;
-
-       hvcsd->open_count = 0;
-
-       /* This will drop any buffered data on the floor which is OK in a hangup
-        * scenario. */
-       memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
-       hvcsd->chars_in_buffer = 0;
-
-       irq = hvcsd->vdev->irq;
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-       free_irq(irq, hvcsd);
-
-       /*
-        * We need to kref_put() for every open_count we have since the
-        * tty_hangup() function doesn't invoke a close per open connection on a
-        * non-console device.
-        */
-       while(temp_open_count) {
-               --temp_open_count;
-               /*
-                * The final put will trigger destruction of the hvcs_struct.
-                * NOTE:  If this hangup was signaled from user space then the
-                * final put will never happen.
-                */
-               kref_put(&hvcsd->kref, destroy_hvcs_struct);
-       }
-}
-
-/*
- * NOTE: This is almost always from_user since user level apps interact with the
- * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by
- * hvcs_remove (which removes the target device and executes tty_hangup()) that
- * tty_hangup will allow hvcs_write time to complete execution before it
- * terminates our device.
- */
-static int hvcs_write(struct tty_struct *tty,
-               const unsigned char *buf, int count)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-       unsigned int unit_address;
-       const unsigned char *charbuf;
-       unsigned long flags;
-       int total_sent = 0;
-       int tosend = 0;
-       int result = 0;
-
-       /*
-        * If they don't check the return code off of their open they may
-        * attempt this even if there is no connected device.
-        */
-       if (!hvcsd)
-               return -ENODEV;
-
-       /* Reasonable size to prevent user level flooding */
-       if (count > HVCS_MAX_FROM_USER) {
-               printk(KERN_WARNING "HVCS write: count being truncated to"
-                               " HVCS_MAX_FROM_USER.\n");
-               count = HVCS_MAX_FROM_USER;
-       }
-
-       charbuf = buf;
-
-       spin_lock_irqsave(&hvcsd->lock, flags);
-
-       /*
-        * Somehow an open succedded but the device was removed or the
-        * connection terminated between the vty-server and partner vty during
-        * the middle of a write operation?  This is a crummy place to do this
-        * but we want to keep it all in the spinlock.
-        */
-       if (hvcsd->open_count <= 0) {
-               spin_unlock_irqrestore(&hvcsd->lock, flags);
-               return -ENODEV;
-       }
-
-       unit_address = hvcsd->vdev->unit_address;
-
-       while (count > 0) {
-               tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer));
-               /*
-                * No more space, this probably means that the last call to
-                * hvcs_write() didn't succeed and the buffer was filled up.
-                */
-               if (!tosend)
-                       break;
-
-               memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer],
-                               &charbuf[total_sent],
-                               tosend);
-
-               hvcsd->chars_in_buffer += tosend;
-
-               result = 0;
-
-               /*
-                * If this is true then we don't want to try writing to the
-                * hypervisor because that is the kernel_threads job now.  We'll
-                * just add to the buffer.
-                */
-               if (!(hvcsd->todo_mask & HVCS_TRY_WRITE))
-                       /* won't send partial writes */
-                       result = hvc_put_chars(unit_address,
-                                       &hvcsd->buffer[0],
-                                       hvcsd->chars_in_buffer);
-
-               /*
-                * Since we know we have enough room in hvcsd->buffer for
-                * tosend we record that it was sent regardless of whether the
-                * hypervisor actually took it because we have it buffered.
-                */
-               total_sent+=tosend;
-               count-=tosend;
-               if (result == 0) {
-                       hvcsd->todo_mask |= HVCS_TRY_WRITE;
-                       hvcs_kick();
-                       break;
-               }
-
-               hvcsd->chars_in_buffer = 0;
-               /*
-                * Test after the chars_in_buffer reset otherwise this could
-                * deadlock our writes if hvc_put_chars fails.
-                */
-               if (result < 0)
-                       break;
-       }
-
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-
-       if (result == -1)
-               return -EIO;
-       else
-               return total_sent;
-}
-
-/*
- * This is really asking how much can we guarentee that we can send or that we
- * absolutely WILL BUFFER if we can't send it.  This driver MUST honor the
- * return value, hence the reason for hvcs_struct buffering.
- */
-static int hvcs_write_room(struct tty_struct *tty)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-
-       if (!hvcsd || hvcsd->open_count <= 0)
-               return 0;
-
-       return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
-}
-
-static int hvcs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct hvcs_struct *hvcsd = tty->driver_data;
-
-       return hvcsd->chars_in_buffer;
-}
-
-static const struct tty_operations hvcs_ops = {
-       .open = hvcs_open,
-       .close = hvcs_close,
-       .hangup = hvcs_hangup,
-       .write = hvcs_write,
-       .write_room = hvcs_write_room,
-       .chars_in_buffer = hvcs_chars_in_buffer,
-       .unthrottle = hvcs_unthrottle,
-       .throttle = hvcs_throttle,
-};
-
-static int hvcs_alloc_index_list(int n)
-{
-       int i;
-
-       hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
-       if (!hvcs_index_list)
-               return -ENOMEM;
-       hvcs_index_count = n;
-       for (i = 0; i < hvcs_index_count; i++)
-               hvcs_index_list[i] = -1;
-       return 0;
-}
-
-static void hvcs_free_index_list(void)
-{
-       /* Paranoia check to be thorough. */
-       kfree(hvcs_index_list);
-       hvcs_index_list = NULL;
-       hvcs_index_count = 0;
-}
-
-static int __init hvcs_module_init(void)
-{
-       int rc;
-       int num_ttys_to_alloc;
-
-       printk(KERN_INFO "Initializing %s\n", hvcs_driver_string);
-
-       /* Has the user specified an overload with an insmod param? */
-       if (hvcs_parm_num_devs <= 0 ||
-               (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) {
-               num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS;
-       } else
-               num_ttys_to_alloc = hvcs_parm_num_devs;
-
-       hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
-       if (!hvcs_tty_driver)
-               return -ENOMEM;
-
-       if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
-               rc = -ENOMEM;
-               goto index_fail;
-       }
-
-       hvcs_tty_driver->owner = THIS_MODULE;
-
-       hvcs_tty_driver->driver_name = hvcs_driver_name;
-       hvcs_tty_driver->name = hvcs_device_node;
-
-       /*
-        * We'll let the system assign us a major number, indicated by leaving
-        * it blank.
-        */
-
-       hvcs_tty_driver->minor_start = HVCS_MINOR_START;
-       hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
-
-       /*
-        * We role our own so that we DONT ECHO.  We can't echo because the
-        * device we are connecting to already echoes by default and this would
-        * throw us into a horrible recursive echo-echo-echo loop.
-        */
-       hvcs_tty_driver->init_termios = hvcs_tty_termios;
-       hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
-
-       tty_set_operations(hvcs_tty_driver, &hvcs_ops);
-
-       /*
-        * The following call will result in sysfs entries that denote the
-        * dynamically assigned major and minor numbers for our devices.
-        */
-       if (tty_register_driver(hvcs_tty_driver)) {
-               printk(KERN_ERR "HVCS: registration as a tty driver failed.\n");
-               rc = -EIO;
-               goto register_fail;
-       }
-
-       hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!hvcs_pi_buff) {
-               rc = -ENOMEM;
-               goto buff_alloc_fail;
-       }
-
-       hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
-       if (IS_ERR(hvcs_task)) {
-               printk(KERN_ERR "HVCS: khvcsd creation failed.  Driver not loaded.\n");
-               rc = -EIO;
-               goto kthread_fail;
-       }
-
-       rc = vio_register_driver(&hvcs_vio_driver);
-       if (rc) {
-               printk(KERN_ERR "HVCS: can't register vio driver\n");
-               goto vio_fail;
-       }
-
-       /*
-        * This needs to be done AFTER the vio_register_driver() call or else
-        * the kobjects won't be initialized properly.
-        */
-       rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
-       if (rc) {
-               printk(KERN_ERR "HVCS: sysfs attr create failed\n");
-               goto attr_fail;
-       }
-
-       printk(KERN_INFO "HVCS: driver module inserted.\n");
-
-       return 0;
-
-attr_fail:
-       vio_unregister_driver(&hvcs_vio_driver);
-vio_fail:
-       kthread_stop(hvcs_task);
-kthread_fail:
-       kfree(hvcs_pi_buff);
-buff_alloc_fail:
-       tty_unregister_driver(hvcs_tty_driver);
-register_fail:
-       hvcs_free_index_list();
-index_fail:
-       put_tty_driver(hvcs_tty_driver);
-       hvcs_tty_driver = NULL;
-       return rc;
-}
-
-static void __exit hvcs_module_exit(void)
-{
-       /*
-        * This driver receives hvcs_remove callbacks for each device upon
-        * module removal.
-        */
-
-       /*
-        * This synchronous operation  will wake the khvcsd kthread if it is
-        * asleep and will return when khvcsd has terminated.
-        */
-       kthread_stop(hvcs_task);
-
-       spin_lock(&hvcs_pi_lock);
-       kfree(hvcs_pi_buff);
-       hvcs_pi_buff = NULL;
-       spin_unlock(&hvcs_pi_lock);
-
-       driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
-
-       vio_unregister_driver(&hvcs_vio_driver);
-
-       tty_unregister_driver(hvcs_tty_driver);
-
-       hvcs_free_index_list();
-
-       put_tty_driver(hvcs_tty_driver);
-
-       printk(KERN_INFO "HVCS: driver module removed.\n");
-}
-
-module_init(hvcs_module_init);
-module_exit(hvcs_module_exit);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
deleted file mode 100644 (file)
index 67a75a5..0000000
+++ /dev/null
@@ -1,1314 +0,0 @@
-/*
- * Copyright (C) 2004 Hollis Blanchard <hollisb@us.ibm.com>, IBM
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS
- * and the service processor on IBM pSeries servers. On these servers, there
- * are no serial ports under the OS's control, and sometimes there is no other
- * console available either. However, the service processor has two standard
- * serial ports, so this over-complicated protocol allows the OS to control
- * those ports by proxy.
- *
- * Besides data, the procotol supports the reading/writing of the serial
- * port's DTR line, and the reading of the CD line. This is to allow the OS to
- * control a modem attached to the service processor's serial port. Note that
- * the OS cannot change the speed of the port through this protocol.
- */
-
-#undef DEBUG
-
-#include <linux/console.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/major.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <asm/hvcall.h>
-#include <asm/hvconsole.h>
-#include <asm/prom.h>
-#include <asm/uaccess.h>
-#include <asm/vio.h>
-#include <asm/param.h>
-
-#define HVSI_MAJOR     229
-#define HVSI_MINOR     128
-#define MAX_NR_HVSI_CONSOLES 4
-
-#define HVSI_TIMEOUT (5*HZ)
-#define HVSI_VERSION 1
-#define HVSI_MAX_PACKET 256
-#define HVSI_MAX_READ 16
-#define HVSI_MAX_OUTGOING_DATA 12
-#define N_OUTBUF 12
-
-/*
- * we pass data via two 8-byte registers, so we would like our char arrays
- * properly aligned for those loads.
- */
-#define __ALIGNED__    __attribute__((__aligned__(sizeof(long))))
-
-struct hvsi_struct {
-       struct delayed_work writer;
-       struct work_struct handshaker;
-       wait_queue_head_t emptyq; /* woken when outbuf is emptied */
-       wait_queue_head_t stateq; /* woken when HVSI state changes */
-       spinlock_t lock;
-       int index;
-       struct tty_struct *tty;
-       int count;
-       uint8_t throttle_buf[128];
-       uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
-       /* inbuf is for packet reassembly. leave a little room for leftovers. */
-       uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ];
-       uint8_t *inbuf_end;
-       int n_throttle;
-       int n_outbuf;
-       uint32_t vtermno;
-       uint32_t virq;
-       atomic_t seqno; /* HVSI packet sequence number */
-       uint16_t mctrl;
-       uint8_t state;  /* HVSI protocol state */
-       uint8_t flags;
-#ifdef CONFIG_MAGIC_SYSRQ
-       uint8_t sysrq;
-#endif /* CONFIG_MAGIC_SYSRQ */
-};
-static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES];
-
-static struct tty_driver *hvsi_driver;
-static int hvsi_count;
-static int (*hvsi_wait)(struct hvsi_struct *hp, int state);
-
-enum HVSI_PROTOCOL_STATE {
-       HVSI_CLOSED,
-       HVSI_WAIT_FOR_VER_RESPONSE,
-       HVSI_WAIT_FOR_VER_QUERY,
-       HVSI_OPEN,
-       HVSI_WAIT_FOR_MCTRL_RESPONSE,
-       HVSI_FSP_DIED,
-};
-#define HVSI_CONSOLE 0x1
-
-#define VS_DATA_PACKET_HEADER           0xff
-#define VS_CONTROL_PACKET_HEADER        0xfe
-#define VS_QUERY_PACKET_HEADER          0xfd
-#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc
-
-/* control verbs */
-#define VSV_SET_MODEM_CTL    1 /* to service processor only */
-#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */
-#define VSV_CLOSE_PROTOCOL   3
-
-/* query verbs */
-#define VSV_SEND_VERSION_NUMBER 1
-#define VSV_SEND_MODEM_CTL_STATUS 2
-
-/* yes, these masks are not consecutive. */
-#define HVSI_TSDTR 0x01
-#define HVSI_TSCD  0x20
-
-struct hvsi_header {
-       uint8_t  type;
-       uint8_t  len;
-       uint16_t seqno;
-} __attribute__((packed));
-
-struct hvsi_data {
-       uint8_t  type;
-       uint8_t  len;
-       uint16_t seqno;
-       uint8_t  data[HVSI_MAX_OUTGOING_DATA];
-} __attribute__((packed));
-
-struct hvsi_control {
-       uint8_t  type;
-       uint8_t  len;
-       uint16_t seqno;
-       uint16_t verb;
-       /* optional depending on verb: */
-       uint32_t word;
-       uint32_t mask;
-} __attribute__((packed));
-
-struct hvsi_query {
-       uint8_t  type;
-       uint8_t  len;
-       uint16_t seqno;
-       uint16_t verb;
-} __attribute__((packed));
-
-struct hvsi_query_response {
-       uint8_t  type;
-       uint8_t  len;
-       uint16_t seqno;
-       uint16_t verb;
-       uint16_t query_seqno;
-       union {
-               uint8_t  version;
-               uint32_t mctrl_word;
-       } u;
-} __attribute__((packed));
-
-
-
-static inline int is_console(struct hvsi_struct *hp)
-{
-       return hp->flags & HVSI_CONSOLE;
-}
-
-static inline int is_open(struct hvsi_struct *hp)
-{
-       /* if we're waiting for an mctrl then we're already open */
-       return (hp->state == HVSI_OPEN)
-                       || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE);
-}
-
-static inline void print_state(struct hvsi_struct *hp)
-{
-#ifdef DEBUG
-       static const char *state_names[] = {
-               "HVSI_CLOSED",
-               "HVSI_WAIT_FOR_VER_RESPONSE",
-               "HVSI_WAIT_FOR_VER_QUERY",
-               "HVSI_OPEN",
-               "HVSI_WAIT_FOR_MCTRL_RESPONSE",
-               "HVSI_FSP_DIED",
-       };
-       const char *name = (hp->state < ARRAY_SIZE(state_names))
-               ? state_names[hp->state] : "UNKNOWN";
-
-       pr_debug("hvsi%i: state = %s\n", hp->index, name);
-#endif /* DEBUG */
-}
-
-static inline void __set_state(struct hvsi_struct *hp, int state)
-{
-       hp->state = state;
-       print_state(hp);
-       wake_up_all(&hp->stateq);
-}
-
-static inline void set_state(struct hvsi_struct *hp, int state)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hp->lock, flags);
-       __set_state(hp, state);
-       spin_unlock_irqrestore(&hp->lock, flags);
-}
-
-static inline int len_packet(const uint8_t *packet)
-{
-       return (int)((struct hvsi_header *)packet)->len;
-}
-
-static inline int is_header(const uint8_t *packet)
-{
-       struct hvsi_header *header = (struct hvsi_header *)packet;
-       return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER;
-}
-
-static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet)
-{
-       if (hp->inbuf_end < packet + sizeof(struct hvsi_header))
-               return 0; /* don't even have the packet header */
-
-       if (hp->inbuf_end < (packet + len_packet(packet)))
-               return 0; /* don't have the rest of the packet */
-
-       return 1;
-}
-
-/* shift remaining bytes in packetbuf down */
-static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to)
-{
-       int remaining = (int)(hp->inbuf_end - read_to);
-
-       pr_debug("%s: %i chars remain\n", __func__, remaining);
-
-       if (read_to != hp->inbuf)
-               memmove(hp->inbuf, read_to, remaining);
-
-       hp->inbuf_end = hp->inbuf + remaining;
-}
-
-#ifdef DEBUG
-#define dbg_dump_packet(packet) dump_packet(packet)
-#define dbg_dump_hex(data, len) dump_hex(data, len)
-#else
-#define dbg_dump_packet(packet) do { } while (0)
-#define dbg_dump_hex(data, len) do { } while (0)
-#endif
-
-static void dump_hex(const uint8_t *data, int len)
-{
-       int i;
-
-       printk("    ");
-       for (i=0; i < len; i++)
-               printk("%.2x", data[i]);
-
-       printk("\n    ");
-       for (i=0; i < len; i++) {
-               if (isprint(data[i]))
-                       printk("%c", data[i]);
-               else
-                       printk(".");
-       }
-       printk("\n");
-}
-
-static void dump_packet(uint8_t *packet)
-{
-       struct hvsi_header *header = (struct hvsi_header *)packet;
-
-       printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len,
-                       header->seqno);
-
-       dump_hex(packet, header->len);
-}
-
-static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
-{
-       unsigned long got;
-
-       got = hvc_get_chars(hp->vtermno, buf, count);
-
-       return got;
-}
-
-static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
-       struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
-{
-       struct hvsi_control *header = (struct hvsi_control *)packet;
-
-       switch (header->verb) {
-               case VSV_MODEM_CTL_UPDATE:
-                       if ((header->word & HVSI_TSCD) == 0) {
-                               /* CD went away; no more connection */
-                               pr_debug("hvsi%i: CD dropped\n", hp->index);
-                               hp->mctrl &= TIOCM_CD;
-                               /* If userland hasn't done an open(2) yet, hp->tty is NULL. */
-                               if (hp->tty && !(hp->tty->flags & CLOCAL))
-                                       *to_hangup = hp->tty;
-                       }
-                       break;
-               case VSV_CLOSE_PROTOCOL:
-                       pr_debug("hvsi%i: service processor came back\n", hp->index);
-                       if (hp->state != HVSI_CLOSED) {
-                               *to_handshake = hp;
-                       }
-                       break;
-               default:
-                       printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ",
-                               hp->index);
-                       dump_packet(packet);
-                       break;
-       }
-}
-
-static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet)
-{
-       struct hvsi_query_response *resp = (struct hvsi_query_response *)packet;
-
-       switch (hp->state) {
-               case HVSI_WAIT_FOR_VER_RESPONSE:
-                       __set_state(hp, HVSI_WAIT_FOR_VER_QUERY);
-                       break;
-               case HVSI_WAIT_FOR_MCTRL_RESPONSE:
-                       hp->mctrl = 0;
-                       if (resp->u.mctrl_word & HVSI_TSDTR)
-                               hp->mctrl |= TIOCM_DTR;
-                       if (resp->u.mctrl_word & HVSI_TSCD)
-                               hp->mctrl |= TIOCM_CD;
-                       __set_state(hp, HVSI_OPEN);
-                       break;
-               default:
-                       printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index);
-                       dump_packet(packet);
-                       break;
-       }
-}
-
-/* respond to service processor's version query */
-static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno)
-{
-       struct hvsi_query_response packet __ALIGNED__;
-       int wrote;
-
-       packet.type = VS_QUERY_RESPONSE_PACKET_HEADER;
-       packet.len = sizeof(struct hvsi_query_response);
-       packet.seqno = atomic_inc_return(&hp->seqno);
-       packet.verb = VSV_SEND_VERSION_NUMBER;
-       packet.u.version = HVSI_VERSION;
-       packet.query_seqno = query_seqno+1;
-
-       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
-       dbg_dump_hex((uint8_t*)&packet, packet.len);
-
-       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
-       if (wrote != packet.len) {
-               printk(KERN_ERR "hvsi%i: couldn't send query response!\n",
-                       hp->index);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
-{
-       struct hvsi_query *query = (struct hvsi_query *)packet;
-
-       switch (hp->state) {
-               case HVSI_WAIT_FOR_VER_QUERY:
-                       hvsi_version_respond(hp, query->seqno);
-                       __set_state(hp, HVSI_OPEN);
-                       break;
-               default:
-                       printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index);
-                       dump_packet(packet);
-                       break;
-       }
-}
-
-static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
-{
-       int i;
-
-       for (i=0; i < len; i++) {
-               char c = buf[i];
-#ifdef CONFIG_MAGIC_SYSRQ
-               if (c == '\0') {
-                       hp->sysrq = 1;
-                       continue;
-               } else if (hp->sysrq) {
-                       handle_sysrq(c);
-                       hp->sysrq = 0;
-                       continue;
-               }
-#endif /* CONFIG_MAGIC_SYSRQ */
-               tty_insert_flip_char(hp->tty, c, 0);
-       }
-}
-
-/*
- * We could get 252 bytes of data at once here. But the tty layer only
- * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow
- * it. Accordingly we won't send more than 128 bytes at a time to the flip
- * buffer, which will give the tty buffer a chance to throttle us. Should the
- * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be
- * revisited.
- */
-#define TTY_THRESHOLD_THROTTLE 128
-static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
-               const uint8_t *packet)
-{
-       const struct hvsi_header *header = (const struct hvsi_header *)packet;
-       const uint8_t *data = packet + sizeof(struct hvsi_header);
-       int datalen = header->len - sizeof(struct hvsi_header);
-       int overflow = datalen - TTY_THRESHOLD_THROTTLE;
-
-       pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
-
-       if (datalen == 0)
-               return NULL;
-
-       if (overflow > 0) {
-               pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
-               datalen = TTY_THRESHOLD_THROTTLE;
-       }
-
-       hvsi_insert_chars(hp, data, datalen);
-
-       if (overflow > 0) {
-               /*
-                * we still have more data to deliver, so we need to save off the
-                * overflow and send it later
-                */
-               pr_debug("%s: deferring overflow\n", __func__);
-               memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
-               hp->n_throttle = overflow;
-       }
-
-       return hp->tty;
-}
-
-/*
- * Returns true/false indicating data successfully read from hypervisor.
- * Used both to get packets for tty connections and to advance the state
- * machine during console handshaking (in which case tty = NULL and we ignore
- * incoming data).
- */
-static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
-               struct tty_struct **hangup, struct hvsi_struct **handshake)
-{
-       uint8_t *packet = hp->inbuf;
-       int chunklen;
-
-       *flip = NULL;
-       *hangup = NULL;
-       *handshake = NULL;
-
-       chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
-       if (chunklen == 0) {
-               pr_debug("%s: 0-length read\n", __func__);
-               return 0;
-       }
-
-       pr_debug("%s: got %i bytes\n", __func__, chunklen);
-       dbg_dump_hex(hp->inbuf_end, chunklen);
-
-       hp->inbuf_end += chunklen;
-
-       /* handle all completed packets */
-       while ((packet < hp->inbuf_end) && got_packet(hp, packet)) {
-               struct hvsi_header *header = (struct hvsi_header *)packet;
-
-               if (!is_header(packet)) {
-                       printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index);
-                       /* skip bytes until we find a header or run out of data */
-                       while ((packet < hp->inbuf_end) && (!is_header(packet)))
-                               packet++;
-                       continue;
-               }
-
-               pr_debug("%s: handling %i-byte packet\n", __func__,
-                               len_packet(packet));
-               dbg_dump_packet(packet);
-
-               switch (header->type) {
-                       case VS_DATA_PACKET_HEADER:
-                               if (!is_open(hp))
-                                       break;
-                               if (hp->tty == NULL)
-                                       break; /* no tty buffer to put data in */
-                               *flip = hvsi_recv_data(hp, packet);
-                               break;
-                       case VS_CONTROL_PACKET_HEADER:
-                               hvsi_recv_control(hp, packet, hangup, handshake);
-                               break;
-                       case VS_QUERY_RESPONSE_PACKET_HEADER:
-                               hvsi_recv_response(hp, packet);
-                               break;
-                       case VS_QUERY_PACKET_HEADER:
-                               hvsi_recv_query(hp, packet);
-                               break;
-                       default:
-                               printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n",
-                                               hp->index, header->type);
-                               dump_packet(packet);
-                               break;
-               }
-
-               packet += len_packet(packet);
-
-               if (*hangup || *handshake) {
-                       pr_debug("%s: hangup or handshake\n", __func__);
-                       /*
-                        * we need to send the hangup now before receiving any more data.
-                        * If we get "data, hangup, data", we can't deliver the second
-                        * data before the hangup.
-                        */
-                       break;
-               }
-       }
-
-       compact_inbuf(hp, packet);
-
-       return 1;
-}
-
-static void hvsi_send_overflow(struct hvsi_struct *hp)
-{
-       pr_debug("%s: delivering %i bytes overflow\n", __func__,
-                       hp->n_throttle);
-
-       hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
-       hp->n_throttle = 0;
-}
-
-/*
- * must get all pending data because we only get an irq on empty->non-empty
- * transition
- */
-static irqreturn_t hvsi_interrupt(int irq, void *arg)
-{
-       struct hvsi_struct *hp = (struct hvsi_struct *)arg;
-       struct tty_struct *flip;
-       struct tty_struct *hangup;
-       struct hvsi_struct *handshake;
-       unsigned long flags;
-       int again = 1;
-
-       pr_debug("%s\n", __func__);
-
-       while (again) {
-               spin_lock_irqsave(&hp->lock, flags);
-               again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
-               spin_unlock_irqrestore(&hp->lock, flags);
-
-               /*
-                * we have to call tty_flip_buffer_push() and tty_hangup() outside our
-                * spinlock. But we also have to keep going until we've read all the
-                * available data.
-                */
-
-               if (flip) {
-                       /* there was data put in the tty flip buffer */
-                       tty_flip_buffer_push(flip);
-                       flip = NULL;
-               }
-
-               if (hangup) {
-                       tty_hangup(hangup);
-               }
-
-               if (handshake) {
-                       pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
-                       schedule_work(&handshake->handshaker);
-               }
-       }
-
-       spin_lock_irqsave(&hp->lock, flags);
-       if (hp->tty && hp->n_throttle
-                       && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
-               /* we weren't hung up and we weren't throttled, so we can deliver the
-                * rest now */
-               flip = hp->tty;
-               hvsi_send_overflow(hp);
-       }
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (flip) {
-               tty_flip_buffer_push(flip);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* for boot console, before the irq handler is running */
-static int __init poll_for_state(struct hvsi_struct *hp, int state)
-{
-       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
-
-       for (;;) {
-               hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */
-
-               if (hp->state == state)
-                       return 0;
-
-               mdelay(5);
-               if (time_after(jiffies, end_jiffies))
-                       return -EIO;
-       }
-}
-
-/* wait for irq handler to change our state */
-static int wait_for_state(struct hvsi_struct *hp, int state)
-{
-       int ret = 0;
-
-       if (!wait_event_timeout(hp->stateq, (hp->state == state), HVSI_TIMEOUT))
-               ret = -EIO;
-
-       return ret;
-}
-
-static int hvsi_query(struct hvsi_struct *hp, uint16_t verb)
-{
-       struct hvsi_query packet __ALIGNED__;
-       int wrote;
-
-       packet.type = VS_QUERY_PACKET_HEADER;
-       packet.len = sizeof(struct hvsi_query);
-       packet.seqno = atomic_inc_return(&hp->seqno);
-       packet.verb = verb;
-
-       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
-       dbg_dump_hex((uint8_t*)&packet, packet.len);
-
-       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
-       if (wrote != packet.len) {
-               printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index,
-                       wrote);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int hvsi_get_mctrl(struct hvsi_struct *hp)
-{
-       int ret;
-
-       set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE);
-       hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS);
-
-       ret = hvsi_wait(hp, HVSI_OPEN);
-       if (ret < 0) {
-               printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index);
-               set_state(hp, HVSI_OPEN);
-               return ret;
-       }
-
-       pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl);
-
-       return 0;
-}
-
-/* note that we can only set DTR */
-static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl)
-{
-       struct hvsi_control packet __ALIGNED__;
-       int wrote;
-
-       packet.type = VS_CONTROL_PACKET_HEADER,
-       packet.seqno = atomic_inc_return(&hp->seqno);
-       packet.len = sizeof(struct hvsi_control);
-       packet.verb = VSV_SET_MODEM_CTL;
-       packet.mask = HVSI_TSDTR;
-
-       if (mctrl & TIOCM_DTR)
-               packet.word = HVSI_TSDTR;
-
-       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
-       dbg_dump_hex((uint8_t*)&packet, packet.len);
-
-       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
-       if (wrote != packet.len) {
-               printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void hvsi_drain_input(struct hvsi_struct *hp)
-{
-       uint8_t buf[HVSI_MAX_READ] __ALIGNED__;
-       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
-
-       while (time_before(end_jiffies, jiffies))
-               if (0 == hvsi_read(hp, buf, HVSI_MAX_READ))
-                       break;
-}
-
-static int hvsi_handshake(struct hvsi_struct *hp)
-{
-       int ret;
-
-       /*
-        * We could have a CLOSE or other data waiting for us before we even try
-        * to open; try to throw it all away so we don't get confused. (CLOSE
-        * is the first message sent up the pipe when the FSP comes online. We
-        * need to distinguish between "it came up a while ago and we're the first
-        * user" and "it was just reset before it saw our handshake packet".)
-        */
-       hvsi_drain_input(hp);
-
-       set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE);
-       ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER);
-       if (ret < 0) {
-               printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index);
-               return ret;
-       }
-
-       ret = hvsi_wait(hp, HVSI_OPEN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static void hvsi_handshaker(struct work_struct *work)
-{
-       struct hvsi_struct *hp =
-               container_of(work, struct hvsi_struct, handshaker);
-
-       if (hvsi_handshake(hp) >= 0)
-               return;
-
-       printk(KERN_ERR "hvsi%i: re-handshaking failed\n", hp->index);
-       if (is_console(hp)) {
-               /*
-                * ttys will re-attempt the handshake via hvsi_open, but
-                * the console will not.
-                */
-               printk(KERN_ERR "hvsi%i: lost console!\n", hp->index);
-       }
-}
-
-static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count)
-{
-       struct hvsi_data packet __ALIGNED__;
-       int ret;
-
-       BUG_ON(count > HVSI_MAX_OUTGOING_DATA);
-
-       packet.type = VS_DATA_PACKET_HEADER;
-       packet.seqno = atomic_inc_return(&hp->seqno);
-       packet.len = count + sizeof(struct hvsi_header);
-       memcpy(&packet.data, buf, count);
-
-       ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
-       if (ret == packet.len) {
-               /* return the number of chars written, not the packet length */
-               return count;
-       }
-       return ret; /* return any errors */
-}
-
-static void hvsi_close_protocol(struct hvsi_struct *hp)
-{
-       struct hvsi_control packet __ALIGNED__;
-
-       packet.type = VS_CONTROL_PACKET_HEADER;
-       packet.seqno = atomic_inc_return(&hp->seqno);
-       packet.len = 6;
-       packet.verb = VSV_CLOSE_PROTOCOL;
-
-       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
-       dbg_dump_hex((uint8_t*)&packet, packet.len);
-
-       hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
-}
-
-static int hvsi_open(struct tty_struct *tty, struct file *filp)
-{
-       struct hvsi_struct *hp;
-       unsigned long flags;
-       int line = tty->index;
-       int ret;
-
-       pr_debug("%s\n", __func__);
-
-       if (line < 0 || line >= hvsi_count)
-               return -ENODEV;
-       hp = &hvsi_ports[line];
-
-       tty->driver_data = hp;
-
-       mb();
-       if (hp->state == HVSI_FSP_DIED)
-               return -EIO;
-
-       spin_lock_irqsave(&hp->lock, flags);
-       hp->tty = tty;
-       hp->count++;
-       atomic_set(&hp->seqno, 0);
-       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (is_console(hp))
-               return 0; /* this has already been handshaked as the console */
-
-       ret = hvsi_handshake(hp);
-       if (ret < 0) {
-               printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name);
-               return ret;
-       }
-
-       ret = hvsi_get_mctrl(hp);
-       if (ret < 0) {
-               printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name);
-               return ret;
-       }
-
-       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
-       if (ret < 0) {
-               printk(KERN_ERR "%s: couldn't set DTR\n", tty->name);
-               return ret;
-       }
-
-       return 0;
-}
-
-/* wait for hvsi_write_worker to empty hp->outbuf */
-static void hvsi_flush_output(struct hvsi_struct *hp)
-{
-       wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);
-
-       /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
-       cancel_delayed_work_sync(&hp->writer);
-       flush_work_sync(&hp->handshaker);
-
-       /*
-        * it's also possible that our timeout expired and hvsi_write_worker
-        * didn't manage to push outbuf. poof.
-        */
-       hp->n_outbuf = 0;
-}
-
-static void hvsi_close(struct tty_struct *tty, struct file *filp)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-       unsigned long flags;
-
-       pr_debug("%s\n", __func__);
-
-       if (tty_hung_up_p(filp))
-               return;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       if (--hp->count == 0) {
-               hp->tty = NULL;
-               hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
-
-               /* only close down connection if it is not the console */
-               if (!is_console(hp)) {
-                       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */
-                       __set_state(hp, HVSI_CLOSED);
-                       /*
-                        * any data delivered to the tty layer after this will be
-                        * discarded (except for XON/XOFF)
-                        */
-                       tty->closing = 1;
-
-                       spin_unlock_irqrestore(&hp->lock, flags);
-
-                       /* let any existing irq handlers finish. no more will start. */
-                       synchronize_irq(hp->virq);
-
-                       /* hvsi_write_worker will re-schedule until outbuf is empty. */
-                       hvsi_flush_output(hp);
-
-                       /* tell FSP to stop sending data */
-                       hvsi_close_protocol(hp);
-
-                       /*
-                        * drain anything FSP is still in the middle of sending, and let
-                        * hvsi_handshake drain the rest on the next open.
-                        */
-                       hvsi_drain_input(hp);
-
-                       spin_lock_irqsave(&hp->lock, flags);
-               }
-       } else if (hp->count < 0)
-               printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
-                      hp - hvsi_ports, hp->count);
-
-       spin_unlock_irqrestore(&hp->lock, flags);
-}
-
-static void hvsi_hangup(struct tty_struct *tty)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-       unsigned long flags;
-
-       pr_debug("%s\n", __func__);
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       hp->count = 0;
-       hp->n_outbuf = 0;
-       hp->tty = NULL;
-
-       spin_unlock_irqrestore(&hp->lock, flags);
-}
-
-/* called with hp->lock held */
-static void hvsi_push(struct hvsi_struct *hp)
-{
-       int n;
-
-       if (hp->n_outbuf <= 0)
-               return;
-
-       n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
-       if (n > 0) {
-               /* success */
-               pr_debug("%s: wrote %i chars\n", __func__, n);
-               hp->n_outbuf = 0;
-       } else if (n == -EIO) {
-               __set_state(hp, HVSI_FSP_DIED);
-               printk(KERN_ERR "hvsi%i: service processor died\n", hp->index);
-       }
-}
-
-/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */
-static void hvsi_write_worker(struct work_struct *work)
-{
-       struct hvsi_struct *hp =
-               container_of(work, struct hvsi_struct, writer.work);
-       unsigned long flags;
-#ifdef DEBUG
-       static long start_j = 0;
-
-       if (start_j == 0)
-               start_j = jiffies;
-#endif /* DEBUG */
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
-
-       if (!is_open(hp)) {
-               /*
-                * We could have a non-open connection if the service processor died
-                * while we were busily scheduling ourselves. In that case, it could
-                * be minutes before the service processor comes back, so only try
-                * again once a second.
-                */
-               schedule_delayed_work(&hp->writer, HZ);
-               goto out;
-       }
-
-       hvsi_push(hp);
-       if (hp->n_outbuf > 0)
-               schedule_delayed_work(&hp->writer, 10);
-       else {
-#ifdef DEBUG
-               pr_debug("%s: outbuf emptied after %li jiffies\n", __func__,
-                               jiffies - start_j);
-               start_j = 0;
-#endif /* DEBUG */
-               wake_up_all(&hp->emptyq);
-               tty_wakeup(hp->tty);
-       }
-
-out:
-       spin_unlock_irqrestore(&hp->lock, flags);
-}
-
-static int hvsi_write_room(struct tty_struct *tty)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-
-       return N_OUTBUF - hp->n_outbuf;
-}
-
-static int hvsi_chars_in_buffer(struct tty_struct *tty)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-
-       return hp->n_outbuf;
-}
-
-static int hvsi_write(struct tty_struct *tty,
-                    const unsigned char *buf, int count)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-       const char *source = buf;
-       unsigned long flags;
-       int total = 0;
-       int origcount = count;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
-
-       if (!is_open(hp)) {
-               /* we're either closing or not yet open; don't accept data */
-               pr_debug("%s: not open\n", __func__);
-               goto out;
-       }
-
-       /*
-        * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf
-        * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
-        * will see there is no room in outbuf and return.
-        */
-       while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
-               int chunksize = min(count, hvsi_write_room(hp->tty));
-
-               BUG_ON(hp->n_outbuf < 0);
-               memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
-               hp->n_outbuf += chunksize;
-
-               total += chunksize;
-               source += chunksize;
-               count -= chunksize;
-               hvsi_push(hp);
-       }
-
-       if (hp->n_outbuf > 0) {
-               /*
-                * we weren't able to write it all to the hypervisor.
-                * schedule another push attempt.
-                */
-               schedule_delayed_work(&hp->writer, 10);
-       }
-
-out:
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (total != origcount)
-               pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount,
-                       total);
-
-       return total;
-}
-
-/*
- * I have never seen throttle or unthrottle called, so this little throttle
- * buffering scheme may or may not work.
- */
-static void hvsi_throttle(struct tty_struct *tty)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-
-       pr_debug("%s\n", __func__);
-
-       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
-}
-
-static void hvsi_unthrottle(struct tty_struct *tty)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-       unsigned long flags;
-       int shouldflip = 0;
-
-       pr_debug("%s\n", __func__);
-
-       spin_lock_irqsave(&hp->lock, flags);
-       if (hp->n_throttle) {
-               hvsi_send_overflow(hp);
-               shouldflip = 1;
-       }
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       if (shouldflip)
-               tty_flip_buffer_push(hp->tty);
-
-       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
-}
-
-static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-
-       hvsi_get_mctrl(hp);
-       return hp->mctrl;
-}
-
-static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
-               unsigned int set, unsigned int clear)
-{
-       struct hvsi_struct *hp = tty->driver_data;
-       unsigned long flags;
-       uint16_t new_mctrl;
-
-       /* we can only alter DTR */
-       clear &= TIOCM_DTR;
-       set &= TIOCM_DTR;
-
-       spin_lock_irqsave(&hp->lock, flags);
-
-       new_mctrl = (hp->mctrl & ~clear) | set;
-
-       if (hp->mctrl != new_mctrl) {
-               hvsi_set_mctrl(hp, new_mctrl);
-               hp->mctrl = new_mctrl;
-       }
-       spin_unlock_irqrestore(&hp->lock, flags);
-
-       return 0;
-}
-
-
-static const struct tty_operations hvsi_ops = {
-       .open = hvsi_open,
-       .close = hvsi_close,
-       .write = hvsi_write,
-       .hangup = hvsi_hangup,
-       .write_room = hvsi_write_room,
-       .chars_in_buffer = hvsi_chars_in_buffer,
-       .throttle = hvsi_throttle,
-       .unthrottle = hvsi_unthrottle,
-       .tiocmget = hvsi_tiocmget,
-       .tiocmset = hvsi_tiocmset,
-};
-
-static int __init hvsi_init(void)
-{
-       int i;
-
-       hvsi_driver = alloc_tty_driver(hvsi_count);
-       if (!hvsi_driver)
-               return -ENOMEM;
-
-       hvsi_driver->owner = THIS_MODULE;
-       hvsi_driver->driver_name = "hvsi";
-       hvsi_driver->name = "hvsi";
-       hvsi_driver->major = HVSI_MAJOR;
-       hvsi_driver->minor_start = HVSI_MINOR;
-       hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
-       hvsi_driver->init_termios = tty_std_termios;
-       hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
-       hvsi_driver->init_termios.c_ispeed = 9600;
-       hvsi_driver->init_termios.c_ospeed = 9600;
-       hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(hvsi_driver, &hvsi_ops);
-
-       for (i=0; i < hvsi_count; i++) {
-               struct hvsi_struct *hp = &hvsi_ports[i];
-               int ret = 1;
-
-               ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp);
-               if (ret)
-                       printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
-                               hp->virq, ret);
-       }
-       hvsi_wait = wait_for_state; /* irqs active now */
-
-       if (tty_register_driver(hvsi_driver))
-               panic("Couldn't register hvsi console driver\n");
-
-       printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count);
-
-       return 0;
-}
-device_initcall(hvsi_init);
-
-/***** console (not tty) code: *****/
-
-static void hvsi_console_print(struct console *console, const char *buf,
-               unsigned int count)
-{
-       struct hvsi_struct *hp = &hvsi_ports[console->index];
-       char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__;
-       unsigned int i = 0, n = 0;
-       int ret, donecr = 0;
-
-       mb();
-       if (!is_open(hp))
-               return;
-
-       /*
-        * ugh, we have to translate LF -> CRLF ourselves, in place.
-        * copied from hvc_console.c:
-        */
-       while (count > 0 || i > 0) {
-               if (count > 0 && i < sizeof(c)) {
-                       if (buf[n] == '\n' && !donecr) {
-                               c[i++] = '\r';
-                               donecr = 1;
-                       } else {
-                               c[i++] = buf[n++];
-                               donecr = 0;
-                               --count;
-                       }
-               } else {
-                       ret = hvsi_put_chars(hp, c, i);
-                       if (ret < 0)
-                               i = 0;
-                       i -= ret;
-               }
-       }
-}
-
-static struct tty_driver *hvsi_console_device(struct console *console,
-       int *index)
-{
-       *index = console->index;
-       return hvsi_driver;
-}
-
-static int __init hvsi_console_setup(struct console *console, char *options)
-{
-       struct hvsi_struct *hp;
-       int ret;
-
-       if (console->index < 0 || console->index >= hvsi_count)
-               return -1;
-       hp = &hvsi_ports[console->index];
-
-       /* give the FSP a chance to change the baud rate when we re-open */
-       hvsi_close_protocol(hp);
-
-       ret = hvsi_handshake(hp);
-       if (ret < 0)
-               return ret;
-
-       ret = hvsi_get_mctrl(hp);
-       if (ret < 0)
-               return ret;
-
-       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
-       if (ret < 0)
-               return ret;
-
-       hp->flags |= HVSI_CONSOLE;
-
-       return 0;
-}
-
-static struct console hvsi_console = {
-       .name           = "hvsi",
-       .write          = hvsi_console_print,
-       .device         = hvsi_console_device,
-       .setup          = hvsi_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static int __init hvsi_console_init(void)
-{
-       struct device_node *vty;
-
-       hvsi_wait = poll_for_state; /* no irqs yet; must poll */
-
-       /* search device tree for vty nodes */
-       for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol");
-                       vty != NULL;
-                       vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
-               struct hvsi_struct *hp;
-               const uint32_t *vtermno, *irq;
-
-               vtermno = of_get_property(vty, "reg", NULL);
-               irq = of_get_property(vty, "interrupts", NULL);
-               if (!vtermno || !irq)
-                       continue;
-
-               if (hvsi_count >= MAX_NR_HVSI_CONSOLES) {
-                       of_node_put(vty);
-                       break;
-               }
-
-               hp = &hvsi_ports[hvsi_count];
-               INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker);
-               INIT_WORK(&hp->handshaker, hvsi_handshaker);
-               init_waitqueue_head(&hp->emptyq);
-               init_waitqueue_head(&hp->stateq);
-               spin_lock_init(&hp->lock);
-               hp->index = hvsi_count;
-               hp->inbuf_end = hp->inbuf;
-               hp->state = HVSI_CLOSED;
-               hp->vtermno = *vtermno;
-               hp->virq = irq_create_mapping(NULL, irq[0]);
-               if (hp->virq == NO_IRQ) {
-                       printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
-                               __func__, irq[0]);
-                       continue;
-               }
-
-               hvsi_count++;
-       }
-
-       if (hvsi_count)
-               register_console(&hvsi_console);
-       return 0;
-}
-console_initcall(hvsi_console_init);
index b6ae6e9..7855f9f 100644 (file)
@@ -320,6 +320,7 @@ static int unload_when_empty = 1;
 static int add_smi(struct smi_info *smi);
 static int try_smi_init(struct smi_info *smi);
 static void cleanup_one_si(struct smi_info *to_clean);
+static void cleanup_ipmi_si(void);
 
 static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
 static int register_xaction_notifier(struct notifier_block *nb)
@@ -3450,16 +3451,7 @@ static int __devinit init_ipmi_si(void)
        mutex_lock(&smi_infos_lock);
        if (unload_when_empty && list_empty(&smi_infos)) {
                mutex_unlock(&smi_infos_lock);
-#ifdef CONFIG_PCI
-               if (pci_registered)
-                       pci_unregister_driver(&ipmi_pci_driver);
-#endif
-
-#ifdef CONFIG_PPC_OF
-               if (of_registered)
-                       of_unregister_platform_driver(&ipmi_of_platform_driver);
-#endif
-               driver_unregister(&ipmi_driver.driver);
+               cleanup_ipmi_si();
                printk(KERN_WARNING PFX
                       "Unable to find any System Interface(s)\n");
                return -ENODEV;
index 777181a..bcbbc71 100644 (file)
@@ -830,8 +830,7 @@ static void monitor_card(unsigned long p)
                            test_bit(IS_ANY_T1, &dev->flags))) {
                                DEBUGP(4, dev, "Perform AUTOPPS\n");
                                set_bit(IS_AUTOPPS_ACT, &dev->flags);
-                               ptsreq.protocol = ptsreq.protocol =
-                                   (0x01 << dev->proto);
+                               ptsreq.protocol = (0x01 << dev->proto);
                                ptsreq.flags = 0x01;
                                ptsreq.pts1 = 0x00;
                                ptsreq.pts2 = 0x00;
index 94b8eb4..444155a 100644 (file)
@@ -78,7 +78,6 @@ static void signalled_reboot_callback(void *callback_data)
 static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 {
        struct ipw_dev *ipw = priv_data;
-       struct resource *io_resource;
        int ret;
 
        p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
@@ -92,9 +91,12 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
        if (ret)
                return ret;
 
-       io_resource = request_region(p_dev->resource[0]->start,
-                               resource_size(p_dev->resource[0]),
-                               IPWIRELESS_PCCARD_NAME);
+       if (!request_region(p_dev->resource[0]->start,
+                           resource_size(p_dev->resource[0]),
+                           IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit;
+       }
 
        p_dev->resource[2]->flags |=
                WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
@@ -105,22 +107,25 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 
        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
        if (ret != 0)
-               goto exit2;
+               goto exit1;
 
        ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
 
-       ipw->attr_memory = ioremap(p_dev->resource[2]->start,
+       ipw->common_memory = ioremap(p_dev->resource[2]->start,
                                resource_size(p_dev->resource[2]));
-       request_mem_region(p_dev->resource[2]->start,
-                       resource_size(p_dev->resource[2]),
-                       IPWIRELESS_PCCARD_NAME);
+       if (!request_mem_region(p_dev->resource[2]->start,
+                               resource_size(p_dev->resource[2]),
+                               IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit2;
+       }
 
        p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
                                        WIN_ENABLE;
        p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
        ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
-               goto exit2;
+               goto exit3;
 
        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
@@ -128,23 +133,28 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 
        ipw->attr_memory = ioremap(p_dev->resource[3]->start,
                                resource_size(p_dev->resource[3]));
-       request_mem_region(p_dev->resource[3]->start,
-                       resource_size(p_dev->resource[3]),
-                       IPWIRELESS_PCCARD_NAME);
+       if (!request_mem_region(p_dev->resource[3]->start,
+                               resource_size(p_dev->resource[3]),
+                               IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit4;
+       }
 
        return 0;
 
+exit4:
+       iounmap(ipw->attr_memory);
 exit3:
+       release_mem_region(p_dev->resource[2]->start,
+                       resource_size(p_dev->resource[2]));
 exit2:
-       if (ipw->common_memory) {
-               release_mem_region(p_dev->resource[2]->start,
-                               resource_size(p_dev->resource[2]));
-               iounmap(ipw->common_memory);
-       }
+       iounmap(ipw->common_memory);
 exit1:
-       release_resource(io_resource);
+       release_region(p_dev->resource[0]->start,
+                      resource_size(p_dev->resource[0]));
+exit:
        pcmcia_disable_device(p_dev);
-       return -1;
+       return ret;
 }
 
 static int config_ipwireless(struct ipw_dev *ipw)
@@ -219,6 +229,8 @@ exit:
 
 static void release_ipwireless(struct ipw_dev *ipw)
 {
+       release_region(ipw->link->resource[0]->start,
+                      resource_size(ipw->link->resource[0]));
        if (ipw->common_memory) {
                release_mem_region(ipw->link->resource[2]->start,
                                resource_size(ipw->link->resource[2]));
index c17a305..dd21df5 100644 (file)
@@ -493,9 +493,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
-       if (is_itpm(to_pnp_dev(dev)))
-               itpm = 1;
-
        if (itpm)
                dev_info(dev, "Intel iTPM workaround enabled\n");
 
@@ -637,6 +634,9 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
        else
                interrupts = 0;
 
+       if (is_itpm(pnp_dev))
+               itpm = 1;
+
        return tpm_tis_init(&pnp_dev->dev, start, len, irq);
 }
 
index 896a2ce..84b164d 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
- * Copyright (C) 2009, 2010 Red Hat, Inc.
+ * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
+ * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +32,7 @@
 #include <linux/virtio_console.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include "hvc_console.h"
+#include "../tty/hvc/hvc_console.h"
 
 /*
  * This is a global struct for storing common data for all the devices
@@ -387,6 +388,10 @@ static void discard_port_data(struct port *port)
        unsigned int len;
        int ret;
 
+       if (!port->portdev) {
+               /* Device has been unplugged.  vqs are already gone. */
+               return;
+       }
        vq = port->in_vq;
        if (port->inbuf)
                buf = port->inbuf;
@@ -469,6 +474,10 @@ static void reclaim_consumed_buffers(struct port *port)
        void *buf;
        unsigned int len;
 
+       if (!port->portdev) {
+               /* Device has been unplugged.  vqs are already gone. */
+               return;
+       }
        while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
                kfree(buf);
                port->outvq_full = false;
@@ -1462,6 +1471,17 @@ static void control_work_handler(struct work_struct *work)
        spin_unlock(&portdev->cvq_lock);
 }
 
+static void out_intr(struct virtqueue *vq)
+{
+       struct port *port;
+
+       port = find_port_by_vq(vq->vdev->priv, vq);
+       if (!port)
+               return;
+
+       wake_up_interruptible(&port->waitqueue);
+}
+
 static void in_intr(struct virtqueue *vq)
 {
        struct port *port;
@@ -1566,7 +1586,7 @@ static int init_vqs(struct ports_device *portdev)
         */
        j = 0;
        io_callbacks[j] = in_intr;
-       io_callbacks[j + 1] = NULL;
+       io_callbacks[j + 1] = out_intr;
        io_names[j] = "input";
        io_names[j + 1] = "output";
        j += 2;
@@ -1580,7 +1600,7 @@ static int init_vqs(struct ports_device *portdev)
                for (i = 1; i < nr_ports; i++) {
                        j += 2;
                        io_callbacks[j] = in_intr;
-                       io_callbacks[j + 1] = NULL;
+                       io_callbacks[j + 1] = out_intr;
                        io_names[j] = "input";
                        io_names[j + 1] = "output";
                }
index cfb0f52..effe797 100644 (file)
@@ -202,17 +202,21 @@ static int __init init_acpi_pm_clocksource(void)
                        printk(KERN_INFO "PM-Timer had inconsistent results:"
                               " 0x%#llx, 0x%#llx - aborting.\n",
                               value1, value2);
+                       pmtmr_ioport = 0;
                        return -EINVAL;
                }
                if (i == ACPI_PM_READ_CHECKS) {
                        printk(KERN_INFO "PM-Timer failed consistency check "
                               " (0x%#llx) - aborting.\n", value1);
+                       pmtmr_ioport = 0;
                        return -ENODEV;
                }
        }
 
-       if (verify_pmtmr_rate() != 0)
+       if (verify_pmtmr_rate() != 0){
+               pmtmr_ioport = 0;
                return -ENODEV;
+       }
 
        return clocksource_register_hz(&clocksource_acpi_pm,
                                                PMTMR_TICKS_PER_SEC);
index 01b886e..79c47e8 100644 (file)
@@ -196,9 +196,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
        clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
        clkevt.clkevt.cpumask = cpumask_of(0);
 
-       setup_irq(irq, &tc_irqaction);
-
        clockevents_register_device(&clkevt.clkevt);
+
+       setup_irq(irq, &tc_irqaction);
 }
 
 #else /* !CONFIG_GENERIC_CLOCKEVENTS */
index a8c8d9c..ca8ee80 100644 (file)
@@ -71,7 +71,7 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE
 
 config CPU_FREQ_DEFAULT_GOV_POWERSAVE
        bool "powersave"
-       depends on EMBEDDED
+       depends on EXPERT
        select CPU_FREQ_GOV_POWERSAVE
        help
          Use the CPUFreq governor 'powersave' as default. This sets
index 1109f68..5cb4d09 100644 (file)
@@ -1919,8 +1919,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
        ret = sysdev_driver_register(&cpu_sysdev_class,
                                        &cpufreq_sysdev_driver);
+       if (ret)
+               goto err_null_driver;
 
-       if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
+       if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
                int i;
                ret = -ENODEV;
 
@@ -1935,21 +1937,22 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                if (ret) {
                        dprintk("no CPU initialized for driver %s\n",
                                                        driver_data->name);
-                       sysdev_driver_unregister(&cpu_sysdev_class,
-                                               &cpufreq_sysdev_driver);
-
-                       spin_lock_irqsave(&cpufreq_driver_lock, flags);
-                       cpufreq_driver = NULL;
-                       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+                       goto err_sysdev_unreg;
                }
        }
 
-       if (!ret) {
-               register_hotcpu_notifier(&cpufreq_cpu_notifier);
-               dprintk("driver %s up and running\n", driver_data->name);
-               cpufreq_debug_enable_ratelimit();
-       }
+       register_hotcpu_notifier(&cpufreq_cpu_notifier);
+       dprintk("driver %s up and running\n", driver_data->name);
+       cpufreq_debug_enable_ratelimit();
 
+       return 0;
+err_sysdev_unreg:
+       sysdev_driver_unregister(&cpu_sysdev_class,
+                       &cpufreq_sysdev_driver);
+err_null_driver:
+       spin_lock_irqsave(&cpufreq_driver_lock, flags);
+       cpufreq_driver = NULL;
+       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
index 297f48b..07bca49 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/dmapool.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
@@ -235,16 +236,19 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
 }
 
 /*
- * Overall DMAC remains enabled always.
+ * Pause the channel by setting the HALT bit.
  *
- * Disabling individual channels could lose data.
+ * For M->P transfers, pause the DMAC first and then stop the peripheral -
+ * the FIFO can only drain if the peripheral is still requesting data.
+ * (note: this can still timeout if the DMAC FIFO never drains of data.)
  *
- * Disable the peripheral DMA after disabling the DMAC in order to allow
- * the DMAC FIFO to drain, and hence allow the channel to show inactive
+ * For P->M transfers, disable the peripheral first to stop it filling
+ * the DMAC FIFO, and then pause the DMAC.
  */
 static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
 {
        u32 val;
+       int timeout;
 
        /* Set the HALT bit and wait for the FIFO to drain */
        val = readl(ch->base + PL080_CH_CONFIG);
@@ -252,8 +256,13 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
        writel(val, ch->base + PL080_CH_CONFIG);
 
        /* Wait for channel inactive */
-       while (pl08x_phy_channel_busy(ch))
-               cpu_relax();
+       for (timeout = 1000; timeout; timeout--) {
+               if (!pl08x_phy_channel_busy(ch))
+                       break;
+               udelay(1);
+       }
+       if (pl08x_phy_channel_busy(ch))
+               pr_err("pl08x: channel%u timeout waiting for pause\n", ch->id);
 }
 
 static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
@@ -267,19 +276,24 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
 }
 
 
-/* Stops the channel */
-static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
+/*
+ * pl08x_terminate_phy_chan() stops the channel, clears the FIFO and
+ * clears any pending interrupt status.  This should not be used for
+ * an on-going transfer, but as a method of shutting down a channel
+ * (eg, when it's no longer used) or terminating a transfer.
+ */
+static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
+       struct pl08x_phy_chan *ch)
 {
-       u32 val;
+       u32 val = readl(ch->base + PL080_CH_CONFIG);
 
-       pl08x_pause_phy_chan(ch);
+       val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
+                PL080_CONFIG_TC_IRQ_MASK);
 
-       /* Disable channel */
-       val = readl(ch->base + PL080_CH_CONFIG);
-       val &= ~PL080_CONFIG_ENABLE;
-       val &= ~PL080_CONFIG_ERR_IRQ_MASK;
-       val &= ~PL080_CONFIG_TC_IRQ_MASK;
        writel(val, ch->base + PL080_CH_CONFIG);
+
+       writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR);
+       writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR);
 }
 
 static inline u32 get_bytes_in_cctl(u32 cctl)
@@ -404,13 +418,12 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
 {
        unsigned long flags;
 
+       spin_lock_irqsave(&ch->lock, flags);
+
        /* Stop the channel and clear its interrupts */
-       pl08x_stop_phy_chan(ch);
-       writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
-       writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
+       pl08x_terminate_phy_chan(pl08x, ch);
 
        /* Mark it as free */
-       spin_lock_irqsave(&ch->lock, flags);
        ch->serving = NULL;
        spin_unlock_irqrestore(&ch->lock, flags);
 }
@@ -1449,7 +1462,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                plchan->state = PL08X_CHAN_IDLE;
 
                if (plchan->phychan) {
-                       pl08x_stop_phy_chan(plchan->phychan);
+                       pl08x_terminate_phy_chan(pl08x, plchan->phychan);
 
                        /*
                         * Mark physical channel as free and free any slave
index e53d438..e18eaab 100644 (file)
@@ -49,6 +49,7 @@ struct imxdma_channel {
 
 struct imxdma_engine {
        struct device                   *dev;
+       struct device_dma_parameters    dma_parms;
        struct dma_device               dma_device;
        struct imxdma_channel           channel[MAX_DMA_CHANNELS];
 };
@@ -242,6 +243,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
        else
                dmamode = DMA_MODE_WRITE;
 
+       switch (imxdmac->word_size) {
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               if (sgl->length & 3 || sgl->dma_address & 3)
+                       return NULL;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               if (sgl->length & 1 || sgl->dma_address & 1)
+                       return NULL;
+               break;
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               break;
+       default:
+               return NULL;
+       }
+
        ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
                 dma_length, imxdmac->per_address, dmamode);
        if (ret)
@@ -329,6 +345,9 @@ static int __init imxdma_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&imxdma->dma_device.channels);
 
+       dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+
        /* Initialize channel parameters */
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
                struct imxdma_channel *imxdmac = &imxdma->channel[i];
@@ -346,11 +365,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                imxdmac->imxdma = imxdma;
                spin_lock_init(&imxdmac->lock);
 
-               dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
-               dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
-
                imxdmac->chan.device = &imxdma->dma_device;
-               imxdmac->chan.chan_id = i;
                imxdmac->channel = i;
 
                /* Add the channel to the DMAC list */
@@ -370,6 +385,9 @@ static int __init imxdma_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, imxdma);
 
+       imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
+       dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
+
        ret = dma_async_device_register(&imxdma->dma_device);
        if (ret) {
                dev_err(&pdev->dev, "unable to register\n");
index d5a5d4d..b6d1455 100644 (file)
@@ -230,7 +230,7 @@ struct sdma_engine;
  * struct sdma_channel - housekeeping for a SDMA channel
  *
  * @sdma               pointer to the SDMA engine for this channel
- * @channel            the channel number, matches dmaengine chan_id
+ * @channel            the channel number, matches dmaengine chan_id + 1
  * @direction          transfer type. Needed for setting SDMA script
  * @peripheral_type    Peripheral type. Needed for setting SDMA script
  * @event_id0          aka dma request line
@@ -301,6 +301,7 @@ struct sdma_firmware_header {
 
 struct sdma_engine {
        struct device                   *dev;
+       struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
@@ -449,7 +450,7 @@ static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
                if (bd->mode.status & BD_RROR)
                        sdmac->status = DMA_ERROR;
                else
-                       sdmac->status = DMA_SUCCESS;
+                       sdmac->status = DMA_IN_PROGRESS;
 
                bd->mode.status |= BD_DONE;
                sdmac->buf_tail++;
@@ -770,15 +771,15 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
        __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
 }
 
-static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma)
+static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
 {
-       dma_cookie_t cookie = sdma->chan.cookie;
+       dma_cookie_t cookie = sdmac->chan.cookie;
 
        if (++cookie < 0)
                cookie = 1;
 
-       sdma->chan.cookie = cookie;
-       sdma->desc.cookie = cookie;
+       sdmac->chan.cookie = cookie;
+       sdmac->desc.cookie = cookie;
 
        return cookie;
 }
@@ -798,7 +799,7 @@ static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
 
        cookie = sdma_assign_cookie(sdmac);
 
-       sdma_enable_channel(sdma, tx->chan->chan_id);
+       sdma_enable_channel(sdma, sdmac->channel);
 
        spin_unlock_irq(&sdmac->lock);
 
@@ -811,10 +812,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
        struct imx_dma_data *data = chan->private;
        int prio, ret;
 
-       /* No need to execute this for internal channel 0 */
-       if (chan->chan_id == 0)
-               return 0;
-
        if (!data)
                return -EINVAL;
 
@@ -879,7 +876,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int ret, i, count;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        struct scatterlist *sg;
 
        if (sdmac->status == DMA_IN_PROGRESS)
@@ -924,22 +921,33 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                        ret =  -EINVAL;
                        goto err_out;
                }
-               if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+
+               switch (sdmac->word_size) {
+               case DMA_SLAVE_BUSWIDTH_4_BYTES:
                        bd->mode.command = 0;
-               else
-                       bd->mode.command = sdmac->word_size;
+                       if (count & 3 || sg->dma_address & 3)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_2_BYTES:
+                       bd->mode.command = 2;
+                       if (count & 1 || sg->dma_address & 1)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_1_BYTE:
+                       bd->mode.command = 1;
+                       break;
+               default:
+                       return NULL;
+               }
 
                param = BD_DONE | BD_EXTD | BD_CONT;
 
-               if (sdmac->flags & IMX_DMA_SG_LOOP) {
+               if (i + 1 == sg_len) {
                        param |= BD_INTR;
-                       if (i + 1 == sg_len)
-                               param |= BD_WRAP;
+                       param |= BD_LAST;
+                       param &= ~BD_CONT;
                }
 
-               if (i + 1 == sg_len)
-                       param |= BD_INTR;
-
                dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
                                i, count, sg->dma_address,
                                param & BD_WRAP ? "wrap" : "",
@@ -953,6 +961,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
        return &sdmac->desc;
 err_out:
+       sdmac->status = DMA_ERROR;
        return NULL;
 }
 
@@ -963,7 +972,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int num_periods = buf_len / period_len;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        int ret, i = 0, buf = 0;
 
        dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
@@ -1066,14 +1075,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        dma_cookie_t last_used;
-       enum dma_status ret;
 
        last_used = chan->cookie;
 
-       ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used);
        dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
 
-       return ret;
+       return sdmac->status;
 }
 
 static void sdma_issue_pending(struct dma_chan *chan)
@@ -1135,7 +1142,7 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
        /* download the RAM image for SDMA */
        sdma_load_script(sdma, ram_code,
                        header->ram_code_size,
-                       sdma->script_addrs->ram_code_start_addr);
+                       addr->ram_code_start_addr);
        clk_disable(sdma->clk);
 
        sdma_add_scripts(sdma, addr);
@@ -1237,7 +1244,6 @@ static int __init sdma_probe(struct platform_device *pdev)
        struct resource *iores;
        struct sdma_platform_data *pdata = pdev->dev.platform_data;
        int i;
-       dma_cap_mask_t mask;
        struct sdma_engine *sdma;
 
        sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
@@ -1280,6 +1286,9 @@ static int __init sdma_probe(struct platform_device *pdev)
 
        sdma->version = pdata->sdma_version;
 
+       dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+
        INIT_LIST_HEAD(&sdma->dma_device.channels);
        /* Initialize channel parameters */
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -1288,15 +1297,17 @@ static int __init sdma_probe(struct platform_device *pdev)
                sdmac->sdma = sdma;
                spin_lock_init(&sdmac->lock);
 
-               dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
-               dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
-
                sdmac->chan.device = &sdma->dma_device;
-               sdmac->chan.chan_id = i;
                sdmac->channel = i;
 
-               /* Add the channel to the DMAC list */
-               list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
+               /*
+                * Add the channel to the DMAC list. Do not add channel 0 though
+                * because we need it internally in the SDMA driver. This also means
+                * that channel 0 in dmaengine counting matches sdma channel 1.
+                */
+               if (i)
+                       list_add_tail(&sdmac->chan.device_node,
+                                       &sdma->dma_device.channels);
        }
 
        ret = sdma_init(sdma);
@@ -1317,6 +1328,8 @@ static int __init sdma_probe(struct platform_device *pdev)
        sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
        sdma->dma_device.device_control = sdma_control;
        sdma->dma_device.device_issue_pending = sdma_issue_pending;
+       sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
+       dma_set_max_seg_size(sdma->dma_device.dev, 65535);
 
        ret = dma_async_device_register(&sdma->dma_device);
        if (ret) {
@@ -1324,13 +1337,6 @@ static int __init sdma_probe(struct platform_device *pdev)
                goto err_init;
        }
 
-       /* request channel 0. This is an internal control channel
-        * to the SDMA engine and not available to clients.
-        */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_request_channel(mask, NULL, NULL);
-
        dev_info(sdma->dev, "initialized\n");
 
        return 0;
@@ -1348,7 +1354,7 @@ err_clk:
 err_request_region:
 err_irq:
        kfree(sdma);
-       return 0;
+       return ret;
 }
 
 static int __exit sdma_remove(struct platform_device *pdev)
index cb26ee9..c1a125e 100644 (file)
@@ -1145,29 +1145,6 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
        reg = idmac_read_icreg(ipu, IDMAC_CHA_EN);
        idmac_write_icreg(ipu, reg & ~chan_mask, IDMAC_CHA_EN);
 
-       /*
-        * Problem (observed with channel DMAIC_7): after enabling the channel
-        * and initialising buffers, there comes an interrupt with current still
-        * pointing at buffer 0, whereas it should use buffer 0 first and only
-        * generate an interrupt when it is done, then current should already
-        * point to buffer 1. This spurious interrupt also comes on channel
-        * DMASDC_0. With DMAIC_7 normally, is we just leave the ISR after the
-        * first interrupt, there comes the second with current correctly
-        * pointing to buffer 1 this time. But sometimes this second interrupt
-        * doesn't come and the channel hangs. Clearing BUFx_RDY when disabling
-        * the channel seems to prevent the channel from hanging, but it doesn't
-        * prevent the spurious interrupt. This might also be unsafe. Think
-        * about the IDMAC controller trying to switch to a buffer, when we
-        * clear the ready bit, and re-enable it a moment later.
-        */
-       reg = idmac_read_ipureg(ipu, IPU_CHA_BUF0_RDY);
-       idmac_write_ipureg(ipu, 0, IPU_CHA_BUF0_RDY);
-       idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF0_RDY);
-
-       reg = idmac_read_ipureg(ipu, IPU_CHA_BUF1_RDY);
-       idmac_write_ipureg(ipu, 0, IPU_CHA_BUF1_RDY);
-       idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF1_RDY);
-
        spin_unlock_irqrestore(&ipu->lock, flags);
 
        return 0;
@@ -1246,33 +1223,6 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
 
        /* Other interrupts do not interfere with this channel */
        spin_lock(&ichan->lock);
-       if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 &&
-                    ((curbuf >> chan_id) & 1) == ichan->active_buffer &&
-                    !list_is_last(ichan->queue.next, &ichan->queue))) {
-               int i = 100;
-
-               /* This doesn't help. See comment in ipu_disable_channel() */
-               while (--i) {
-                       curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF);
-                       if (((curbuf >> chan_id) & 1) != ichan->active_buffer)
-                               break;
-                       cpu_relax();
-               }
-
-               if (!i) {
-                       spin_unlock(&ichan->lock);
-                       dev_dbg(dev,
-                               "IRQ on active buffer on channel %x, active "
-                               "%d, ready %x, %x, current %x!\n", chan_id,
-                               ichan->active_buffer, ready0, ready1, curbuf);
-                       return IRQ_NONE;
-               } else
-                       dev_dbg(dev,
-                               "Buffer deactivated on channel %x, active "
-                               "%d, ready %x, %x, current %x, rest %d!\n", chan_id,
-                               ichan->active_buffer, ready0, ready1, curbuf, i);
-       }
-
        if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) ||
                     (!ichan->active_buffer && (ready0 >> chan_id) & 1)
                     )) {
index 4a5ecc5..23e0355 100644 (file)
@@ -826,8 +826,6 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)
 /* Display and decode various NB registers for debug purposes. */
 static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
 {
-       int ganged;
-
        debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
 
        debugf1("  NB two channel DRAM capable: %s\n",
@@ -851,28 +849,19 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
        debugf1("  DramHoleValid: %s\n",
                (pvt->dhar & DHAR_VALID) ? "yes" : "no");
 
+       amd64_debug_display_dimm_sizes(0, pvt);
+
        /* everything below this point is Fam10h and above */
-       if (boot_cpu_data.x86 == 0xf) {
-               amd64_debug_display_dimm_sizes(0, pvt);
+       if (boot_cpu_data.x86 == 0xf)
                return;
-       }
+
+       amd64_debug_display_dimm_sizes(1, pvt);
 
        amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4"));
 
        /* Only if NOT ganged does dclr1 have valid info */
        if (!dct_ganging_enabled(pvt))
                amd64_dump_dramcfg_low(pvt->dclr1, 1);
-
-       /*
-        * Determine if ganged and then dump memory sizes for first controller,
-        * and if NOT ganged dump info for 2nd controller.
-        */
-       ganged = dct_ganging_enabled(pvt);
-
-       amd64_debug_display_dimm_sizes(0, pvt);
-
-       if (!ganged)
-               amd64_debug_display_dimm_sizes(1, pvt);
 }
 
 /* Read in both of DBAM registers */
@@ -1644,11 +1633,10 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
                       WARN_ON(ctrl != 0);
        }
 
-       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
-               ctrl, ctrl ? pvt->dbam1 : pvt->dbam0);
+       dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
+       dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0;
 
-       dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
-       dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0;
+       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
 
        edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
 
index 68f942c..0c56989 100644 (file)
@@ -49,15 +49,13 @@ config FIREWIRE_SBP2
          configuration section.
 
 config FIREWIRE_NET
-       tristate "IP networking over 1394 (EXPERIMENTAL)"
-       depends on FIREWIRE && INET && EXPERIMENTAL
+       tristate "IP networking over 1394"
+       depends on FIREWIRE && INET
        help
          This enables IPv4 over IEEE 1394, providing IP connectivity with
          other implementations of RFC 2734 as found on several operating
          systems.  Multicast support is currently limited.
 
-         NOTE, this driver is not stable yet!
-
          To compile this driver as a module, say M here:  The module will be
          called firewire-net.
 
index be04923..24ff355 100644 (file)
@@ -75,6 +75,8 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_IRMC               ((1) << 31)
 #define NODE_CAPABILITIES      0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
 
+#define CANON_OUI              0x000085
+
 static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 {
        struct fw_descriptor *desc;
@@ -284,6 +286,7 @@ static void bm_work(struct work_struct *work)
        bool root_device_is_running;
        bool root_device_is_cmc;
        bool irm_is_1394_1995_only;
+       bool keep_this_irm;
 
        spin_lock_irq(&card->lock);
 
@@ -305,6 +308,10 @@ static void bm_work(struct work_struct *work)
        irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
                        (irm_device->config_rom[2] & 0x000000f0) == 0;
 
+       /* Canon MV5i works unreliably if it is not root node. */
+       keep_this_irm = irm_device && irm_device->config_rom &&
+                       irm_device->config_rom[3] >> 8 == CANON_OUI;
+
        root_id  = root_node->node_id;
        irm_id   = card->irm_node->node_id;
        local_id = card->local_node->node_id;
@@ -333,7 +340,7 @@ static void bm_work(struct work_struct *work)
                        goto pick_me;
                }
 
-               if (irm_is_1394_1995_only) {
+               if (irm_is_1394_1995_only && !keep_this_irm) {
                        new_root_id = local_id;
                        fw_notify("%s, making local node (%02x) root.\n",
                                  "IRM is not 1394a compliant", new_root_id);
@@ -382,7 +389,7 @@ static void bm_work(struct work_struct *work)
 
                spin_lock_irq(&card->lock);
 
-               if (rcode != RCODE_COMPLETE) {
+               if (rcode != RCODE_COMPLETE && !keep_this_irm) {
                        /*
                         * The lock request failed, maybe the IRM
                         * isn't really IRM capable after all. Let's
index c2e194c..7ed08fd 100644 (file)
@@ -191,6 +191,7 @@ struct fwnet_peer {
        struct fwnet_device *dev;
        u64 guid;
        u64 fifo;
+       __be32 ip;
 
        /* guarded by dev->lock */
        struct list_head pd_list; /* received partial datagrams */
@@ -570,6 +571,8 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
                                peer->speed = sspd;
                        if (peer->max_payload > max_payload)
                                peer->max_payload = max_payload;
+
+                       peer->ip = arp1394->sip;
                }
                spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -1470,6 +1473,7 @@ static int fwnet_add_peer(struct fwnet_device *dev,
        peer->dev = dev;
        peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
        peer->fifo = FWNET_NO_FIFO_ADDR;
+       peer->ip = 0;
        INIT_LIST_HEAD(&peer->pd_list);
        peer->pdg_size = 0;
        peer->datagram_label = 0;
@@ -1589,10 +1593,13 @@ static int fwnet_remove(struct device *_dev)
 
        mutex_lock(&fwnet_device_mutex);
 
+       net = dev->netdev;
+       if (net && peer->ip)
+               arp_invalidate(net, peer->ip);
+
        fwnet_remove_peer(peer, dev);
 
        if (list_empty(&dev->peer_list)) {
-               net = dev->netdev;
                unregister_netdev(net);
 
                if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
index e8b6a13..e710424 100644 (file)
@@ -27,7 +27,7 @@ config EDD_OFF
          using the kernel parameter 'edd={on|skipmbr|off}'.
 
 config FIRMWARE_MEMMAP
-    bool "Add firmware-provided memory map to sysfs" if EMBEDDED
+    bool "Add firmware-provided memory map to sysfs" if EXPERT
     default X86
     help
       Add the firmware-provided (unmodified) memory map to /sys/firmware/memmap.
index e28e416..bcb1126 100644 (file)
@@ -378,10 +378,17 @@ static void __init print_filtered(const char *info)
 
 static void __init dmi_dump_ids(void)
 {
+       const char *board;      /* Board Name is optional */
+
        printk(KERN_DEBUG "DMI: ");
-       print_filtered(dmi_get_system_info(DMI_BOARD_NAME));
-       printk(KERN_CONT "/");
+       print_filtered(dmi_get_system_info(DMI_SYS_VENDOR));
+       printk(KERN_CONT " ");
        print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
+       board = dmi_get_system_info(DMI_BOARD_NAME);
+       if (board) {
+               printk(KERN_CONT "/");
+               print_filtered(board);
+       }
        printk(KERN_CONT ", BIOS ");
        print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
        printk(KERN_CONT " ");
index d81cc74..54d70a4 100644 (file)
@@ -187,7 +187,7 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
 
 static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
+       struct lnw_gpio *lnw = get_irq_data(irq);
        u32 base, gpio;
        void __iomem *gedr;
        u32 gedr_v;
@@ -206,7 +206,12 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
                /* clear the edge detect status bit */
                writel(gedr_v, gedr);
        }
-       desc->chip->eoi(irq);
+
+       if (desc->chip->irq_eoi)
+               desc->chip->irq_eoi(irq_get_irq_data(irq));
+       else
+               dev_warn(lnw->chip.dev, "missing EOI handler for irq %d\n", irq);
+
 }
 
 static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
index a261972..b473429 100644 (file)
@@ -60,6 +60,7 @@ struct pca953x_chip {
        unsigned gpio_start;
        uint16_t reg_output;
        uint16_t reg_direction;
+       struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
        struct mutex irq_lock;
@@ -119,13 +120,17 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        reg_val = chip->reg_direction | (1u << off);
        ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_direction = reg_val;
-       return 0;
+       ret = 0;
+exit:
+       mutex_unlock(&chip->i2c_lock);
+       return ret;
 }
 
 static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@@ -137,6 +142,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        /* set output level */
        if (val)
                reg_val = chip->reg_output | (1u << off);
@@ -145,7 +151,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_output = reg_val;
 
@@ -153,10 +159,13 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
        reg_val = chip->reg_direction & ~(1u << off);
        ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_direction = reg_val;
-       return 0;
+       ret = 0;
+exit:
+       mutex_unlock(&chip->i2c_lock);
+       return ret;
 }
 
 static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
@@ -167,7 +176,9 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+       mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
                /* NOTE:  diagnostic already emitted; that's all we should
                 * do unless gpio_*_value_cansleep() calls become different
@@ -187,6 +198,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        if (val)
                reg_val = chip->reg_output | (1u << off);
        else
@@ -194,9 +206,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 
        ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
        if (ret)
-               return;
+               goto exit;
 
        chip->reg_output = reg_val;
+exit:
+       mutex_unlock(&chip->i2c_lock);
 }
 
 static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
@@ -517,6 +531,8 @@ static int __devinit pca953x_probe(struct i2c_client *client,
 
        chip->names = pdata->names;
 
+       mutex_init(&chip->i2c_lock);
+
        /* initialize cached registers from their original values.
         * we can't share this chip with another i2c master.
         */
index 64828a7..0902d44 100644 (file)
@@ -23,7 +23,7 @@ config DRM_KMS_HELPER
        tristate
        depends on DRM
        select FB
-       select FRAMEBUFFER_CONSOLE if !EMBEDDED
+       select FRAMEBUFFER_CONSOLE if !EXPERT
        help
          FB and CRTC helpers for KMS drivers.
 
@@ -100,7 +100,10 @@ config DRM_I830
 config DRM_I915
        tristate "i915 driver"
        depends on AGP_INTEL
+       # we need shmfs for the swappable backing store, and in particular
+       # the shmem_readpage() which depends upon tmpfs
        select SHMEM
+       select TMPFS
        select DRM_KMS_HELPER
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
index 2baa670..654faa8 100644 (file)
@@ -2674,3 +2674,23 @@ out:
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
+
+void drm_mode_config_reset(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               if (crtc->funcs->reset)
+                       crtc->funcs->reset(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->funcs->reset)
+                       encoder->funcs->reset(encoder);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->funcs->reset)
+                       connector->funcs->reset(connector);
+}
+EXPORT_SYMBOL(drm_mode_config_reset);
index 952b3d4..9236965 100644 (file)
@@ -343,13 +343,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        struct drm_encoder *encoder;
        bool ret = true;
 
-       adjusted_mode = drm_mode_duplicate(dev, mode);
-
        crtc->enabled = drm_helper_crtc_in_use(crtc);
-
        if (!crtc->enabled)
                return true;
 
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
        saved_hwmode = crtc->hwmode;
        saved_mode = crtc->mode;
        saved_x = crtc->x;
@@ -437,10 +436,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
         */
        drm_calc_timestamping_constants(crtc);
 
-       /* XXX free adjustedmode */
-       drm_mode_destroy(dev, adjusted_mode);
        /* FIXME: add subpixel order */
 done:
+       drm_mode_destroy(dev, adjusted_mode);
        if (!ret) {
                crtc->hwmode = saved_hwmode;
                crtc->mode = saved_mode;
@@ -497,14 +495,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        crtc_funcs = set->crtc->helper_private;
 
+       if (!set->mode)
+               set->fb = NULL;
+
        if (set->fb) {
                DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
                                set->crtc->base.id, set->fb->base.id,
                                (int)set->num_connectors, set->x, set->y);
        } else {
-               DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
-                               set->crtc->base.id, (int)set->num_connectors,
-                               set->x, set->y);
+               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+               set->mode = NULL;
+               set->num_connectors = 0;
        }
 
        dev = set->crtc->dev;
@@ -649,8 +650,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                mode_changed = true;
 
        if (mode_changed) {
-               set->crtc->enabled = (set->mode != NULL);
-               if (set->mode != NULL) {
+               set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
+               if (set->crtc->enabled) {
                        DRM_DEBUG_KMS("attempting to set mode from"
                                        " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
@@ -665,6 +666,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                ret = -EINVAL;
                                goto fail;
                        }
+                       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+                       for (i = 0; i < set->num_connectors; i++) {
+                               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+                                             drm_get_connector_name(set->connectors[i]));
+                               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+                       }
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
@@ -681,12 +688,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        goto fail;
                }
        }
-       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
-       for (i = 0; i < set->num_connectors; i++) {
-               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
-                             drm_get_connector_name(set->connectors[i]));
-               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
-       }
 
        kfree(save_connectors);
        kfree(save_encoders);
index 5c4f9b9..6977a1c 100644 (file)
@@ -1533,11 +1533,11 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
 
-/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EMBEDDED)
+/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
  * but the module doesn't depend on any fb console symbols.  At least
  * attempt to load fbcon to avoid leaving the system without a usable console.
  */
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EMBEDDED)
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
 static int __init drm_fb_helper_modinit(void)
 {
        const char *name = "fbcon";
index 3cdbaf3..be9a9c0 100644 (file)
@@ -283,17 +283,18 @@ int drm_vma_info(struct seq_file *m, void *data)
 #endif
 
        mutex_lock(&dev->struct_mutex);
-       seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n",
+       seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n",
                   atomic_read(&dev->vma_count),
-                  high_memory, (u64)virt_to_phys(high_memory));
+                  high_memory, (void *)virt_to_phys(high_memory));
 
        list_for_each_entry(pt, &dev->vmalist, head) {
                vma = pt->vma;
                if (!vma)
                        continue;
                seq_printf(m,
-                          "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
-                          pt->pid, vma->vm_start, vma->vm_end,
+                          "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
+                          pt->pid,
+                          (void *)vma->vm_start, (void *)vma->vm_end,
                           vma->vm_flags & VM_READ ? 'r' : '-',
                           vma->vm_flags & VM_WRITE ? 'w' : '-',
                           vma->vm_flags & VM_EXEC ? 'x' : '-',
index 0054e95..28d1d3c 100644 (file)
@@ -164,8 +164,10 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * available. In that case we can't account for this and just
         * hope for the best.
         */
-       if ((vblrc > 0) && (abs(diff_ns) > 1000000))
+       if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
                atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
+       }
 
        /* Invalidate all timestamps while vblank irq's are off. */
        clear_vblank_timestamps(dev, crtc);
@@ -491,6 +493,12 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
        /* Dot clock in Hz: */
        dotclock = (u64) crtc->hwmode.clock * 1000;
 
+       /* Fields of interlaced scanout modes are only halve a frame duration.
+        * Double the dotclock to get halve the frame-/line-/pixelduration.
+        */
+       if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
+               dotclock *= 2;
+
        /* Valid dotclock? */
        if (dotclock > 0) {
                /* Convert scanline length in pixels and video dot clock to
@@ -603,14 +611,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                return -EAGAIN;
        }
 
-       /* Don't know yet how to handle interlaced or
-        * double scan modes. Just no-op for now.
-        */
-       if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) {
-               DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc);
-               return -ENOTSUPP;
-       }
-
        /* Get current scanout position with system timestamp.
         * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
         * if single query takes longer than max_error nanoseconds.
@@ -858,10 +858,11 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
        if (rc) {
                tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
                vblanktimestamp(dev, crtc, tslot) = t_vblank;
-               smp_wmb();
        }
 
+       smp_mb__before_atomic_inc();
        atomic_add(diff, &dev->_vblank_count[crtc]);
+       smp_mb__after_atomic_inc();
 }
 
 /**
@@ -1011,7 +1012,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       int crtc, ret = 0;
+       int ret = 0;
+       unsigned int crtc;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
@@ -1250,7 +1252,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
  */
-void drm_handle_vblank(struct drm_device *dev, int crtc)
+bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
        u32 vblcount;
        s64 diff_ns;
@@ -1258,7 +1260,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        unsigned long irqflags;
 
        if (!dev->num_crtcs)
-               return;
+               return false;
 
        /* Need timestamp lock to prevent concurrent execution with
         * vblank enable/disable, as this would cause inconsistent
@@ -1269,7 +1271,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        /* Vblank irq handling disabled. Nothing to do. */
        if (!dev->vblank_enabled[crtc]) {
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
-               return;
+               return false;
        }
 
        /* Fetch corresponding timestamp for this vblank interval from
@@ -1293,15 +1295,16 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
         * e.g., due to spurious vblank interrupts. We need to
         * ignore those for accounting.
         */
-       if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
+       if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
                /* Store new timestamp in ringbuffer. */
                vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
-               smp_wmb();
 
                /* Increment cooked vblank count. This also atomically commits
                 * the timestamp computed above.
                 */
+               smp_mb__before_atomic_inc();
                atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
        } else {
                DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
                          crtc, (int) diff_ns);
@@ -1311,5 +1314,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        drm_handle_vblank_events(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
index 844f3c9..e33d9be 100644 (file)
@@ -152,7 +152,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
-       struct intel_ring_buffer *ring = LP_RING(dev_priv);
+       int ret;
 
        master_priv->sarea = drm_getsarea(dev);
        if (master_priv->sarea) {
@@ -163,33 +163,22 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
        }
 
        if (init->ring_size != 0) {
-               if (ring->obj != NULL) {
+               if (LP_RING(dev_priv)->obj != NULL) {
                        i915_dma_cleanup(dev);
                        DRM_ERROR("Client tried to initialize ringbuffer in "
                                  "GEM mode\n");
                        return -EINVAL;
                }
 
-               ring->size = init->ring_size;
-
-               ring->map.offset = init->ring_start;
-               ring->map.size = init->ring_size;
-               ring->map.type = 0;
-               ring->map.flags = 0;
-               ring->map.mtrr = 0;
-
-               drm_core_ioremap_wc(&ring->map, dev);
-
-               if (ring->map.handle == NULL) {
+               ret = intel_render_ring_init_dri(dev,
+                                                init->ring_start,
+                                                init->ring_size);
+               if (ret) {
                        i915_dma_cleanup(dev);
-                       DRM_ERROR("can not ioremap virtual address for"
-                                 " ring buffer\n");
-                       return -ENOMEM;
+                       return ret;
                }
        }
 
-       ring->virtual_start = ring->map.handle;
-
        dev_priv->cpp = init->cpp;
        dev_priv->back_offset = init->back_offset;
        dev_priv->front_offset = init->front_offset;
@@ -1226,9 +1215,15 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
 
-       /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+       /* If we have > 1 VGA cards, then we need to arbitrate access
+        * to the common VGA resources.
+        *
+        * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA),
+        * then we do not take part in VGA arbitration and the
+        * vga_client_register() fails with -ENODEV.
+        */
        ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
-       if (ret)
+       if (ret && ret != -ENODEV)
                goto cleanup_ringbuffer;
 
        intel_register_dsm_handler();
@@ -1900,6 +1895,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (IS_GEN2(dev))
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
 
+       /* 965GM sometimes incorrectly writes to hardware status page (HWS)
+        * using 32bit addressing, overwriting memory if HWS is located
+        * above 4GB.
+        *
+        * The documentation also mentions an issue with undefined
+        * behaviour if any general state is accessed within a page above 4GB,
+        * which also needs to be handled carefully.
+        */
+       if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
+               dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+
        mmio_bar = IS_GEN2(dev) ? 1 : 0;
        dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
        if (!dev_priv->regs) {
index 72fea2b..0ad533f 100644 (file)
@@ -46,6 +46,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 unsigned int i915_powersave = 1;
 module_param_named(powersave, i915_powersave, int, 0600);
 
+unsigned int i915_enable_rc6 = 0;
+module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
+
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
@@ -60,7 +63,7 @@ extern int intel_agp_enabled;
 
 #define INTEL_VGA_DEVICE(id, info) {           \
        .class = PCI_CLASS_DISPLAY_VGA << 8,    \
-       .class_mask = 0xffff00,                 \
+       .class_mask = 0xff0000,                 \
        .vendor = 0x8086,                       \
        .device = id,                           \
        .subvendor = PCI_ANY_ID,                \
@@ -354,12 +357,13 @@ static int i915_drm_thaw(struct drm_device *dev)
                error = i915_gem_init_ringbuffer(dev);
                mutex_unlock(&dev->struct_mutex);
 
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
 
                /* Resume the modeset for every activated CRTC */
                drm_helper_resume_force_mode(dev);
 
-               if (dev_priv->renderctx && dev_priv->pwrctx)
+               if (IS_IRONLAKE_M(dev))
                        ironlake_enable_rc6(dev);
        }
 
@@ -542,6 +546,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
 
                mutex_unlock(&dev->struct_mutex);
                drm_irq_uninstall(dev);
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
                mutex_lock(&dev->struct_mutex);
        }
@@ -566,6 +571,14 @@ int i915_reset(struct drm_device *dev, u8 flags)
 static int __devinit
 i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       /* Only bind to function 0 of the device. Early generations
+        * used function 1 as a placeholder for multi-head. This causes
+        * us confusion instead, especially on the systems where both
+        * functions have the same PCI-ID!
+        */
+       if (PCI_FUNC(pdev->devfn))
+               return -ENODEV;
+
        return drm_get_pci_dev(pdev, ent, &driver);
 }
 
@@ -752,6 +765,9 @@ static int __init i915_init(void)
                driver.driver_features &= ~DRIVER_MODESET;
 #endif
 
+       if (!(driver.driver_features & DRIVER_MODESET))
+               driver.get_vblank_timestamp = NULL;
+
        return drm_init(&driver);
 }
 
index 5969f46..65dfe81 100644 (file)
@@ -543,8 +543,11 @@ typedef struct drm_i915_private {
                /** List of all objects in gtt_space. Used to restore gtt
                 * mappings on resume */
                struct list_head gtt_list;
-               /** End of mappable part of GTT */
+
+               /** Usable portion of the GTT for GEM */
+               unsigned long gtt_start;
                unsigned long gtt_mappable_end;
+               unsigned long gtt_end;
 
                struct io_mapping *gtt_mapping;
                int gtt_mtrr;
@@ -955,6 +958,7 @@ extern unsigned int i915_fbpercrtc;
 extern unsigned int i915_powersave;
 extern unsigned int i915_lvds_downclock;
 extern unsigned int i915_panel_use_ssc;
+extern unsigned int i915_enable_rc6;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
index 3dfc848..cf4f74c 100644 (file)
@@ -140,12 +140,16 @@ void i915_gem_do_init(struct drm_device *dev,
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       drm_mm_init(&dev_priv->mm.gtt_space, start,
-                   end - start);
+       drm_mm_init(&dev_priv->mm.gtt_space, start, end - start);
 
+       dev_priv->mm.gtt_start = start;
+       dev_priv->mm.gtt_mappable_end = mappable_end;
+       dev_priv->mm.gtt_end = end;
        dev_priv->mm.gtt_total = end - start;
        dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
-       dev_priv->mm.gtt_mappable_end = mappable_end;
+
+       /* Take over this portion of the GTT */
+       intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE);
 }
 
 int
@@ -1857,7 +1861,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
 
        seqno = ring->get_seqno(ring);
 
-       for (i = 0; i < I915_NUM_RINGS; i++)
+       for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++)
                if (seqno >= ring->sync_seqno[i])
                        ring->sync_seqno[i] = 0;
 
index dcfdf41..d2f445e 100644 (file)
@@ -1175,7 +1175,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
 
        seqno = i915_gem_next_request_seqno(dev, ring);
-       for (i = 0; i < I915_NUM_RINGS-1; i++) {
+       for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) {
                if (seqno < ring->sync_seqno[i]) {
                        /* The GPU can not handle its semaphore value wrapping,
                         * so every billion or so execbuffers, we need to stall
index 70433ae..b0abdc6 100644 (file)
@@ -34,6 +34,10 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
+       /* First fill our portion of the GTT with scratch pages */
+       intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
+                             (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
+
        list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
                i915_gem_clflush_object(obj);
 
index 22a32b9..79a04fd 100644 (file)
@@ -184,7 +184,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
 static bool
 i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 {
-       int tile_width;
+       int tile_width, tile_height;
 
        /* Linear is always fine */
        if (tiling_mode == I915_TILING_NONE)
@@ -215,6 +215,20 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
                }
        }
 
+       if (IS_GEN2(dev) ||
+           (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
+               tile_height = 32;
+       else
+               tile_height = 8;
+       /* i8xx is strange: It has 2 interleaved rows of tiles, so needs an even
+        * number of tile rows. */
+       if (IS_GEN2(dev))
+               tile_height *= 2;
+
+       /* Size needs to be aligned to a full tile row */
+       if (size & (tile_height * stride - 1))
+               return false;
+
        /* 965+ just needs multiples of tile width */
        if (INTEL_INFO(dev)->gen >= 4) {
                if (stride & (tile_width - 1))
index b8e509a..8a9e08b 100644 (file)
@@ -274,24 +274,35 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        return ret;
 }
 
-int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
+int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                              int *max_error,
                              struct timeval *vblank_time,
                              unsigned flags)
 {
-       struct drm_crtc *drmcrtc;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
 
-       if (crtc < 0 || crtc >= dev->num_crtcs) {
-               DRM_ERROR("Invalid crtc %d\n", crtc);
+       if (pipe < 0 || pipe >= dev_priv->num_pipe) {
+               DRM_ERROR("Invalid crtc %d\n", pipe);
                return -EINVAL;
        }
 
        /* Get drm_crtc to timestamp: */
-       drmcrtc = intel_get_crtc_for_pipe(dev, crtc);
+       crtc = intel_get_crtc_for_pipe(dev, pipe);
+       if (crtc == NULL) {
+               DRM_ERROR("Invalid crtc %d\n", pipe);
+               return -EINVAL;
+       }
+
+       if (!crtc->enabled) {
+               DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+               return -EBUSY;
+       }
 
        /* Helper routine in DRM core does all the work: */
-       return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
-                                                    vblank_time, flags, drmcrtc);
+       return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
+                                                    vblank_time, flags,
+                                                    crtc);
 }
 
 /*
@@ -305,6 +316,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
 
+       DRM_DEBUG_KMS("running encoder hotplug functions\n");
+
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
                if (encoder->hot_plug)
                        encoder->hot_plug(encoder);
@@ -348,8 +361,12 @@ static void notify_ring(struct drm_device *dev,
                        struct intel_ring_buffer *ring)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 seqno = ring->get_seqno(ring);
+       u32 seqno;
 
+       if (ring->obj == NULL)
+               return;
+
+       seqno = ring->get_seqno(ring);
        trace_i915_gem_request_complete(dev, seqno);
 
        ring->irq_seqno = seqno;
@@ -831,6 +848,8 @@ static void i915_capture_error_state(struct drm_device *dev)
                i++;
        error->pinned_bo_count = i - error->active_bo_count;
 
+       error->active_bo = NULL;
+       error->pinned_bo = NULL;
        if (i) {
                error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
                                           GFP_ATOMIC);
@@ -1179,18 +1198,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                intel_finish_page_flip_plane(dev, 1);
                }
 
-               if (pipea_stats & vblank_status) {
+               if (pipea_stats & vblank_status &&
+                   drm_handle_vblank(dev, 0)) {
                        vblank++;
-                       drm_handle_vblank(dev, 0);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 0);
                                intel_finish_page_flip(dev, 0);
                        }
                }
 
-               if (pipeb_stats & vblank_status) {
+               if (pipeb_stats & vblank_status &&
+                   drm_handle_vblank(dev, 1)) {
                        vblank++;
-                       drm_handle_vblank(dev, 1);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 1);
                                intel_finish_page_flip(dev, 1);
@@ -1278,12 +1297,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
-       ret = -ENODEV;
        if (ring->irq_get(ring)) {
                DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
                            READ_BREADCRUMB(dev_priv) >= irq_nr);
                ring->irq_put(ring);
-       }
+       } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000))
+               ret = -EBUSY;
 
        if (ret == -EBUSY) {
                DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
@@ -1632,9 +1651,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        } else {
                hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
                               SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
-               hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK;
-               I915_WRITE(FDI_RXA_IMR, 0);
-               I915_WRITE(FDI_RXB_IMR, 0);
+               hotplug_mask |= SDE_AUX_MASK;
        }
 
        dev_priv->pch_irq_mask = ~hotplug_mask;
index 40a407f..729d423 100644 (file)
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*x-1)
-#define MI_FLUSH_DW            MI_INSTR(0x26, 2) /* for GEN6 */
+#define MI_FLUSH_DW            MI_INSTR(0x26, 1) /* for GEN6 */
+#define   MI_INVALIDATE_TLB    (1<<18)
+#define   MI_INVALIDATE_BSD    (1<<7)
 #define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE  (1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define   GEN6_BLITTER_SYNC_STATUS                     (1 << 24)
 #define   GEN6_BLITTER_USER_INTERRUPT                  (1 << 22)
 
+#define GEN6_BLITTER_ECOSKPD   0x221d0
+#define   GEN6_BLITTER_LOCK_SHIFT                      16
+#define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
+
 #define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
 #define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK      (1 << 16)
 #define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE          (1 << 0)
 
 /* Backlight control */
 #define BLC_PWM_CTL            0x61254
-#define   BACKLIGHT_MODULATION_FREQ_SHIFT              (17)
 #define BLC_PWM_CTL2           0x61250 /* 965+ only */
-#define   BLM_COMBINATION_MODE (1 << 30)
-/*
- * This is the most significant 15 bits of the number of backlight cycles in a
- * complete cycle of the modulated backlight control.
- *
- * The actual value is this field multiplied by two.
- */
-#define   BACKLIGHT_MODULATION_FREQ_MASK               (0x7fff << 17)
-#define   BLM_LEGACY_MODE                              (1 << 16)
 /*
  * This is the number of cycles out of the backlight modulation cycle for which
  * the backlight is on.
 #define DISPLAY_PORT_PLL_BIOS_2         0x46014
 
 #define PCH_DSPCLK_GATE_D      0x42020
+# define DPFCUNIT_CLOCK_GATE_DISABLE           (1 << 9)
+# define DPFCRUNIT_CLOCK_GATE_DISABLE          (1 << 8)
 # define DPFDUNIT_CLOCK_GATE_DISABLE           (1 << 7)
 # define DPARBUNIT_CLOCK_GATE_DISABLE          (1 << 5)
 
index 17035b8..8a77ff4 100644 (file)
@@ -535,6 +535,15 @@ static int intel_crt_set_property(struct drm_connector *connector,
        return 0;
 }
 
+static void intel_crt_reset(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
+
+       if (HAS_PCH_SPLIT(dev))
+               crt->force_hotplug_required = 1;
+}
+
 /*
  * Routines for controlling stuff on the analog port
  */
@@ -548,6 +557,7 @@ static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
 };
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
+       .reset = intel_crt_reset,
        .dpms = drm_helper_connector_dpms,
        .detect = intel_crt_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
index 98967f3..e79b25b 100644 (file)
@@ -1213,6 +1213,26 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
        return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
+static void sandybridge_blit_fbc_update(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 blt_ecoskpd;
+
+       /* Make sure blitter notifies FBC of writes */
+       __gen6_force_wake_get(dev_priv);
+       blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
+       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
+               GEN6_BLITTER_LOCK_SHIFT;
+       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
+       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+       blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
+                        GEN6_BLITTER_LOCK_SHIFT);
+       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+       POSTING_READ(GEN6_BLITTER_ECOSKPD);
+       __gen6_force_wake_put(dev_priv);
+}
+
 static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct drm_device *dev = crtc->dev;
@@ -1266,6 +1286,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(SNB_DPFC_CTL_SA,
                           SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence);
                I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+               sandybridge_blit_fbc_update(dev);
        }
 
        DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
@@ -1609,19 +1630,19 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
 
                wait_event(dev_priv->pending_flip_queue,
+                          atomic_read(&dev_priv->mm.wedged) ||
                           atomic_read(&obj->pending_flip) == 0);
 
                /* Big Hammer, we also need to ensure that any pending
                 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
                 * current scanout is retired before unpinning the old
                 * framebuffer.
+                *
+                * This should only fail upon a hung GPU, in which case we
+                * can safely continue.
                 */
                ret = i915_gem_object_flush_gpu(obj, false);
-               if (ret) {
-                       i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
-                       mutex_unlock(&dev->struct_mutex);
-                       return ret;
-               }
+               (void) ret;
        }
 
        ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
@@ -2024,6 +2045,31 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
                   atomic_read(&obj->pending_flip) == 0);
 }
 
+static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+
+       /*
+        * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
+        * must be driven by its own crtc; no sharing is possible.
+        */
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_EDP:
+                       if (!intel_encoder_is_pch_edp(&encoder->base))
+                               return false;
+                       continue;
+               }
+       }
+
+       return true;
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -2032,6 +2078,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        u32 reg, temp;
+       bool is_pch_port = false;
 
        if (intel_crtc->active)
                return;
@@ -2045,7 +2092,56 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                        I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
        }
 
-       ironlake_fdi_enable(crtc);
+       is_pch_port = intel_crtc_driving_pch(crtc);
+
+       if (is_pch_port)
+               ironlake_fdi_enable(crtc);
+       else {
+               /* disable CPU FDI tx and PCH FDI rx */
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+               POSTING_READ(reg);
+
+               reg = FDI_RX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(0x7 << 16);
+               temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+               I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+               POSTING_READ(reg);
+               udelay(100);
+
+               /* Ironlake workaround, disable clock pointer after downing FDI */
+               if (HAS_PCH_IBX(dev))
+                       I915_WRITE(FDI_RX_CHICKEN(pipe),
+                                  I915_READ(FDI_RX_CHICKEN(pipe) &
+                                            ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
+               /* still set train pattern 1 */
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(reg, temp);
+
+               reg = FDI_RX_CTL(pipe);
+               temp = I915_READ(reg);
+               if (HAS_PCH_CPT(dev)) {
+                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+               } else {
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+               }
+               /* BPC in FDI rx is consistent with that in PIPECONF */
+               temp &= ~(0x07 << 16);
+               temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(100);
+       }
 
        /* Enable panel fitting for LVDS */
        if (dev_priv->pch_pf_size &&
@@ -2079,6 +2175,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                intel_flush_display_plane(dev, plane);
        }
 
+       /* Skip the PCH stuff if possible */
+       if (!is_pch_port)
+               goto done;
+
        /* For PCH output, training FDI link */
        if (IS_GEN6(dev))
                gen6_fdi_link_train(crtc);
@@ -2163,7 +2263,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        I915_WRITE(reg, temp | TRANS_ENABLE);
        if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
                DRM_ERROR("failed to enable transcoder %d\n", pipe);
-
+done:
        intel_crtc_load_lut(crtc);
        intel_update_fbc(dev);
        intel_crtc_update_cursor(crtc, true);
@@ -5530,6 +5630,16 @@ cleanup_work:
        return ret;
 }
 
+static void intel_crtc_reset(struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       /* Reset flags back to the 'unknown' status so that they
+        * will be correctly set on the initial modeset.
+        */
+       intel_crtc->dpms_mode = -1;
+}
+
 static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .dpms = intel_crtc_dpms,
        .mode_fixup = intel_crtc_mode_fixup,
@@ -5541,6 +5651,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .reset = intel_crtc_reset,
        .cursor_set = intel_crtc_cursor_set,
        .cursor_move = intel_crtc_cursor_move,
        .gamma_set = intel_crtc_gamma_set,
@@ -5631,8 +5742,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
-       intel_crtc->cursor_addr = 0;
-       intel_crtc->dpms_mode = -1;
+       intel_crtc_reset(&intel_crtc->base);
        intel_crtc->active = true; /* force the pipe off on setup_init_config */
 
        if (HAS_PCH_SPLIT(dev)) {
@@ -6286,7 +6396,9 @@ void intel_enable_clock_gating(struct drm_device *dev)
 
                if (IS_GEN5(dev)) {
                        /* Required for FBC */
-                       dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
+                       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+                               DPFCRUNIT_CLOCK_GATE_DISABLE |
+                               DPFDUNIT_CLOCK_GATE_DISABLE;
                        /* Required for CxSR */
                        dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
 
@@ -6429,52 +6541,60 @@ void intel_enable_clock_gating(struct drm_device *dev)
        }
 }
 
-void intel_disable_clock_gating(struct drm_device *dev)
+static void ironlake_teardown_rc6(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (dev_priv->renderctx) {
-               struct drm_i915_gem_object *obj = dev_priv->renderctx;
-
-               I915_WRITE(CCID, 0);
-               POSTING_READ(CCID);
-
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_unpin(dev_priv->renderctx);
+               drm_gem_object_unreference(&dev_priv->renderctx->base);
                dev_priv->renderctx = NULL;
        }
 
        if (dev_priv->pwrctx) {
-               struct drm_i915_gem_object *obj = dev_priv->pwrctx;
+               i915_gem_object_unpin(dev_priv->pwrctx);
+               drm_gem_object_unreference(&dev_priv->pwrctx->base);
+               dev_priv->pwrctx = NULL;
+       }
+}
+
+static void ironlake_disable_rc6(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (I915_READ(PWRCTXA)) {
+               /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+               wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+                        50);
 
                I915_WRITE(PWRCTXA, 0);
                POSTING_READ(PWRCTXA);
 
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
-               dev_priv->pwrctx = NULL;
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+               POSTING_READ(RSTDBYCTL);
        }
+
+       ironlake_teardown_rc6(dev);
 }
 
-static void ironlake_disable_rc6(struct drm_device *dev)
+static int ironlake_setup_rc6(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
-       wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
-                10);
-       POSTING_READ(CCID);
-       I915_WRITE(PWRCTXA, 0);
-       POSTING_READ(PWRCTXA);
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-       POSTING_READ(RSTDBYCTL);
-       i915_gem_object_unpin(dev_priv->renderctx);
-       drm_gem_object_unreference(&dev_priv->renderctx->base);
-       dev_priv->renderctx = NULL;
-       i915_gem_object_unpin(dev_priv->pwrctx);
-       drm_gem_object_unreference(&dev_priv->pwrctx->base);
-       dev_priv->pwrctx = NULL;
+       if (dev_priv->renderctx == NULL)
+               dev_priv->renderctx = intel_alloc_context_page(dev);
+       if (!dev_priv->renderctx)
+               return -ENOMEM;
+
+       if (dev_priv->pwrctx == NULL)
+               dev_priv->pwrctx = intel_alloc_context_page(dev);
+       if (!dev_priv->pwrctx) {
+               ironlake_teardown_rc6(dev);
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 void ironlake_enable_rc6(struct drm_device *dev)
@@ -6482,15 +6602,26 @@ void ironlake_enable_rc6(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       /* rc6 disabled by default due to repeated reports of hanging during
+        * boot and resume.
+        */
+       if (!i915_enable_rc6)
+               return;
+
+       ret = ironlake_setup_rc6(dev);
+       if (ret)
+               return;
+
        /*
         * GPU can automatically power down the render unit if given a page
         * to save state.
         */
        ret = BEGIN_LP_RING(6);
        if (ret) {
-               ironlake_disable_rc6(dev);
+               ironlake_teardown_rc6(dev);
                return;
        }
+
        OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
        OUT_RING(MI_SET_CONTEXT);
        OUT_RING(dev_priv->renderctx->gtt_offset |
@@ -6507,6 +6638,7 @@ void ironlake_enable_rc6(struct drm_device *dev)
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
 }
 
+
 /* Set up chip specific display functions */
 static void intel_init_display(struct drm_device *dev)
 {
@@ -6749,21 +6881,9 @@ void intel_modeset_init(struct drm_device *dev)
        if (IS_GEN6(dev))
                gen6_enable_rps(dev_priv);
 
-       if (IS_IRONLAKE_M(dev)) {
-               dev_priv->renderctx = intel_alloc_context_page(dev);
-               if (!dev_priv->renderctx)
-                       goto skip_rc6;
-               dev_priv->pwrctx = intel_alloc_context_page(dev);
-               if (!dev_priv->pwrctx) {
-                       i915_gem_object_unpin(dev_priv->renderctx);
-                       drm_gem_object_unreference(&dev_priv->renderctx->base);
-                       dev_priv->renderctx = NULL;
-                       goto skip_rc6;
-               }
+       if (IS_IRONLAKE_M(dev))
                ironlake_enable_rc6(dev);
-       }
 
-skip_rc6:
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
index 1f4242b..51cb4e3 100644 (file)
@@ -1639,6 +1639,24 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        return 0;
 }
 
+static bool
+intel_dp_detect_audio(struct drm_connector *connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct edid *edid;
+       bool has_audio = false;
+
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               has_audio = drm_detect_monitor_audio(edid);
+
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
+       }
+
+       return has_audio;
+}
+
 static int
 intel_dp_set_property(struct drm_connector *connector,
                      struct drm_property *property,
@@ -1652,17 +1670,23 @@ intel_dp_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_dp->force_audio_property) {
-               if (val == intel_dp->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_dp->force_audio)
                        return 0;
 
-               intel_dp->force_audio = val;
+               intel_dp->force_audio = i;
 
-               if (val > 0 && intel_dp->has_audio)
-                       return 0;
-               if (val < 0 && !intel_dp->has_audio)
+               if (i == 0)
+                       has_audio = intel_dp_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_dp->has_audio)
                        return 0;
 
-               intel_dp->has_audio = val > 0;
+               intel_dp->has_audio = has_audio;
                goto done;
        }
 
index 74db255..2c43104 100644 (file)
@@ -298,7 +298,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
 extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
                                    u16 *blue, int regno);
 extern void intel_enable_clock_gating(struct drm_device *dev);
-extern void intel_disable_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
 extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
index 0d0273e..c635c9e 100644 (file)
@@ -251,6 +251,27 @@ static int intel_hdmi_get_modes(struct drm_connector *connector)
                                   &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 }
 
+static bool
+intel_hdmi_detect_audio(struct drm_connector *connector)
+{
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct edid *edid;
+       bool has_audio = false;
+
+       edid = drm_get_edid(connector,
+                           &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+       if (edid) {
+               if (edid->input & DRM_EDID_INPUT_DIGITAL)
+                       has_audio = drm_detect_monitor_audio(edid);
+
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
+       }
+
+       return has_audio;
+}
+
 static int
 intel_hdmi_set_property(struct drm_connector *connector,
                      struct drm_property *property,
@@ -264,17 +285,23 @@ intel_hdmi_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_hdmi->force_audio_property) {
-               if (val == intel_hdmi->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_hdmi->force_audio)
                        return 0;
 
-               intel_hdmi->force_audio = val;
+               intel_hdmi->force_audio = i;
 
-               if (val > 0 && intel_hdmi->has_audio)
-                       return 0;
-               if (val < 0 && !intel_hdmi->has_audio)
+               if (i == 0)
+                       has_audio = intel_hdmi_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_hdmi->has_audio)
                        return 0;
 
-               intel_hdmi->has_audio = val > 0;
+               intel_hdmi->has_audio = has_audio;
                goto done;
        }
 
index ace8d5d..bcdba7b 100644 (file)
@@ -261,12 +261,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                return true;
        }
 
-       /* Make sure pre-965s set dither correctly */
-       if (INTEL_INFO(dev)->gen < 4) {
-               if (dev_priv->lvds_dither)
-                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-       }
-
        /* Native modes don't need fitting */
        if (adjusted_mode->hdisplay == mode->hdisplay &&
            adjusted_mode->vdisplay == mode->vdisplay)
@@ -374,10 +368,16 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
 out:
+       /* If not enabling scaling, be consistent and always use 0. */
        if ((pfit_control & PFIT_ENABLE) == 0) {
                pfit_control = 0;
                pfit_pgm_ratios = 0;
        }
+
+       /* Make sure pre-965 set dither correctly */
+       if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
+               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
        if (pfit_control != intel_lvds->pfit_control ||
            pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
                intel_lvds->pfit_control = pfit_control;
index f295a7a..64fd644 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <acpi/video.h>
 
 #include "drmP.h"
@@ -476,7 +477,7 @@ int intel_opregion_setup(struct drm_device *dev)
                return -ENOTSUPP;
        }
 
-       base = ioremap(asls, OPREGION_SIZE);
+       base = acpi_os_ioremap(asls, OPREGION_SIZE);
        if (!base)
                return -ENOMEM;
 
index c65992d..d860abe 100644 (file)
@@ -30,8 +30,6 @@
 
 #include "intel_drv.h"
 
-#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
-
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
@@ -112,19 +110,6 @@ done:
        dev_priv->pch_pf_size = (width << 16) | height;
 }
 
-static int is_backlight_combination_mode(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (INTEL_INFO(dev)->gen >= 4)
-               return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
-
-       if (IS_GEN2(dev))
-               return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
-
-       return 0;
-}
-
 static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
 {
        u32 val;
@@ -181,9 +166,6 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
                        if (INTEL_INFO(dev)->gen < 4)
                                max &= ~1;
                }
-
-               if (is_backlight_combination_mode(dev))
-                       max *= 0xff;
        }
 
        DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
@@ -201,15 +183,6 @@ u32 intel_panel_get_backlight(struct drm_device *dev)
                val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
                if (IS_PINEVIEW(dev))
                        val >>= 1;
-
-               if (is_backlight_combination_mode(dev)){
-                       u8 lbpc;
-
-                       val &= ~1;
-                       pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
-                       val *= lbpc;
-                       val >>= 1;
-               }
        }
 
        DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
@@ -232,16 +205,6 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
 
        if (HAS_PCH_SPLIT(dev))
                return intel_pch_panel_set_backlight(dev, level);
-
-       if (is_backlight_combination_mode(dev)){
-               u32 max = intel_panel_get_max_backlight(dev);
-               u8 lpbc;
-
-               lpbc = level * 0xfe / max + 1;
-               level /= lpbc;
-               pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
-       }
-
        tmp = I915_READ(BLC_PWM_CTL);
        if (IS_PINEVIEW(dev)) {
                tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
index 03e3370..445f27e 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+static inline int ring_space(struct intel_ring_buffer *ring)
+{
+       int space = (ring->head & HEAD_ADDR) - (ring->tail + 8);
+       if (space < 0)
+               space += ring->size;
+       return space;
+}
+
 static u32 i915_gem_get_seqno(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -204,11 +212,9 @@ static int init_ring_common(struct intel_ring_buffer *ring)
        if (!drm_core_check_feature(ring->dev, DRIVER_MODESET))
                i915_kernel_lost_context(ring->dev);
        else {
-               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               ring->head = I915_READ_HEAD(ring);
                ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-               ring->space = ring->head - (ring->tail + 8);
-               if (ring->space < 0)
-                       ring->space += ring->size;
+               ring->space = ring_space(ring);
        }
 
        return 0;
@@ -921,7 +927,7 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
        }
 
        ring->tail = 0;
-       ring->space = ring->head - 8;
+       ring->space = ring_space(ring);
 
        return 0;
 }
@@ -933,20 +939,22 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
        unsigned long end;
        u32 head;
 
+       /* If the reported head position has wrapped or hasn't advanced,
+        * fallback to the slow and accurate path.
+        */
+       head = intel_read_status_page(ring, 4);
+       if (head > ring->head) {
+               ring->head = head;
+               ring->space = ring_space(ring);
+               if (ring->space >= n)
+                       return 0;
+       }
+
        trace_i915_ring_wait_begin (dev);
        end = jiffies + 3 * HZ;
        do {
-               /* If the reported head position has wrapped or hasn't advanced,
-                * fallback to the slow and accurate path.
-                */
-               head = intel_read_status_page(ring, 4);
-               if (head < ring->actual_head)
-                       head = I915_READ_HEAD(ring);
-               ring->actual_head = head;
-               ring->head = head & HEAD_ADDR;
-               ring->space = ring->head - (ring->tail + 8);
-               if (ring->space < 0)
-                       ring->space += ring->size;
+               ring->head = I915_READ_HEAD(ring);
+               ring->space = ring_space(ring);
                if (ring->space >= n) {
                        trace_i915_ring_wait_end(dev);
                        return 0;
@@ -1051,22 +1059,25 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
 }
 
 static int gen6_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                          u32 invalidate, u32 flush)
 {
+       uint32_t cmd;
        int ret;
 
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
 
        ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_GPU_DOMAINS)
+               cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
 }
@@ -1222,22 +1233,25 @@ static int blt_ring_begin(struct intel_ring_buffer *ring,
 }
 
 static int blt_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                         u32 invalidate, u32 flush)
 {
+       uint32_t cmd;
        int ret;
 
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0)
                return 0;
 
        ret = blt_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_DOMAIN_RENDER)
+               cmd |= MI_INVALIDATE_TLB;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
 }
@@ -1291,6 +1305,48 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
        return intel_init_ring_buffer(dev, ring);
 }
 
+int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+
+       *ring = render_ring;
+       if (INTEL_INFO(dev)->gen >= 6) {
+               ring->add_request = gen6_add_request;
+               ring->irq_get = gen6_render_ring_get_irq;
+               ring->irq_put = gen6_render_ring_put_irq;
+       } else if (IS_GEN5(dev)) {
+               ring->add_request = pc_render_add_request;
+               ring->get_seqno = pc_render_get_seqno;
+       }
+
+       ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       INIT_LIST_HEAD(&ring->gpu_write_list);
+
+       ring->size = size;
+       ring->effective_size = ring->size;
+       if (IS_I830(ring->dev))
+               ring->effective_size -= 128;
+
+       ring->map.offset = start;
+       ring->map.size = size;
+       ring->map.type = 0;
+       ring->map.flags = 0;
+       ring->map.mtrr = 0;
+
+       drm_core_ioremap_wc(&ring->map, dev);
+       if (ring->map.handle == NULL) {
+               DRM_ERROR("can not ioremap virtual address for"
+                         " ring buffer\n");
+               return -ENOMEM;
+       }
+
+       ring->virtual_start = (void __force __iomem *)ring->map.handle;
+       return 0;
+}
+
 int intel_init_bsd_ring_buffer(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
index be9087e..6d6fde8 100644 (file)
@@ -47,7 +47,6 @@ struct  intel_ring_buffer {
        struct          drm_device *dev;
        struct          drm_i915_gem_object *obj;
 
-       u32             actual_head;
        u32             head;
        u32             tail;
        int             space;
@@ -167,4 +166,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev);
 u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
 
+/* DRI warts */
+int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size);
+
 #endif /* _INTEL_RINGBUFFER_H_ */
index 45cd376..7c50cdc 100644 (file)
@@ -46,6 +46,7 @@
                          SDVO_TV_MASK)
 
 #define IS_TV(c)       (c->output_flag & SDVO_TV_MASK)
+#define IS_TMDS(c)     (c->output_flag & SDVO_TMDS_MASK)
 #define IS_LVDS(c)     (c->output_flag & SDVO_LVDS_MASK)
 #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
 
@@ -473,20 +474,6 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
                return false;
        }
 
-       i = 3;
-       while (status == SDVO_CMD_STATUS_PENDING && i--) {
-               if (!intel_sdvo_read_byte(intel_sdvo,
-                                         SDVO_I2C_CMD_STATUS,
-                                         &status))
-                       return false;
-       }
-       if (status != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("command returns response %s [%d]\n",
-                             status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
-                             status);
-               return false;
-       }
-
        return true;
 }
 
@@ -497,6 +484,8 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        u8 status;
        int i;
 
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+
        /*
         * The documentation states that all commands will be
         * processed within 15µs, and that we need only poll
@@ -505,14 +494,19 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
         *
         * Check 5 times in case the hardware failed to read the docs.
         */
-       do {
+       if (!intel_sdvo_read_byte(intel_sdvo,
+                                 SDVO_I2C_CMD_STATUS,
+                                 &status))
+               goto log_fail;
+
+       while (status == SDVO_CMD_STATUS_PENDING && retry--) {
+               udelay(15);
                if (!intel_sdvo_read_byte(intel_sdvo,
                                          SDVO_I2C_CMD_STATUS,
                                          &status))
-                       return false;
-       } while (status == SDVO_CMD_STATUS_PENDING && --retry);
+                       goto log_fail;
+       }
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
                DRM_LOG_KMS("(%s)", cmd_status_names[status]);
        else
@@ -533,7 +527,7 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        return true;
 
 log_fail:
-       DRM_LOG_KMS("\n");
+       DRM_LOG_KMS("... failed\n");
        return false;
 }
 
@@ -550,6 +544,7 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
 static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
                                              u8 ddc_bus)
 {
+       /* This must be the immediately preceding write before the i2c xfer */
        return intel_sdvo_write_cmd(intel_sdvo,
                                    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
                                    &ddc_bus, 1);
@@ -557,7 +552,10 @@ static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-       return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
+       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
+               return false;
+
+       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
 }
 
 static bool
@@ -859,18 +857,21 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 
        intel_dip_infoframe_csum(&avi_if);
 
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
                                  set_buf_index, 2))
                return false;
 
        for (i = 0; i < sizeof(avi_if); i += 8) {
-               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+               if (!intel_sdvo_set_value(intel_sdvo,
+                                         SDVO_CMD_SET_HBUF_DATA,
                                          data, 8))
                        return false;
                data++;
        }
 
-       return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_HBUF_TXRATE,
                                    &tx_rate, 1);
 }
 
@@ -1359,7 +1360,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
                                intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
                                intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
                        }
-               }
+               } else
+                       status = connector_status_disconnected;
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@ -1407,10 +1409,25 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
        if ((intel_sdvo_connector->output_flag & response) == 0)
                ret = connector_status_disconnected;
-       else if (response & SDVO_TMDS_MASK)
+       else if (IS_TMDS(intel_sdvo_connector))
                ret = intel_sdvo_hdmi_sink_detect(connector);
-       else
-               ret = connector_status_connected;
+       else {
+               struct edid *edid;
+
+               /* if we have an edid check it matches the connection */
+               edid = intel_sdvo_get_edid(connector);
+               if (edid == NULL)
+                       edid = intel_sdvo_get_analog_edid(connector);
+               if (edid != NULL) {
+                       if (edid->input & DRM_EDID_INPUT_DIGITAL)
+                               ret = connector_status_disconnected;
+                       else
+                               ret = connector_status_connected;
+                       connector->display_info.raw_edid = NULL;
+                       kfree(edid);
+               } else
+                       ret = connector_status_connected;
+       }
 
        /* May update encoder flag for like clock for SDVO TV, etc.*/
        if (ret == connector_status_connected) {
@@ -1446,10 +1463,15 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
                edid = intel_sdvo_get_analog_edid(connector);
 
        if (edid != NULL) {
-               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+               struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+               bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
+               bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector);
+
+               if (connector_is_digital == monitor_is_digital) {
                        drm_mode_connector_update_edid_property(connector, edid);
                        drm_add_edid_modes(connector, edid);
                }
+
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@ -1668,6 +1690,22 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
        kfree(connector);
 }
 
+static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct edid *edid;
+       bool has_audio = false;
+
+       if (!intel_sdvo->is_hdmi)
+               return false;
+
+       edid = intel_sdvo_get_edid(connector);
+       if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)
+               has_audio = drm_detect_monitor_audio(edid);
+
+       return has_audio;
+}
+
 static int
 intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
@@ -1684,17 +1722,23 @@ intel_sdvo_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_sdvo_connector->force_audio_property) {
-               if (val == intel_sdvo_connector->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_sdvo_connector->force_audio)
                        return 0;
 
-               intel_sdvo_connector->force_audio = val;
+               intel_sdvo_connector->force_audio = i;
 
-               if (val > 0 && intel_sdvo->has_hdmi_audio)
-                       return 0;
-               if (val < 0 && !intel_sdvo->has_hdmi_audio)
+               if (i == 0)
+                       has_audio = intel_sdvo_detect_hdmi_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_sdvo->has_hdmi_audio)
                        return 0;
 
-               intel_sdvo->has_hdmi_audio = val > 0;
+               intel_sdvo->has_hdmi_audio = has_audio;
                goto done;
        }
 
index 93206e4..fe4a53a 100644 (file)
@@ -1234,7 +1234,8 @@ static const struct drm_display_mode reported_modes[] = {
  * \return false if TV is disconnected.
  */
 static int
-intel_tv_detect_type (struct intel_tv *intel_tv)
+intel_tv_detect_type (struct intel_tv *intel_tv,
+                     struct drm_connector *connector)
 {
        struct drm_encoder *encoder = &intel_tv->base.base;
        struct drm_device *dev = encoder->dev;
@@ -1245,11 +1246,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
        int type;
 
        /* Disable TV interrupts around load detect or we'll recurse */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_disable_pipestat(dev_priv, 0,
-                             PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                             PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_disable_pipestat(dev_priv, 0,
+                                     PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                     PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
 
        save_tv_dac = tv_dac = I915_READ(TV_DAC);
        save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
@@ -1302,11 +1305,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
        I915_WRITE(TV_CTL, save_tv_ctl);
 
        /* Restore interrupt config */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0,
-                            PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                            PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_enable_pipestat(dev_priv, 0,
+                                    PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                    PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
 
        return type;
 }
@@ -1356,7 +1361,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
        if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
-               type = intel_tv_detect_type(intel_tv);
+               type = intel_tv_detect_type(intel_tv, connector);
        } else if (force) {
                struct drm_crtc *crtc;
                int dpms_mode;
@@ -1364,7 +1369,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
                crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
                                                  &mode, &dpms_mode);
                if (crtc) {
-                       type = intel_tv_detect_type(intel_tv);
+                       type = intel_tv_detect_type(intel_tv, connector);
                        intel_release_load_detect_pipe(&intel_tv->base, connector,
                                                       dpms_mode);
                } else
@@ -1658,6 +1663,18 @@ intel_tv_init(struct drm_device *dev)
        intel_encoder = &intel_tv->base;
        connector = &intel_connector->base;
 
+       /* The documentation, for the older chipsets at least, recommend
+        * using a polling method rather than hotplug detection for TVs.
+        * This is because in order to perform the hotplug detection, the PLLs
+        * for the TV must be kept alive increasing power drain and starving
+        * bandwidth from other encoders. Notably for instance, it causes
+        * pipe underruns on Crestline when this encoder is supposedly idle.
+        *
+        * More recent chipsets favour HDMI rather than integrated S-Video.
+        */
+       connector->polled =
+               DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
 
index 21d6c29..de70959 100644 (file)
@@ -8,7 +8,7 @@ config DRM_NOUVEAU
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select FB
-       select FRAMEBUFFER_CONSOLE if !EMBEDDED
+       select FRAMEBUFFER_CONSOLE if !EXPERT
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
        help
index 2aef5cd..6bdab89 100644 (file)
@@ -6228,7 +6228,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
                entry->tvconf.has_component_output = false;
                break;
        case OUTPUT_LVDS:
-               if ((conn & 0x00003f00) != 0x10)
+               if ((conn & 0x00003f00) >> 8 != 0x10)
                        entry->lvdsconf.use_straps_for_mode = true;
                entry->lvdsconf.use_power_scripts = true;
                break;
@@ -6310,6 +6310,9 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
 static bool
 apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+
        /* Dell Precision M6300
         *   DCB entry 2: 02025312 00000010
         *   DCB entry 3: 02026312 00000020
@@ -6327,6 +6330,18 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
                        return false;
        }
 
+       /* GeForce3 Ti 200
+        *
+        * DCB reports an LVDS output that should be TMDS:
+        *   DCB entry 1: f2005014 ffffffff
+        */
+       if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) {
+               if (*conn == 0xf2005014 && *conf == 0xffffffff) {
+                       fabricate_dcb_output(dcb, OUTPUT_TMDS, 1, 1, 1);
+                       return false;
+               }
+       }
+
        return true;
 }
 
index a7fae26..a521840 100644 (file)
@@ -49,7 +49,10 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
                DRM_ERROR("bo %p still attached to GEM object\n", bo);
 
        nv10_mem_put_tile_region(dev, nvbo->tile, NULL);
-       nouveau_vm_put(&nvbo->vma);
+       if (nvbo->vma.node) {
+               nouveau_vm_unmap(&nvbo->vma);
+               nouveau_vm_put(&nvbo->vma);
+       }
        kfree(nvbo);
 }
 
@@ -128,6 +131,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
                }
        }
 
+       nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
        nouveau_bo_placement_set(nvbo, flags, 0);
 
        nvbo->channel = chan;
@@ -166,17 +170,17 @@ static void
 set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+       int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
 
        if (dev_priv->card_type == NV_10 &&
-           nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+           nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
+           nvbo->bo.mem.num_pages < vram_pages / 2) {
                /*
                 * Make sure that the color and depth buffers are handled
                 * by independent memory controller units. Up to a 9x
                 * speed up when alpha-blending and depth-test are enabled
                 * at the same time.
                 */
-               int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
-
                if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
                        nvbo->placement.fpfn = vram_pages / 2;
                        nvbo->placement.lpfn = ~0;
@@ -785,7 +789,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                goto out;
 
-       ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+       ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem);
 out:
        ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
@@ -811,11 +815,11 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem);
+       ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem);
        if (ret)
                goto out;
 
-       ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem);
+       ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, new_mem);
        if (ret)
                goto out;
 
index a21e000..390d82c 100644 (file)
@@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector)
        int high_w = 0, high_h = 0, high_v = 0;
 
        list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
+               mode->vrefresh = drm_mode_vrefresh(mode);
                if (helper->mode_valid(connector, mode) != MODE_OK ||
                    (mode->flags & DRM_MODE_FLAG_INTERLACE))
                        continue;
index 65699bf..b368ed7 100644 (file)
@@ -83,7 +83,8 @@ nouveau_dma_init(struct nouveau_channel *chan)
                return ret;
 
        /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
-       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy);
+       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000,
+                                    &chan->m2mf_ntfy);
        if (ret)
                return ret;
 
index 13bb672..f658a04 100644 (file)
@@ -234,9 +234,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                pci_set_power_state(pdev, PCI_D3hot);
        }
 
-       acquire_console_sem();
+       console_lock();
        nouveau_fbcon_set_suspend(dev, 1);
-       release_console_sem();
+       console_unlock();
        nouveau_fbcon_restore_accel(dev);
        return 0;
 
@@ -359,9 +359,9 @@ nouveau_pci_resume(struct pci_dev *pdev)
                nv_crtc->lut.depth = 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        nouveau_fbcon_set_suspend(dev, 0);
-       release_console_sem();
+       console_unlock();
 
        nouveau_fbcon_zfill_all(dev);
 
index 01bffc4..982d70b 100644 (file)
@@ -848,14 +848,12 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev,
                                     struct nouveau_fence *fence);
 extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
 
-/* nvc0_vram.c */
-extern const struct ttm_mem_type_manager_func nvc0_vram_manager;
-
 /* nouveau_notifier.c */
 extern int  nouveau_notifier_init_channel(struct nouveau_channel *);
 extern void nouveau_notifier_takedown_channel(struct nouveau_channel *);
 extern int  nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle,
-                                  int cout, uint32_t *offset);
+                                  int cout, uint32_t start, uint32_t end,
+                                  uint32_t *offset);
 extern int  nouveau_notifier_offset(struct nouveau_gpuobj *, uint32_t *);
 extern int  nouveau_ioctl_notifier_alloc(struct drm_device *, void *data,
                                         struct drm_file *);
index fe29d60..5ea1676 100644 (file)
@@ -96,7 +96,8 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
 
 int
 nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
-                      int size, uint32_t *b_offset)
+                      int size, uint32_t start, uint32_t end,
+                      uint32_t *b_offset)
 {
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj *nobj = NULL;
@@ -104,9 +105,10 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        uint32_t offset;
        int target, ret;
 
-       mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
+       mem = drm_mm_search_free_in_range(&chan->notifier_heap, size, 0,
+                                         start, end, 0);
        if (mem)
-               mem = drm_mm_get_block(mem, size, 0);
+               mem = drm_mm_get_block_range(mem, size, 0, start, end);
        if (!mem) {
                NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
                return -ENOMEM;
@@ -177,7 +179,8 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
        if (IS_ERR(chan))
                return PTR_ERR(chan);
 
-       ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
+       ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,
+                                    &na->offset);
        nouveau_channel_put(&chan);
        return ret;
 }
index fb846a3..4399e2f 100644 (file)
@@ -443,7 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 
        if (pm->hwmon) {
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
+               sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
                hwmon_device_unregister(pm->hwmon);
        }
 #endif
@@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev)
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
        struct nouveau_pm_level *perflvl;
 
-       if (pm->cur == &pm->boot)
+       if (!pm->cur || pm->cur == &pm->boot)
                return;
 
        perflvl = pm->cur;
index 7ecc4ad..8d9968e 100644 (file)
@@ -265,8 +265,8 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
        struct i2c_board_info info[] = {
                { I2C_BOARD_INFO("w83l785ts", 0x2d) },
                { I2C_BOARD_INFO("w83781d", 0x2d) },
-               { I2C_BOARD_INFO("f75375", 0x2e) },
                { I2C_BOARD_INFO("adt7473", 0x2e) },
+               { I2C_BOARD_INFO("f75375", 0x2e) },
                { I2C_BOARD_INFO("lm99", 0x4c) },
                { }
        };
index ef23550..c82db37 100644 (file)
@@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
        if (nv_encoder->dcb->type == OUTPUT_LVDS) {
                bool duallink, dummy;
 
-               nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode->
-                                             clock, &duallink, &dummy);
+               nouveau_bios_parse_lvds_table(dev, output_mode->clock,
+                                             &duallink, &dummy);
                if (duallink)
                        regp->fp_control |= (8 << 28);
        } else
@@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
                return;
 
        if (nv_encoder->dcb->lvdsconf.use_power_scripts) {
-               struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
-
                /* when removing an output, crtc may not be set, but PANEL_OFF
                 * must still be run
                 */
@@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
                           nv04_dfp_get_bound_head(dev, nv_encoder->dcb);
 
                if (mode == DRM_MODE_DPMS_ON) {
-                       if (!nv_connector->native_mode) {
-                               NV_ERROR(dev, "Not turning on LVDS without native mode\n");
-                               return;
-                       }
                        call_lvds_script(dev, nv_encoder->dcb, head,
-                                        LVDS_PANEL_ON, nv_connector->native_mode->clock);
+                                        LVDS_PANEL_ON, nv_encoder->mode.clock);
                } else
                        /* pxclk of 0 is fine for PANEL_OFF, and for a
                         * disconnected LVDS encoder there is no native_mode
index 8870d72..18d30c2 100644 (file)
@@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
        struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
 
        switch (dev_priv->chipset) {
+       case 0x40:
+       case 0x41: /* guess */
+       case 0x42:
+       case 0x43:
+       case 0x45: /* guess */
+       case 0x4e:
+               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
+               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
+               nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
+               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+               nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+               break;
        case 0x44:
        case 0x4a:
-       case 0x4e:
                nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
                nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
                nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
                break;
-
        case 0x46:
        case 0x47:
        case 0x49:
        case 0x4b:
+       case 0x4c:
+       case 0x67:
+       default:
                nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
                nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
                nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
@@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
                nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
                nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
                break;
-
-       default:
-               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-               nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-               nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
-               break;
        }
 }
 
@@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev)
                break;
        default:
                switch (dev_priv->chipset) {
-               case 0x46:
-               case 0x47:
-               case 0x49:
-               case 0x4b:
-                       nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
-                       nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
-                       break;
-               default:
+               case 0x41:
+               case 0x42:
+               case 0x43:
+               case 0x45:
+               case 0x4e:
+               case 0x44:
+               case 0x4a:
                        nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
                        nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
                        break;
+               default:
+                       nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
+                       nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
+                       break;
                }
                nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
                nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
index 14e24e9..0ea090f 100644 (file)
@@ -283,8 +283,7 @@ nv50_evo_create(struct drm_device *dev)
                        nv50_evo_channel_del(&dev_priv->evo);
                        return ret;
                }
-       } else
-       if (dev_priv->chipset != 0x50) {
+       } else {
                ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19,
                                          0, 0xffffffff, 0x00010000);
                if (ret) {
index 2d7ea75..37e21d2 100644 (file)
@@ -256,6 +256,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        unsigned long flags;
 
@@ -265,6 +266,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
                return;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       pfifo->reassign(dev, false);
        pgraph->fifo_access(dev, false);
 
        if (pgraph->channel(dev) == chan)
@@ -275,6 +277,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
        dev_priv->engine.instmem.flush(dev);
 
        pgraph->fifo_access(dev, true);
+       pfifo->reassign(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
index 38e523e..459ff08 100644 (file)
@@ -45,11 +45,6 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
        }
 
        if (phys & 1) {
-               if (dev_priv->vram_sys_base) {
-                       phys += dev_priv->vram_sys_base;
-                       phys |= 0x30;
-               }
-
                if (coverage <= 32 * 1024 * 1024)
                        phys |= 0x60;
                else if (coverage <= 64 * 1024 * 1024)
index e6ea7d8..eb18a7e 100644 (file)
@@ -31,6 +31,7 @@
 #include "nvc0_graph.h"
 
 static void nvc0_graph_isr(struct drm_device *);
+static void nvc0_runk140_isr(struct drm_device *);
 static int  nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
 
 void
@@ -281,6 +282,7 @@ nvc0_graph_destroy(struct drm_device *dev)
                return;
 
        nouveau_irq_unregister(dev, 12);
+       nouveau_irq_unregister(dev, 25);
 
        nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
        nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
@@ -390,6 +392,7 @@ nvc0_graph_create(struct drm_device *dev)
        }
 
        nouveau_irq_register(dev, 12, nvc0_graph_isr);
+       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
        NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
        NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
        NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
@@ -512,8 +515,8 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000);
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000);
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000);
-                       nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe);
-                       nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f);
+                       nv_wr32(dev, TP_UNIT(gpc, tp, 0x644), 0x001ffffe);
+                       nv_wr32(dev, TP_UNIT(gpc, tp, 0x64c), 0x0000000f);
                }
                nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
                nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
@@ -777,3 +780,19 @@ nvc0_graph_isr(struct drm_device *dev)
 
        nv_wr32(dev, 0x400500, 0x00010001);
 }
+
+static void
+nvc0_runk140_isr(struct drm_device *dev)
+{
+       u32 units = nv_rd32(dev, 0x00017c) & 0x1f;
+
+       while (units) {
+               u32 unit = ffs(units) - 1;
+               u32 reg = 0x140000 + unit * 0x2000;
+               u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0);
+               u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0);
+
+               NV_INFO(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1);
+               units &= ~(1 << unit);
+       }
+}
index b9e68b2..f880ff7 100644 (file)
@@ -1830,7 +1830,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
 
        for (tp = 0, id = 0; tp < 4; tp++) {
                for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-                       if (tp <= priv->tp_nr[gpc]) {
+                       if (tp < priv->tp_nr[gpc]) {
                                nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id);
                                nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id);
                                nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id);
index b0ab185..a4e5e53 100644 (file)
@@ -48,29 +48,29 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
 
        switch (radeon_crtc->rmx_type) {
        case RMX_CENTER:
-               args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
-               args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
-               args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
-               args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+               args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+               args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+               args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
+               args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
                break;
        case RMX_ASPECT:
                a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
                a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
 
                if (a1 > a2) {
-                       args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
-                       args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+                       args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
+                       args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
                } else if (a2 > a1) {
-                       args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
-                       args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+                       args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
+                       args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
                }
                break;
        case RMX_FULL:
        default:
-               args.usOverscanRight = radeon_crtc->h_border;
-               args.usOverscanLeft = radeon_crtc->h_border;
-               args.usOverscanBottom = radeon_crtc->v_border;
-               args.usOverscanTop = radeon_crtc->v_border;
+               args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border);
+               args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border);
+               args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border);
+               args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border);
                break;
        }
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -419,23 +419,23 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
        memset(&args, 0, sizeof(args));
 
        if (ASIC_IS_DCE5(rdev)) {
-               args.v3.usSpreadSpectrumAmountFrac = 0;
+               args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
                args.v3.ucSpreadSpectrumType = ss->type;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
-                       args.v3.usSpreadSpectrumAmount = ss->amount;
-                       args.v3.usSpreadSpectrumStep = ss->step;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_PPLL2:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
-                       args.v3.usSpreadSpectrumAmount = ss->amount;
-                       args.v3.usSpreadSpectrumStep = ss->step;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_DCPLL:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
-                       args.v3.usSpreadSpectrumAmount = 0;
-                       args.v3.usSpreadSpectrumStep = 0;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(0);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(0);
                        break;
                case ATOM_PPLL_INVALID:
                        return;
@@ -447,18 +447,18 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
-                       args.v2.usSpreadSpectrumAmount = ss->amount;
-                       args.v2.usSpreadSpectrumStep = ss->step;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_PPLL2:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
-                       args.v2.usSpreadSpectrumAmount = ss->amount;
-                       args.v2.usSpreadSpectrumStep = ss->step;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_DCPLL:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
-                       args.v2.usSpreadSpectrumAmount = 0;
-                       args.v2.usSpreadSpectrumStep = 0;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(0);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(0);
                        break;
                case ATOM_PPLL_INVALID:
                        return;
@@ -538,7 +538,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
                else
                        pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
-
        }
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -555,23 +554,28 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                        dp_clock = dig_connector->dp_clock;
                                }
                        }
-#if 0 /* doesn't work properly on some laptops */
+
                        /* use recommended ref_div for ss */
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                                if (ss_enabled) {
                                        if (ss->refdiv) {
+                                               pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
                                                pll->flags |= RADEON_PLL_USE_REF_DIV;
                                                pll->reference_div = ss->refdiv;
+                                               if (ASIC_IS_AVIVO(rdev))
+                                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        }
                                }
                        }
-#endif
+
                        if (ASIC_IS_AVIVO(rdev)) {
                                /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
                                if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
                                        adjusted_clock = mode->clock * 2;
                                if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
                                        pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
+                               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                                       pll->flags |= RADEON_PLL_IS_LCD;
                        } else {
                                if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
                                        pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@@ -606,14 +610,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
                                args.v1.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v1.ucEncodeMode = encoder_mode;
-                               if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                       if (ss_enabled)
-                                               args.v1.ucConfig |=
-                                                       ADJUST_DISPLAY_CONFIG_SS_ENABLE;
-                               } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
+                               if (ss_enabled)
                                        args.v1.ucConfig |=
                                                ADJUST_DISPLAY_CONFIG_SS_ENABLE;
-                               }
 
                                atom_execute_table(rdev->mode_info.atom_context,
                                                   index, (uint32_t *)&args);
@@ -624,12 +623,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v3.sInput.ucEncodeMode = encoder_mode;
                                args.v3.sInput.ucDispPllConfig = 0;
+                               if (ss_enabled)
+                                       args.v3.sInput.ucDispPllConfig |=
+                                               DISPPLL_CONFIG_SS_ENABLE;
                                if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                                        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                               if (ss_enabled)
-                                                       args.v3.sInput.ucDispPllConfig |=
-                                                               DISPPLL_CONFIG_SS_ENABLE;
                                                args.v3.sInput.ucDispPllConfig |=
                                                        DISPPLL_CONFIG_COHERENT_MODE;
                                                /* 16200 or 27000 */
@@ -649,18 +648,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                        }
                                } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-                                               if (ss_enabled)
-                                                       args.v3.sInput.ucDispPllConfig |=
-                                                               DISPPLL_CONFIG_SS_ENABLE;
                                                args.v3.sInput.ucDispPllConfig |=
                                                        DISPPLL_CONFIG_COHERENT_MODE;
                                                /* 16200 or 27000 */
                                                args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
-                                       } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
-                                               if (ss_enabled)
-                                                       args.v3.sInput.ucDispPllConfig |=
-                                                               DISPPLL_CONFIG_SS_ENABLE;
-                                       } else {
+                                       } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) {
                                                if (mode->clock > 165000)
                                                        args.v3.sInput.ucDispPllConfig |=
                                                                DISPPLL_CONFIG_DUAL_LINK;
@@ -670,10 +662,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                                   index, (uint32_t *)&args);
                                adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
                                if (args.v3.sOutput.ucRefDiv) {
+                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        pll->flags |= RADEON_PLL_USE_REF_DIV;
                                        pll->reference_div = args.v3.sOutput.ucRefDiv;
                                }
                                if (args.v3.sOutput.ucPostDiv) {
+                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        pll->flags |= RADEON_PLL_USE_POST_DIV;
                                        pll->post_div = args.v3.sOutput.ucPostDiv;
                                }
@@ -727,14 +721,14 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc,
                         * SetPixelClock provides the dividers
                         */
                        args.v5.ucCRTC = ATOM_CRTC_INVALID;
-                       args.v5.usPixelClock = dispclk;
+                       args.v5.usPixelClock = cpu_to_le16(dispclk);
                        args.v5.ucPpll = ATOM_DCPLL;
                        break;
                case 6:
                        /* if the default dcpll clock is specified,
                         * SetPixelClock provides the dividers
                         */
-                       args.v6.ulDispEngClkFreq = dispclk;
+                       args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
                        args.v6.ucPpll = ATOM_DCPLL;
                        break;
                default:
@@ -963,8 +957,12 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        /* adjust pixel clock as needed */
        adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
 
-       radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
-                          &ref_div, &post_div);
+       if (ASIC_IS_AVIVO(rdev))
+               radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                                        &ref_div, &post_div);
+       else
+               radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                                         &ref_div, &post_div);
 
        atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
 
@@ -993,9 +991,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        }
 }
 
-static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
-                                     struct drm_framebuffer *fb,
-                                     int x, int y, int atomic)
+static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                int x, int y, int atomic)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -1006,6 +1004,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        struct radeon_bo *rbo;
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+       u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
        int r;
 
        /* no fb bound */
@@ -1057,11 +1056,17 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        case 16:
                fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
                             EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
                break;
        case 24:
        case 32:
                fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
                             EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
+#endif
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
@@ -1106,6 +1111,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
               (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
        WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+       WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
 
        WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
        WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
@@ -1127,12 +1133,6 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
 
-       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
-               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
-                      EVERGREEN_INTERLEAVE_EN);
-       else
-               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
-
        if (!atomic && fb && fb != crtc->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
@@ -1162,6 +1162,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        struct drm_framebuffer *target_fb;
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+       u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
        int r;
 
        /* no fb bound */
@@ -1215,12 +1216,18 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
                fb_format =
                    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
                    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
+#ifdef __BIG_ENDIAN
+               fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
+#endif
                break;
        case 24:
        case 32:
                fb_format =
                    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
                    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
+#ifdef __BIG_ENDIAN
+               fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
+#endif
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
@@ -1260,6 +1267,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
               radeon_crtc->crtc_offset, (u32) fb_location);
        WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
 
        WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
        WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
@@ -1281,12 +1290,6 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
 
-       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
-               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
-                      AVIVO_D1MODE_INTERLEAVE_EN);
-       else
-               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
-
        if (!atomic && fb && fb != crtc->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
@@ -1310,7 +1313,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev))
-               return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0);
+               return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else if (ASIC_IS_AVIVO(rdev))
                return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else
@@ -1325,7 +1328,7 @@ int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev))
-               return evergreen_crtc_do_set_base(crtc, fb, x, y, 1);
+               return dce4_crtc_do_set_base(crtc, fb, x, y, 1);
        else if (ASIC_IS_AVIVO(rdev))
                return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
        else
index 4e7778d..695de9a 100644 (file)
@@ -187,9 +187,9 @@ static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
 int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
 {
        int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
-       int bw = dp_lanes_for_mode_clock(dpcd, mode_clock);
+       int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock);
 
-       if ((lanes == 0) || (bw == 0))
+       if ((lanes == 0) || (dp_clock == 0))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
index a8973ac..d270b3f 100644 (file)
@@ -97,26 +97,29 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 }
 
 /* get temperature in millidegrees */
-u32 evergreen_get_temp(struct radeon_device *rdev)
+int evergreen_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
        u32 actual_temp = 0;
 
-       if ((temp >> 10) & 1)
-               actual_temp = 0;
-       else if ((temp >> 9) & 1)
+       if (temp & 0x400)
+               actual_temp = -256;
+       else if (temp & 0x200)
                actual_temp = 255;
-       else
-               actual_temp = (temp >> 1) & 0xff;
+       else if (temp & 0x100) {
+               actual_temp = temp & 0x1ff;
+               actual_temp |= ~0x1ff;
+       } else
+               actual_temp = temp & 0xff;
 
-       return actual_temp * 1000;
+       return (actual_temp * 1000) / 2;
 }
 
-u32 sumo_get_temp(struct radeon_device *rdev)
+int sumo_get_temp(struct radeon_device *rdev)
 {
        u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff;
-       u32 actual_temp = (temp >> 1) & 0xff;
+       int actual_temp = temp - 49;
 
        return actual_temp * 1000;
 }
@@ -1182,6 +1185,22 @@ static void evergreen_mc_program(struct radeon_device *rdev)
 /*
  * CP.
  */
+void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       /* set to DX10/11 mode */
+       radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0));
+       radeon_ring_write(rdev, 1);
+       /* FIXME: implement */
+       radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (ib->gpu_addr & 0xFFFFFFFC));
+       radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF);
+       radeon_ring_write(rdev, ib->length_dw);
+}
+
 
 static int evergreen_cp_load_microcode(struct radeon_device *rdev)
 {
@@ -1192,7 +1211,11 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev)
                return -EINVAL;
 
        r700_cp_stop(rdev);
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        fw_data = (const __be32 *)rdev->pfp_fw->data;
        WREG32(CP_PFP_UCODE_ADDR, 0);
@@ -1233,7 +1256,7 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        cp_me = 0xff;
        WREG32(CP_ME_CNTL, cp_me);
 
-       r = radeon_ring_lock(rdev, evergreen_default_size + 15);
+       r = radeon_ring_lock(rdev, evergreen_default_size + 19);
        if (r) {
                DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
                return r;
@@ -1266,6 +1289,11 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        radeon_ring_write(rdev, 0xffffffff);
        radeon_ring_write(rdev, 0xffffffff);
 
+       radeon_ring_write(rdev, 0xc0026900);
+       radeon_ring_write(rdev, 0x00000316);
+       radeon_ring_write(rdev, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+       radeon_ring_write(rdev, 0x00000010); /*  */
+
        radeon_ring_unlock_commit(rdev);
 
        return 0;
@@ -1306,7 +1334,11 @@ int evergreen_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_WPTR, 0);
 
        /* set the wb address wether it's enabled or not */
-       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR,
+#ifdef __BIG_ENDIAN
+              RB_RPTR_SWAP(2) |
+#endif
+              ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC));
        WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
        WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
 
@@ -2072,6 +2104,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation);
 
        WREG32(VGT_GS_VERTEX_REUSE, 16);
+       WREG32(PA_SU_LINE_STIPPLE_VALUE, 0);
        WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
 
        WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, 14);
@@ -2201,6 +2234,9 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
        struct evergreen_mc_save save;
        u32 grbm_reset = 0;
 
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               return 0;
+
        dev_info(rdev->dev, "GPU softreset \n");
        dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
                RREG32(GRBM_STATUS));
@@ -2603,8 +2639,8 @@ restart_ih:
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
-               src_id =  rdev->ih.ring[ring_index] & 0xff;
-               src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff;
+               src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+               src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 
                switch (src_id) {
                case 1: /* D1 vblank/vline */
index b758dc7..2adfb03 100644 (file)
@@ -55,7 +55,7 @@ set_render_target(struct radeon_device *rdev, int format,
        if (h < 8)
                h = 8;
 
-       cb_color_info = ((format << 2) | (1 << 24));
+       cb_color_info = ((format << 2) | (1 << 24) | (1 << 8));
        pitch = (w / 8) - 1;
        slice = ((w * h) / 64) - 1;
 
@@ -133,6 +133,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
 
        /* high addr, stride */
        sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
        /* xyzw swizzles */
        sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12);
 
@@ -173,7 +176,7 @@ set_tex_resource(struct radeon_device *rdev,
        sq_tex_resource_word0 = (1 << 0); /* 2D */
        sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) |
                                  ((w - 1) << 18));
-       sq_tex_resource_word1 = ((h - 1) << 0);
+       sq_tex_resource_word1 = ((h - 1) << 0) | (1 << 28);
        /* xyzw swizzles */
        sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25);
 
@@ -221,7 +224,11 @@ draw_auto(struct radeon_device *rdev)
        radeon_ring_write(rdev, DI_PT_RECTLIST);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
-       radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 2) |
+#endif
+                         DI_INDEX_SIZE_16_BIT);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
        radeon_ring_write(rdev, 1);
@@ -232,7 +239,7 @@ draw_auto(struct radeon_device *rdev)
 
 }
 
-/* emits 30 */
+/* emits 36 */
 static void
 set_default_state(struct radeon_device *rdev)
 {
@@ -245,6 +252,8 @@ set_default_state(struct radeon_device *rdev)
        int num_hs_threads, num_ls_threads;
        int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
        int num_hs_stack_entries, num_ls_stack_entries;
+       u64 gpu_addr;
+       int dwords;
 
        switch (rdev->family) {
        case CHIP_CEDAR:
@@ -497,6 +506,18 @@ set_default_state(struct radeon_device *rdev)
        radeon_ring_write(rdev, 0x00000000);
        radeon_ring_write(rdev, 0x00000000);
 
+       /* set to DX10/11 mode */
+       radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0));
+       radeon_ring_write(rdev, 1);
+
+       /* emit an IB pointing at default state */
+       dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
+       gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
+       radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+       radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
+       radeon_ring_write(rdev, dwords);
+
 }
 
 static inline uint32_t i2f(uint32_t input)
@@ -527,8 +548,10 @@ static inline uint32_t i2f(uint32_t input)
 int evergreen_blit_init(struct radeon_device *rdev)
 {
        u32 obj_size;
-       int r;
+       int i, r, dwords;
        void *ptr;
+       u32 packet2s[16];
+       int num_packet2s = 0;
 
        /* pin copy shader into vram if already initialized */
        if (rdev->r600_blit.shader_obj)
@@ -536,8 +559,17 @@ int evergreen_blit_init(struct radeon_device *rdev)
 
        mutex_init(&rdev->r600_blit.mutex);
        rdev->r600_blit.state_offset = 0;
-       rdev->r600_blit.state_len = 0;
-       obj_size = 0;
+
+       rdev->r600_blit.state_len = evergreen_default_size;
+
+       dwords = rdev->r600_blit.state_len;
+       while (dwords & 0xf) {
+               packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0));
+               dwords++;
+       }
+
+       obj_size = dwords * 4;
+       obj_size = ALIGN(obj_size, 256);
 
        rdev->r600_blit.vs_offset = obj_size;
        obj_size += evergreen_vs_size * 4;
@@ -567,8 +599,16 @@ int evergreen_blit_init(struct radeon_device *rdev)
                return r;
        }
 
-       memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4);
-       memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4);
+       memcpy_toio(ptr + rdev->r600_blit.state_offset,
+                   evergreen_default_state, rdev->r600_blit.state_len * 4);
+
+       if (num_packet2s)
+               memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
+                           packet2s, num_packet2s * 4);
+       for (i = 0; i < evergreen_vs_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(evergreen_vs[i]);
+       for (i = 0; i < evergreen_ps_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(evergreen_ps[i]);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 
@@ -652,7 +692,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
        /* calculate number of loops correctly */
        ring_size = num_loops * dwords_per_loop;
        /* set default  + shaders */
-       ring_size += 46; /* shaders + def state */
+       ring_size += 52; /* shaders + def state */
        ring_size += 10; /* fence emit for VB IB */
        ring_size += 5; /* done copy */
        ring_size += 10; /* fence emit for done copy */
@@ -660,7 +700,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
        if (r)
                return r;
 
-       set_default_state(rdev); /* 30 */
+       set_default_state(rdev); /* 36 */
        set_shaders(rdev); /* 16 */
        return 0;
 }
index ef1d28c..3a10399 100644 (file)
@@ -311,11 +311,19 @@ const u32 evergreen_vs[] =
        0x00000000,
        0x3c000000,
        0x67961001,
+#ifdef __BIG_ENDIAN
+       0x000a0000,
+#else
        0x00080000,
+#endif
        0x00000000,
        0x1c000000,
        0x67961000,
+#ifdef __BIG_ENDIAN
+       0x00020008,
+#else
        0x00000008,
+#endif
        0x00000000,
 };
 
index 36d32d8..eb4acf4 100644 (file)
@@ -98,6 +98,7 @@
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
+#define                RB_RPTR_SWAP(x)                                 ((x) << 0)
 #define        CP_RB_RPTR_ADDR_HI                              0xC110
 #define        CP_RB_RPTR_WR                                   0xC108
 #define        CP_RB_WPTR                                      0xC114
 #define                FORCE_EOV_MAX_CLK_CNT(x)                        ((x) << 0)
 #define                FORCE_EOV_MAX_REZ_CNT(x)                        ((x) << 16)
 #define PA_SC_LINE_STIPPLE                             0x28A0C
+#define        PA_SU_LINE_STIPPLE_VALUE                        0x8A60
 #define        PA_SC_LINE_STIPPLE_STATE                        0x8B10
 
 #define        SCRATCH_REG0                                    0x8500
 #define        PACKET3_DISPATCH_DIRECT                         0x15
 #define        PACKET3_DISPATCH_INDIRECT                       0x16
 #define        PACKET3_INDIRECT_BUFFER_END                     0x17
+#define        PACKET3_MODE_CONTROL                            0x18
 #define        PACKET3_SET_PREDICATION                         0x20
 #define        PACKET3_REG_RMW                                 0x21
 #define        PACKET3_COND_EXEC                               0x22
index 607241c..5a82b6b 100644 (file)
@@ -673,8 +673,10 @@ static int parser_auth(struct table *t, const char *filename)
        last_reg = strtol(last_reg_s, NULL, 16);
 
        do {
-               if (fgets(buf, 1024, file) == NULL)
+               if (fgets(buf, 1024, file) == NULL) {
+                       fclose(file);
                        return -1;
+               }
                len = strlen(buf);
                if (ftell(file) == end)
                        done = 1;
@@ -685,6 +687,7 @@ static int parser_auth(struct table *t, const char *filename)
                                fprintf(stderr,
                                        "Error matching regular expression %d in %s\n",
                                        r, filename);
+                               fclose(file);
                                return -1;
                        } else {
                                buf[match[0].rm_eo] = 0;
index 46da514..93fa735 100644 (file)
@@ -1031,8 +1031,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
        WREG32(RADEON_CP_CSQ_MODE,
               REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
               REG_SET(RADEON_INDIRECT1_START, indirect1_start));
-       WREG32(0x718, 0);
-       WREG32(0x744, 0x00004D4D);
+       WREG32(RADEON_CP_RB_WPTR_DELAY, 0);
+       WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D);
        WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
        radeon_ring_start(rdev);
        r = radeon_ring_test(rdev);
@@ -1427,6 +1427,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
@@ -1439,6 +1440,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_PP_TXOFFSET_0:
@@ -1454,6 +1456,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T0_0:
        case RADEON_PP_CUBIC_OFFSET_T0_1:
@@ -1471,6 +1474,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[0].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[0].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T1_0:
        case RADEON_PP_CUBIC_OFFSET_T1_1:
@@ -1488,6 +1492,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[1].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[1].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T2_0:
        case RADEON_PP_CUBIC_OFFSET_T2_1:
@@ -1505,9 +1510,12 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[2].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[2].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_RE_WIDTH_HEIGHT:
                track->maxy = ((idx_value >> 16) & 0x7FF);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_COLORPITCH:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1528,9 +1536,11 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
+               track->cb_dirty = true;
                break;
        case RADEON_RB3D_DEPTHPITCH:
                track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_CNTL:
                switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) {
@@ -1555,6 +1565,8 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
                track->z_enabled = !!(idx_value & RADEON_Z_ENABLE);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZSTENCILCNTL:
                switch (idx_value & 0xf) {
@@ -1572,6 +1584,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                default:
                        break;
                }
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1588,6 +1601,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        uint32_t temp = idx_value >> 4;
                        for (i = 0; i < track->num_texture; i++)
                                track->textures[i].enabled = !!(temp & (1 << i));
+                       track->tex_dirty = true;
                }
                break;
        case RADEON_SE_VF_CNTL:
@@ -1602,12 +1616,14 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                i = (reg - RADEON_PP_TEX_SIZE_0) / 8;
                track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1;
                track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TEX_PITCH_0:
        case RADEON_PP_TEX_PITCH_1:
        case RADEON_PP_TEX_PITCH_2:
                i = (reg - RADEON_PP_TEX_PITCH_0) / 8;
                track->textures[i].pitch = idx_value + 32;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TXFILTER_0:
        case RADEON_PP_TXFILTER_1:
@@ -1621,6 +1637,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                tmp = (idx_value >> 27) & 0x7;
                if (tmp == 2 || tmp == 6)
                        track->textures[i].roundup_h = false;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TXFORMAT_0:
        case RADEON_PP_TXFORMAT_1:
@@ -1673,6 +1690,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);
                track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf);
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_FACES_0:
        case RADEON_PP_CUBIC_FACES_1:
@@ -1683,6 +1701,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf);
                        track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf);
                }
+               track->tex_dirty = true;
                break;
        default:
                printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
@@ -2347,10 +2366,10 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state)
 
        temp = RREG32(RADEON_CONFIG_CNTL);
        if (state == false) {
-               temp &= ~(1<<8);
-               temp |= (1<<9);
+               temp &= ~RADEON_CFG_VGA_RAM_EN;
+               temp |= RADEON_CFG_VGA_IO_DIS;
        } else {
-               temp &= ~(1<<9);
+               temp &= ~RADEON_CFG_VGA_IO_DIS;
        }
        WREG32(RADEON_CONFIG_CNTL, temp);
 }
@@ -3318,9 +3337,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
        unsigned long size;
        unsigned prim_walk;
        unsigned nverts;
-       unsigned num_cb = track->num_cb;
+       unsigned num_cb = track->cb_dirty ? track->num_cb : 0;
 
-       if (!track->zb_cb_clear && !track->color_channel_mask &&
+       if (num_cb && !track->zb_cb_clear && !track->color_channel_mask &&
            !track->blend_read_enable)
                num_cb = 0;
 
@@ -3341,7 +3360,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                        return -EINVAL;
                }
        }
-       if (track->z_enabled) {
+       track->cb_dirty = false;
+
+       if (track->zb_dirty && track->z_enabled) {
                if (track->zb.robj == NULL) {
                        DRM_ERROR("[drm] No buffer for z buffer !\n");
                        return -EINVAL;
@@ -3358,6 +3379,28 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                        return -EINVAL;
                }
        }
+       track->zb_dirty = false;
+
+       if (track->aa_dirty && track->aaresolve) {
+               if (track->aa.robj == NULL) {
+                       DRM_ERROR("[drm] No buffer for AA resolve buffer %d !\n", i);
+                       return -EINVAL;
+               }
+               /* I believe the format comes from colorbuffer0. */
+               size = track->aa.pitch * track->cb[0].cpp * track->maxy;
+               size += track->aa.offset;
+               if (size > radeon_bo_size(track->aa.robj)) {
+                       DRM_ERROR("[drm] Buffer too small for AA resolve buffer %d "
+                                 "(need %lu have %lu) !\n", i, size,
+                                 radeon_bo_size(track->aa.robj));
+                       DRM_ERROR("[drm] AA resolve buffer %d (%u %u %u %u)\n",
+                                 i, track->aa.pitch, track->cb[0].cpp,
+                                 track->aa.offset, track->maxy);
+                       return -EINVAL;
+               }
+       }
+       track->aa_dirty = false;
+
        prim_walk = (track->vap_vf_cntl >> 4) & 0x3;
        if (track->vap_vf_cntl & (1 << 14)) {
                nverts = track->vap_alt_nverts;
@@ -3417,13 +3460,23 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                          prim_walk);
                return -EINVAL;
        }
-       return r100_cs_track_texture_check(rdev, track);
+
+       if (track->tex_dirty) {
+               track->tex_dirty = false;
+               return r100_cs_track_texture_check(rdev, track);
+       }
+       return 0;
 }
 
 void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track)
 {
        unsigned i, face;
 
+       track->cb_dirty = true;
+       track->zb_dirty = true;
+       track->tex_dirty = true;
+       track->aa_dirty = true;
+
        if (rdev->family < CHIP_R300) {
                track->num_cb = 1;
                if (rdev->family <= CHIP_RS200)
@@ -3437,6 +3490,8 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track
                track->num_texture = 16;
                track->maxy = 4096;
                track->separate_cube = 0;
+               track->aaresolve = false;
+               track->aa.robj = NULL;
        }
 
        for (i = 0; i < track->num_cb; i++) {
@@ -3522,7 +3577,7 @@ int r100_ring_test(struct radeon_device *rdev)
        if (i < rdev->usec_timeout) {
                DRM_INFO("ring test succeeded in %d usecs\n", i);
        } else {
-               DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n",
+               DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n",
                          scratch, tmp);
                r = -EINVAL;
        }
@@ -3746,8 +3801,6 @@ static int r100_startup(struct radeon_device *rdev)
        r100_mc_program(rdev);
        /* Resume clock */
        r100_clock_startup(rdev);
-       /* Initialize GPU configuration (# pipes, ...) */
-//     r100_gpu_init(rdev);
        /* Initialize GART (initialize after TTM so we can allocate
         * memory through TTM but finalize after TTM) */
        r100_enable_bm(rdev);
index af65600..2fef9de 100644 (file)
@@ -52,14 +52,7 @@ struct r100_cs_track_texture {
        unsigned                compress_format;
 };
 
-struct r100_cs_track_limits {
-       unsigned num_cb;
-       unsigned num_texture;
-       unsigned max_levels;
-};
-
 struct r100_cs_track {
-       struct radeon_device *rdev;
        unsigned                        num_cb;
        unsigned                        num_texture;
        unsigned                        maxy;
@@ -73,11 +66,17 @@ struct r100_cs_track {
        struct r100_cs_track_array      arrays[11];
        struct r100_cs_track_cb         cb[R300_MAX_CB];
        struct r100_cs_track_cb         zb;
+       struct r100_cs_track_cb         aa;
        struct r100_cs_track_texture    textures[R300_TRACK_MAX_TEXTURE];
        bool                            z_enabled;
        bool                            separate_cube;
        bool                            zb_cb_clear;
        bool                            blend_read_enable;
+       bool                            cb_dirty;
+       bool                            zb_dirty;
+       bool                            tex_dirty;
+       bool                            aa_dirty;
+       bool                            aaresolve;
 };
 
 int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track);
index d2408c3..f240583 100644 (file)
@@ -184,6 +184,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
@@ -196,6 +197,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R200_PP_TXOFFSET_0:
@@ -214,6 +216,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case R200_PP_CUBIC_OFFSET_F1_0:
        case R200_PP_CUBIC_OFFSET_F2_0:
@@ -257,9 +260,12 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                track->textures[i].cube_info[face - 1].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].cube_info[face - 1].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_RE_WIDTH_HEIGHT:
                track->maxy = ((idx_value >> 16) & 0x7FF);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_COLORPITCH:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -280,9 +286,11 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
+               track->cb_dirty = true;
                break;
        case RADEON_RB3D_DEPTHPITCH:
                track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_CNTL:
                switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) {
@@ -312,6 +320,8 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
 
                track->z_enabled = !!(idx_value & RADEON_Z_ENABLE);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZSTENCILCNTL:
                switch (idx_value & 0xf) {
@@ -329,6 +339,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                default:
                        break;
                }
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -345,6 +356,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        uint32_t temp = idx_value >> 4;
                        for (i = 0; i < track->num_texture; i++)
                                track->textures[i].enabled = !!(temp & (1 << i));
+                       track->tex_dirty = true;
                }
                break;
        case RADEON_SE_VF_CNTL:
@@ -369,6 +381,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                i = (reg - R200_PP_TXSIZE_0) / 32;
                track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1;
                track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXPITCH_0:
        case R200_PP_TXPITCH_1:
@@ -378,6 +391,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
        case R200_PP_TXPITCH_5:
                i = (reg - R200_PP_TXPITCH_0) / 32;
                track->textures[i].pitch = idx_value + 32;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXFILTER_0:
        case R200_PP_TXFILTER_1:
@@ -394,6 +408,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                tmp = (idx_value >> 27) & 0x7;
                if (tmp == 2 || tmp == 6)
                        track->textures[i].roundup_h = false;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXMULTI_CTL_0:
        case R200_PP_TXMULTI_CTL_1:
@@ -432,6 +447,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].tex_coord_type = 1;
                        break;
                }
+               track->tex_dirty = true;
                break;
        case R200_PP_TXFORMAT_0:
        case R200_PP_TXFORMAT_1:
@@ -488,6 +504,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);
                track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf);
+               track->tex_dirty = true;
                break;
        case R200_PP_CUBIC_FACES_0:
        case R200_PP_CUBIC_FACES_1:
@@ -501,6 +518,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf);
                        track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf);
                }
+               track->tex_dirty = true;
                break;
        default:
                printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
index cf862ca..069efa8 100644 (file)
@@ -69,6 +69,9 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
        mb();
 }
 
+#define R300_PTE_WRITEABLE (1 << 2)
+#define R300_PTE_READABLE  (1 << 3)
+
 int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 {
        void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
@@ -78,7 +81,7 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
        }
        addr = (lower_32_bits(addr) >> 8) |
               ((upper_32_bits(addr) & 0xff) << 24) |
-              0xc;
+              R300_PTE_WRITEABLE | R300_PTE_READABLE;
        /* on x86 we want this to be CPU endian, on powerpc
         * on powerpc without HW swappers, it'll get swapped on way
         * into VRAM - so no need for cpu_to_le32 on VRAM tables */
@@ -135,7 +138,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
        WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start);
        WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
        /* Clear error */
-       WREG32_PCIE(0x18, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_ERROR, 0);
        tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
        tmp |= RADEON_PCIE_TX_GART_EN;
        tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
@@ -664,6 +667,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[i].robj = reloc->robj;
                track->cb[i].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R300_ZB_DEPTHOFFSET:
@@ -676,6 +680,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R300_TX_OFFSET_0:
@@ -714,6 +719,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                tmp |= tile_flags;
                ib[idx] = tmp;
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        /* Tracked registers */
        case 0x2084:
@@ -740,6 +746,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                if (p->rdev->family < CHIP_RV515) {
                        track->maxy -= 1440;
                }
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case 0x4E00:
                /* RB3D_CCTL */
@@ -749,6 +757,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
                track->num_cb = ((idx_value >> 5) & 0x3) + 1;
+               track->cb_dirty = true;
                break;
        case 0x4E38:
        case 0x4E3C:
@@ -811,6 +820,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                  ((idx_value >> 21) & 0xF));
                        return -EINVAL;
                }
+               track->cb_dirty = true;
                break;
        case 0x4F00:
                /* ZB_CNTL */
@@ -819,6 +829,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                } else {
                        track->z_enabled = false;
                }
+               track->zb_dirty = true;
                break;
        case 0x4F10:
                /* ZB_FORMAT */
@@ -835,6 +846,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                  (idx_value & 0xF));
                        return -EINVAL;
                }
+               track->zb_dirty = true;
                break;
        case 0x4F24:
                /* ZB_DEPTHPITCH */
@@ -858,14 +870,17 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->zb.pitch = idx_value & 0x3FFC;
+               track->zb_dirty = true;
                break;
        case 0x4104:
+               /* TX_ENABLE */
                for (i = 0; i < 16; i++) {
                        bool enabled;
 
                        enabled = !!(idx_value & (1 << i));
                        track->textures[i].enabled = enabled;
                }
+               track->tex_dirty = true;
                break;
        case 0x44C0:
        case 0x44C4:
@@ -895,6 +910,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].compress_format = R100_TRACK_COMP_NONE;
                        break;
                case R300_TX_FORMAT_X16:
+               case R300_TX_FORMAT_FL_I16:
                case R300_TX_FORMAT_Y8X8:
                case R300_TX_FORMAT_Z5Y6X5:
                case R300_TX_FORMAT_Z6Y5X5:
@@ -907,6 +923,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].compress_format = R100_TRACK_COMP_NONE;
                        break;
                case R300_TX_FORMAT_Y16X16:
+               case R300_TX_FORMAT_FL_I16A16:
                case R300_TX_FORMAT_Z11Y11X10:
                case R300_TX_FORMAT_Z10Y11X11:
                case R300_TX_FORMAT_W8Z8Y8X8:
@@ -948,8 +965,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        DRM_ERROR("Invalid texture format %u\n",
                                  (idx_value & 0x1F));
                        return -EINVAL;
-                       break;
                }
+               track->tex_dirty = true;
                break;
        case 0x4400:
        case 0x4404:
@@ -977,6 +994,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                if (tmp == 2 || tmp == 4 || tmp == 6) {
                        track->textures[i].roundup_h = false;
                }
+               track->tex_dirty = true;
                break;
        case 0x4500:
        case 0x4504:
@@ -1014,6 +1032,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        DRM_ERROR("Forbidden bit TXFORMAT_MSB\n");
                        return -EINVAL;
                }
+               track->tex_dirty = true;
                break;
        case 0x4480:
        case 0x4484:
@@ -1043,6 +1062,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                track->textures[i].use_pitch = !!tmp;
                tmp = (idx_value >> 22) & 0xF;
                track->textures[i].txdepth = tmp;
+               track->tex_dirty = true;
                break;
        case R300_ZB_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1057,6 +1077,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4e0c:
                /* RB3D_COLOR_CHANNEL_MASK */
                track->color_channel_mask = idx_value;
+               track->cb_dirty = true;
                break;
        case 0x43a4:
                /* SC_HYPERZ_EN */
@@ -1070,6 +1091,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4f1c:
                /* ZB_BW_CNTL */
                track->zb_cb_clear = !!(idx_value & (1 << 5));
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                if (p->rdev->hyperz_filp != p->filp) {
                        if (idx_value & (R300_HIZ_ENABLE |
                                         R300_RD_COMP_ENABLE |
@@ -1081,8 +1104,28 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4e04:
                /* RB3D_BLENDCNTL */
                track->blend_read_enable = !!(idx_value & (1 << 2));
+               track->cb_dirty = true;
+               break;
+       case R300_RB3D_AARESOLVE_OFFSET:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                 idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               track->aa.robj = reloc->robj;
+               track->aa.offset = idx_value;
+               track->aa_dirty = true;
+               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case R300_RB3D_AARESOLVE_PITCH:
+               track->aa.pitch = idx_value & 0x3FFE;
+               track->aa_dirty = true;
                break;
-       case 0x4f28: /* ZB_DEPTHCLEARVALUE */
+       case R300_RB3D_AARESOLVE_CTL:
+               track->aaresolve = idx_value & 0x1;
+               track->aa_dirty = true;
                break;
        case 0x4f30: /* ZB_MASK_OFFSET */
        case 0x4f34: /* ZB_ZMASK_PITCH */
index 1a0d536..f0bce39 100644 (file)
 #define R300_RB3D_COLORPITCH2               0x4E40 /* GUESS */
 #define R300_RB3D_COLORPITCH3               0x4E44 /* GUESS */
 
+#define R300_RB3D_AARESOLVE_OFFSET          0x4E80
+#define R300_RB3D_AARESOLVE_PITCH           0x4E84
 #define R300_RB3D_AARESOLVE_CTL             0x4E88
 /* gap */
 
index c387346..0b59ed7 100644 (file)
@@ -96,7 +96,7 @@ void r420_pipes_init(struct radeon_device *rdev)
                       "programming pipes. Bad things might happen.\n");
        }
        /* get max number of pipes */
-       gb_pipe_select = RREG32(0x402C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
        num_pipes = ((gb_pipe_select >> 12) & 3) + 1;
 
        /* SE chips have 1 pipe */
index 3c8677f..2ce80d9 100644 (file)
@@ -79,8 +79,8 @@ static void r520_gpu_init(struct radeon_device *rdev)
                WREG32(0x4128, 0xFF);
        }
        r420_pipes_init(rdev);
-       gb_pipe_select = RREG32(0x402C);
-       tmp = RREG32(0x170C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
        pipe_select_current = (tmp >> 2) & 3;
        tmp = (1 << pipe_select_current) |
              (((gb_pipe_select >> 8) & 0xF) << 4);
index aca2236..de88624 100644 (file)
@@ -97,12 +97,16 @@ void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 
 /* get temperature in millidegrees */
-u32 rv6xx_get_temp(struct radeon_device *rdev)
+int rv6xx_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
+       int actual_temp = temp & 0xff;
 
-       return temp * 1000;
+       if (temp & 0x100)
+               actual_temp -= 256;
+
+       return actual_temp * 1000;
 }
 
 void r600_pm_get_dynpm_state(struct radeon_device *rdev)
@@ -1287,6 +1291,9 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
                        S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
        u32 tmp;
 
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               return 0;
+
        dev_info(rdev->dev, "GPU softreset \n");
        dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
                RREG32(R_008010_GRBM_STATUS));
@@ -2098,7 +2105,11 @@ static int r600_cp_load_microcode(struct radeon_device *rdev)
 
        r600_cp_stop(rdev);
 
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        /* Reset cp */
        WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
@@ -2185,7 +2196,11 @@ int r600_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_WPTR, 0);
 
        /* set the wb address whether it's enabled or not */
-       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR,
+#ifdef __BIG_ENDIAN
+              RB_RPTR_SWAP(2) |
+#endif
+              ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC));
        WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
        WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
 
@@ -2621,7 +2636,11 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        /* FIXME: implement */
        radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
-       radeon_ring_write(rdev, ib->gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF);
        radeon_ring_write(rdev, ib->length_dw);
 }
@@ -3290,8 +3309,8 @@ restart_ih:
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
-               src_id =  rdev->ih.ring[ring_index] & 0xff;
-               src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff;
+               src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+               src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 
                switch (src_id) {
                case 1: /* D1 vblank/vline */
index ca5c29f..7f10434 100644 (file)
@@ -137,9 +137,9 @@ set_shaders(struct drm_device *dev)
        ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256);
 
        for (i = 0; i < r6xx_vs_size; i++)
-               vs[i] = r6xx_vs[i];
+               vs[i] = cpu_to_le32(r6xx_vs[i]);
        for (i = 0; i < r6xx_ps_size; i++)
-               ps[i] = r6xx_ps[i];
+               ps[i] = cpu_to_le32(r6xx_ps[i]);
 
        dev_priv->blit_vb->used = 512;
 
@@ -192,6 +192,9 @@ set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr)
        DRM_DEBUG("\n");
 
        sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
 
        BEGIN_RING(9);
        OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
@@ -291,7 +294,11 @@ draw_auto(drm_radeon_private_t *dev_priv)
        OUT_RING(DI_PT_RECTLIST);
 
        OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0));
+#ifdef __BIG_ENDIAN
+       OUT_RING((2 << 2) | DI_INDEX_SIZE_16_BIT);
+#else
        OUT_RING(DI_INDEX_SIZE_16_BIT);
+#endif
 
        OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0));
        OUT_RING(1);
index 86e5aa0..41f7aaf 100644 (file)
@@ -54,7 +54,7 @@ set_render_target(struct radeon_device *rdev, int format,
        if (h < 8)
                h = 8;
 
-       cb_color_info = ((format << 2) | (1 << 27));
+       cb_color_info = ((format << 2) | (1 << 27) | (1 << 8));
        pitch = (w / 8) - 1;
        slice = ((w * h) / 64) - 1;
 
@@ -165,6 +165,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
        u32 sq_vtx_constant_word2;
 
        sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
 
        radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7));
        radeon_ring_write(rdev, 0x460);
@@ -199,7 +202,7 @@ set_tex_resource(struct radeon_device *rdev,
        if (h < 1)
                h = 1;
 
-       sq_tex_resource_word0 = (1 << 0);
+       sq_tex_resource_word0 = (1 << 0) | (1 << 3);
        sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) |
                                  ((w - 1) << 19));
 
@@ -253,7 +256,11 @@ draw_auto(struct radeon_device *rdev)
        radeon_ring_write(rdev, DI_PT_RECTLIST);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
-       radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 2) |
+#endif
+                         DI_INDEX_SIZE_16_BIT);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
        radeon_ring_write(rdev, 1);
@@ -424,7 +431,11 @@ set_default_state(struct radeon_device *rdev)
        dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
        gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
        radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
-       radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
        radeon_ring_write(rdev, dwords);
 
@@ -467,7 +478,7 @@ static inline uint32_t i2f(uint32_t input)
 int r600_blit_init(struct radeon_device *rdev)
 {
        u32 obj_size;
-       int r, dwords;
+       int i, r, dwords;
        void *ptr;
        u32 packet2s[16];
        int num_packet2s = 0;
@@ -486,7 +497,7 @@ int r600_blit_init(struct radeon_device *rdev)
 
        dwords = rdev->r600_blit.state_len;
        while (dwords & 0xf) {
-               packet2s[num_packet2s++] = PACKET2(0);
+               packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0));
                dwords++;
        }
 
@@ -529,8 +540,10 @@ int r600_blit_init(struct radeon_device *rdev)
        if (num_packet2s)
                memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
                            packet2s, num_packet2s * 4);
-       memcpy(ptr + rdev->r600_blit.vs_offset, r6xx_vs, r6xx_vs_size * 4);
-       memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
+       for (i = 0; i < r6xx_vs_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(r6xx_vs[i]);
+       for (i = 0; i < r6xx_ps_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(r6xx_ps[i]);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 
index e8151c1..2d1f6c5 100644 (file)
@@ -684,7 +684,11 @@ const u32 r6xx_vs[] =
        0x00000000,
        0x3c000000,
        0x68cd1000,
+#ifdef __BIG_ENDIAN
+       0x000a0000,
+#else
        0x00080000,
+#endif
        0x00000000,
 };
 
index 4f4cd8b..c3ab959 100644 (file)
@@ -396,6 +396,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
        r600_do_cp_stop(dev_priv);
 
        RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
                     R600_RB_NO_UPDATE |
                     R600_RB_BLKSZ(15) |
                     R600_RB_BUFSZ(3));
@@ -486,9 +489,12 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
        r600_do_cp_stop(dev_priv);
 
        RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
                     R600_RB_NO_UPDATE |
-                    (15 << 8) |
-                    (3 << 0));
+                    R600_RB_BLKSZ(15) |
+                    R600_RB_BUFSZ(3));
 
        RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
        RADEON_READ(R600_GRBM_SOFT_RESET);
@@ -550,8 +556,12 @@ static void r600_test_writeback(drm_radeon_private_t *dev_priv)
 
        if (!dev_priv->writeback_works) {
                /* Disable writeback to avoid unnecessary bus master transfer */
-               RADEON_WRITE(R600_CP_RB_CNTL, RADEON_READ(R600_CP_RB_CNTL) |
-                            RADEON_RB_NO_UPDATE);
+               RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                            R600_BUF_SWAP_32BIT |
+#endif
+                            RADEON_READ(R600_CP_RB_CNTL) |
+                            R600_RB_NO_UPDATE);
                RADEON_WRITE(R600_SCRATCH_UMSK, 0);
        }
 }
@@ -575,7 +585,11 @@ int r600_do_engine_reset(struct drm_device *dev)
 
        RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
        cp_rb_cntl = RADEON_READ(R600_CP_RB_CNTL);
-       RADEON_WRITE(R600_CP_RB_CNTL, R600_RB_RPTR_WR_ENA);
+       RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
+                    R600_RB_RPTR_WR_ENA);
 
        RADEON_WRITE(R600_CP_RB_RPTR_WR, cp_ptr);
        RADEON_WRITE(R600_CP_RB_WPTR, cp_ptr);
@@ -1838,7 +1852,10 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev,
                        + dev_priv->gart_vm_start;
        }
        RADEON_WRITE(R600_CP_RB_RPTR_ADDR,
-                    rptr_addr & 0xffffffff);
+#ifdef __BIG_ENDIAN
+                    (2 << 0) |
+#endif
+                    (rptr_addr & 0xfffffffc));
        RADEON_WRITE(R600_CP_RB_RPTR_ADDR_HI,
                     upper_32_bits(rptr_addr));
 
@@ -1889,7 +1906,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev,
        {
                u64 scratch_addr;
 
-               scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR);
+               scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR) & 0xFFFFFFFC;
                scratch_addr |= ((u64)RADEON_READ(R600_CP_RB_RPTR_ADDR_HI)) << 32;
                scratch_addr += R600_SCRATCH_REG_OFFSET;
                scratch_addr >>= 8;
index 7831e08..153095f 100644 (file)
@@ -295,17 +295,18 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        }
 
        if (!IS_ALIGNED(pitch, pitch_align)) {
-               dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-                        __func__, __LINE__, pitch);
+               dev_warn(p->dev, "%s:%d cb pitch (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, pitch, pitch_align, array_mode);
                return -EINVAL;
        }
        if (!IS_ALIGNED(height, height_align)) {
-               dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-                        __func__, __LINE__, height);
+               dev_warn(p->dev, "%s:%d cb height (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, height, height_align, array_mode);
                return -EINVAL;
        }
        if (!IS_ALIGNED(base_offset, base_align)) {
-               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+               dev_warn(p->dev, "%s offset[%d] 0x%llx 0x%llx, %d not aligned\n", __func__, i,
+                        base_offset, base_align, array_mode);
                return -EINVAL;
        }
 
@@ -320,7 +321,10 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                         * broken userspace.
                         */
                } else {
-                       dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+                       dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big\n", __func__, i,
+                                array_mode,
+                                track->cb_color_bo_offset[i], tmp,
+                                radeon_bo_size(track->cb_color_bo[i]));
                        return -EINVAL;
                }
        }
@@ -455,17 +459,18 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                        }
 
                        if (!IS_ALIGNED(pitch, pitch_align)) {
-                               dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-                                        __func__, __LINE__, pitch);
+                               dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
+                                        __func__, __LINE__, pitch, pitch_align, array_mode);
                                return -EINVAL;
                        }
                        if (!IS_ALIGNED(height, height_align)) {
-                               dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-                                        __func__, __LINE__, height);
+                               dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
+                                        __func__, __LINE__, height, height_align, array_mode);
                                return -EINVAL;
                        }
                        if (!IS_ALIGNED(base_offset, base_align)) {
-                               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+                               dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i,
+                                        base_offset, base_align, array_mode);
                                return -EINVAL;
                        }
 
@@ -473,9 +478,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                        nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
                        tmp = ntiles * bpe * 64 * nviews;
                        if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-                               dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
-                                               track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
-                                               radeon_bo_size(track->db_bo));
+                               dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
+                                        array_mode,
+                                        track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+                                        radeon_bo_size(track->db_bo));
                                return -EINVAL;
                        }
                }
@@ -1227,18 +1233,18 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
        /* XXX check height as well... */
 
        if (!IS_ALIGNED(pitch, pitch_align)) {
-               dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-                        __func__, __LINE__, pitch);
+               dev_warn(p->dev, "%s:%d tex pitch (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, pitch, pitch_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
        if (!IS_ALIGNED(base_offset, base_align)) {
-               dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
-                        __func__, __LINE__, base_offset);
+               dev_warn(p->dev, "%s:%d tex base offset (0x%llx, 0x%llx, %d) invalid\n",
+                        __func__, __LINE__, base_offset, base_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
        if (!IS_ALIGNED(mip_offset, base_align)) {
-               dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
-                        __func__, __LINE__, mip_offset);
+               dev_warn(p->dev, "%s:%d tex mip offset (0x%llx, 0x%llx, %d) invalid\n",
+                        __func__, __LINE__, mip_offset, base_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
 
index 33cda01..f869897 100644 (file)
 #define R600_MEDIUM_VID_LOWER_GPIO_CNTL                            0x720
 #define R600_LOW_VID_LOWER_GPIO_CNTL                               0x724
 
-
+#define R600_D1GRPH_SWAP_CONTROL                               0x610C
+#       define R600_D1GRPH_SWAP_ENDIAN_NONE                    (0 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_16BIT                   (1 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_32BIT                   (2 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_64BIT                   (3 << 0)
 
 #define R600_HDP_NONSURFACE_BASE                                0x2c04
 
index a5d898b..04bac0b 100644 (file)
 #define                ROQ_IB2_START(x)                                ((x) << 8)
 #define        CP_RB_BASE                                      0xC100
 #define        CP_RB_CNTL                                      0xC104
-#define                RB_BUFSZ(x)                                     ((x)<<0)
-#define                RB_BLKSZ(x)                                     ((x)<<8)
-#define                RB_NO_UPDATE                                    (1<<27)
-#define                RB_RPTR_WR_ENA                                  (1<<31)
+#define                RB_BUFSZ(x)                                     ((x) << 0)
+#define                RB_BLKSZ(x)                                     ((x) << 8)
+#define                RB_NO_UPDATE                                    (1 << 27)
+#define                RB_RPTR_WR_ENA                                  (1 << 31)
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
+#define                RB_RPTR_SWAP(x)                                 ((x) << 0)
 #define        CP_RB_RPTR_ADDR_HI                              0xC110
 #define        CP_RB_RPTR_WR                                   0xC108
 #define        CP_RB_WPTR                                      0xC114
index 71d2a55..56c48b6 100644 (file)
@@ -179,10 +179,10 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
 void rs690_pm_info(struct radeon_device *rdev);
-extern u32 rv6xx_get_temp(struct radeon_device *rdev);
-extern u32 rv770_get_temp(struct radeon_device *rdev);
-extern u32 evergreen_get_temp(struct radeon_device *rdev);
-extern u32 sumo_get_temp(struct radeon_device *rdev);
+extern int rv6xx_get_temp(struct radeon_device *rdev);
+extern int rv770_get_temp(struct radeon_device *rdev);
+extern int evergreen_get_temp(struct radeon_device *rdev);
+extern int sumo_get_temp(struct radeon_device *rdev);
 
 /*
  * Fences.
@@ -812,8 +812,7 @@ struct radeon_pm {
        fixed20_12              sclk;
        fixed20_12              mclk;
        fixed20_12              needed_bandwidth;
-       /* XXX: use a define for num power modes */
-       struct radeon_power_state power_state[8];
+       struct radeon_power_state *power_state;
        /* number of valid power states */
        int                     num_power_states;
        int                     current_power_state_index;
index 3a1b161..e75d63b 100644 (file)
@@ -759,7 +759,7 @@ static struct radeon_asic evergreen_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
@@ -805,7 +805,7 @@ static struct radeon_asic sumo_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
@@ -848,7 +848,7 @@ static struct radeon_asic btc_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
index e01f077..c59bd98 100644 (file)
@@ -355,6 +355,7 @@ int evergreen_resume(struct radeon_device *rdev);
 bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
 int evergreen_asic_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
+void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int evergreen_copy_blit(struct radeon_device *rdev,
                        uint64_t src_offset, uint64_t dst_offset,
                        unsigned num_pages, struct radeon_fence *fence);
index 1573202..02d5c41 100644 (file)
@@ -88,7 +88,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
                        /* some evergreen boards have bad data for this entry */
                        if (ASIC_IS_DCE4(rdev)) {
                                if ((i == 7) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1936) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
                                    (gpio->sucI2cId.ucAccess == 0)) {
                                        gpio->sucI2cId.ucAccess = 0x97;
                                        gpio->ucDataMaskShift = 8;
@@ -101,7 +101,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
                        /* some DCE3 boards have bad data for this entry */
                        if (ASIC_IS_DCE3(rdev)) {
                                if ((i == 4) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
                                    (gpio->sucI2cId.ucAccess == 0x94))
                                        gpio->sucI2cId.ucAccess = 0x14;
                        }
@@ -172,7 +172,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
                        /* some evergreen boards have bad data for this entry */
                        if (ASIC_IS_DCE4(rdev)) {
                                if ((i == 7) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1936) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
                                    (gpio->sucI2cId.ucAccess == 0)) {
                                        gpio->sucI2cId.ucAccess = 0x97;
                                        gpio->ucDataMaskShift = 8;
@@ -185,7 +185,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
                        /* some DCE3 boards have bad data for this entry */
                        if (ASIC_IS_DCE3(rdev)) {
                                if ((i == 4) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
                                    (gpio->sucI2cId.ucAccess == 0x94))
                                        gpio->sucI2cId.ucAccess = 0x14;
                        }
@@ -252,7 +252,7 @@ static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rd
                        pin = &gpio_info->asGPIO_Pin[i];
                        if (id == pin->ucGPIO_ID) {
                                gpio.id = pin->ucGPIO_ID;
-                               gpio.reg = pin->usGpioPin_AIndex * 4;
+                               gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
                                gpio.mask = (1 << pin->ucGpioPinBitShift);
                                gpio.valid = true;
                                break;
@@ -387,15 +387,11 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                        *line_mux = 0x90;
        }
 
-       /* mac rv630 */
-       if ((dev->pdev->device == 0x9588) &&
-           (dev->pdev->subsystem_vendor == 0x106b) &&
-           (dev->pdev->subsystem_device == 0x00a6)) {
-               if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
-                   (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
-                       *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
-                       *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
-               }
+       /* mac rv630, rv730, others */
+       if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
+           (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
+               *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
+               *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
        }
 
        /* ASUS HD 3600 XT board lists the DVI port as HDMI */
@@ -1167,16 +1163,6 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                                p1pll->pll_out_min = 64800;
                        else
                                p1pll->pll_out_min = 20000;
-               } else if (p1pll->pll_out_min > 64800) {
-                       /* Limiting the pll output range is a good thing generally as
-                        * it limits the number of possible pll combinations for a given
-                        * frequency presumably to the ones that work best on each card.
-                        * However, certain duallink DVI monitors seem to like
-                        * pll combinations that would be limited by this at least on
-                        * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
-                        * family.
-                        */
-                       p1pll->pll_out_min = 64800;
                }
 
                p1pll->pll_in_min =
@@ -1288,11 +1274,11 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev)
                                      data_offset);
                switch (crev) {
                case 1:
-                       if (igp_info->info.ulBootUpMemoryClock)
+                       if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
                                return true;
                        break;
                case 2:
-                       if (igp_info->info_2.ulBootUpSidePortClock)
+                       if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
                                return true;
                        break;
                default:
@@ -1456,7 +1442,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
 
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1470,7 +1456,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1484,7 +1470,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1567,8 +1553,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                if (misc & ATOM_DOUBLE_CLOCK_MODE)
                        lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
 
-               lvds->native_mode.width_mm = lvds_info->info.sLCDTiming.usImageHSize;
-               lvds->native_mode.height_mm = lvds_info->info.sLCDTiming.usImageVSize;
+               lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
+               lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
 
                /* set crtc values */
                drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
@@ -1583,13 +1569,13 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                        lvds->linkb = false;
 
                /* parse the lcd record table */
-               if (lvds_info->info.usModePatchTableOffset) {
+               if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
                        ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
                        ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
                        bool bad_record = false;
                        u8 *record = (u8 *)(mode_info->atom_context->bios +
                                            data_offset +
-                                           lvds_info->info.usModePatchTableOffset);
+                                           le16_to_cpu(lvds_info->info.usModePatchTableOffset));
                        while (*record != ATOM_RECORD_END_TYPE) {
                                switch (*record) {
                                case LCD_MODE_PATCH_RECORD_MODE_TYPE:
@@ -1991,6 +1977,9 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
        num_modes = power_info->info.ucNumOfPowerModeEntries;
        if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
                num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        /* last mode is usually default, array is low to high */
        for (i = 0; i < num_modes; i++) {
                rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
@@ -2200,7 +2189,7 @@ static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev)
                firmware_info =
                        (union firmware_info *)(mode_info->atom_context->bios +
                                                data_offset);
-               vddc = firmware_info->info_14.usBootUpVDDCVoltage;
+               vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
        }
 
        return vddc;
@@ -2295,7 +2284,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                        VOLTAGE_SW;
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
-                       clock_info->evergreen.usVDDC;
+                       le16_to_cpu(clock_info->evergreen.usVDDC);
        } else {
                sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
                sclk |= clock_info->r600.ucEngineClockHigh << 16;
@@ -2306,7 +2295,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                        VOLTAGE_SW;
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
-                       clock_info->r600.usVDDC;
+                       le16_to_cpu(clock_info->r600.usVDDC);
        }
 
        if (rdev->flags & RADEON_IS_IGP) {
@@ -2342,6 +2331,10 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
        power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
 
        radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
+                                      power_info->pplib.ucNumStates, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        /* first mode is usually default, followed by low to high */
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                mode_index = 0;
@@ -2415,13 +2408,17 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
        radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
        state_array = (struct StateArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usStateArrayOffset);
+                le16_to_cpu(power_info->pplib.usStateArrayOffset));
        clock_info_array = (struct ClockInfoArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usClockInfoArrayOffset);
+                le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
        non_clock_info_array = (struct NonClockInfoArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usNonClockInfoArrayOffset);
+                le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
+                                      state_array->ucNumEntries, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        for (i = 0; i < state_array->ucNumEntries; i++) {
                mode_index = 0;
                power_state = (union pplib_power_state *)&state_array->states[i];
@@ -2495,19 +2492,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                        break;
                }
        } else {
-               /* add the default mode */
-               rdev->pm.power_state[state_index].type =
-                       POWER_STATE_TYPE_DEFAULT;
-               rdev->pm.power_state[state_index].num_clock_modes = 1;
-               rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
-               rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
-               rdev->pm.power_state[state_index].default_clock_mode =
-                       &rdev->pm.power_state[state_index].clock_info[0];
-               rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
-               rdev->pm.power_state[state_index].pcie_lanes = 16;
-               rdev->pm.default_power_state_index = state_index;
-               rdev->pm.power_state[state_index].flags = 0;
-               state_index++;
+               rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
+               if (rdev->pm.power_state) {
+                       /* add the default mode */
+                       rdev->pm.power_state[state_index].type =
+                               POWER_STATE_TYPE_DEFAULT;
+                       rdev->pm.power_state[state_index].num_clock_modes = 1;
+                       rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+                       rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+                       rdev->pm.power_state[state_index].default_clock_mode =
+                               &rdev->pm.power_state[state_index].clock_info[0];
+                       rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+                       rdev->pm.power_state[state_index].pcie_lanes = 16;
+                       rdev->pm.default_power_state_index = state_index;
+                       rdev->pm.power_state[state_index].flags = 0;
+                       state_index++;
+               }
        }
 
        rdev->pm.num_power_states = state_index;
@@ -2533,7 +2533,7 @@ uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
        int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-       return args.ulReturnEngineClock;
+       return le32_to_cpu(args.ulReturnEngineClock);
 }
 
 uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
@@ -2542,7 +2542,7 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
        int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-       return args.ulReturnMemoryClock;
+       return le32_to_cpu(args.ulReturnMemoryClock);
 }
 
 void radeon_atom_set_engine_clock(struct radeon_device *rdev,
@@ -2551,7 +2551,7 @@ void radeon_atom_set_engine_clock(struct radeon_device *rdev,
        SET_ENGINE_CLOCK_PS_ALLOCATION args;
        int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
 
-       args.ulTargetEngineClock = eng_clock;   /* 10 khz */
+       args.ulTargetEngineClock = cpu_to_le32(eng_clock);      /* 10 khz */
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -2565,7 +2565,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev,
        if (rdev->flags & RADEON_IS_IGP)
                return;
 
-       args.ulTargetMemoryClock = mem_clock;   /* 10 khz */
+       args.ulTargetMemoryClock = cpu_to_le32(mem_clock);      /* 10 khz */
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -2623,7 +2623,7 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
        bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
 
        /* tell the bios not to handle mode switching */
-       bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE);
+       bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
 
        if (rdev->family >= CHIP_R600) {
                WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
@@ -2674,10 +2674,13 @@ void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
        else
                bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
 
-       if (lock)
+       if (lock) {
                bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
-       else
+               bios_6_scratch &= ~ATOM_S6_ACC_MODE;
+       } else {
                bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
+               bios_6_scratch |= ATOM_S6_ACC_MODE;
+       }
 
        if (rdev->family >= CHIP_R600)
                WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
index 591fcae..cf7c8d5 100644 (file)
@@ -1504,6 +1504,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                           (rdev->pdev->subsystem_device == 0x4a48)) {
                        /* Mac X800 */
                        rdev->mode_info.connector_table = CT_MAC_X800;
+               } else if ((rdev->pdev->device == 0x4150) &&
+                          (rdev->pdev->subsystem_vendor == 0x1002) &&
+                          (rdev->pdev->subsystem_device == 0x4150)) {
+                       /* Mac G5 9600 */
+                       rdev->mode_info.connector_table = CT_MAC_G5_9600;
                } else
 #endif /* CONFIG_PPC_PMAC */
 #ifdef CONFIG_PPC64
@@ -2022,6 +2027,48 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I,
                                            &hpd);
                break;
+       case CT_MAC_G5_9600:
+               DRM_INFO("Connector Table: %d (mac g5 9600)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI - tv dac, dvo */
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+               hpd.hpd = RADEON_HPD_1; /* ??? */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_DFP2_SUPPORT,
+                                                                 0),
+                                         ATOM_DEVICE_DFP2_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_CRT2_SUPPORT,
+                                                                 2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 0,
+                                           ATOM_DEVICE_DFP2_SUPPORT |
+                                           ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+                                           &hpd);
+               /* ADC - primary dac, internal tmds */
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+               hpd.hpd = RADEON_HPD_2; /* ??? */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_DFP1_SUPPORT,
+                                                                 0),
+                                         ATOM_DEVICE_DFP1_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_CRT1_SUPPORT,
+                                                                 1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1,
+                                           ATOM_DEVICE_DFP1_SUPPORT |
+                                           ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+                                           &hpd);
+               break;
        default:
                DRM_INFO("Connector table: %d (invalid)\n",
                         rdev->mode_info.connector_table);
@@ -2442,6 +2489,17 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
 
        rdev->pm.default_power_state_index = -1;
 
+       /* allocate 2 power states */
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL);
+       if (!rdev->pm.power_state) {
+               rdev->pm.default_power_state_index = state_index;
+               rdev->pm.num_power_states = 0;
+
+               rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
+               rdev->pm.current_clock_mode_index = 0;
+               return;
+       }
+
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
                if (offset) {
index 26091d6..4954e2d 100644 (file)
@@ -891,9 +891,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
                pci_disable_device(dev->pdev);
                pci_set_power_state(dev->pdev, PCI_D3hot);
        }
-       acquire_console_sem();
+       console_lock();
        radeon_fbdev_set_suspend(rdev, 1);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
@@ -905,11 +905,11 @@ int radeon_resume_kms(struct drm_device *dev)
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev->pdev, PCI_D0);
        pci_restore_state(dev->pdev);
        if (pci_enable_device(dev->pdev)) {
-               release_console_sem();
+               console_unlock();
                return -1;
        }
        pci_set_master(dev->pdev);
@@ -920,7 +920,7 @@ int radeon_resume_kms(struct drm_device *dev)
        radeon_restore_bios_scratch_regs(rdev);
 
        radeon_fbdev_set_suspend(rdev, 0);
-       release_console_sem();
+       console_unlock();
 
        /* reset hpd state */
        radeon_hpd_init(rdev);
@@ -936,8 +936,11 @@ int radeon_resume_kms(struct drm_device *dev)
 int radeon_gpu_reset(struct radeon_device *rdev)
 {
        int r;
+       int resched;
 
        radeon_save_bios_scratch_regs(rdev);
+       /* block TTM */
+       resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
        radeon_suspend(rdev);
 
        r = radeon_asic_reset(rdev);
@@ -946,6 +949,7 @@ int radeon_gpu_reset(struct radeon_device *rdev)
                radeon_resume(rdev);
                radeon_restore_bios_scratch_regs(rdev);
                drm_helper_resume_force_mode(rdev->ddev);
+               ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
                return 0;
        }
        /* bad news, how to tell it to userspace ? */
index d26dabf..3e7e7f9 100644 (file)
@@ -780,6 +780,125 @@ static int radeon_ddc_dump(struct drm_connector *connector)
        return ret;
 }
 
+/* avivo */
+static void avivo_get_fb_div(struct radeon_pll *pll,
+                            u32 target_clock,
+                            u32 post_div,
+                            u32 ref_div,
+                            u32 *fb_div,
+                            u32 *frac_fb_div)
+{
+       u32 tmp = post_div * ref_div;
+
+       tmp *= target_clock;
+       *fb_div = tmp / pll->reference_freq;
+       *frac_fb_div = tmp % pll->reference_freq;
+
+        if (*fb_div > pll->max_feedback_div)
+               *fb_div = pll->max_feedback_div;
+        else if (*fb_div < pll->min_feedback_div)
+                *fb_div = pll->min_feedback_div;
+}
+
+static u32 avivo_get_post_div(struct radeon_pll *pll,
+                             u32 target_clock)
+{
+       u32 vco, post_div, tmp;
+
+       if (pll->flags & RADEON_PLL_USE_POST_DIV)
+               return pll->post_div;
+
+       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
+               if (pll->flags & RADEON_PLL_IS_LCD)
+                       vco = pll->lcd_pll_out_min;
+               else
+                       vco = pll->pll_out_min;
+       } else {
+               if (pll->flags & RADEON_PLL_IS_LCD)
+                       vco = pll->lcd_pll_out_max;
+               else
+                       vco = pll->pll_out_max;
+       }
+
+       post_div = vco / target_clock;
+       tmp = vco % target_clock;
+
+       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
+               if (tmp)
+                       post_div++;
+       } else {
+               if (!tmp)
+                       post_div--;
+       }
+
+       if (post_div > pll->max_post_div)
+               post_div = pll->max_post_div;
+       else if (post_div < pll->min_post_div)
+               post_div = pll->min_post_div;
+
+       return post_div;
+}
+
+#define MAX_TOLERANCE 10
+
+void radeon_compute_pll_avivo(struct radeon_pll *pll,
+                             u32 freq,
+                             u32 *dot_clock_p,
+                             u32 *fb_div_p,
+                             u32 *frac_fb_div_p,
+                             u32 *ref_div_p,
+                             u32 *post_div_p)
+{
+       u32 target_clock = freq / 10;
+       u32 post_div = avivo_get_post_div(pll, target_clock);
+       u32 ref_div = pll->min_ref_div;
+       u32 fb_div = 0, frac_fb_div = 0, tmp;
+
+       if (pll->flags & RADEON_PLL_USE_REF_DIV)
+               ref_div = pll->reference_div;
+
+       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+               avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div);
+               frac_fb_div = (100 * frac_fb_div) / pll->reference_freq;
+               if (frac_fb_div >= 5) {
+                       frac_fb_div -= 5;
+                       frac_fb_div = frac_fb_div / 10;
+                       frac_fb_div++;
+               }
+               if (frac_fb_div >= 10) {
+                       fb_div++;
+                       frac_fb_div = 0;
+               }
+       } else {
+               while (ref_div <= pll->max_ref_div) {
+                       avivo_get_fb_div(pll, target_clock, post_div, ref_div,
+                                        &fb_div, &frac_fb_div);
+                       if (frac_fb_div >= (pll->reference_freq / 2))
+                               fb_div++;
+                       frac_fb_div = 0;
+                       tmp = (pll->reference_freq * fb_div) / (post_div * ref_div);
+                       tmp = (tmp * 10000) / target_clock;
+
+                       if (tmp > (10000 + MAX_TOLERANCE))
+                               ref_div++;
+                       else if (tmp >= (10000 - MAX_TOLERANCE))
+                               break;
+                       else
+                               ref_div++;
+               }
+       }
+
+       *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) /
+               (ref_div * post_div * 10);
+       *fb_div_p = fb_div;
+       *frac_fb_div_p = frac_fb_div;
+       *ref_div_p = ref_div;
+       *post_div_p = post_div;
+       DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div);
+}
+
+/* pre-avivo */
 static inline uint32_t radeon_div(uint64_t n, uint32_t d)
 {
        uint64_t mod;
@@ -790,13 +909,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
        return n;
 }
 
-void radeon_compute_pll(struct radeon_pll *pll,
-                       uint64_t freq,
-                       uint32_t *dot_clock_p,
-                       uint32_t *fb_div_p,
-                       uint32_t *frac_fb_div_p,
-                       uint32_t *ref_div_p,
-                       uint32_t *post_div_p)
+void radeon_compute_pll_legacy(struct radeon_pll *pll,
+                              uint64_t freq,
+                              uint32_t *dot_clock_p,
+                              uint32_t *fb_div_p,
+                              uint32_t *frac_fb_div_p,
+                              uint32_t *ref_div_p,
+                              uint32_t *post_div_p)
 {
        uint32_t min_ref_div = pll->min_ref_div;
        uint32_t max_ref_div = pll->max_ref_div;
@@ -826,6 +945,9 @@ void radeon_compute_pll(struct radeon_pll *pll,
                pll_out_max = pll->pll_out_max;
        }
 
+       if (pll_out_min > 64800)
+               pll_out_min = 64800;
+
        if (pll->flags & RADEON_PLL_USE_REF_DIV)
                min_ref_div = max_ref_div = pll->reference_div;
        else {
@@ -965,6 +1087,10 @@ void radeon_compute_pll(struct radeon_pll *pll,
        *frac_fb_div_p = best_frac_feedback_div;
        *ref_div_p = best_ref_div;
        *post_div_p = best_post_div;
+       DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+                     best_ref_div, best_post_div);
+
 }
 
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
index d5680a0..275b26a 100644 (file)
@@ -48,7 +48,7 @@
  * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
  * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
  *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
- *   2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK
+ *   2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
  */
 #define KMS_DRIVER_MAJOR       2
 #define KMS_DRIVER_MINOR       8
index 448eba8..5cba46b 100644 (file)
@@ -1524,6 +1524,7 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
 #define R600_CP_RB_CNTL                                        0xc104
 #       define R600_RB_BUFSZ(x)                                ((x) << 0)
 #       define R600_RB_BLKSZ(x)                                ((x) << 8)
+#      define R600_BUF_SWAP_32BIT                             (2 << 16)
 #       define R600_RB_NO_UPDATE                               (1 << 27)
 #       define R600_RB_RPTR_WR_ENA                             (1 << 31)
 #define R600_CP_RB_RPTR_WR                                     0xc108
index 8fd1842..b427488 100644 (file)
@@ -641,7 +641,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -655,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -673,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
                        return ATOM_ENCODER_MODE_DP;
-               else if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -910,7 +910,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 
        args.v1.ucAction = action;
        if (action == ATOM_TRANSMITTER_ACTION_INIT) {
-               args.v1.usInitInfo = connector_object_id;
+               args.v1.usInitInfo = cpu_to_le16(connector_object_id);
        } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
                args.v1.asMode.ucLaneSel = lane_num;
                args.v1.asMode.ucLaneSet = lane_set;
@@ -1063,7 +1063,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        if (!ASIC_IS_DCE4(rdev))
                return;
 
-       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
                return;
 
@@ -1140,7 +1140,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                case 3:
                        args.v3.sExtEncoder.ucAction = action;
                        if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
-                               args.v3.sExtEncoder.usConnectorId = connector_object_id;
+                               args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
                        else
                                args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
                        args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
@@ -1570,11 +1570,21 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 
        /* set scaler clears this on some chips */
-       /* XXX check DCE4 */
-       if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) {
-               if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
-                       WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
-                              AVIVO_D1MODE_INTERLEAVE_EN);
+       if (ASIC_IS_AVIVO(rdev) &&
+           (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
+               if (ASIC_IS_DCE4(rdev)) {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      EVERGREEN_INTERLEAVE_EN);
+                       else
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               } else {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      AVIVO_D1MODE_INTERLEAVE_EN);
+                       else
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               }
        }
 }
 
index 66324b5..cc44bdf 100644 (file)
@@ -113,11 +113,14 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
        u32 tiling_flags = 0;
        int ret;
        int aligned_size, size;
+       int height = mode_cmd->height;
 
        /* need to align pitch with crtc limits */
        mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
 
-       size = mode_cmd->pitch * mode_cmd->height;
+       if (rdev->family >= CHIP_R600)
+               height = ALIGN(mode_cmd->height, 8);
+       size = mode_cmd->pitch * height;
        aligned_size = ALIGN(size, PAGE_SIZE);
        ret = radeon_gem_object_create(rdev, aligned_size, 0,
                                       RADEON_GEM_DOMAIN_VRAM,
index a289646..9ec830c 100644 (file)
@@ -110,11 +110,14 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
 
 int radeon_irq_kms_init(struct radeon_device *rdev)
 {
+       int i;
        int r = 0;
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
 
        spin_lock_init(&rdev->irq.sw_lock);
+       for (i = 0; i < rdev->num_crtc; i++)
+               spin_lock_init(&rdev->irq.pflip_lock[i]);
        r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
        if (r) {
                return r;
index 28a53e4..8387d32 100644 (file)
@@ -201,6 +201,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                }
                radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value);
                break;
+       case RADEON_INFO_CLOCK_CRYSTAL_FREQ:
+               /* return clock value in KHz */
+               value = rdev->clock.spll.reference_freq * 10;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
@@ -243,6 +247,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
        struct radeon_device *rdev = dev->dev_private;
        if (rdev->hyperz_filp == file_priv)
                rdev->hyperz_filp = NULL;
+       if (rdev->cmask_filp == file_priv)
+               rdev->cmask_filp = NULL;
 }
 
 /*
index ace2e63..cf0638c 100644 (file)
@@ -778,9 +778,9 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
        DRM_DEBUG_KMS("\n");
 
        if (!use_bios_divs) {
-               radeon_compute_pll(pll, mode->clock,
-                                  &freq, &feedback_div, &frac_fb_div,
-                                  &reference_div, &post_divider);
+               radeon_compute_pll_legacy(pll, mode->clock,
+                                         &freq, &feedback_div, &frac_fb_div,
+                                         &reference_div, &post_divider);
 
                for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
                        if (post_div->divider == post_divider)
index 12bdeab..a670caa 100644 (file)
@@ -149,6 +149,7 @@ struct radeon_tmds_pll {
 #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
 #define RADEON_PLL_USE_POST_DIV         (1 << 12)
 #define RADEON_PLL_IS_LCD               (1 << 13)
+#define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14)
 
 struct radeon_pll {
        /* reference frequency */
@@ -208,6 +209,7 @@ enum radeon_connector_table {
        CT_EMAC,
        CT_RN50_POWER,
        CT_MAC_X800,
+       CT_MAC_G5_9600,
 };
 
 enum radeon_dvo_chip {
@@ -510,13 +512,21 @@ extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                             struct radeon_atom_ss *ss,
                                             int id, u32 clock);
 
-extern void radeon_compute_pll(struct radeon_pll *pll,
-                              uint64_t freq,
-                              uint32_t *dot_clock_p,
-                              uint32_t *fb_div_p,
-                              uint32_t *frac_fb_div_p,
-                              uint32_t *ref_div_p,
-                              uint32_t *post_div_p);
+extern void radeon_compute_pll_legacy(struct radeon_pll *pll,
+                                     uint64_t freq,
+                                     uint32_t *dot_clock_p,
+                                     uint32_t *fb_div_p,
+                                     uint32_t *frac_fb_div_p,
+                                     uint32_t *ref_div_p,
+                                     uint32_t *post_div_p);
+
+extern void radeon_compute_pll_avivo(struct radeon_pll *pll,
+                                    u32 freq,
+                                    u32 *dot_clock_p,
+                                    u32 *fb_div_p,
+                                    u32 *frac_fb_div_p,
+                                    u32 *ref_div_p,
+                                    u32 *post_div_p);
 
 extern void radeon_setup_encoder_clones(struct drm_device *dev);
 
index 3b1b2bf..2aed03b 100644 (file)
@@ -430,7 +430,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
 {
        struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
        struct radeon_device *rdev = ddev->dev_private;
-       u32 temp;
+       int temp;
 
        switch (rdev->pm.int_thermal_type) {
        case THERMAL_TYPE_RV6XX:
@@ -646,6 +646,9 @@ void radeon_pm_fini(struct radeon_device *rdev)
 #endif
        }
 
+       if (rdev->pm.power_state)
+               kfree(rdev->pm.power_state);
+
        radeon_hwmon_fini(rdev);
 }
 
index 3cd4dac..ec93a75 100644 (file)
 #define RADEON_CONFIG_APER_SIZE             0x0108
 #define RADEON_CONFIG_BONDS                 0x00e8
 #define RADEON_CONFIG_CNTL                  0x00e0
+#       define RADEON_CFG_VGA_RAM_EN        (1 << 8)
+#       define RADEON_CFG_VGA_IO_DIS        (1 << 9)
 #       define RADEON_CFG_ATI_REV_A11       (0   << 16)
 #       define RADEON_CFG_ATI_REV_A12       (1   << 16)
 #       define RADEON_CFG_ATI_REV_A13       (2   << 16)
index 1272e4b..e5b2cf1 100644 (file)
@@ -787,9 +787,9 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
                radeon_mem_types_list[i].show = &radeon_mm_dump_table;
                radeon_mem_types_list[i].driver_features = 0;
                if (i == 0)
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv;
+                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv;
                else
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv;
+                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv;
 
        }
        /* Add ttm page pool to debugfs */
index b506ec1..e8a1786 100644 (file)
@@ -683,9 +683,7 @@ r300 0x4f60
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -706,13 +704,11 @@ r300 0x4f60
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index 8c1214c..722074e 100644 (file)
@@ -130,7 +130,6 @@ r420 0x4f60
 0x401C GB_SELECT
 0x4020 GB_AA_CONFIG
 0x4024 GB_FIFO_SIZE
-0x4028 GB_Z_PEQ_CONFIG
 0x4100 TX_INVALTAGS
 0x4200 GA_POINT_S0
 0x4204 GA_POINT_T0
@@ -750,9 +749,7 @@ r420 0x4f60
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -773,13 +770,11 @@ r420 0x4f60
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index 0828d80..d9f6286 100644 (file)
@@ -749,9 +749,7 @@ rs600 0x6d40
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -772,13 +770,11 @@ rs600 0x6d40
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index ef422bb..911a8fb 100644 (file)
@@ -164,7 +164,6 @@ rv515 0x6d40
 0x401C GB_SELECT
 0x4020 GB_AA_CONFIG
 0x4024 GB_FIFO_SIZE
-0x4028 GB_Z_PEQ_CONFIG
 0x4100 TX_INVALTAGS
 0x4114 SU_TEX_WRAP_PS3
 0x4118 PS3_ENABLE
@@ -461,9 +460,7 @@ rv515 0x6d40
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -484,9 +481,6 @@ rv515 0x6d40
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4EF8 RB3D_CONSTANT_COLOR_AR
@@ -496,4 +490,5 @@ rv515 0x6d40
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
 0x4F58 ZB_ZPASS_DATA
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4FD4 ZB_STENCILREFMASK_BF
index 5512e4e..c76283d 100644 (file)
@@ -203,6 +203,9 @@ void rs400_gart_fini(struct radeon_device *rdev)
        radeon_gart_table_ram_free(rdev);
 }
 
+#define RS400_PTE_WRITEABLE (1 << 2)
+#define RS400_PTE_READABLE  (1 << 3)
+
 int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 {
        uint32_t entry;
@@ -213,7 +216,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 
        entry = (lower_32_bits(addr) & PAGE_MASK) |
                ((upper_32_bits(addr) & 0xff) << 4) |
-               0xc;
+               RS400_PTE_WRITEABLE | RS400_PTE_READABLE;
        entry = cpu_to_le32(entry);
        rdev->gart.table.ram.ptr[i] = entry;
        return 0;
@@ -226,8 +229,8 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev)
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                /* read MC_STATUS */
-               tmp = RREG32(0x0150);
-               if (tmp & (1 << 2)) {
+               tmp = RREG32(RADEON_MC_STATUS);
+               if (tmp & RADEON_MC_IDLE) {
                        return 0;
                }
                DRM_UDELAY(1);
@@ -241,7 +244,7 @@ void rs400_gpu_init(struct radeon_device *rdev)
        r420_pipes_init(rdev);
        if (rs400_mc_wait_for_idle(rdev)) {
                printk(KERN_WARNING "rs400: Failed to wait MC idle while "
-                      "programming pipes. Bad things might happen. %08x\n", RREG32(0x150));
+                      "programming pipes. Bad things might happen. %08x\n", RREG32(RADEON_MC_STATUS));
        }
 }
 
@@ -300,9 +303,9 @@ static int rs400_debugfs_gart_info(struct seq_file *m, void *data)
                seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp);
                tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION);
                seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp);
-               tmp = RREG32_MC(0x100);
+               tmp = RREG32_MC(RS690_MCCFG_FB_LOCATION);
                seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp);
-               tmp = RREG32(0x134);
+               tmp = RREG32(RS690_HDP_FB_LOCATION);
                seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp);
        } else {
                tmp = RREG32(RADEON_AGP_BASE);
index 0137d3e..6638c8e 100644 (file)
@@ -77,9 +77,9 @@ void rs690_pm_info(struct radeon_device *rdev)
                switch (crev) {
                case 1:
                        tmp.full = dfixed_const(100);
-                       rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info.ulBootUpMemoryClock);
+                       rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info.ulBootUpMemoryClock));
                        rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp);
-                       if (info->info.usK8MemoryClock)
+                       if (le16_to_cpu(info->info.usK8MemoryClock))
                                rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock));
                        else if (rdev->clock.default_mclk) {
                                rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk);
@@ -91,16 +91,16 @@ void rs690_pm_info(struct radeon_device *rdev)
                        break;
                case 2:
                        tmp.full = dfixed_const(100);
-                       rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info_v2.ulBootUpSidePortClock);
+                       rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpSidePortClock));
                        rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp);
-                       if (info->info_v2.ulBootUpUMAClock)
-                               rdev->pm.igp_system_mclk.full = dfixed_const(info->info_v2.ulBootUpUMAClock);
+                       if (le32_to_cpu(info->info_v2.ulBootUpUMAClock))
+                               rdev->pm.igp_system_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpUMAClock));
                        else if (rdev->clock.default_mclk)
                                rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk);
                        else
                                rdev->pm.igp_system_mclk.full = dfixed_const(66700);
                        rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp);
-                       rdev->pm.igp_ht_link_clk.full = dfixed_const(info->info_v2.ulHTLinkFreq);
+                       rdev->pm.igp_ht_link_clk.full = dfixed_const(le32_to_cpu(info->info_v2.ulHTLinkFreq));
                        rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp);
                        rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth));
                        break;
index 5d569f4..64b57af 100644 (file)
@@ -69,13 +69,13 @@ void rv515_ring_start(struct radeon_device *rdev)
                          ISYNC_CPSCRATCH_IDLEGUI);
        radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0));
        radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN);
-       radeon_ring_write(rdev, PACKET0(0x170C, 0));
-       radeon_ring_write(rdev, 1 << 31);
+       radeon_ring_write(rdev, PACKET0(R300_DST_PIPE_CONFIG, 0));
+       radeon_ring_write(rdev, R300_PIPE_AUTO_CONFIG);
        radeon_ring_write(rdev, PACKET0(GB_SELECT, 0));
        radeon_ring_write(rdev, 0);
        radeon_ring_write(rdev, PACKET0(GB_ENABLE, 0));
        radeon_ring_write(rdev, 0);
-       radeon_ring_write(rdev, PACKET0(0x42C8, 0));
+       radeon_ring_write(rdev, PACKET0(R500_SU_REG_DEST, 0));
        radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1);
        radeon_ring_write(rdev, PACKET0(VAP_INDEX_OFFSET, 0));
        radeon_ring_write(rdev, 0);
@@ -153,8 +153,8 @@ void rv515_gpu_init(struct radeon_device *rdev)
        }
        rv515_vga_render_disable(rdev);
        r420_pipes_init(rdev);
-       gb_pipe_select = RREG32(0x402C);
-       tmp = RREG32(0x170C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
        pipe_select_current = (tmp >> 2) & 3;
        tmp = (1 << pipe_select_current) |
              (((gb_pipe_select >> 8) & 0xF) << 4);
index 491dc90..d8ba676 100644 (file)
@@ -78,18 +78,23 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 }
 
 /* get temperature in millidegrees */
-u32 rv770_get_temp(struct radeon_device *rdev)
+int rv770_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
-       u32 actual_temp = 0;
-
-       if ((temp >> 9) & 1)
-               actual_temp = 0;
-       else
-               actual_temp = (temp >> 1) & 0xff;
-
-       return actual_temp * 1000;
+       int actual_temp;
+
+       if (temp & 0x400)
+               actual_temp = -256;
+       else if (temp & 0x200)
+               actual_temp = 255;
+       else if (temp & 0x100) {
+               actual_temp = temp & 0x1ff;
+               actual_temp |= ~0x1ff;
+       } else
+               actual_temp = temp & 0xff;
+
+       return (actual_temp * 1000) / 2;
 }
 
 void rv770_pm_misc(struct radeon_device *rdev)
@@ -316,7 +321,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev)
                return -EINVAL;
 
        r700_cp_stop(rdev);
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        /* Reset cp */
        WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
index abc8cf5..79fa588 100644 (file)
 #define                ROQ_IB1_START(x)                                ((x) << 0)
 #define                ROQ_IB2_START(x)                                ((x) << 8)
 #define        CP_RB_CNTL                                      0xC104
-#define                RB_BUFSZ(x)                                     ((x)<<0)
-#define                RB_BLKSZ(x)                                     ((x)<<8)
-#define                RB_NO_UPDATE                                    (1<<27)
-#define                RB_RPTR_WR_ENA                                  (1<<31)
+#define                RB_BUFSZ(x)                                     ((x) << 0)
+#define                RB_BLKSZ(x)                                     ((x) << 8)
+#define                RB_NO_UPDATE                                    (1 << 27)
+#define                RB_RPTR_WR_ENA                                  (1 << 31)
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
index 09aea5f..70e60a4 100644 (file)
@@ -1,11 +1,13 @@
 config STUB_POULSBO
        tristate "Intel GMA500 Stub Driver"
        depends on PCI
+       depends on NET # for THERMAL
        # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
+       select THERMAL if ACPI
        help
          Choose this option if you have a system that has Intel GMA500
          (Poulsbo) integrated graphics. If M is selected, the module will
index 8d0e31a..96c83a9 100644 (file)
@@ -1,5 +1,5 @@
 config VGA_ARB
-       bool "VGA Arbitration" if EMBEDDED
+       bool "VGA Arbitration" if EXPERT
        default y
        depends on PCI
        help
index c380c65..ace2b16 100644 (file)
@@ -636,7 +636,7 @@ int vga_client_register(struct pci_dev *pdev, void *cookie,
                        void (*irq_set_state)(void *cookie, bool state),
                        unsigned int (*set_vga_decode)(void *cookie, bool decode))
 {
-       int ret = -1;
+       int ret = -ENODEV;
        struct vga_device *vgadev;
        unsigned long flags;
 
index 24cca2f..2560f01 100644 (file)
@@ -62,9 +62,9 @@ config HID_3M_PCT
        Support for 3M PCT touch screens.
 
 config HID_A4TECH
-       tristate "A4 tech mice" if EMBEDDED
+       tristate "A4 tech mice" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for A4 tech X5 and WOP-35 / Trust 450L mice.
 
@@ -77,9 +77,9 @@ config HID_ACRUX_FF
        game controllers.
 
 config HID_APPLE
-       tristate "Apple {i,Power,Mac}Books" if EMBEDDED
+       tristate "Apple {i,Power,Mac}Books" if EXPERT
        depends on (USB_HID || BT_HIDP)
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for some Apple devices which less or more break
        HID specification.
@@ -88,9 +88,9 @@ config HID_APPLE
        MacBooks, MacBook Pros and Apple Aluminum.
 
 config HID_BELKIN
-       tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED
+       tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Belkin Flip KVM and Wireless keyboard.
 
@@ -101,16 +101,16 @@ config HID_CANDO
        Support for Cando dual touch panel.
 
 config HID_CHERRY
-       tristate "Cherry Cymotion keyboard" if EMBEDDED
+       tristate "Cherry Cymotion keyboard" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Cherry Cymotion keyboard.
 
 config HID_CHICONY
-       tristate "Chicony Tactical pad" if EMBEDDED
+       tristate "Chicony Tactical pad" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Chicony Tactical pad.
 
@@ -130,9 +130,9 @@ config HID_PRODIKEYS
          and some additional multimedia keys.
 
 config HID_CYPRESS
-       tristate "Cypress mouse and barcode readers" if EMBEDDED
+       tristate "Cypress mouse and barcode readers" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for cypress mouse and barcode readers.
 
@@ -174,16 +174,16 @@ config HID_ELECOM
        Support for the ELECOM BM084 (bluetooth mouse).
 
 config HID_EZKEY
-       tristate "Ezkey BTC 8193 keyboard" if EMBEDDED
+       tristate "Ezkey BTC 8193 keyboard" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Ezkey BTC 8193 keyboard.
 
 config HID_KYE
-       tristate "Kye/Genius Ergo Mouse" if EMBEDDED
+       tristate "Kye/Genius Ergo Mouse" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Kye/Genius Ergo Mouse.
 
@@ -212,16 +212,16 @@ config HID_TWINHAN
        Support for Twinhan IR remote control.
 
 config HID_KENSINGTON
-       tristate "Kensington Slimblade Trackball" if EMBEDDED
+       tristate "Kensington Slimblade Trackball" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Kensington Slimblade Trackball.
 
 config HID_LOGITECH
-       tristate "Logitech devices" if EMBEDDED
+       tristate "Logitech devices" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Logitech devices that are not fully compliant with HID standard.
 
@@ -276,9 +276,9 @@ config HID_MAGICMOUSE
        Apple Wireless "Magic" Mouse.
 
 config HID_MICROSOFT
-       tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED
+       tristate "Microsoft non-fully HID-compliant devices" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Microsoft devices that are not fully compliant with HID standard.
 
@@ -289,9 +289,9 @@ config HID_MOSART
        Support for MosArt dual-touch panels.
 
 config HID_MONTEREY
-       tristate "Monterey Genius KB29E keyboard" if EMBEDDED
+       tristate "Monterey Genius KB29E keyboard" if EXPERT
        depends on USB_HID
-       default !EMBEDDED
+       default !EXPERT
        ---help---
        Support for Monterey Genius KB29E.
 
@@ -365,8 +365,8 @@ config HID_PICOLCD
          - IR
 
 config HID_PICOLCD_FB
-       bool "Framebuffer support" if EMBEDDED
-       default !EMBEDDED
+       bool "Framebuffer support" if EXPERT
+       default !EXPERT
        depends on HID_PICOLCD
        depends on HID_PICOLCD=FB || FB=y
        select FB_DEFERRED_IO
@@ -379,8 +379,8 @@ config HID_PICOLCD_FB
          frambuffer device.
 
 config HID_PICOLCD_BACKLIGHT
-       bool "Backlight control" if EMBEDDED
-       default !EMBEDDED
+       bool "Backlight control" if EXPERT
+       default !EXPERT
        depends on HID_PICOLCD
        depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y
        ---help---
@@ -388,16 +388,16 @@ config HID_PICOLCD_BACKLIGHT
          class.
 
 config HID_PICOLCD_LCD
-       bool "Contrast control" if EMBEDDED
-       default !EMBEDDED
+       bool "Contrast control" if EXPERT
+       default !EXPERT
        depends on HID_PICOLCD
        depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y
        ---help---
          Provide access to PicoLCD's LCD contrast via lcd class.
 
 config HID_PICOLCD_LEDS
-       bool "GPO via leds class" if EMBEDDED
-       default !EMBEDDED
+       bool "GPO via leds class" if EXPERT
+       default !EXPERT
        depends on HID_PICOLCD
        depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y
        ---help---
index 4edb3be..0f20fd1 100644 (file)
@@ -45,7 +45,7 @@ config USB_HIDDEV
          If unsure, say Y.
 
 menu "USB HID Boot Protocol drivers"
-       depends on USB!=n && USB_HID!=y && EMBEDDED
+       depends on USB!=n && USB_HID!=y && EXPERT
 
 config USB_KBD
        tristate "USB HIDBP Keyboard (simple Boot) support"
index 773e484..297bc9a 100644 (file)
@@ -238,13 +238,13 @@ config SENSORS_K8TEMP
          will be called k8temp.
 
 config SENSORS_K10TEMP
-       tristate "AMD Phenom/Sempron/Turion/Opteron temperature sensor"
+       tristate "AMD Family 10h/11h/12h/14h temperature sensor"
        depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported are later revisions of
-         the AMD Family 10h and all revisions of the AMD Family 11h
-         microarchitectures.
+         the AMD Family 10h and all revisions of the AMD Family 11h,
+         12h (Llano), and 14h (Brazos) microarchitectures.
 
          This driver can also be built as a module.  If so, the module
          will be called k10temp.
@@ -455,13 +455,14 @@ config SENSORS_JZ4740
          called jz4740-hwmon.
 
 config SENSORS_JC42
-       tristate "JEDEC JC42.4 compliant temperature sensors"
+       tristate "JEDEC JC42.4 compliant memory module temperature sensors"
        depends on I2C
        help
-         If you say yes here you get support for Jedec JC42.4 compliant
-         temperature sensors. Support will include, but not be limited to,
-         ADT7408, CAT34TS02,, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
-         MCP9843, SE97, SE98, STTS424, TSE2002B3, and TS3000B3.
+         If you say yes here, you get support for JEDEC JC42.4 compliant
+         temperature sensors, which are used on many DDR3 memory modules for
+         mobile devices and servers.  Support will include, but not be limited
+         to, ADT7408, CAT34TS02, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
+         MCP9843, SE97, SE98, STTS424(E), TSE2002B3, and TS3000B3.
 
          This driver can also be built as a module.  If so, the module
          will be called jc42.
@@ -574,7 +575,7 @@ config SENSORS_LM85
        help
          If you say yes here you get support for National Semiconductor LM85
          sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
-         EMC6D101 and EMC6D102.
+         EMC6D101, EMC6D102, and EMC6D103.
 
          This driver can also be built as a module.  If so, the module
          will be called lm85.
index 86d822a..d46c0c7 100644 (file)
@@ -242,6 +242,7 @@ static const struct i2c_device_id ad7414_id[] = {
        { "ad7414", 0 },
        {}
 };
+MODULE_DEVICE_TABLE(i2c, ad7414_id);
 
 static struct i2c_driver ad7414_driver = {
        .driver = {
index f13c843..5cc3e37 100644 (file)
@@ -334,6 +334,7 @@ static const struct i2c_device_id adt7411_id[] = {
        { "adt7411", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, adt7411_id);
 
 static struct i2c_driver adt7411_driver = {
        .driver         = {
index ce0372f..4c07436 100644 (file)
@@ -1072,6 +1072,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
                        node->sda.dev_attr.show = grp->show;
                        node->sda.dev_attr.store = grp->store;
                        attr = &node->sda.dev_attr.attr;
+                       sysfs_attr_init(attr);
                        attr->name = node->name;
                        attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
                        ret = sysfs_create_file(&pdev->dev.kobj, attr);
index 2d68cf3..b5e8920 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acpixf.h>
 
 #define ATK_HID "ATK0110"
 
+static bool new_if;
+module_param(new_if, bool, 0);
+MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
+
+static const struct dmi_system_id __initconst atk_force_new_if[] = {
+       {
+               /* Old interface has broken MCH temp monitoring */
+               .ident = "Asus Sabertooth X58",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
+               }
+       },
+       { }
+};
+
 /* Minimum time between readings, enforced in order to avoid
  * hogging the CPU.
  */
@@ -1302,7 +1318,9 @@ static int atk_probe_if(struct atk_data *data)
         * analysis of multiple DSDTs indicates that when both interfaces
         * are present the new one (GGRP/GITM) is not functional.
         */
-       if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle)
+       if (new_if)
+               dev_info(dev, "Overriding interface detection\n");
+       if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if)
                data->old_interface = true;
        else if (data->enumerate_handle && data->read_handle &&
                        data->write_handle)
@@ -1420,6 +1438,9 @@ static int __init atk0110_init(void)
                return -EBUSY;
        }
 
+       if (dmi_check_system(atk_force_new_if))
+               new_if = true;
+
        ret = acpi_bus_register_driver(&atk_driver);
        if (ret)
                pr_info("acpi_bus_register_driver failed: %d\n", ret);
index 5dea9fa..cd2a6e4 100644 (file)
@@ -344,7 +344,7 @@ static int emc1403_remove(struct i2c_client *client)
 }
 
 static const unsigned short emc1403_address_list[] = {
-       0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END
+       0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END
 };
 
 static const struct i2c_device_id emc1403_idtable[] = {
index 340fc78..9349912 100644 (file)
@@ -53,6 +53,8 @@ static const unsigned short normal_i2c[] = {
 
 /* Configuration register defines */
 #define JC42_CFG_CRIT_ONLY     (1 << 2)
+#define JC42_CFG_TCRIT_LOCK    (1 << 6)
+#define JC42_CFG_EVENT_LOCK    (1 << 7)
 #define JC42_CFG_SHUTDOWN      (1 << 8)
 #define JC42_CFG_HYST_SHIFT    9
 #define JC42_CFG_HYST_MASK     0x03
@@ -332,7 +334,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct jc42_data *data = i2c_get_clientdata(client);
-       long val;
+       unsigned long val;
        int diff, hyst;
        int err;
        int ret = count;
@@ -380,14 +382,14 @@ static ssize_t show_alarm(struct device *dev,
 
 static DEVICE_ATTR(temp1_input, S_IRUGO,
                   show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_crit, S_IRUGO,
                   show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_min, S_IRUGO,
                   show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_max, S_IRUGO,
                   show_temp_max, set_temp_max);
 
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
                   show_temp_crit_hyst, set_temp_crit_hyst);
 static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
                   show_temp_max_hyst, NULL);
@@ -412,8 +414,31 @@ static struct attribute *jc42_attributes[] = {
        NULL
 };
 
+static mode_t jc42_attribute_mode(struct kobject *kobj,
+                                 struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct jc42_data *data = i2c_get_clientdata(client);
+       unsigned int config = data->config;
+       bool readonly;
+
+       if (attr == &dev_attr_temp1_crit.attr)
+               readonly = config & JC42_CFG_TCRIT_LOCK;
+       else if (attr == &dev_attr_temp1_min.attr ||
+                attr == &dev_attr_temp1_max.attr)
+               readonly = config & JC42_CFG_EVENT_LOCK;
+       else if (attr == &dev_attr_temp1_crit_hyst.attr)
+               readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
+       else
+               readonly = true;
+
+       return S_IRUGO | (readonly ? 0 : S_IWUSR);
+}
+
 static const struct attribute_group jc42_group = {
        .attrs = jc42_attributes,
+       .is_visible = jc42_attribute_mode,
 };
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
index da5a240..82bf65a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * k10temp.c - AMD Family 10h/11h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring
  *
  * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
  *
@@ -25,7 +25,7 @@
 #include <linux/pci.h>
 #include <asm/processor.h>
 
-MODULE_DESCRIPTION("AMD Family 10h/11h CPU core temperature monitor");
+MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL");
 
@@ -208,6 +208,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
 static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index 1b674b7..d805e8e 100644 (file)
@@ -957,7 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
        /* bail if we did not get an IRQ from the bus layer */
        if (!dev->irq) {
-               pr_err("No IRQ. Disabling /dev/freefall\n");
+               pr_debug("No IRQ. Disabling /dev/freefall\n");
                goto out;
        }
 
index 776aeb3..508cb29 100644 (file)
@@ -98,6 +98,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
  * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
  * For remote temperature, low and high limits, it uses signed 11-bit values
  * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
+ * For LM64 the actual remote diode temperature is 16 degree Celsius higher
+ * than the register reading. Remote temperature setpoints have to be
+ * adapted accordingly.
  */
 
 #define FAN_FROM_REG(reg)      ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
@@ -165,6 +168,8 @@ struct lm63_data {
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
+       int kind;
+       int temp2_offset;
 
        /* registers values */
        u8 config, config_fan;
@@ -247,16 +252,34 @@ static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dum
        return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
 }
 
-static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
-                         char *buf)
+/*
+ * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
+ * For remote sensor registers temp2_offset has to be considered,
+ * for local sensor it must not.
+ * So we need separate 8bit accessors for local and remote sensor.
+ */
+static ssize_t show_local_temp8(struct device *dev,
+                               struct device_attribute *devattr,
+                               char *buf)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
 }
 
-static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy,
-                        const char *buf, size_t count)
+static ssize_t show_remote_temp8(struct device *dev,
+                                struct device_attribute *devattr,
+                                char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])
+                      + data->temp2_offset);
+}
+
+static ssize_t set_local_temp8(struct device *dev,
+                              struct device_attribute *dummy,
+                              const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
@@ -274,7 +297,8 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]));
+       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])
+                      + data->temp2_offset);
 }
 
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
@@ -294,7 +318,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
        int nr = attr->index;
 
        mutex_lock(&data->update_lock);
-       data->temp11[nr] = TEMP11_TO_REG(val);
+       data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
                                  data->temp11[nr] >> 8);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
@@ -310,6 +334,7 @@ static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute
 {
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
+                      + data->temp2_offset
                       - TEMP8_FROM_REG(data->temp2_crit_hyst));
 }
 
@@ -324,7 +349,7 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *
        long hyst;
 
        mutex_lock(&data->update_lock);
-       hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
+       hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
        i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
                                  HYST_TO_REG(hyst));
        mutex_unlock(&data->update_lock);
@@ -355,16 +380,21 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
 static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
 static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
-       set_temp8, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
+       set_local_temp8, 1);
 
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 1);
 static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 2);
-static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
+/*
+ * On LM63, temp2_crit can be set only once, which should be job
+ * of the bootloader.
+ */
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
+       NULL, 2);
 static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
        set_temp2_crit_hyst);
 
@@ -479,7 +509,12 @@ static int lm63_probe(struct i2c_client *new_client,
        data->valid = 0;
        mutex_init(&data->update_lock);
 
-       /* Initialize the LM63 chip */
+       /* Set the device type */
+       data->kind = id->driver_data;
+       if (data->kind == lm64)
+               data->temp2_offset = 16000;
+
+       /* Initialize chip */
        lm63_init_client(new_client);
 
        /* Register sysfs hooks */
index 1e22984..d2cc286 100644 (file)
@@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 enum chips {
        any_chip, lm85b, lm85c,
        adm1027, adt7463, adt7468,
-       emc6d100, emc6d102
+       emc6d100, emc6d102, emc6d103
 };
 
 /* The LM85 registers */
@@ -90,6 +90,9 @@ enum chips {
 #define        LM85_VERSTEP_EMC6D100_A0        0x60
 #define        LM85_VERSTEP_EMC6D100_A1        0x61
 #define        LM85_VERSTEP_EMC6D102           0x65
+#define        LM85_VERSTEP_EMC6D103_A0        0x68
+#define        LM85_VERSTEP_EMC6D103_A1        0x69
+#define        LM85_VERSTEP_EMC6D103S          0x6A    /* Also known as EMC6D103:A2 */
 
 #define        LM85_REG_CONFIG                 0x40
 
@@ -348,6 +351,7 @@ static const struct i2c_device_id lm85_id[] = {
        { "emc6d100", emc6d100 },
        { "emc6d101", emc6d100 },
        { "emc6d102", emc6d102 },
+       { "emc6d103", emc6d103 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm85_id);
@@ -1250,6 +1254,20 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
                case LM85_VERSTEP_EMC6D102:
                        type_name = "emc6d102";
                        break;
+               case LM85_VERSTEP_EMC6D103_A0:
+               case LM85_VERSTEP_EMC6D103_A1:
+                       type_name = "emc6d103";
+                       break;
+               /*
+                * Registers apparently missing in EMC6D103S/EMC6D103:A2
+                * compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102
+                * (according to the data sheets), but used unconditionally
+                * in the driver: 62[5:7], 6D[0:7], and 6E[0:7].
+                * So skip EMC6D103S for now.
+               case LM85_VERSTEP_EMC6D103S:
+                       type_name = "emc6d103s";
+                       break;
+                */
                }
        } else {
                dev_dbg(&adapter->dev,
@@ -1283,6 +1301,7 @@ static int lm85_probe(struct i2c_client *client,
        case adt7468:
        case emc6d100:
        case emc6d102:
+       case emc6d103:
                data->freq_map = adm1027_freq_map;
                break;
        default:
@@ -1468,7 +1487,7 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                        /* More alarm bits */
                        data->alarms |= lm85_read_value(client,
                                                EMC6D100_REG_ALARM3) << 16;
-               } else if (data->type == emc6d102) {
+               } else if (data->type == emc6d102 || data->type == emc6d103) {
                        /* Have to read LSB bits after the MSB ones because
                           the reading of the MSB bits has frozen the
                           LSBs (backward from the ADM1027).
index b605ff3..829a2a1 100644 (file)
@@ -847,11 +847,15 @@ complete:
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
                }
+               /*
+                * ProDB0017052: Clear ARDY bit twice
+                */
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, stat &
                                (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
+                               OMAP_I2C_STAT_ARDY));
                        omap_i2c_complete_cmd(dev, err);
                        return IRQ_HANDLED;
                }
@@ -1137,12 +1141,41 @@ omap_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_SUSPEND
+static int omap_i2c_suspend(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+                       dev->bus->pm->runtime_suspend(dev);
+
+       return 0;
+}
+
+static int omap_i2c_resume(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+                       dev->bus->pm->runtime_resume(dev);
+
+       return 0;
+}
+
+static struct dev_pm_ops omap_i2c_pm_ops = {
+       .suspend = omap_i2c_suspend,
+       .resume = omap_i2c_resume,
+};
+#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
+#else
+#define OMAP_I2C_PM_OPS NULL
+#endif
+
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
        .remove         = omap_i2c_remove,
        .driver         = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
+               .pm     = OMAP_I2C_PM_OPS,
        },
 };
 
index 495be45..266135d 100644 (file)
@@ -942,7 +942,7 @@ stu300_probe(struct platform_device *pdev)
        adap->owner = THIS_MODULE;
        /* DDC class but actually often used for more generic I2C */
        adap->class = I2C_CLASS_DDC;
-       strncpy(adap->name, "ST Microelectronics DDC I2C adapter",
+       strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
                sizeof(adap->name));
        adap->nr = bus_nr;
        adap->algo = &stu300_algo;
index 98ccfeb..9827c5e 100644 (file)
@@ -134,7 +134,7 @@ config BLK_DEV_IDECD
          module will be called ide-cd.
 
 config BLK_DEV_IDECD_VERBOSE_ERRORS
-       bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED
+       bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT
        depends on BLK_DEV_IDECD
        default y
        help
index 7acb32e..4a5c4a4 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <asm/mwait.h>
+#include <asm/msr.h>
 
 #define INTEL_IDLE_VERSION "0.4"
 #define PREFIX "intel_idle: "
@@ -85,6 +86,12 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
 static struct cpuidle_state *cpuidle_state_table;
 
 /*
+ * Hardware C-state auto-demotion may not always be optimal.
+ * Indicate which enable bits to clear here.
+ */
+static unsigned long long auto_demotion_disable_flags;
+
+/*
  * Set this flag for states where the HW flushes the TLB for us
  * and so we don't need cross-calls to keep it consistent.
  * If this flag is set, SW flushes the TLB, so even if the
@@ -263,7 +270,7 @@ static void __setup_broadcast_timer(void *arg)
        clockevents_notify(reason, &cpu);
 }
 
-static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n,
+static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
                unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -273,18 +280,23 @@ static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n,
                smp_call_function_single(hotcpu, __setup_broadcast_timer,
                        (void *)true, 1);
                break;
-       case CPU_DOWN_PREPARE:
-               smp_call_function_single(hotcpu, __setup_broadcast_timer,
-                       (void *)false, 1);
-               break;
        }
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata setup_broadcast_notifier = {
+static struct notifier_block setup_broadcast_notifier = {
        .notifier_call = setup_broadcast_cpuhp_notify,
 };
 
+static void auto_demotion_disable(void *dummy)
+{
+       unsigned long long msr_bits;
+
+       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+       msr_bits &= ~auto_demotion_disable_flags;
+       wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+}
+
 /*
  * intel_idle_probe()
  */
@@ -328,11 +340,17 @@ static int intel_idle_probe(void)
        case 0x25:      /* Westmere */
        case 0x2C:      /* Westmere */
                cpuidle_state_table = nehalem_cstates;
+               auto_demotion_disable_flags =
+                       (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE);
                break;
 
        case 0x1C:      /* 28 - Atom Processor */
+               cpuidle_state_table = atom_cstates;
+               break;
+
        case 0x26:      /* 38 - Lincroft Atom Processor */
                cpuidle_state_table = atom_cstates;
+               auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE;
                break;
 
        case 0x2A:      /* SNB */
@@ -440,6 +458,8 @@ static int intel_idle_cpuidle_devices_init(void)
                        return -EIO;
                }
        }
+       if (auto_demotion_disable_flags)
+               smp_call_function(auto_demotion_disable, NULL, 1);
 
        return 0;
 }
index e38be1b..fbbfa24 100644 (file)
@@ -1079,7 +1079,7 @@ static void ib_sa_remove_one(struct ib_device *device)
 
        ib_unregister_event_handler(&sa_dev->event_handler);
 
-       flush_scheduled_work();
+       flush_workqueue(ib_wq);
 
        for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
                if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) {
index ca12acf..ec1e9da 100644 (file)
@@ -636,6 +636,16 @@ static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
        }
 }
 
+static void ucma_copy_iw_route(struct rdma_ucm_query_route_resp *resp,
+                              struct rdma_route *route)
+{
+       struct rdma_dev_addr *dev_addr;
+
+       dev_addr = &route->addr.dev_addr;
+       rdma_addr_get_dgid(dev_addr, (union ib_gid *) &resp->ib_route[0].dgid);
+       rdma_addr_get_sgid(dev_addr, (union ib_gid *) &resp->ib_route[0].sgid);
+}
+
 static ssize_t ucma_query_route(struct ucma_file *file,
                                const char __user *inbuf,
                                int in_len, int out_len)
@@ -670,8 +680,10 @@ static ssize_t ucma_query_route(struct ucma_file *file,
 
        resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
        resp.port_num = ctx->cm_id->port_num;
-       if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
-               switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
+       switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
+       case RDMA_TRANSPORT_IB:
+               switch (rdma_port_get_link_layer(ctx->cm_id->device,
+                       ctx->cm_id->port_num)) {
                case IB_LINK_LAYER_INFINIBAND:
                        ucma_copy_ib_route(&resp, &ctx->cm_id->route);
                        break;
@@ -681,6 +693,12 @@ static ssize_t ucma_query_route(struct ucma_file *file,
                default:
                        break;
                }
+               break;
+       case RDMA_TRANSPORT_IWARP:
+               ucma_copy_iw_route(&resp, &ctx->cm_id->route);
+               break;
+       default:
+               break;
        }
 
 out:
index 9ce7819..2ec716f 100644 (file)
@@ -107,7 +107,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
        r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
        if (r) {
                init_waitqueue_head(&r->wait_object);
-               r->reply_msg = (u64) NULL;
+               r->reply_msg = 0;
                r->event = 0;
                r->cm_id = NULL;
                r->qp = NULL;
@@ -123,7 +123,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
  */
 void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
 {
-       r->reply_msg = (u64) NULL;
+       r->reply_msg = 0;
        if (atomic_dec_and_test(&r->refcnt)) {
                kfree(r);
        }
@@ -151,7 +151,7 @@ void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
 void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
 {
        if (atomic_dec_and_test(&r->refcnt)) {
-               if (r->reply_msg != (u64) NULL)
+               if (r->reply_msg != 0)
                        vq_repbuf_free(c2dev,
                                       (void *) (unsigned long) r->reply_msg);
                kfree(r);
index 0dc62b1..8b00e6c 100644 (file)
@@ -380,7 +380,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
                                          16)) | FW_WR_FLOWID(ep->hwtid));
 
        flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
-       flowc->mnemval[0].val = cpu_to_be32(0);
+       flowc->mnemval[0].val = cpu_to_be32(PCI_FUNC(ep->com.dev->rdev.lldi.pdev->devfn) << 8);
        flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
        flowc->mnemval[1].val = cpu_to_be32(ep->tx_chan);
        flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT;
index 2080090..4f0be25 100644 (file)
@@ -220,7 +220,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_DCAEN(0) |
                V_FW_RI_RES_WR_DCACPU(0) |
                V_FW_RI_RES_WR_FBMIN(2) |
-               V_FW_RI_RES_WR_FBMAX(3) |
+               V_FW_RI_RES_WR_FBMAX(2) |
                V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
                V_FW_RI_RES_WR_CIDXFTHRESH(0) |
                V_FW_RI_RES_WR_EQSIZE(eqsize));
@@ -243,7 +243,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_DCAEN(0) |
                V_FW_RI_RES_WR_DCACPU(0) |
                V_FW_RI_RES_WR_FBMIN(2) |
-               V_FW_RI_RES_WR_FBMAX(3) |
+               V_FW_RI_RES_WR_FBMAX(2) |
                V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
                V_FW_RI_RES_WR_CIDXFTHRESH(0) |
                V_FW_RI_RES_WR_EQSIZE(eqsize));
index 03efc07..da314c3 100644 (file)
@@ -7,7 +7,7 @@ config INFINIBAND_MTHCA
          ("Tavor") and the MT25208 PCI Express HCA ("Arbel").
 
 config INFINIBAND_MTHCA_DEBUG
-       bool "Verbose debugging output" if EMBEDDED
+       bool "Verbose debugging output" if EXPERT
        depends on INFINIBAND_MTHCA
        default y
        ---help---
index 8b606fd..08c1948 100644 (file)
@@ -2610,9 +2610,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                        netif_carrier_on(nesvnic->netdev);
 
                                        spin_lock(&nesvnic->port_ibevent_lock);
-                                       if (nesdev->iw_status == 0) {
-                                               nesdev->iw_status = 1;
-                                               nes_port_ibevent(nesvnic);
+                                       if (nesvnic->of_device_registered) {
+                                               if (nesdev->iw_status == 0) {
+                                                       nesdev->iw_status = 1;
+                                                       nes_port_ibevent(nesvnic);
+                                               }
                                        }
                                        spin_unlock(&nesvnic->port_ibevent_lock);
                                }
@@ -2642,9 +2644,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                        netif_carrier_off(nesvnic->netdev);
 
                                        spin_lock(&nesvnic->port_ibevent_lock);
-                                       if (nesdev->iw_status == 1) {
-                                               nesdev->iw_status = 0;
-                                               nes_port_ibevent(nesvnic);
+                                       if (nesvnic->of_device_registered) {
+                                               if (nesdev->iw_status == 1) {
+                                                       nesdev->iw_status = 0;
+                                                       nes_port_ibevent(nesvnic);
+                                               }
                                        }
                                        spin_unlock(&nesvnic->port_ibevent_lock);
                                }
@@ -2703,9 +2707,11 @@ void nes_recheck_link_status(struct work_struct *work)
                                netif_carrier_on(nesvnic->netdev);
 
                                spin_lock(&nesvnic->port_ibevent_lock);
-                               if (nesdev->iw_status == 0) {
-                                       nesdev->iw_status = 1;
-                                       nes_port_ibevent(nesvnic);
+                               if (nesvnic->of_device_registered) {
+                                       if (nesdev->iw_status == 0) {
+                                               nesdev->iw_status = 1;
+                                               nes_port_ibevent(nesvnic);
+                                       }
                                }
                                spin_unlock(&nesvnic->port_ibevent_lock);
                        }
@@ -2723,9 +2729,11 @@ void nes_recheck_link_status(struct work_struct *work)
                                netif_carrier_off(nesvnic->netdev);
 
                                spin_lock(&nesvnic->port_ibevent_lock);
-                               if (nesdev->iw_status == 1) {
-                                       nesdev->iw_status = 0;
-                                       nes_port_ibevent(nesvnic);
+                               if (nesvnic->of_device_registered) {
+                                       if (nesdev->iw_status == 1) {
+                                               nesdev->iw_status = 0;
+                                               nes_port_ibevent(nesvnic);
+                                       }
                                }
                                spin_unlock(&nesvnic->port_ibevent_lock);
                        }
index 50cceb3..b01809a 100644 (file)
@@ -623,7 +623,6 @@ struct qib_chippport_specific {
        u8 ibmalfusesnap;
        struct qib_qsfp_data qsfp_data;
        char epmsgbuf[192]; /* for port error interrupt msg buffer */
-       u8 bounced;
 };
 
 static struct {
@@ -1881,23 +1880,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                    IB_PHYSPORTSTATE_DISABLED)
                        qib_set_ib_7322_lstate(ppd, 0,
                               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
-               else {
-                       u32 lstate;
-                       /*
-                        * We need the current logical link state before
-                        * lflags are set in handle_e_ibstatuschanged.
-                        */
-                       lstate = qib_7322_iblink_state(ibcs);
-
-                       if (IS_QMH(dd) && !ppd->cpspec->bounced &&
-                           ltstate == IB_PHYSPORTSTATE_LINKUP &&
-                           (lstate >= IB_PORT_INIT &&
-                               lstate <= IB_PORT_ACTIVE)) {
-                               ppd->cpspec->bounced = 1;
-                               qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
-                                       IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL);
-                       }
-
+               else
                        /*
                         * Since going into a recovery state causes the link
                         * state to go down and since recovery is transitory,
@@ -1911,7 +1894,6 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
                                qib_handle_e_ibstatuschanged(ppd, ibcs);
-               }
        }
        if (*msg && iserr)
                qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
@@ -2381,6 +2363,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
        qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl);
        spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
 
+       /* Hold the link state machine for mezz boards */
+       if (IS_QMH(dd) || IS_QME(dd))
+               qib_set_ib_7322_lstate(ppd, 0,
+                                      QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+
        /* Also enable IBSTATUSCHG interrupt.  */
        val = qib_read_kreg_port(ppd, krp_errmask);
        qib_write_kreg_port(ppd, krp_errmask,
@@ -5702,6 +5689,11 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
                                ppd->cpspec->h1_val = h1;
                        /* now change the IBC and serdes, overriding generic */
                        init_txdds_table(ppd, 1);
+                       /* Re-enable the physical state machine on mezz boards
+                        * now that the correct settings have been set. */
+                       if (IS_QMH(dd) || IS_QME(dd))
+                               qib_set_ib_7322_lstate(ppd, 0,
+                                           QLOGIC_IB_IBCC_LINKINITCMD_SLEEP);
                        any++;
                }
                if (*nxt == '\n')
index 8245237..eca0c41 100644 (file)
@@ -1005,7 +1005,8 @@ void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr)
         * there are still requests that haven't been acked.
         */
        if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail &&
-           !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)))
+           !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)) &&
+           (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
                start_timer(qp);
 
        while (qp->s_last != qp->s_acked) {
@@ -1439,6 +1440,8 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp,
        }
 
        spin_lock_irqsave(&qp->s_lock, flags);
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto ack_done;
 
        /* Ignore invalid responses. */
        if (qib_cmp24(psn, qp->s_next_psn) >= 0)
index 55855ee..cda8eac 100644 (file)
@@ -24,7 +24,7 @@ config INFINIBAND_IPOIB_CM
          unless you limit mtu for these destinations to 2044.
 
 config INFINIBAND_IPOIB_DEBUG
-       bool "IP-over-InfiniBand debugging" if EMBEDDED
+       bool "IP-over-InfiniBand debugging" if EXPERT
        depends on INFINIBAND_IPOIB
        default y
        ---help---
index 07c2cd4..1903c0f 100644 (file)
@@ -6,7 +6,7 @@ menu "Input device support"
        depends on !S390
 
 config INPUT
-       tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
+       tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
        default y
        help
          Say Y here if you have any input device (mouse, keyboard, tablet,
@@ -67,7 +67,7 @@ config INPUT_SPARSEKMAP
 comment "Userland interfaces"
 
 config INPUT_MOUSEDEV
-       tristate "Mouse interface" if EMBEDDED
+       tristate "Mouse interface" if EXPERT
        default y
        help
          Say Y here if you want your mouse to be accessible as char devices
@@ -150,7 +150,7 @@ config INPUT_EVBUG
          module will be called evbug.
 
 config INPUT_APMPOWER
-       tristate "Input Power Event -> APM Bridge" if EMBEDDED
+       tristate "Input Power Event -> APM Bridge" if EXPERT
        depends on INPUT && APM_EMULATION
        help
          Say Y here if you want suspend key events to trigger a user
index 23cf8fc..5b8f59d 100644 (file)
@@ -360,7 +360,7 @@ static int gameport_queue_event(void *object, struct module *owner,
        event->owner = owner;
 
        list_add_tail(&event->node, &gameport_event_list);
-       schedule_work(&gameport_event_work);
+       queue_work(system_long_wq, &gameport_event_work);
 
 out:
        spin_unlock_irqrestore(&gameport_event_lock, flags);
index 7985114..11905b6 100644 (file)
@@ -75,7 +75,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
-                            struct input_handler *src_handler,
                             unsigned int type, unsigned int code, int value)
 {
        struct input_handler *handler;
@@ -94,15 +93,6 @@ static void input_pass_event(struct input_dev *dev,
                                continue;
 
                        handler = handle->handler;
-
-                       /*
-                        * If this is the handler that injected this
-                        * particular event we want to skip it to avoid
-                        * filters firing again and again.
-                        */
-                       if (handler == src_handler)
-                               continue;
-
                        if (!handler->filter) {
                                if (filtered)
                                        break;
@@ -132,7 +122,7 @@ static void input_repeat_key(unsigned long data)
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
 
-               input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
+               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
 
                if (dev->sync) {
                        /*
@@ -141,7 +131,7 @@ static void input_repeat_key(unsigned long data)
                         * Otherwise assume that the driver will send
                         * SYN_REPORT once it's done.
                         */
-                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
                }
 
                if (dev->rep[REP_PERIOD])
@@ -174,7 +164,6 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
-                                 struct input_handler *src_handler,
                                  unsigned int code, int *pval)
 {
        bool is_mt_event;
@@ -218,15 +207,13 @@ static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, src_handler,
-                                EV_ABS, ABS_MT_SLOT, dev->slot);
+               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
 static void input_handle_event(struct input_dev *dev,
-                              struct input_handler *src_handler,
                               unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
@@ -279,8 +266,7 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_ABS:
                if (is_event_supported(code, dev->absbit, ABS_MAX))
-                       disposition = input_handle_abs_event(dev, src_handler,
-                                                            code, &value);
+                       disposition = input_handle_abs_event(dev, code, &value);
 
                break;
 
@@ -338,7 +324,7 @@ static void input_handle_event(struct input_dev *dev,
                dev->event(dev, type, code, value);
 
        if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, src_handler, type, code, value);
+               input_pass_event(dev, type, code, value);
 }
 
 /**
@@ -367,7 +353,7 @@ void input_event(struct input_dev *dev,
 
                spin_lock_irqsave(&dev->event_lock, flags);
                add_input_randomness(type, code, value);
-               input_handle_event(dev, NULL, type, code, value);
+               input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
@@ -397,8 +383,7 @@ void input_inject_event(struct input_handle *handle,
                rcu_read_lock();
                grab = rcu_dereference(dev->grab);
                if (!grab || grab == handle)
-                       input_handle_event(dev, handle->handler,
-                                          type, code, value);
+                       input_handle_event(dev, type, code, value);
                rcu_read_unlock();
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -611,10 +596,10 @@ static void input_dev_release_keys(struct input_dev *dev)
                for (code = 0; code <= KEY_MAX; code++) {
                        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
                            __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, NULL, EV_KEY, code, 0);
+                               input_pass_event(dev, EV_KEY, code, 0);
                        }
                }
-               input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
        }
 }
 
@@ -889,9 +874,9 @@ int input_set_keycode(struct input_dev *dev,
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
 
-               input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
+               input_pass_event(dev, EV_KEY, old_keycode, 0);
                if (dev->sync)
-                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
        }
 
  out:
index 7b3c0b8..c7a9202 100644 (file)
@@ -2,7 +2,7 @@
 # Input core configuration
 #
 menuconfig INPUT_KEYBOARD
-       bool "Keyboards" if EMBEDDED || !X86
+       bool "Keyboards" if EXPERT || !X86
        default y
        help
          Say Y here, and a list of supported keyboards will be displayed.
@@ -57,7 +57,7 @@ config KEYBOARD_ATARI
          module will be called atakbd.
 
 config KEYBOARD_ATKBD
-       tristate "AT keyboard" if EMBEDDED || !X86
+       tristate "AT keyboard" if EXPERT || !X86
        default y
        select SERIO
        select SERIO_LIBPS2
@@ -343,6 +343,16 @@ config KEYBOARD_NOMADIK
          To compile this driver as a module, choose M here: the
          module will be called nmk-ske-keypad.
 
+config KEYBOARD_TEGRA
+       tristate "NVIDIA Tegra internal matrix keyboard controller support"
+       depends on ARCH_TEGRA
+       help
+         Say Y here if you want to use a matrix keyboard connected directly
+         to the internal keyboard controller on Tegra SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tegra-kbc.
+
 config KEYBOARD_OPENCORES
        tristate "OpenCores Keyboard Controller"
        help
index 4e5571b..468c627 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_KEYBOARD_STMPE)          += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TC3589X)         += tc3589x-keypad.o
+obj-$(CONFIG_KEYBOARD_TEGRA)           += tegra-kbc.o
 obj-$(CONFIG_KEYBOARD_TNETV107X)       += tnetv107x-keypad.o
 obj-$(CONFIG_KEYBOARD_TWL4030)         += twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
index 6069abe..eb30063 100644 (file)
@@ -322,7 +322,7 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
        struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
-       int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
+       int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
 
        input_event(input, type, button->code, !!state);
        input_sync(input);
@@ -410,8 +410,8 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
        if (!button->can_disable)
                irqflags |= IRQF_SHARED;
 
-       error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
-       if (error) {
+       error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
+       if (error < 0) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        irq, error);
                goto fail3;
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
new file mode 100644 (file)
index 0000000..99ce903
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix
+ * keyboard controller
+ *
+ * Copyright (c) 2009-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/kbc.h>
+
+#define KBC_MAX_DEBOUNCE_CNT   0x3ffu
+
+/* KBC row scan time and delay for beginning the row scan. */
+#define KBC_ROW_SCAN_TIME      16
+#define KBC_ROW_SCAN_DLY       5
+
+/* KBC uses a 32KHz clock so a cycle = 1/32Khz */
+#define KBC_CYCLE_USEC 32
+
+/* KBC Registers */
+
+/* KBC Control Register */
+#define KBC_CONTROL_0  0x0
+#define KBC_FIFO_TH_CNT_SHIFT(cnt)     (cnt << 14)
+#define KBC_DEBOUNCE_CNT_SHIFT(cnt)    (cnt << 4)
+#define KBC_CONTROL_FIFO_CNT_INT_EN    (1 << 3)
+#define KBC_CONTROL_KBC_EN             (1 << 0)
+
+/* KBC Interrupt Register */
+#define KBC_INT_0      0x4
+#define KBC_INT_FIFO_CNT_INT_STATUS    (1 << 2)
+
+#define KBC_ROW_CFG0_0 0x8
+#define KBC_COL_CFG0_0 0x18
+#define KBC_INIT_DLY_0 0x28
+#define KBC_RPT_DLY_0  0x2c
+#define KBC_KP_ENT0_0  0x30
+#define KBC_KP_ENT1_0  0x34
+#define KBC_ROW0_MASK_0        0x38
+
+#define KBC_ROW_SHIFT  3
+
+struct tegra_kbc {
+       void __iomem *mmio;
+       struct input_dev *idev;
+       unsigned int irq;
+       unsigned int wake_enable_rows;
+       unsigned int wake_enable_cols;
+       spinlock_t lock;
+       unsigned int repoll_dly;
+       unsigned long cp_dly_jiffies;
+       bool use_fn_map;
+       const struct tegra_kbc_platform_data *pdata;
+       unsigned short keycode[KBC_MAX_KEY * 2];
+       unsigned short current_keys[KBC_MAX_KPENT];
+       unsigned int num_pressed_keys;
+       struct timer_list timer;
+       struct clk *clk;
+};
+
+static const u32 tegra_kbc_default_keymap[] = {
+       KEY(0, 2, KEY_W),
+       KEY(0, 3, KEY_S),
+       KEY(0, 4, KEY_A),
+       KEY(0, 5, KEY_Z),
+       KEY(0, 7, KEY_FN),
+
+       KEY(1, 7, KEY_LEFTMETA),
+
+       KEY(2, 6, KEY_RIGHTALT),
+       KEY(2, 7, KEY_LEFTALT),
+
+       KEY(3, 0, KEY_5),
+       KEY(3, 1, KEY_4),
+       KEY(3, 2, KEY_R),
+       KEY(3, 3, KEY_E),
+       KEY(3, 4, KEY_F),
+       KEY(3, 5, KEY_D),
+       KEY(3, 6, KEY_X),
+
+       KEY(4, 0, KEY_7),
+       KEY(4, 1, KEY_6),
+       KEY(4, 2, KEY_T),
+       KEY(4, 3, KEY_H),
+       KEY(4, 4, KEY_G),
+       KEY(4, 5, KEY_V),
+       KEY(4, 6, KEY_C),
+       KEY(4, 7, KEY_SPACE),
+
+       KEY(5, 0, KEY_9),
+       KEY(5, 1, KEY_8),
+       KEY(5, 2, KEY_U),
+       KEY(5, 3, KEY_Y),
+       KEY(5, 4, KEY_J),
+       KEY(5, 5, KEY_N),
+       KEY(5, 6, KEY_B),
+       KEY(5, 7, KEY_BACKSLASH),
+
+       KEY(6, 0, KEY_MINUS),
+       KEY(6, 1, KEY_0),
+       KEY(6, 2, KEY_O),
+       KEY(6, 3, KEY_I),
+       KEY(6, 4, KEY_L),
+       KEY(6, 5, KEY_K),
+       KEY(6, 6, KEY_COMMA),
+       KEY(6, 7, KEY_M),
+
+       KEY(7, 1, KEY_EQUAL),
+       KEY(7, 2, KEY_RIGHTBRACE),
+       KEY(7, 3, KEY_ENTER),
+       KEY(7, 7, KEY_MENU),
+
+       KEY(8, 4, KEY_RIGHTSHIFT),
+       KEY(8, 5, KEY_LEFTSHIFT),
+
+       KEY(9, 5, KEY_RIGHTCTRL),
+       KEY(9, 7, KEY_LEFTCTRL),
+
+       KEY(11, 0, KEY_LEFTBRACE),
+       KEY(11, 1, KEY_P),
+       KEY(11, 2, KEY_APOSTROPHE),
+       KEY(11, 3, KEY_SEMICOLON),
+       KEY(11, 4, KEY_SLASH),
+       KEY(11, 5, KEY_DOT),
+
+       KEY(12, 0, KEY_F10),
+       KEY(12, 1, KEY_F9),
+       KEY(12, 2, KEY_BACKSPACE),
+       KEY(12, 3, KEY_3),
+       KEY(12, 4, KEY_2),
+       KEY(12, 5, KEY_UP),
+       KEY(12, 6, KEY_PRINT),
+       KEY(12, 7, KEY_PAUSE),
+
+       KEY(13, 0, KEY_INSERT),
+       KEY(13, 1, KEY_DELETE),
+       KEY(13, 3, KEY_PAGEUP),
+       KEY(13, 4, KEY_PAGEDOWN),
+       KEY(13, 5, KEY_RIGHT),
+       KEY(13, 6, KEY_DOWN),
+       KEY(13, 7, KEY_LEFT),
+
+       KEY(14, 0, KEY_F11),
+       KEY(14, 1, KEY_F12),
+       KEY(14, 2, KEY_F8),
+       KEY(14, 3, KEY_Q),
+       KEY(14, 4, KEY_F4),
+       KEY(14, 5, KEY_F3),
+       KEY(14, 6, KEY_1),
+       KEY(14, 7, KEY_F7),
+
+       KEY(15, 0, KEY_ESC),
+       KEY(15, 1, KEY_GRAVE),
+       KEY(15, 2, KEY_F5),
+       KEY(15, 3, KEY_TAB),
+       KEY(15, 4, KEY_F1),
+       KEY(15, 5, KEY_F2),
+       KEY(15, 6, KEY_CAPSLOCK),
+       KEY(15, 7, KEY_F6),
+
+       /* Software Handled Function Keys */
+       KEY(20, 0, KEY_KP7),
+
+       KEY(21, 0, KEY_KP9),
+       KEY(21, 1, KEY_KP8),
+       KEY(21, 2, KEY_KP4),
+       KEY(21, 4, KEY_KP1),
+
+       KEY(22, 1, KEY_KPSLASH),
+       KEY(22, 2, KEY_KP6),
+       KEY(22, 3, KEY_KP5),
+       KEY(22, 4, KEY_KP3),
+       KEY(22, 5, KEY_KP2),
+       KEY(22, 7, KEY_KP0),
+
+       KEY(27, 1, KEY_KPASTERISK),
+       KEY(27, 3, KEY_KPMINUS),
+       KEY(27, 4, KEY_KPPLUS),
+       KEY(27, 5, KEY_KPDOT),
+
+       KEY(28, 5, KEY_VOLUMEUP),
+
+       KEY(29, 3, KEY_HOME),
+       KEY(29, 4, KEY_END),
+       KEY(29, 5, KEY_BRIGHTNESSDOWN),
+       KEY(29, 6, KEY_VOLUMEDOWN),
+       KEY(29, 7, KEY_BRIGHTNESSUP),
+
+       KEY(30, 0, KEY_NUMLOCK),
+       KEY(30, 1, KEY_SCROLLLOCK),
+       KEY(30, 2, KEY_MUTE),
+
+       KEY(31, 4, KEY_HELP),
+};
+
+static const struct matrix_keymap_data tegra_kbc_default_keymap_data = {
+       .keymap         = tegra_kbc_default_keymap,
+       .keymap_size    = ARRAY_SIZE(tegra_kbc_default_keymap),
+};
+
+static void tegra_kbc_report_released_keys(struct input_dev *input,
+                                          unsigned short old_keycodes[],
+                                          unsigned int old_num_keys,
+                                          unsigned short new_keycodes[],
+                                          unsigned int new_num_keys)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < old_num_keys; i++) {
+               for (j = 0; j < new_num_keys; j++)
+                       if (old_keycodes[i] == new_keycodes[j])
+                               break;
+
+               if (j == new_num_keys)
+                       input_report_key(input, old_keycodes[i], 0);
+       }
+}
+
+static void tegra_kbc_report_pressed_keys(struct input_dev *input,
+                                         unsigned char scancodes[],
+                                         unsigned short keycodes[],
+                                         unsigned int num_pressed_keys)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_pressed_keys; i++) {
+               input_event(input, EV_MSC, MSC_SCAN, scancodes[i]);
+               input_report_key(input, keycodes[i], 1);
+       }
+}
+
+static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
+{
+       unsigned char scancodes[KBC_MAX_KPENT];
+       unsigned short keycodes[KBC_MAX_KPENT];
+       u32 val = 0;
+       unsigned int i;
+       unsigned int num_down = 0;
+       unsigned long flags;
+       bool fn_keypress = false;
+
+       spin_lock_irqsave(&kbc->lock, flags);
+       for (i = 0; i < KBC_MAX_KPENT; i++) {
+               if ((i % 4) == 0)
+                       val = readl(kbc->mmio + KBC_KP_ENT0_0 + i);
+
+               if (val & 0x80) {
+                       unsigned int col = val & 0x07;
+                       unsigned int row = (val >> 3) & 0x0f;
+                       unsigned char scancode =
+                               MATRIX_SCAN_CODE(row, col, KBC_ROW_SHIFT);
+
+                       scancodes[num_down] = scancode;
+                       keycodes[num_down] = kbc->keycode[scancode];
+                       /* If driver uses Fn map, do not report the Fn key. */
+                       if ((keycodes[num_down] == KEY_FN) && kbc->use_fn_map)
+                               fn_keypress = true;
+                       else
+                               num_down++;
+               }
+
+               val >>= 8;
+       }
+
+       /*
+        * If the platform uses Fn keymaps, translate keys on a Fn keypress.
+        * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
+        */
+       if (fn_keypress) {
+               for (i = 0; i < num_down; i++) {
+                       scancodes[i] += KBC_MAX_KEY;
+                       keycodes[i] = kbc->keycode[scancodes[i]];
+               }
+       }
+
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       tegra_kbc_report_released_keys(kbc->idev,
+                                      kbc->current_keys, kbc->num_pressed_keys,
+                                      keycodes, num_down);
+       tegra_kbc_report_pressed_keys(kbc->idev, scancodes, keycodes, num_down);
+       input_sync(kbc->idev);
+
+       memcpy(kbc->current_keys, keycodes, sizeof(kbc->current_keys));
+       kbc->num_pressed_keys = num_down;
+}
+
+static void tegra_kbc_keypress_timer(unsigned long data)
+{
+       struct tegra_kbc *kbc = (struct tegra_kbc *)data;
+       unsigned long flags;
+       u32 val;
+       unsigned int i;
+
+       val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
+       if (val) {
+               unsigned long dly;
+
+               tegra_kbc_report_keys(kbc);
+
+               /*
+                * If more than one keys are pressed we need not wait
+                * for the repoll delay.
+                */
+               dly = (val == 1) ? kbc->repoll_dly : 1;
+               mod_timer(&kbc->timer, jiffies + msecs_to_jiffies(dly));
+       } else {
+               /* Release any pressed keys and exit the polling loop */
+               for (i = 0; i < kbc->num_pressed_keys; i++)
+                       input_report_key(kbc->idev, kbc->current_keys[i], 0);
+               input_sync(kbc->idev);
+
+               kbc->num_pressed_keys = 0;
+
+               /* All keys are released so enable the keypress interrupt */
+               spin_lock_irqsave(&kbc->lock, flags);
+               val = readl(kbc->mmio + KBC_CONTROL_0);
+               val |= KBC_CONTROL_FIFO_CNT_INT_EN;
+               writel(val, kbc->mmio + KBC_CONTROL_0);
+               spin_unlock_irqrestore(&kbc->lock, flags);
+       }
+}
+
+static irqreturn_t tegra_kbc_isr(int irq, void *args)
+{
+       struct tegra_kbc *kbc = args;
+       u32 val, ctl;
+
+       /*
+        * Until all keys are released, defer further processing to
+        * the polling loop in tegra_kbc_keypress_timer
+        */
+       ctl = readl(kbc->mmio + KBC_CONTROL_0);
+       ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
+       writel(ctl, kbc->mmio + KBC_CONTROL_0);
+
+       /*
+        * Quickly bail out & reenable interrupts if the fifo threshold
+        * count interrupt wasn't the interrupt source
+        */
+       val = readl(kbc->mmio + KBC_INT_0);
+       writel(val, kbc->mmio + KBC_INT_0);
+
+       if (val & KBC_INT_FIFO_CNT_INT_STATUS) {
+               /*
+                * Schedule timer to run when hardware is in continuous
+                * polling mode.
+                */
+               mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
+       } else {
+               ctl |= KBC_CONTROL_FIFO_CNT_INT_EN;
+               writel(ctl, kbc->mmio + KBC_CONTROL_0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       int i;
+       unsigned int rst_val;
+
+       BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
+       rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+
+       for (i = 0; i < KBC_MAX_ROW; i++)
+               writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
+
+       if (filter) {
+               for (i = 0; i < pdata->wake_cnt; i++) {
+                       u32 val, addr;
+                       addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
+                       val = readl(kbc->mmio + addr);
+                       val &= ~(1 << pdata->wake_cfg[i].col);
+                       writel(val, kbc->mmio + addr);
+               }
+       }
+}
+
+static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       int i;
+
+       for (i = 0; i < KBC_MAX_GPIO; i++) {
+               u32 r_shft = 5 * (i % 6);
+               u32 c_shft = 4 * (i % 8);
+               u32 r_mask = 0x1f << r_shft;
+               u32 c_mask = 0x0f << c_shft;
+               u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0;
+               u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0;
+               u32 row_cfg = readl(kbc->mmio + r_offs);
+               u32 col_cfg = readl(kbc->mmio + c_offs);
+
+               row_cfg &= ~r_mask;
+               col_cfg &= ~c_mask;
+
+               if (pdata->pin_cfg[i].is_row)
+                       row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
+               else
+                       col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+
+               writel(row_cfg, kbc->mmio + r_offs);
+               writel(col_cfg, kbc->mmio + c_offs);
+       }
+}
+
+static int tegra_kbc_start(struct tegra_kbc *kbc)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       unsigned long flags;
+       unsigned int debounce_cnt;
+       u32 val = 0;
+
+       clk_enable(kbc->clk);
+
+       /* Reset the KBC controller to clear all previous status.*/
+       tegra_periph_reset_assert(kbc->clk);
+       udelay(100);
+       tegra_periph_reset_deassert(kbc->clk);
+       udelay(100);
+
+       tegra_kbc_config_pins(kbc);
+       tegra_kbc_setup_wakekeys(kbc, false);
+
+       writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
+
+       /* Keyboard debounce count is maximum of 12 bits. */
+       debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+       val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
+       val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
+       val |= KBC_CONTROL_FIFO_CNT_INT_EN;  /* interrupt on FIFO threshold */
+       val |= KBC_CONTROL_KBC_EN;     /* enable */
+       writel(val, kbc->mmio + KBC_CONTROL_0);
+
+       /*
+        * Compute the delay(ns) from interrupt mode to continuous polling
+        * mode so the timer routine is scheduled appropriately.
+        */
+       val = readl(kbc->mmio + KBC_INIT_DLY_0);
+       kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32);
+
+       kbc->num_pressed_keys = 0;
+
+       /*
+        * Atomically clear out any remaining entries in the key FIFO
+        * and enable keyboard interrupts.
+        */
+       spin_lock_irqsave(&kbc->lock, flags);
+       while (1) {
+               val = readl(kbc->mmio + KBC_INT_0);
+               val >>= 4;
+               if (!val)
+                       break;
+
+               val = readl(kbc->mmio + KBC_KP_ENT0_0);
+               val = readl(kbc->mmio + KBC_KP_ENT1_0);
+       }
+       writel(0x7, kbc->mmio + KBC_INT_0);
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       enable_irq(kbc->irq);
+
+       return 0;
+}
+
+static void tegra_kbc_stop(struct tegra_kbc *kbc)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&kbc->lock, flags);
+       val = readl(kbc->mmio + KBC_CONTROL_0);
+       val &= ~1;
+       writel(val, kbc->mmio + KBC_CONTROL_0);
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       disable_irq(kbc->irq);
+       del_timer_sync(&kbc->timer);
+
+       clk_disable(kbc->clk);
+}
+
+static int tegra_kbc_open(struct input_dev *dev)
+{
+       struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+       return tegra_kbc_start(kbc);
+}
+
+static void tegra_kbc_close(struct input_dev *dev)
+{
+       struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+       return tegra_kbc_stop(kbc);
+}
+
+static bool __devinit
+tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
+                       struct device *dev, unsigned int *num_rows)
+{
+       int i;
+
+       *num_rows = 0;
+
+       for (i = 0; i < KBC_MAX_GPIO; i++) {
+               const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
+
+               if (pin_cfg->is_row) {
+                       if (pin_cfg->num >= KBC_MAX_ROW) {
+                               dev_err(dev,
+                                       "pin_cfg[%d]: invalid row number %d\n",
+                                       i, pin_cfg->num);
+                               return false;
+                       }
+                       (*num_rows)++;
+               } else {
+                       if (pin_cfg->num >= KBC_MAX_COL) {
+                               dev_err(dev,
+                                       "pin_cfg[%d]: invalid column number %d\n",
+                                       i, pin_cfg->num);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+static int __devinit tegra_kbc_probe(struct platform_device *pdev)
+{
+       const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
+       const struct matrix_keymap_data *keymap_data;
+       struct tegra_kbc *kbc;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int err;
+       int i;
+       int num_rows = 0;
+       unsigned int debounce_cnt;
+       unsigned int scan_time_rows;
+
+       if (!pdata)
+               return -EINVAL;
+
+       if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               return -ENXIO;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
+               return -ENXIO;
+       }
+
+       kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kbc || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kbc->pdata = pdata;
+       kbc->idev = input_dev;
+       kbc->irq = irq;
+       spin_lock_init(&kbc->lock);
+       setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               err = -EBUSY;
+               goto err_free_mem;
+       }
+
+       kbc->mmio = ioremap(res->start, resource_size(res));
+       if (!kbc->mmio) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               err = -ENXIO;
+               goto err_free_mem_region;
+       }
+
+       kbc->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(kbc->clk)) {
+               dev_err(&pdev->dev, "failed to get keyboard clock\n");
+               err = PTR_ERR(kbc->clk);
+               goto err_iounmap;
+       }
+
+       kbc->wake_enable_rows = 0;
+       kbc->wake_enable_cols = 0;
+       for (i = 0; i < pdata->wake_cnt; i++) {
+               kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
+               kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
+       }
+
+       /*
+        * The time delay between two consecutive reads of the FIFO is
+        * the sum of the repeat time and the time taken for scanning
+        * the rows. There is an additional delay before the row scanning
+        * starts. The repoll delay is computed in milliseconds.
+        */
+       debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+       scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
+       kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
+       kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000;
+
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = tegra_kbc_open;
+       input_dev->close = tegra_kbc_close;
+
+       input_set_drvdata(input_dev, kbc);
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       input_dev->keycode = kbc->keycode;
+       input_dev->keycodesize = sizeof(kbc->keycode[0]);
+       input_dev->keycodemax = KBC_MAX_KEY;
+       if (pdata->use_fn_map)
+               input_dev->keycodemax *= 2;
+
+       kbc->use_fn_map = pdata->use_fn_map;
+       keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
+       matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
+                                  input_dev->keycode, input_dev->keybit);
+
+       err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH,
+                         pdev->name, kbc);
+       if (err) {
+               dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
+               goto err_put_clk;
+       }
+
+       disable_irq(kbc->irq);
+
+       err = input_register_device(kbc->idev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, kbc);
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+       return 0;
+
+err_free_irq:
+       free_irq(kbc->irq, pdev);
+err_put_clk:
+       clk_put(kbc->clk);
+err_iounmap:
+       iounmap(kbc->mmio);
+err_free_mem_region:
+       release_mem_region(res->start, resource_size(res));
+err_free_mem:
+       input_free_device(kbc->idev);
+       kfree(kbc);
+
+       return err;
+}
+
+static int __devexit tegra_kbc_remove(struct platform_device *pdev)
+{
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       free_irq(kbc->irq, pdev);
+       clk_put(kbc->clk);
+
+       input_unregister_device(kbc->idev);
+       iounmap(kbc->mmio);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(kbc);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_kbc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev)) {
+               tegra_kbc_setup_wakekeys(kbc, true);
+               enable_irq_wake(kbc->irq);
+               /* Forcefully clear the interrupt status */
+               writel(0x7, kbc->mmio + KBC_INT_0);
+               msleep(30);
+       } else {
+               mutex_lock(&kbc->idev->mutex);
+               if (kbc->idev->users)
+                       tegra_kbc_stop(kbc);
+               mutex_unlock(&kbc->idev->mutex);
+       }
+
+       return 0;
+}
+
+static int tegra_kbc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+       int err = 0;
+
+       if (device_may_wakeup(&pdev->dev)) {
+               disable_irq_wake(kbc->irq);
+               tegra_kbc_setup_wakekeys(kbc, false);
+       } else {
+               mutex_lock(&kbc->idev->mutex);
+               if (kbc->idev->users)
+                       err = tegra_kbc_start(kbc);
+               mutex_unlock(&kbc->idev->mutex);
+       }
+
+       return err;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);
+
+static struct platform_driver tegra_kbc_driver = {
+       .probe          = tegra_kbc_probe,
+       .remove         = __devexit_p(tegra_kbc_remove),
+       .driver = {
+               .name   = "tegra-kbc",
+               .owner  = THIS_MODULE,
+               .pm     = &tegra_kbc_pm_ops,
+       },
+};
+
+static void __exit tegra_kbc_exit(void)
+{
+       platform_driver_unregister(&tegra_kbc_driver);
+}
+module_exit(tegra_kbc_exit);
+
+static int __init tegra_kbc_init(void)
+{
+       return platform_driver_register(&tegra_kbc_driver);
+}
+module_init(tegra_kbc_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>");
+MODULE_DESCRIPTION("Tegra matrix keyboard controller driver");
+MODULE_ALIAS("platform:tegra-kbc");
index b4a81eb..c8f097a 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -219,9 +220,9 @@ static int __devinit keypad_probe(struct platform_device *pdev)
        }
 
        kp->clk = clk_get(dev, NULL);
-       if (!kp->clk) {
+       if (IS_ERR(kp->clk)) {
                dev_err(dev, "cannot claim device clock\n");
-               error = -EINVAL;
+               error = PTR_ERR(kp->clk);
                goto error_clk;
        }
 
index 9dfd6e5..1f38302 100644 (file)
@@ -69,11 +69,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned
        }
 
        if (value > 20 && value < 32767)
-#ifndef FREQ
-               count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1;
-#else
-               count = (FREQ / (value * 4)) - 1;
-#endif
+               count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1;
 
        ixp4xx_spkr_control(pin, count);
 
index 1f8e010..7e64d01 100644 (file)
@@ -176,7 +176,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
 
        /* request the IRQs */
        err = request_irq(encoder->irq_a, &rotary_encoder_irq,
-                         IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
                dev_err(&pdev->dev, "unable to request IRQ %d\n",
@@ -185,7 +185,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
        }
 
        err = request_irq(encoder->irq_b, &rotary_encoder_irq,
-                         IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
                dev_err(&pdev->dev, "unable to request IRQ %d\n",
index bf5fd7f..9c1e6ee 100644 (file)
@@ -39,7 +39,7 @@ config MOUSE_PS2
          module will be called psmouse.
 
 config MOUSE_PS2_ALPS
-       bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
+       bool "ALPS PS/2 mouse protocol extension" if EXPERT
        default y
        depends on MOUSE_PS2
        help
@@ -49,7 +49,7 @@ config MOUSE_PS2_ALPS
          If unsure, say Y.
 
 config MOUSE_PS2_LOGIPS2PP
-       bool "Logitech PS/2++ mouse protocol extension" if EMBEDDED
+       bool "Logitech PS/2++ mouse protocol extension" if EXPERT
        default y
        depends on MOUSE_PS2
        help
@@ -59,7 +59,7 @@ config MOUSE_PS2_LOGIPS2PP
          If unsure, say Y.
 
 config MOUSE_PS2_SYNAPTICS
-       bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
+       bool "Synaptics PS/2 mouse protocol extension" if EXPERT
        default y
        depends on MOUSE_PS2
        help
@@ -69,7 +69,7 @@ config MOUSE_PS2_SYNAPTICS
          If unsure, say Y.
 
 config MOUSE_PS2_LIFEBOOK
-       bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
+       bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
        default y
        depends on MOUSE_PS2 && X86 && DMI
        help
@@ -79,7 +79,7 @@ config MOUSE_PS2_LIFEBOOK
          If unsure, say Y.
 
 config MOUSE_PS2_TRACKPOINT
-       bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
+       bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT
        default y
        depends on MOUSE_PS2
        help
index da392c2..aa186cf 100644 (file)
@@ -755,23 +755,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        struct synaptics_data old_priv = *priv;
+       int retry = 0;
+       int error;
 
-       psmouse_reset(psmouse);
+       do {
+               psmouse_reset(psmouse);
+               error = synaptics_detect(psmouse, 0);
+       } while (error && ++retry < 3);
 
-       if (synaptics_detect(psmouse, 0))
+       if (error)
                return -1;
 
+       if (retry > 1)
+               printk(KERN_DEBUG "Synaptics reconnected after %d tries\n",
+                       retry);
+
        if (synaptics_query_hardware(psmouse)) {
                printk(KERN_ERR "Unable to query Synaptics hardware.\n");
                return -1;
        }
 
-       if (old_priv.identity != priv->identity ||
-           old_priv.model_id != priv->model_id ||
-           old_priv.capabilities != priv->capabilities ||
-           old_priv.ext_cap != priv->ext_cap)
-               return -1;
-
        if (synaptics_set_absolute_mode(psmouse)) {
                printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
                return -1;
@@ -782,6 +785,19 @@ static int synaptics_reconnect(struct psmouse *psmouse)
                return -1;
        }
 
+       if (old_priv.identity != priv->identity ||
+           old_priv.model_id != priv->model_id ||
+           old_priv.capabilities != priv->capabilities ||
+           old_priv.ext_cap != priv->ext_cap) {
+               printk(KERN_ERR "Synaptics hardware appears to be different: "
+                       "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
+                       old_priv.identity, priv->identity,
+                       old_priv.model_id, priv->model_id,
+                       old_priv.capabilities, priv->capabilities,
+                       old_priv.ext_cap, priv->ext_cap);
+               return -1;
+       }
+
        return 0;
 }
 
index 25e5d04..7453938 100644 (file)
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+
+/*
+ * The following describes response for the 0x0c query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    adjustable threshold    capacitive button sensitivity
+ *                                     can be adjusted
+ * 1   0x02    report max              query 0x0d gives max coord reported
+ * 1   0x04    clearpad                sensor is ClearPad product
+ * 1   0x08    advanced gesture        not particularly meaningful
+ * 1   0x10    clickpad bit 0          1-button ClickPad
+ * 1   0x60    multifinger mode        identifies firmware finger counting
+ *                                     (not reporting!) algorithm.
+ *                                     Not particularly meaningful
+ * 1   0x80    covered pad             W clipped to 14, 15 == pad mostly covered
+ * 2   0x01    clickpad bit 1          2-button ClickPad
+ * 2   0x02    deluxe LED controls     touchpad support LED commands
+ *                                     ala multimedia control bar
+ * 2   0x04    reduced filtering       firmware does less filtering on
+ *                                     position data, driver should watch
+ *                                     for noise.
+ */
 #define SYN_CAP_CLICKPAD(ex0c)         ((ex0c) & 0x100000) /* 1-button ClickPad */
 #define SYN_CAP_CLICKPAD2BTN(ex0c)     ((ex0c) & 0x000100) /* 2-button ClickPad */
 #define SYN_CAP_MAX_DIMENSIONS(ex0c)   ((ex0c) & 0x020000)
index 307eef7..55f2c22 100644 (file)
@@ -2,7 +2,7 @@
 # Input core configuration
 #
 config SERIO
-       tristate "Serial I/O support" if EMBEDDED || !X86
+       tristate "Serial I/O support" if EXPERT || !X86
        default y
        help
          Say Yes here if you have any input device that uses serial I/O to
@@ -19,7 +19,7 @@ config SERIO
 if SERIO
 
 config SERIO_I8042
-       tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
+       tristate "i8042 PC Keyboard controller" if EXPERT || !X86
        default y
        depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
                   (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
@@ -168,7 +168,7 @@ config SERIO_MACEPS2
          module will be called maceps2.
 
 config SERIO_LIBPS2
-       tristate "PS/2 driver library" if EMBEDDED
+       tristate "PS/2 driver library" if EXPERT
        depends on SERIO_I8042 || SERIO_I8042=n
        help
          Say Y here if you are using a driver for device connected
index 448c772..8528165 100644 (file)
@@ -111,9 +111,11 @@ static void ct82c710_close(struct serio *serio)
 static int ct82c710_open(struct serio *serio)
 {
        unsigned char status;
+       int err;
 
-       if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
-               return -1;
+       err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
+       if (err)
+               return err;
 
        status = inb_p(CT82C710_STATUS);
 
@@ -131,7 +133,7 @@ static int ct82c710_open(struct serio *serio)
                status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
                outb_p(status, CT82C710_STATUS);
                free_irq(CT82C710_IRQ, NULL);
-               return -1;
+               return -EBUSY;
        }
 
        return 0;
index db5b0bc..ba70058 100644 (file)
@@ -188,7 +188,8 @@ static void serio_free_event(struct serio_event *event)
        kfree(event);
 }
 
-static void serio_remove_duplicate_events(struct serio_event *event)
+static void serio_remove_duplicate_events(void *object,
+                                         enum serio_event_type type)
 {
        struct serio_event *e, *next;
        unsigned long flags;
@@ -196,13 +197,13 @@ static void serio_remove_duplicate_events(struct serio_event *event)
        spin_lock_irqsave(&serio_event_lock, flags);
 
        list_for_each_entry_safe(e, next, &serio_event_list, node) {
-               if (event->object == e->object) {
+               if (object == e->object) {
                        /*
                         * If this event is of different type we should not
                         * look further - we only suppress duplicate events
                         * that were sent back-to-back.
                         */
-                       if (event->type != e->type)
+                       if (type != e->type)
                                break;
 
                        list_del_init(&e->node);
@@ -245,7 +246,7 @@ static void serio_handle_event(struct work_struct *work)
                        break;
                }
 
-               serio_remove_duplicate_events(event);
+               serio_remove_duplicate_events(event->object, event->type);
                serio_free_event(event);
        }
 
@@ -298,7 +299,7 @@ static int serio_queue_event(void *object, struct module *owner,
        event->owner = owner;
 
        list_add_tail(&event->node, &serio_event_list);
-       schedule_work(&serio_event_work);
+       queue_work(system_long_wq, &serio_event_work);
 
 out:
        spin_unlock_irqrestore(&serio_event_lock, flags);
@@ -436,10 +437,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
        } else if (!strncmp(buf, "rescan", count)) {
                serio_disconnect_port(serio);
                serio_find_driver(serio);
+               serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
                serio_disconnect_port(serio);
                error = serio_bind_driver(serio, to_serio_driver(drv));
                put_driver(drv);
+               serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else {
                error = -EINVAL;
        }
index 6e362de..8755f5f 100644 (file)
@@ -116,14 +116,15 @@ static void serport_ldisc_close(struct tty_struct *tty)
 
 /*
  * serport_ldisc_receive() is called by the low level tty driver when characters
- * are ready for us. We forward the characters, one by one to the 'interrupt'
- * routine.
+ * are ready for us. We forward the characters and flags, one by one to the
+ * 'interrupt' routine.
  */
 
 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
+       unsigned int ch_flags;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
@@ -131,8 +132,23 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
        if (!test_bit(SERPORT_ACTIVE, &serport->flags))
                goto out;
 
-       for (i = 0; i < count; i++)
-               serio_interrupt(serport->serio, cp[i], 0);
+       for (i = 0; i < count; i++) {
+               switch (fp[i]) {
+               case TTY_FRAME:
+                       ch_flags = SERIO_FRAME;
+                       break;
+
+               case TTY_PARITY:
+                       ch_flags = SERIO_PARITY;
+                       break;
+
+               default:
+                       ch_flags = 0;
+                       break;
+               }
+
+               serio_interrupt(serport->serio, cp[i], ch_flags);
+       }
 
 out:
        spin_unlock_irqrestore(&serport->lock, flags);
index a29a781..7729e54 100644 (file)
@@ -201,6 +201,7 @@ int sparse_keymap_setup(struct input_dev *dev,
                        break;
 
                case KE_SW:
+               case KE_VSW:
                        __set_bit(EV_SW, dev->evbit);
                        __set_bit(entry->sw.code, dev->swbit);
                        break;
index fc38149..cf8fb9f 100644 (file)
@@ -519,7 +519,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        /* Retrieve the physical and logical size for OEM devices */
        error = wacom_retrieve_hid_descriptor(intf, features);
        if (error)
-               goto fail2;
+               goto fail3;
 
        wacom_setup_device_quirks(features);
 
index 5187829..367fa82 100644 (file)
@@ -1101,6 +1101,13 @@ void wacom_setup_device_quirks(struct wacom_features *features)
        }
 }
 
+static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
+                                             unsigned int physical_max)
+{
+       /* Touch physical dimensions are in 100th of mm */
+       return (logical_max * 100) / physical_max;
+}
+
 void wacom_setup_input_capabilities(struct input_dev *input_dev,
                                    struct wacom_wac *wacom_wac)
 {
@@ -1228,8 +1235,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case TABLETPC:
                if (features->device_type == BTN_TOOL_DOUBLETAP ||
                    features->device_type == BTN_TOOL_TRIPLETAP) {
-                       input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
-                       input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+                       input_abs_set_res(input_dev, ABS_X,
+                               wacom_calculate_touch_res(features->x_max,
+                                                       features->x_phy));
+                       input_abs_set_res(input_dev, ABS_Y,
+                               wacom_calculate_touch_res(features->y_max,
+                                                       features->y_phy));
                        __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
                }
 
@@ -1272,6 +1283,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                        input_set_abs_params(input_dev, ABS_MT_PRESSURE,
                                             0, features->pressure_max,
                                             features->pressure_fuzz, 0);
+                       input_abs_set_res(input_dev, ABS_X,
+                               wacom_calculate_touch_res(features->x_max,
+                                                       features->x_phy));
+                       input_abs_set_res(input_dev, ABS_Y,
+                               wacom_calculate_touch_res(features->y_max,
+                                                       features->y_phy));
                } else if (features->device_type == BTN_TOOL_PEN) {
                        __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                        __set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1426,6 +1443,10 @@ static struct wacom_features wacom_features_0xD3 =
        { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13530, 1023, 63, BAMBOO_PT };
 static const struct wacom_features wacom_features_0xD4 =
        { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200,  255, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD6 =
+       { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD7 =
+       { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720,  9200, 1023, 63, BAMBOO_PT };
 static struct wacom_features wacom_features_0xD8 =
        { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN,   21648, 13530, 1023, 63, BAMBOO_PT };
 static struct wacom_features wacom_features_0xDA =
@@ -1507,6 +1528,8 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xD2) },
        { USB_DEVICE_WACOM(0xD3) },
        { USB_DEVICE_WACOM(0xD4) },
+       { USB_DEVICE_WACOM(0xD6) },
+       { USB_DEVICE_WACOM(0xD7) },
        { USB_DEVICE_WACOM(0xD8) },
        { USB_DEVICE_WACOM(0xDA) },
        { USB_DEVICE_WACOM(0xDB) },
index 0c9f4b1..61834ae 100644 (file)
@@ -540,62 +540,62 @@ config TOUCHSCREEN_MC13783
 
 config TOUCHSCREEN_USB_EGALAX
        default y
-       bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+       bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_PANJIT
        default y
-       bool "PanJit device support" if EMBEDDED
+       bool "PanJit device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_3M
        default y
-       bool "3M/Microtouch EX II series device support" if EMBEDDED
+       bool "3M/Microtouch EX II series device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_ITM
        default y
-       bool "ITM device support" if EMBEDDED
+       bool "ITM device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_ETURBO
        default y
-       bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+       bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_GUNZE
        default y
-       bool "Gunze AHL61 device support" if EMBEDDED
+       bool "Gunze AHL61 device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_DMC_TSC10
        default y
-       bool "DMC TSC-10/25 device support" if EMBEDDED
+       bool "DMC TSC-10/25 device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_IRTOUCH
        default y
-       bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
+       bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_IDEALTEK
        default y
-       bool "IdealTEK URTC1000 device support" if EMBEDDED
+       bool "IdealTEK URTC1000 device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_GENERAL_TOUCH
        default y
-       bool "GeneralTouch Touchscreen device support" if EMBEDDED
+       bool "GeneralTouch Touchscreen device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_GOTOP
        default y
-       bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+       bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_JASTEC
        default y
-       bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+       bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_E2I
@@ -605,17 +605,17 @@ config TOUCHSCREEN_USB_E2I
 
 config TOUCHSCREEN_USB_ZYTRONIC
        default y
-       bool "Zytronic controller" if EMBEDDED
+       bool "Zytronic controller" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_ETT_TC45USB
        default y
-       bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED
+       bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_NEXIO
        default y
-       bool "NEXIO/iNexio device support" if EMBEDDED
+       bool "NEXIO/iNexio device support" if EXPERT
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_TOUCHIT213
index 14ea54b..4bf2316 100644 (file)
@@ -941,28 +941,29 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
        struct ads7846_platform_data *pdata = spi->dev.platform_data;
        int err;
 
-       /* REVISIT when the irq can be triggered active-low, or if for some
+       /*
+        * REVISIT when the irq can be triggered active-low, or if for some
         * reason the touchscreen isn't hooked up, we don't need to access
         * the pendown state.
         */
-       if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
-               dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
-               return -EINVAL;
-       }
 
        if (pdata->get_pendown_state) {
                ts->get_pendown_state = pdata->get_pendown_state;
-               return 0;
-       }
+       } else if (gpio_is_valid(pdata->gpio_pendown)) {
 
-       err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
-       if (err) {
-               dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
-                       pdata->gpio_pendown);
-               return err;
-       }
+               err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
+               if (err) {
+                       dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
+                               pdata->gpio_pendown);
+                       return err;
+               }
 
-       ts->gpio_pendown = pdata->gpio_pendown;
+               ts->gpio_pendown = pdata->gpio_pendown;
+
+       } else {
+               dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1353,7 +1354,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
  err_put_regulator:
        regulator_put(ts->reg);
  err_free_gpio:
-       if (ts->gpio_pendown != -1)
+       if (!ts->get_pendown_state)
                gpio_free(ts->gpio_pendown);
  err_cleanup_filter:
        if (ts->filter_cleanup)
@@ -1383,8 +1384,13 @@ static int __devexit ads7846_remove(struct spi_device *spi)
        regulator_disable(ts->reg);
        regulator_put(ts->reg);
 
-       if (ts->gpio_pendown != -1)
+       if (!ts->get_pendown_state) {
+               /*
+                * If we are not using specialized pendown method we must
+                * have been relying on gpio we set up ourselves.
+                */
                gpio_free(ts->gpio_pendown);
+       }
 
        if (ts->filter_cleanup)
                ts->filter_cleanup(ts->filter_data);
index f7fa9ef..1507ce1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/input/bu21013.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
 #define PEN_DOWN_INTR  0
 #define MAX_FINGERS    2
  * @chip: pointer to the touch panel controller
  * @in_dev: pointer to the input device structure
  * @intr_pin: interrupt pin value
+ * @regulator: pointer to the Regulator used for touch screen
  *
  * Touch panel device data structure
  */
@@ -149,6 +151,7 @@ struct bu21013_ts_data {
        const struct bu21013_platform_device *chip;
        struct input_dev *in_dev;
        unsigned int intr_pin;
+       struct regulator *regulator;
 };
 
 /**
@@ -456,6 +459,20 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        bu21013_data->in_dev = in_dev;
        bu21013_data->chip = pdata;
        bu21013_data->client = client;
+
+       bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");
+       if (IS_ERR(bu21013_data->regulator)) {
+               dev_err(&client->dev, "regulator_get failed\n");
+               error = PTR_ERR(bu21013_data->regulator);
+               goto err_free_mem;
+       }
+
+       error = regulator_enable(bu21013_data->regulator);
+       if (error < 0) {
+               dev_err(&client->dev, "regulator enable failed\n");
+               goto err_put_regulator;
+       }
+
        bu21013_data->touch_stopped = false;
        init_waitqueue_head(&bu21013_data->wait);
 
@@ -464,7 +481,7 @@ static int __devinit bu21013_probe(struct i2c_client *client,
                error = pdata->cs_en(pdata->cs_pin);
                if (error < 0) {
                        dev_err(&client->dev, "chip init failed\n");
-                       goto err_free_mem;
+                       goto err_disable_regulator;
                }
        }
 
@@ -485,9 +502,9 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        __set_bit(EV_ABS, in_dev->evbit);
 
        input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
-                                               pdata->x_max_res, 0, 0);
+                                               pdata->touch_x_max, 0, 0);
        input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
-                                               pdata->y_max_res, 0, 0);
+                                               pdata->touch_y_max, 0, 0);
        input_set_drvdata(in_dev, bu21013_data);
 
        error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
@@ -513,6 +530,10 @@ err_free_irq:
        bu21013_free_irq(bu21013_data);
 err_cs_disable:
        pdata->cs_dis(pdata->cs_pin);
+err_disable_regulator:
+       regulator_disable(bu21013_data->regulator);
+err_put_regulator:
+       regulator_put(bu21013_data->regulator);
 err_free_mem:
        input_free_device(in_dev);
        kfree(bu21013_data);
@@ -535,6 +556,10 @@ static int __devexit bu21013_remove(struct i2c_client *client)
        bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
 
        input_unregister_device(bu21013_data->in_dev);
+
+       regulator_disable(bu21013_data->regulator);
+       regulator_put(bu21013_data->regulator);
+
        kfree(bu21013_data);
 
        device_init_wakeup(&client->dev, false);
@@ -561,6 +586,8 @@ static int bu21013_suspend(struct device *dev)
        else
                disable_irq(bu21013_data->chip->irq);
 
+       regulator_disable(bu21013_data->regulator);
+
        return 0;
 }
 
@@ -577,6 +604,12 @@ static int bu21013_resume(struct device *dev)
        struct i2c_client *client = bu21013_data->client;
        int retval;
 
+       retval = regulator_enable(bu21013_data->regulator);
+       if (retval < 0) {
+               dev_err(&client->dev, "bu21013 regulator enable failed\n");
+               return retval;
+       }
+
        retval = bu21013_init_chip(bu21013_data);
        if (retval < 0) {
                dev_err(&client->dev, "bu21013 controller config failed\n");
index cf1dba2..22a3411 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -289,9 +290,9 @@ static int __devinit tsc_probe(struct platform_device *pdev)
        }
 
        ts->clk = clk_get(dev, NULL);
-       if (!ts->clk) {
+       if (IS_ERR(ts->clk)) {
                dev_err(dev, "cannot claim device clock\n");
-               error = -EINVAL;
+               error = PTR_ERR(ts->clk);
                goto error_clk;
        }
 
index 5cb8449..c14412e 100644 (file)
@@ -51,6 +51,10 @@ MODULE_LICENSE("GPL");
 #define W8001_PKTLEN_TPCCTL    11      /* control packet */
 #define W8001_PKTLEN_TOUCH2FG  13
 
+/* resolution in points/mm */
+#define W8001_PEN_RESOLUTION    100
+#define W8001_TOUCH_RESOLUTION  10
+
 struct w8001_coord {
        u8 rdy;
        u8 tsw;
@@ -198,7 +202,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
                query->y = 1024;
                if (query->panel_res)
                        query->x = query->y = (1 << query->panel_res);
-               query->panel_res = 10;
+               query->panel_res = W8001_TOUCH_RESOLUTION;
        }
 }
 
@@ -394,6 +398,8 @@ static int w8001_setup(struct w8001 *w8001)
 
                input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
                input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+               input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+               input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
                input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
                if (coord.tilt_x && coord.tilt_y) {
                        input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
@@ -418,14 +424,17 @@ static int w8001_setup(struct w8001 *w8001)
                w8001->max_touch_x = touch.x;
                w8001->max_touch_y = touch.y;
 
-               /* scale to pen maximum */
                if (w8001->max_pen_x && w8001->max_pen_y) {
+                       /* if pen is supported scale to pen maximum */
                        touch.x = w8001->max_pen_x;
                        touch.y = w8001->max_pen_y;
+                       touch.panel_res = W8001_PEN_RESOLUTION;
                }
 
                input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
                input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
+               input_abs_set_res(dev, ABS_X, touch.panel_res);
+               input_abs_set_res(dev, ABS_Y, touch.panel_res);
 
                switch (touch.sensor_id) {
                case 0:
index 18f8798..7bd5baa 100644 (file)
@@ -62,7 +62,7 @@ void diva_xdi_provide_istream_info (ADAPTER* a,
   stream interface.
   If synchronous service was requested, then function
   does return amount of data written to stream.
-  'final' does indicate that pice of data to be written is
+  'final' does indicate that piece of data to be written is
   final part of frame (necessary only by structured datatransfer)
   return  0 if zero lengh packet was written
   return -1 if stream is full
index 0858791..cfff0c4 100644 (file)
@@ -1247,10 +1247,10 @@ static void
 l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct sk_buff *skb, *oskb;
+       struct sk_buff *skb;
        struct Layer2 *l2 = &st->l2;
        u_char header[MAX_HEADER_LEN];
-       int i;
+       int i, hdr_space_needed;
        int unsigned p1;
        u_long flags;
 
@@ -1261,6 +1261,16 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
        if (!skb)
                return;
 
+       hdr_space_needed = l2headersize(l2, 0);
+       if (hdr_space_needed > skb_headroom(skb)) {
+               struct sk_buff *orig_skb = skb;
+
+               skb = skb_realloc_headroom(skb, hdr_space_needed);
+               if (!skb) {
+                       dev_kfree_skb(orig_skb);
+                       return;
+               }
+       }
        spin_lock_irqsave(&l2->lock, flags);
        if(test_bit(FLG_MOD128, &l2->flag))
                p1 = (l2->vs - l2->va) % 128;
@@ -1285,19 +1295,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
                l2->vs = (l2->vs + 1) % 8;
        }
        spin_unlock_irqrestore(&l2->lock, flags);
-       p1 = skb->data - skb->head;
-       if (p1 >= i)
-               memcpy(skb_push(skb, i), header, i);
-       else {
-               printk(KERN_WARNING
-               "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
-               oskb = skb;
-               skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
-               memcpy(skb_put(skb, i), header, i);
-               skb_copy_from_linear_data(oskb,
-                                         skb_put(skb, oskb->len), oskb->len);
-               dev_kfree_skb(oskb);
-       }
+       memcpy(skb_push(skb, i), header, i);
        st->l2.l2l1(st, PH_PULL | INDICATION, skb);
        test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
        if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
index 729df40..18b801a 100644 (file)
@@ -227,7 +227,6 @@ extern hysdn_card *card_root;       /* pointer to first card */
 /*************************/
 /* im/exported functions */
 /*************************/
-extern char *hysdn_getrev(const char *);
 
 /* hysdn_procconf.c */
 extern int hysdn_procconf_init(void);  /* init proc config filesys */
@@ -259,7 +258,6 @@ extern int hysdn_tx_cfgline(hysdn_card *, unsigned char *,
 
 /* hysdn_net.c */
 extern unsigned int hynet_enable; 
-extern char *hysdn_net_revision;
 extern int hysdn_net_create(hysdn_card *);     /* create a new net device */
 extern int hysdn_net_release(hysdn_card *);    /* delete the device */
 extern char *hysdn_net_getname(hysdn_card *);  /* get name of net interface */
index b7cc5c2..0ab42ac 100644 (file)
@@ -36,7 +36,6 @@ MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards");
 MODULE_AUTHOR("Werner Cornelius");
 MODULE_LICENSE("GPL");
 
-static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
 static int cardmax;            /* number of found cards */
 hysdn_card *card_root = NULL;  /* pointer to first card */
 static hysdn_card *card_last = NULL;   /* pointer to first card */
@@ -49,25 +48,6 @@ static hysdn_card *card_last = NULL; /* pointer to first card */
 /* Additionally newer versions may be activated without rebooting.          */
 /****************************************************************************/
 
-/******************************************************/
-/* extract revision number from string for log output */
-/******************************************************/
-char *
-hysdn_getrev(const char *revision)
-{
-       char *rev;
-       char *p;
-
-       if ((p = strchr(revision, ':'))) {
-               rev = p + 2;
-               p = strchr(rev, '$');
-               *--p = 0;
-       } else
-               rev = "???";
-       return rev;
-}
-
-
 /****************************************************************************/
 /* init_module is called once when the module is loaded to do all necessary */
 /* things like autodetect...                                                */
@@ -175,13 +155,9 @@ static int hysdn_have_procfs;
 static int __init
 hysdn_init(void)
 {
-       char tmp[50];
        int rc;
 
-       strcpy(tmp, hysdn_init_revision);
-       printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
-       strcpy(tmp, hysdn_net_revision);
-       printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
+       printk(KERN_NOTICE "HYSDN: module loaded\n");
 
        rc = pci_register_driver(&hysdn_pci_driver);
        if (rc)
index feec8d8..11f2cce 100644 (file)
@@ -26,9 +26,6 @@
 unsigned int hynet_enable = 0xffffffff; 
 module_param(hynet_enable, uint, 0);
 
-/* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
-
 #define MAX_SKB_BUFFERS 20     /* number of buffers for keeping TX-data */
 
 /****************************************************************************/
index 96b3e39..5fe83bd 100644 (file)
@@ -23,7 +23,6 @@
 #include "hysdn_defs.h"
 
 static DEFINE_MUTEX(hysdn_conf_mutex);
-static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
 
 #define INFO_OUT_LEN 80                /* length of info line including lf */
 
@@ -404,7 +403,7 @@ hysdn_procconf_init(void)
                card = card->next;      /* next entry */
        }
 
-       printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
+       printk(KERN_NOTICE "HYSDN: procfs initialised\n");
        return (0);
 }                              /* hysdn_procconf_init */
 
index f2b5bab..1f355bb 100644 (file)
@@ -1627,7 +1627,7 @@ __setup("icn=", icn_setup);
 static int __init icn_init(void)
 {
        char *p;
-       char rev[20];
+       char rev[21];
 
        memset(&dev, 0, sizeof(icn_dev));
        dev.memaddr = (membase & 0x0ffc000);
@@ -1638,6 +1638,7 @@ static int __init icn_init(void)
 
        if ((p = strchr(revision, ':'))) {
                strncpy(rev, p + 1, 20);
+               rev[20] = '\0';
                p = strchr(rev, '$');
                if (p)
                        *p = 0;
index da3fa8d..666daf7 100644 (file)
@@ -69,6 +69,7 @@ static int led_pwm_probe(struct platform_device *pdev)
                led_dat->pwm = pwm_request(cur_led->pwm_id,
                                cur_led->name);
                if (IS_ERR(led_dat->pwm)) {
+                       ret = PTR_ERR(led_dat->pwm);
                        dev_err(&pdev->dev, "unable to request PWM %d\n",
                                        cur_led->pwm_id);
                        goto err;
index 991d93b..ecc4bf3 100644 (file)
@@ -99,7 +99,7 @@ static ssize_t gpio_trig_inverted_show(struct device *dev,
        struct led_classdev *led = dev_get_drvdata(dev);
        struct gpio_trig_data *gpio_data = led->trigger_data;
 
-       return sprintf(buf, "%s\n", gpio_data->inverted ? "yes" : "no");
+       return sprintf(buf, "%u\n", gpio_data->inverted);
 }
 
 static ssize_t gpio_trig_inverted_store(struct device *dev,
@@ -107,16 +107,17 @@ static ssize_t gpio_trig_inverted_store(struct device *dev,
 {
        struct led_classdev *led = dev_get_drvdata(dev);
        struct gpio_trig_data *gpio_data = led->trigger_data;
-       unsigned inverted;
+       unsigned long inverted;
        int ret;
 
-       ret = sscanf(buf, "%u", &inverted);
-       if (ret < 1) {
-               dev_err(dev, "invalid value\n");
+       ret = strict_strtoul(buf, 10, &inverted);
+       if (ret < 0)
+               return ret;
+
+       if (inverted > 1)
                return -EINVAL;
-       }
 
-       gpio_data->inverted = !!inverted;
+       gpio_data->inverted = inverted;
 
        /* After inverting, we need to update the LED. */
        schedule_work(&gpio_data->work);
index 04b2212..d21578e 100644 (file)
@@ -1137,7 +1137,7 @@ void free_guest_pagetable(struct lguest *lg)
  */
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
-       pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+       pte_t *switcher_pte_page = __this_cpu_read(switcher_pte_pages);
        pte_t regs_pte;
 
 #ifdef CONFIG_X86_PAE
index b4eb675..9f1659c 100644 (file)
@@ -90,8 +90,8 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
         * meanwhile).  If that's not the case, we pretend everything in the
         * Guest has changed.
         */
-       if (__get_cpu_var(lg_last_cpu) != cpu || cpu->last_pages != pages) {
-               __get_cpu_var(lg_last_cpu) = cpu;
+       if (__this_cpu_read(lg_last_cpu) != cpu || cpu->last_pages != pages) {
+               __this_cpu_write(lg_last_cpu, cpu);
                cpu->last_pages = pages;
                cpu->changed = CHANGED_ALL;
        }
index 2e041fd..f3a29f2 100644 (file)
@@ -443,7 +443,7 @@ static int fan_read_reg(int reg, unsigned char *buf, int nb)
        tries = 0;
        for (;;) {
                nr = i2c_master_recv(fcu, buf, nb);
-               if (nr > 0 || (nr < 0 && nr != ENODEV) || tries >= 100)
+               if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
                        break;
                msleep(10);
                ++tries;
@@ -464,7 +464,7 @@ static int fan_write_reg(int reg, const unsigned char *ptr, int nb)
        tries = 0;
        for (;;) {
                nw = i2c_master_send(fcu, buf, nb);
-               if (nw > 0 || (nw < 0 && nw != EIO) || tries >= 100)
+               if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
                        break;
                msleep(10);
                ++tries;
index 8a2f767..0ed7f6b 100644 (file)
@@ -216,7 +216,6 @@ static int linear_run (mddev_t *mddev)
 
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
        conf = linear_conf(mddev, mddev->raid_disks);
 
        if (!conf)
index b76cfc8..818313e 100644 (file)
@@ -287,6 +287,7 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
        mddev_t *mddev = q->queuedata;
        int rv;
        int cpu;
+       unsigned int sectors;
 
        if (mddev == NULL || mddev->pers == NULL
            || !mddev->ready) {
@@ -311,12 +312,16 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
        atomic_inc(&mddev->active_io);
        rcu_read_unlock();
 
+       /*
+        * save the sectors now since our bio can
+        * go away inside make_request
+        */
+       sectors = bio_sectors(bio);
        rv = mddev->pers->make_request(mddev, bio);
 
        cpu = part_stat_lock();
        part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
-       part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
-                     bio_sectors(bio));
+       part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
        part_stat_unlock();
 
        if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
@@ -548,6 +553,9 @@ static mddev_t * mddev_find(dev_t unit)
 {
        mddev_t *mddev, *new = NULL;
 
+       if (unit && MAJOR(unit) != MD_MAJOR)
+               unit &= ~((1<<MdpMinorShift)-1);
+
  retry:
        spin_lock(&all_mddevs_lock);
 
@@ -1947,8 +1955,6 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
                        __bdevname(dev, b));
                return PTR_ERR(bdev);
        }
-       if (!shared)
-               set_bit(AllReserved, &rdev->flags);
        rdev->bdev = bdev;
        return err;
 }
@@ -2465,6 +2471,9 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                if (rdev->raid_disk != -1)
                        return -EBUSY;
 
+               if (test_bit(MD_RECOVERY_RUNNING, &rdev->mddev->recovery))
+                       return -EBUSY;
+
                if (rdev->mddev->pers->hot_add_disk == NULL)
                        return -EINVAL;
 
@@ -2610,12 +2619,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 
                        mddev_lock(mddev);
                        list_for_each_entry(rdev2, &mddev->disks, same_set)
-                               if (test_bit(AllReserved, &rdev2->flags) ||
-                                   (rdev->bdev == rdev2->bdev &&
-                                    rdev != rdev2 &&
-                                    overlaps(rdev->data_offset, rdev->sectors,
-                                             rdev2->data_offset,
-                                             rdev2->sectors))) {
+                               if (rdev->bdev == rdev2->bdev &&
+                                   rdev != rdev2 &&
+                                   overlaps(rdev->data_offset, rdev->sectors,
+                                            rdev2->data_offset,
+                                            rdev2->sectors)) {
                                        overlap = 1;
                                        break;
                                }
@@ -4133,10 +4141,10 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
        }
 
        mddev->array_sectors = sectors;
-       set_capacity(mddev->gendisk, mddev->array_sectors);
-       if (mddev->pers)
+       if (mddev->pers) {
+               set_capacity(mddev->gendisk, mddev->array_sectors);
                revalidate_disk(mddev->gendisk);
-
+       }
        return len;
 }
 
@@ -4619,6 +4627,7 @@ static int do_md_run(mddev_t *mddev)
        }
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
+       mddev->changed = 1;
        kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
 out:
        return err;
@@ -4707,6 +4716,7 @@ static void md_clean(mddev_t *mddev)
        mddev->sync_speed_min = mddev->sync_speed_max = 0;
        mddev->recovery = 0;
        mddev->in_sync = 0;
+       mddev->changed = 0;
        mddev->degraded = 0;
        mddev->safemode = 0;
        mddev->bitmap_info.offset = 0;
@@ -4822,6 +4832,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
 
                set_capacity(disk, 0);
                mutex_unlock(&mddev->open_mutex);
+               mddev->changed = 1;
                revalidate_disk(disk);
 
                if (mddev->ro)
@@ -5578,6 +5589,8 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
        mddev->delta_disks = raid_disks - mddev->raid_disks;
 
        rv = mddev->pers->check_reshape(mddev);
+       if (rv < 0)
+               mddev->delta_disks = 0;
        return rv;
 }
 
@@ -6004,7 +6017,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
        atomic_inc(&mddev->openers);
        mutex_unlock(&mddev->open_mutex);
 
-       check_disk_size_change(mddev->gendisk, bdev);
+       check_disk_change(bdev);
  out:
        return err;
 }
@@ -6019,6 +6032,21 @@ static int md_release(struct gendisk *disk, fmode_t mode)
 
        return 0;
 }
+
+static int md_media_changed(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       return mddev->changed;
+}
+
+static int md_revalidate(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       mddev->changed = 0;
+       return 0;
+}
 static const struct block_device_operations md_fops =
 {
        .owner          = THIS_MODULE,
@@ -6029,6 +6057,8 @@ static const struct block_device_operations md_fops =
        .compat_ioctl   = md_compat_ioctl,
 #endif
        .getgeo         = md_getgeo,
+       .media_changed  = md_media_changed,
+       .revalidate_disk= md_revalidate,
 };
 
 static int md_thread(void * arg)
@@ -6985,9 +7015,6 @@ void md_do_sync(mddev_t *mddev)
        } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
                mddev->resync_min = mddev->curr_resync_completed;
        mddev->curr_resync = 0;
-       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
-               mddev->curr_resync_completed = 0;
-       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        wake_up(&resync_wait);
        set_bit(MD_RECOVERY_DONE, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
@@ -7028,7 +7055,7 @@ static int remove_and_add_spares(mddev_t *mddev)
                        }
                }
 
-       if (mddev->degraded && ! mddev->ro && !mddev->recovery_disabled) {
+       if (mddev->degraded && !mddev->recovery_disabled) {
                list_for_each_entry(rdev, &mddev->disks, same_set) {
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(In_sync, &rdev->flags) &&
@@ -7151,7 +7178,20 @@ void md_check_recovery(mddev_t *mddev)
                        /* Only thing we do on a ro array is remove
                         * failed devices.
                         */
-                       remove_and_add_spares(mddev);
+                       mdk_rdev_t *rdev;
+                       list_for_each_entry(rdev, &mddev->disks, same_set)
+                               if (rdev->raid_disk >= 0 &&
+                                   !test_bit(Blocked, &rdev->flags) &&
+                                   test_bit(Faulty, &rdev->flags) &&
+                                   atomic_read(&rdev->nr_pending)==0) {
+                                       if (mddev->pers->hot_remove_disk(
+                                                   mddev, rdev->raid_disk)==0) {
+                                               char nm[20];
+                                               sprintf(nm,"rd%d", rdev->raid_disk);
+                                               sysfs_remove_link(&mddev->kobj, nm);
+                                               rdev->raid_disk = -1;
+                                       }
+                               }
                        clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        goto unlock;
                }
index eec517c..12215d4 100644 (file)
@@ -93,8 +93,6 @@ struct mdk_rdev_s
 #define        Faulty          1               /* device is known to have a fault */
 #define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
-#define        AllReserved     6               /* If whole device is reserved for
-                                        * one array */
 #define        AutoDetected    7               /* added by auto-detect */
 #define Blocked                8               /* An error occured on an externally
                                         * managed array, don't allow writes
@@ -276,6 +274,8 @@ struct mddev_s
        atomic_t                        active;         /* general refcount */
        atomic_t                        openers;        /* number of active opens */
 
+       int                             changed;        /* True if we might need to
+                                                        * reread partition info */
        int                             degraded;       /* whether md should consider
                                                         * adding a spare
                                                         */
index 6d7ddf3..3a62d44 100644 (file)
@@ -435,7 +435,6 @@ static int multipath_run (mddev_t *mddev)
         * bookkeeping area. [whatever we allocate in multipath_run(),
         * should be freed in multipath_stop()]
         */
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
 
        conf = kzalloc(sizeof(multipath_conf_t), GFP_KERNEL);
        mddev->private = conf;
index a39f4c3..c0ac457 100644 (file)
@@ -179,6 +179,14 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
                        rdev1->new_raid_disk = j;
                }
 
+               if (mddev->level == 1) {
+                       /* taiking over a raid1 array-
+                        * we have only one active disk
+                        */
+                       j = 0;
+                       rdev1->new_raid_disk = j;
+               }
+
                if (j < 0 || j >= mddev->raid_disks) {
                        printk(KERN_ERR "md/raid0:%s: bad disk number %d - "
                               "aborting!\n", mdname(mddev), j);
@@ -353,7 +361,6 @@ static int raid0_run(mddev_t *mddev)
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
        blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
 
        /* if private is not null, we are here after takeover */
        if (mddev->private == NULL) {
@@ -644,12 +651,39 @@ static void *raid0_takeover_raid10(mddev_t *mddev)
        return priv_conf;
 }
 
+static void *raid0_takeover_raid1(mddev_t *mddev)
+{
+       raid0_conf_t *priv_conf;
+
+       /* Check layout:
+        *  - (N - 1) mirror drives must be already faulty
+        */
+       if ((mddev->raid_disks - 1) != mddev->degraded) {
+               printk(KERN_ERR "md/raid0:%s: (N - 1) mirrors drives must be already faulty!\n",
+                      mdname(mddev));
+               return ERR_PTR(-EINVAL);
+       }
+
+       /* Set new parameters */
+       mddev->new_level = 0;
+       mddev->new_layout = 0;
+       mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */
+       mddev->delta_disks = 1 - mddev->raid_disks;
+       mddev->raid_disks = 1;
+       /* make sure it will be not marked as dirty */
+       mddev->recovery_cp = MaxSector;
+
+       create_strip_zones(mddev, &priv_conf);
+       return priv_conf;
+}
+
 static void *raid0_takeover(mddev_t *mddev)
 {
        /* raid0 can take over:
         *  raid4 - if all data disks are active.
         *  raid5 - providing it is Raid4 layout and one disk is faulty
         *  raid10 - assuming we have all necessary active disks
+        *  raid1 - with (N -1) mirror drives faulty
         */
        if (mddev->level == 4)
                return raid0_takeover_raid45(mddev);
@@ -665,6 +699,12 @@ static void *raid0_takeover(mddev_t *mddev)
        if (mddev->level == 10)
                return raid0_takeover_raid10(mddev);
 
+       if (mddev->level == 1)
+               return raid0_takeover_raid1(mddev);
+
+       printk(KERN_ERR "Takeover from raid%i to raid0 not supported\n",
+               mddev->level);
+
        return ERR_PTR(-EINVAL);
 }
 
index a23ffa3..06cd712 100644 (file)
@@ -593,7 +593,10 @@ static int flush_pending_writes(conf_t *conf)
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
+               /* Only take the spinlock to quiet a warning */
+               spin_lock(conf->mddev->queue->queue_lock);
                blk_remove_plug(conf->mddev->queue);
+               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to
                 * disk before proceeding w/ I/O */
@@ -959,7 +962,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r1_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device(mddev->queue);
+               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
        r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL);
@@ -2021,7 +2024,6 @@ static int run(mddev_t *mddev)
        if (IS_ERR(conf))
                return PTR_ERR(conf);
 
-       mddev->queue->queue_lock = &conf->device_lock;
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
index 69b6595..747d061 100644 (file)
@@ -662,7 +662,10 @@ static int flush_pending_writes(conf_t *conf)
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
+               /* Spinlock only taken to quiet a warning */
+               spin_lock(conf->mddev->queue->queue_lock);
                blk_remove_plug(conf->mddev->queue);
+               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to disk
                 * before proceeding w/ I/O */
@@ -971,7 +974,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r10_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device(mddev->queue);
+               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
 
@@ -2304,8 +2307,6 @@ static int run(mddev_t *mddev)
        if (!conf)
                goto out;
 
-       mddev->queue->queue_lock = &conf->device_lock;
-
        mddev->thread = conf->thread;
        conf->thread = NULL;
 
@@ -2463,11 +2464,13 @@ static void *raid10_takeover_raid0(mddev_t *mddev)
        mddev->recovery_cp = MaxSector;
 
        conf = setup_conf(mddev);
-       if (!IS_ERR(conf))
+       if (!IS_ERR(conf)) {
                list_for_each_entry(rdev, &mddev->disks, same_set)
                        if (rdev->raid_disk >= 0)
                                rdev->new_raid_disk = rdev->raid_disk * 2;
-               
+               conf->barrier = 1;
+       }
+
        return conf;
 }
 
index 5044bab..78536fd 100644 (file)
@@ -5204,7 +5204,6 @@ static int run(mddev_t *mddev)
 
                mddev->queue->backing_dev_info.congested_data = mddev;
                mddev->queue->backing_dev_info.congested_fn = raid5_congested;
-               mddev->queue->queue_lock = &conf->device_lock;
                mddev->queue->unplug_fn = raid5_unplug_queue;
 
                chunk_size = mddev->chunk_sectors << 9;
@@ -5517,7 +5516,6 @@ static int raid5_start_reshape(mddev_t *mddev)
        raid5_conf_t *conf = mddev->private;
        mdk_rdev_t *rdev;
        int spares = 0;
-       int added_devices = 0;
        unsigned long flags;
 
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
@@ -5527,8 +5525,8 @@ static int raid5_start_reshape(mddev_t *mddev)
                return -ENOSPC;
 
        list_for_each_entry(rdev, &mddev->disks, same_set)
-               if ((rdev->raid_disk < 0 || rdev->raid_disk >= conf->raid_disks)
-                    && !test_bit(Faulty, &rdev->flags))
+               if (!test_bit(In_sync, &rdev->flags)
+                   && !test_bit(Faulty, &rdev->flags))
                        spares++;
 
        if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
@@ -5571,34 +5569,35 @@ static int raid5_start_reshape(mddev_t *mddev)
         * to correctly record the "partially reconstructed" state of
         * such devices during the reshape and confusion could result.
         */
-       if (mddev->delta_disks >= 0)
-           list_for_each_entry(rdev, &mddev->disks, same_set)
-               if (rdev->raid_disk < 0 &&
-                   !test_bit(Faulty, &rdev->flags)) {
-                       if (raid5_add_disk(mddev, rdev) == 0) {
-                               char nm[20];
-                               if (rdev->raid_disk >= conf->previous_raid_disks) {
-                                       set_bit(In_sync, &rdev->flags);
-                                       added_devices++;
-                               } else
-                                       rdev->recovery_offset = 0;
-                               sprintf(nm, "rd%d", rdev->raid_disk);
-                               if (sysfs_create_link(&mddev->kobj,
-                                                     &rdev->kobj, nm))
-                                       /* Failure here is OK */;
-                       } else
-                               break;
-               } else if (rdev->raid_disk >= conf->previous_raid_disks
-                          && !test_bit(Faulty, &rdev->flags)) {
-                       /* This is a spare that was manually added */
-                       set_bit(In_sync, &rdev->flags);
-                       added_devices++;
-               }
+       if (mddev->delta_disks >= 0) {
+               int added_devices = 0;
+               list_for_each_entry(rdev, &mddev->disks, same_set)
+                       if (rdev->raid_disk < 0 &&
+                           !test_bit(Faulty, &rdev->flags)) {
+                               if (raid5_add_disk(mddev, rdev) == 0) {
+                                       char nm[20];
+                                       if (rdev->raid_disk
+                                           >= conf->previous_raid_disks) {
+                                               set_bit(In_sync, &rdev->flags);
+                                               added_devices++;
+                                       } else
+                                               rdev->recovery_offset = 0;
+                                       sprintf(nm, "rd%d", rdev->raid_disk);
+                                       if (sysfs_create_link(&mddev->kobj,
+                                                             &rdev->kobj, nm))
+                                               /* Failure here is OK */;
+                               }
+                       } else if (rdev->raid_disk >= conf->previous_raid_disks
+                                  && !test_bit(Faulty, &rdev->flags)) {
+                               /* This is a spare that was manually added */
+                               set_bit(In_sync, &rdev->flags);
+                               added_devices++;
+                       }
 
-       /* When a reshape changes the number of devices, ->degraded
-        * is measured against the larger of the pre and post number of
-        * devices.*/
-       if (mddev->delta_disks > 0) {
+               /* When a reshape changes the number of devices,
+                * ->degraded is measured against the larger of the
+                * pre and post number of devices.
+                */
                spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded += (conf->raid_disks - conf->previous_raid_disks)
                        - added_devices;
index 982f000..9f47e38 100644 (file)
@@ -452,7 +452,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
        dev->ext = ext;
 
-       mutex_init(&dev->lock);
+       mutex_init(&dev->v4l2_lock);
        spin_lock_init(&dev->int_slock);
        spin_lock_init(&dev->slock);
 
index e3fedc6..1bd3dd7 100644 (file)
@@ -15,18 +15,15 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
        }
 
        /* is it free? */
-       mutex_lock(&dev->lock);
        if (vv->resources & bit) {
                DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
                /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        vv->resources |= bit;
        DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
-       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -37,11 +34,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
 
        BUG_ON((fh->resources & bits) != bits);
 
-       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        vv->resources &= ~bits;
        DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
-       mutex_unlock(&dev->lock);
 }
 
 
@@ -396,7 +391,7 @@ static const struct v4l2_file_operations video_fops =
        .write          = fops_write,
        .poll           = fops_poll,
        .mmap           = fops_mmap,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static void vv_callback(struct saa7146_dev *dev, unsigned long status)
@@ -505,6 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        vfd->fops = &video_fops;
        vfd->ioctl_ops = &dev->ext_vv_data->ops;
        vfd->release = video_device_release;
+       vfd->lock = &dev->v4l2_lock;
        vfd->tvnorms = 0;
        for (i = 0; i < dev->ext_vv_data->num_stds; i++)
                vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
index 2d4533a..afe8580 100644 (file)
@@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
                            V4L2_BUF_TYPE_VBI_CAPTURE,
                            V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
                            sizeof(struct saa7146_buf),
-                           file, NULL);
+                           file, &dev->v4l2_lock);
 
        init_timer(&fh->vbi_read_timeout);
        fh->vbi_read_timeout.function = vbi_read_timeout;
index 0ac5c61..9aafa4e 100644 (file)
@@ -553,8 +553,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
                }
        }
 
-       mutex_lock(&dev->lock);
-
        /* ok, accept it */
        vv->ov_fb = *fb;
        vv->ov_fmt = fmt;
@@ -563,8 +561,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
                vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
                DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
        }
-
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -649,8 +645,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
                return -EINVAL;
        }
 
-       mutex_lock(&dev->lock);
-
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_BOOLEAN:
        case V4L2_CTRL_TYPE_MENU:
@@ -693,7 +687,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
                /* fixme: we can support changing VFLIP and HFLIP here... */
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
                        DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
-                       mutex_unlock(&dev->lock);
                        return -EBUSY;
                }
                vv->hflip = c->value;
@@ -701,16 +694,13 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
        case V4L2_CID_VFLIP:
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
                        DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
-                       mutex_unlock(&dev->lock);
                        return -EBUSY;
                }
                vv->vflip = c->value;
                break;
        default:
-               mutex_unlock(&dev->lock);
                return -EINVAL;
        }
-       mutex_unlock(&dev->lock);
 
        if (IS_OVERLAY_ACTIVE(fh) != 0) {
                saa7146_stop_preview(fh);
@@ -902,22 +892,18 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
        err = vidioc_try_fmt_vid_overlay(file, fh, f);
        if (0 != err)
                return err;
-       mutex_lock(&dev->lock);
        fh->ov.win    = f->fmt.win;
        fh->ov.nclips = f->fmt.win.clipcount;
        if (fh->ov.nclips > 16)
                fh->ov.nclips = 16;
        if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
                                sizeof(struct v4l2_clip) * fh->ov.nclips)) {
-               mutex_unlock(&dev->lock);
                return -EFAULT;
        }
 
        /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
        fh->ov.fh = fh;
 
-       mutex_unlock(&dev->lock);
-
        /* check if our current overlay is active */
        if (IS_OVERLAY_ACTIVE(fh) != 0) {
                saa7146_stop_preview(fh);
@@ -976,8 +962,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
                }
        }
 
-       mutex_lock(&dev->lock);
-
        for (i = 0; i < dev->ext_vv_data->num_stds; i++)
                if (*id & dev->ext_vv_data->stds[i].id)
                        break;
@@ -988,8 +972,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
                found = 1;
        }
 
-       mutex_unlock(&dev->lock);
-
        if (vv->ov_suspend != NULL) {
                saa7146_start_preview(vv->ov_suspend);
                vv->ov_suspend = NULL;
@@ -1354,7 +1336,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct saa7146_buf),
-                           file, NULL);
+                           file, &dev->v4l2_lock);
 
        return 0;
 }
index 78b0895..6fc79f1 100644 (file)
@@ -34,7 +34,7 @@ config MEDIA_TUNER
 config MEDIA_TUNER_CUSTOMISE
        bool "Customize analog and hybrid tuner modules to build"
        depends on MEDIA_TUNER
-       default y if EMBEDDED
+       default y if EXPERT
        help
          This allows the user to deselect tuner drivers unnecessary
          for their hardware from the build. Use this option with care
index c9062ce..bc6a677 100644 (file)
@@ -95,8 +95,7 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
                msleep(20);
        } else {
                msg = disable;
-               tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1);
 
                buf[2] = msg[1];
                buf[2] &= ~0x04;
@@ -233,19 +232,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
                tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
        }
 
+
        tda8290_i2c_bridge(fe, 1);
 
        if (fe->ops.tuner_ops.set_analog_params)
                fe->ops.tuner_ops.set_analog_params(fe, params);
 
        for (i = 0; i < 3; i++) {
-               tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                        &addr_pll_stat, 1, &pll_stat, 1);
                if (pll_stat & 0x80) {
-                       tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
-                       tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
-                       tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
-                       tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+                       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                                &addr_adc_sat, 1,
+                                                &adc_sat, 1);
+                       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                                &addr_agc_stat, 1,
+                                                &agc_stat, 1);
                        tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
                        break;
                } else {
@@ -259,20 +261,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
                           agc_stat, adc_sat, pll_stat & 0x80);
                tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
                msleep(100);
-               tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
-               tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                        &addr_agc_stat, 1, &agc_stat, 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                        &addr_pll_stat, 1, &pll_stat, 1);
                if ((agc_stat > 115) || !(pll_stat & 0x80)) {
                        tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
                                   agc_stat, pll_stat & 0x80);
                        if (priv->cfg.agcf)
                                priv->cfg.agcf(fe);
                        msleep(100);
-                       tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
-                       tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
-                       tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
-                       tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+                       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                                &addr_agc_stat, 1,
+                                                &agc_stat, 1);
+                       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                                &addr_pll_stat, 1,
+                                                &pll_stat, 1);
                        if((agc_stat > 115) || !(pll_stat & 0x80)) {
                                tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
                                tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
@@ -284,10 +288,12 @@ static void tda8290_set_params(struct dvb_frontend *fe,
 
        /* l/ l' deadlock? */
        if(priv->tda8290_easy_mode & 0x60) {
-               tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
-               tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
-               tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                        &addr_adc_sat, 1,
+                                        &adc_sat, 1);
+               tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                        &addr_pll_stat, 1,
+                                        &pll_stat, 1);
                if ((adc_sat > 20) || !(pll_stat & 0x80)) {
                        tuner_dbg("trying to resolve SECAM L deadlock\n");
                        tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
@@ -307,8 +313,7 @@ static void tda8295_power(struct dvb_frontend *fe, int enable)
        struct tda8290_priv *priv = fe->analog_demod_priv;
        unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
 
        if (enable)
                buf[1] = 0x01;
@@ -323,8 +328,7 @@ static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
        struct tda8290_priv *priv = fe->analog_demod_priv;
        unsigned char buf[] = { 0x01, 0x00 };
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
 
        if (enable)
                buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
@@ -353,8 +357,7 @@ static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
        struct tda8290_priv *priv = fe->analog_demod_priv;
        unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
 
        if (enable)
                buf[1] &= ~0x40;
@@ -370,10 +373,10 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
        unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
        unsigned char set_gpio_val[]   = { 0x46, 0x00 };
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
-       tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                &set_gpio_cf[0], 1, &set_gpio_cf[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                &set_gpio_val[0], 1, &set_gpio_val[1], 1);
 
        set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
 
@@ -392,8 +395,7 @@ static int tda8295_has_signal(struct dvb_frontend *fe)
        unsigned char hvpll_stat = 0x26;
        unsigned char ret;
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
        return (ret & 0x01) ? 65535 : 0;
 }
 
@@ -413,8 +415,8 @@ static void tda8295_set_params(struct dvb_frontend *fe,
        tda8295_power(fe, 1);
        tda8295_agc1_out(fe, 1);
 
-       tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
-       tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                &blanking_mode[0], 1, &blanking_mode[1], 1);
 
        tda8295_set_video_std(fe);
 
@@ -447,8 +449,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe)
        unsigned char i2c_get_afc[1] = { 0x1B };
        unsigned char afc = 0;
 
-       tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
-       tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+       tuner_i2c_xfer_send_recv(&priv->i2c_props,
+                                i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
        return (afc & 0x80)? 65535:0;
 }
 
@@ -654,20 +656,26 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
 static int tda8290_probe(struct tuner_i2c_props *i2c_props)
 {
 #define TDA8290_ID 0x89
-       unsigned char tda8290_id[] = { 0x1f, 0x00 };
+       u8 reg = 0x1f, id;
+       struct i2c_msg msg_read[] = {
+               { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+       };
 
        /* detect tda8290 */
-       tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
-       tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
+       if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+               printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+                              __func__, reg);
+               return -ENODEV;
+       }
 
-       if (tda8290_id[1] == TDA8290_ID) {
+       if (id == TDA8290_ID) {
                if (debug)
                        printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
                               __func__, i2c_adapter_id(i2c_props->adap),
                               i2c_props->addr);
                return 0;
        }
-
        return -ENODEV;
 }
 
@@ -675,16 +683,23 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props)
 {
 #define TDA8295_ID 0x8a
 #define TDA8295C2_ID 0x8b
-       unsigned char tda8295_id[] = { 0x2f, 0x00 };
+       u8 reg = 0x2f, id;
+       struct i2c_msg msg_read[] = {
+               { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+       };
 
-       /* detect tda8295 */
-       tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
-       tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
+       /* detect tda8290 */
+       if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+               printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+                              __func__, reg);
+               return -ENODEV;
+       }
 
-       if ((tda8295_id[1] & 0xfe) == TDA8295_ID) {
+       if ((id & 0xfe) == TDA8295_ID) {
                if (debug)
                        printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
-                              __func__, (tda8295_id[1] == TDA8295_ID) ?
+                              __func__, (id == TDA8295_ID) ?
                               "tda8295c1" : "tda8295c2",
                               i2c_adapter_id(i2c_props->adap),
                               i2c_props->addr);
@@ -740,9 +755,11 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
                       sizeof(struct analog_demod_ops));
        }
 
-       if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
-           (tda829x_find_tuner(fe) < 0))
-               goto fail;
+       if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
+               tda8295_power(fe, 1);
+               if (tda829x_find_tuner(fe) < 0)
+                       goto fail;
+       }
 
        switch (priv->ver) {
        case TDA8290:
@@ -786,6 +803,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
        return fe;
 
 fail:
+       memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops));
+
        tda829x_release(fe);
        return NULL;
 }
@@ -809,8 +828,8 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
        int i;
 
        /* rule out tda9887, which would return the same byte repeatedly */
-       tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
-       tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
+       tuner_i2c_xfer_send_recv(&i2c_props,
+                                soft_reset, 1, buf, PROBE_BUFFER_SIZE);
        for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
                if (buf[i] != buf[0])
                        break;
@@ -827,13 +846,12 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
        /* fall back to old probing method */
        tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
        tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
-       tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
-       tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+       tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1);
        if (data == 0) {
                tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
                tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
-               tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
-               tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+               tuner_i2c_xfer_send_recv(&i2c_props,
+                                        &addr_dto_lsb, 1, &data, 1);
                if (data == 0x7b) {
                        return 0;
                }
index 8ca48f7..98ffb40 100644 (file)
@@ -514,8 +514,8 @@ struct dib0700_rc_response {
        union {
                u16 system16;
                struct {
-                       u8 system;
                        u8 not_system;
+                       u8 system;
                };
        };
        u8 data;
@@ -575,7 +575,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
                        deb_data("NEC extended protocol\n");
                        /* NEC extended code - 24 bits */
-                       keycode = poll_reply->system16 << 8 | poll_reply->data;
+                       keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
                } else {
                        deb_data("NEC normal protocol\n");
                        /* normal NEC code - 16 bits */
@@ -587,7 +587,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                deb_data("RC5 protocol\n");
                /* RC5 Protocol */
                toggle = poll_reply->report_id;
-               keycode = poll_reply->system16 << 8 | poll_reply->data;
+               keycode = poll_reply->system << 8 | poll_reply->data;
 
                break;
        }
index fcf3828..f82d4a9 100644 (file)
@@ -172,7 +172,8 @@ void fdtv_unregister_rc(struct firedtv *fdtv)
 
 void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
 {
-       u16 *keycode = fdtv->remote_ctrl_dev->keycode;
+       struct input_dev *idev = fdtv->remote_ctrl_dev;
+       u16 *keycode = idev->keycode;
 
        if (code >= 0x0300 && code <= 0x031f)
                code = keycode[code - 0x0300];
@@ -188,6 +189,8 @@ void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
                return;
        }
 
-       input_report_key(fdtv->remote_ctrl_dev, code, 1);
-       input_report_key(fdtv->remote_ctrl_dev, code, 0);
+       input_report_key(idev, code, 1);
+       input_sync(idev);
+       input_report_key(idev, code, 0);
+       input_sync(idev);
 }
index ef3e43a..b8519ba 100644 (file)
@@ -1,7 +1,7 @@
 config DVB_FE_CUSTOMISE
        bool "Customise the frontend modules to build"
        depends on DVB_CORE
-       default y if EMBEDDED
+       default y if EXPERT
        help
          This allows the user to select/deselect frontend drivers for their
          hardware from the build.
index ce22205..ba25fa0 100644 (file)
@@ -334,11 +334,11 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
                                if_sample_freq = 3300000; /* 3.3 MHz */
                                break;
                        case BANDWIDTH_7_MHZ:
-                               if_sample_freq = 3800000; /* 3.8 MHz */
+                               if_sample_freq = 3500000; /* 3.5 MHz */
                                break;
                        case BANDWIDTH_8_MHZ:
                        default:
-                               if_sample_freq = 4300000; /* 4.3 MHz */
+                               if_sample_freq = 4000000; /* 4.0 MHz */
                                break;
                        }
                } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
index 6360c68..6c2e929 100644 (file)
@@ -311,7 +311,7 @@ struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
        return fe;
 
 error:
-       ix2505v_release(fe);
+       kfree(state);
        return NULL;
 }
 EXPORT_SYMBOL(ix2505v_attach);
index d3ad3e7..cc4acd2 100644 (file)
@@ -43,6 +43,8 @@ struct mb86a20s_state {
        const struct mb86a20s_config *config;
 
        struct dvb_frontend frontend;
+
+       bool need_init;
 };
 
 struct regdata {
@@ -318,7 +320,7 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
 
        rc = i2c_transfer(state->i2c, &msg, 1);
        if (rc != 1) {
-               printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+               printk("%s: writereg error (rc == %i, reg == 0x%02x,"
                         " data == 0x%02x)\n", __func__, rc, reg, data);
                return rc;
        }
@@ -353,7 +355,7 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
        rc = i2c_transfer(state->i2c, msg, 2);
 
        if (rc != 2) {
-               rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+               rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
                return rc;
        }
 
@@ -382,23 +384,31 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
        /* Initialize the frontend */
        rc = mb86a20s_writeregdata(state, mb86a20s_init);
        if (rc < 0)
-               return rc;
+               goto err;
 
        if (!state->config->is_serial) {
                regD5 &= ~1;
 
                rc = mb86a20s_writereg(state, 0x50, 0xd5);
                if (rc < 0)
-                       return rc;
+                       goto err;
                rc = mb86a20s_writereg(state, 0x51, regD5);
                if (rc < 0)
-                       return rc;
+                       goto err;
        }
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
-       return 0;
+err:
+       if (rc < 0) {
+               state->need_init = true;
+               printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
+       } else {
+               state->need_init = false;
+               dprintk("Initialization succeded.\n");
+       }
+       return rc;
 }
 
 static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
@@ -485,8 +495,22 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe,
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
+       dprintk("Calling tuner set parameters\n");
        fe->ops.tuner_ops.set_params(fe, p);
 
+       /*
+        * Make it more reliable: if, for some reason, the initial
+        * device initialization doesn't happen, initialize it when
+        * a SBTVD parameters are adjusted.
+        *
+        * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+        * the agc callback logic is not called during DVB attach time,
+        * causing mb86a20s to not be initialized with Kworld SBTVD.
+        * So, this hack is needed, in order to make Kworld SBTVD to work.
+        */
+       if (state->need_init)
+               mb86a20s_initfe(fe);
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
        rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
index 122c728..9fc1dd0 100644 (file)
@@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
        {
                ca_slot_info_t *info=(ca_slot_info_t *)parg;
 
-               if (info->num > 1)
+               if (info->num < 0 || info->num > 1)
                        return -EINVAL;
                av7110->ci_slot[info->num].num = info->num;
                av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
index 3c5a473..ecdffa6 100644 (file)
@@ -151,20 +151,6 @@ config RADIO_GEMTEK_PROBE
          following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
          0x28c.
 
-config RADIO_GEMTEK_PCI
-       tristate "GemTek PCI Radio Card support"
-       depends on VIDEO_V4L2 && PCI
-       ---help---
-         Choose Y here if you have this PCI FM radio card.
-
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video for Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-gemtek-pci.
-
 config RADIO_MAXIRADIO
        tristate "Guillemot MAXI Radio FM 2000 radio"
        depends on VIDEO_V4L2 && PCI
index d297074..717656d 100644 (file)
@@ -13,7 +13,6 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
-obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
index 6cc5d13..4ce10db 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
+#include <linux/delay.h>       /* msleep                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
deleted file mode 100644 (file)
index 28fa85b..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- ***************************************************************************
- *
- *     radio-gemtek-pci.c - Gemtek PCI Radio driver
- *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
- *
- ***************************************************************************
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of
- *     the License, or (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this program; if not, write to the Free
- *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- *     USA.
- *
- ***************************************************************************
- *
- *     Gemtek Corp still silently refuses to release any specifications
- *     of their multimedia devices, so the protocol still has to be
- *     reverse engineered.
- *
- *     The v4l code was inspired by Jonas Munsin's  Gemtek serial line
- *     radio device driver.
- *
- *     Please, let me know if this piece of code was useful :)
- *
- *     TODO: multiple device support and portability were not tested
- *
- *     Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- ***************************************************************************
- */
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/errno.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
-MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
-MODULE_LICENSE("GPL");
-
-static int nr_radio = -1;
-static int mx = 1;
-
-module_param(mx, bool, 0);
-MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
-module_param(nr_radio, int, 0);
-MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
-#ifndef PCI_VENDOR_ID_GEMTEK
-#define PCI_VENDOR_ID_GEMTEK 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GEMTEK_PR103
-#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_LOW
-#define GEMTEK_PCI_RANGE_LOW (87*16000)
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_HIGH
-#define GEMTEK_PCI_RANGE_HIGH (108*16000)
-#endif
-
-struct gemtek_pci {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct mutex lock;
-       struct pci_dev *pdev;
-
-       u32 iobase;
-       u32 length;
-
-       u32 current_frequency;
-       u8  mute;
-};
-
-static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
-{
-       return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
-}
-
-static inline u8 gemtek_pci_out(u16 value, u32 port)
-{
-       outw(value, port);
-
-       return (u8)value;
-}
-
-#define _b0(v) (*((u8 *)&v))
-
-static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
-{
-       u8 byte = *last_byte;
-
-       if (!value) {
-               if (!keep)
-                       value = (u16)port;
-               byte &= 0xfd;
-       } else
-               byte |= 2;
-
-       _b0(value) = byte;
-       outw(value, port);
-       byte |= 1;
-       _b0(value) = byte;
-       outw(value, port);
-       byte &= 0xfe;
-       _b0(value) = byte;
-       outw(value, port);
-
-       *last_byte = byte;
-}
-
-static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
-{
-       __gemtek_pci_cmd(0x00, port, last_byte, false);
-}
-
-static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
-{
-       __gemtek_pci_cmd(cmd, port, last_byte, true);
-}
-
-static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
-{
-       int i;
-       u32 value = frequency / 200 + 856;
-       u16 mask = 0x8000;
-       u8 last_byte;
-       u32 port = card->iobase;
-
-       mutex_lock(&card->lock);
-       card->current_frequency = frequency;
-       last_byte = gemtek_pci_out(0x06, port);
-
-       i = 0;
-       do {
-               gemtek_pci_nil(port, &last_byte);
-               i++;
-       } while (i < 9);
-
-       i = 0;
-       do {
-               gemtek_pci_cmd(value & mask, port, &last_byte);
-               mask >>= 1;
-               i++;
-       } while (i < 16);
-
-       outw(0x10, port);
-       mutex_unlock(&card->lock);
-}
-
-
-static void gemtek_pci_mute(struct gemtek_pci *card)
-{
-       mutex_lock(&card->lock);
-       outb(0x1f, card->iobase);
-       card->mute = true;
-       mutex_unlock(&card->lock);
-}
-
-static void gemtek_pci_unmute(struct gemtek_pci *card)
-{
-       if (card->mute) {
-               gemtek_pci_setfrequency(card, card->current_frequency);
-               card->mute = false;
-       }
-}
-
-static int gemtek_pci_getsignal(struct gemtek_pci *card)
-{
-       int sig;
-
-       mutex_lock(&card->lock);
-       sig = (inb(card->iobase) & 0x08) ? 0 : 1;
-       mutex_unlock(&card->lock);
-       return sig;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
-                                       struct v4l2_capability *v)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
-       strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
-       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = GEMTEK_PCI_RANGE_LOW;
-       v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xffff * gemtek_pci_getsignal(card);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
-           f->frequency > GEMTEK_PCI_RANGE_HIGH)
-               return -EINVAL;
-       gemtek_pci_setfrequency(card, f->frequency);
-       card->mute = false;
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = card->current_frequency;
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = card->mute;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (card->mute)
-                       ctrl->value = 0;
-               else
-                       ctrl->value = 65535;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct gemtek_pci *card = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       gemtek_pci_mute(card);
-               else
-                       gemtek_pci_unmute(card);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (ctrl->value)
-                       gemtek_pci_unmute(card);
-               else
-                       gemtek_pci_mute(card);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-enum {
-       GEMTEK_PR103
-};
-
-static char *card_names[] __devinitdata = {
-       "GEMTEK_PR103"
-};
-
-static struct pci_device_id gemtek_pci_id[] =
-{
-       { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
-       { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
-
-static const struct v4l2_file_operations gemtek_pci_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
-       struct gemtek_pci *card;
-       struct v4l2_device *v4l2_dev;
-       int res;
-
-       card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
-       if (card == NULL) {
-               dev_err(&pdev->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       v4l2_dev = &card->v4l2_dev;
-       mutex_init(&card->lock);
-       card->pdev = pdev;
-
-       strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
-
-       res = v4l2_device_register(&pdev->dev, v4l2_dev);
-       if (res < 0) {
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               kfree(card);
-               return res;
-       }
-
-       if (pci_enable_device(pdev))
-               goto err_pci;
-
-       card->iobase = pci_resource_start(pdev, 0);
-       card->length = pci_resource_len(pdev, 0);
-
-       if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
-               v4l2_err(v4l2_dev, "i/o port already in use\n");
-               goto err_pci;
-       }
-
-       strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
-       card->vdev.v4l2_dev = v4l2_dev;
-       card->vdev.fops = &gemtek_pci_fops;
-       card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
-       card->vdev.release = video_device_release_empty;
-       video_set_drvdata(&card->vdev, card);
-
-       gemtek_pci_mute(card);
-
-       if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
-               goto err_video;
-
-       v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
-               pdev->revision, card->iobase, card->iobase + card->length - 1);
-
-       return 0;
-
-err_video:
-       release_region(card->iobase, card->length);
-
-err_pci:
-       v4l2_device_unregister(v4l2_dev);
-       kfree(card);
-       return -ENODEV;
-}
-
-static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
-
-       video_unregister_device(&card->vdev);
-       v4l2_device_unregister(v4l2_dev);
-
-       release_region(card->iobase, card->length);
-
-       if (mx)
-               gemtek_pci_mute(card);
-
-       kfree(card);
-}
-
-static struct pci_driver gemtek_pci_driver = {
-       .name           = "gemtek_pci",
-       .id_table       = gemtek_pci_id,
-       .probe          = gemtek_pci_probe,
-       .remove         = __devexit_p(gemtek_pci_remove),
-};
-
-static int __init gemtek_pci_init(void)
-{
-       return pci_register_driver(&gemtek_pci_driver);
-}
-
-static void __exit gemtek_pci_exit(void)
-{
-       pci_unregister_driver(&gemtek_pci_driver);
-}
-
-module_init(gemtek_pci_init);
-module_exit(gemtek_pci_exit);
index 6459a22..5c2a905 100644 (file)
@@ -77,8 +77,8 @@ MODULE_PARM_DESC(debug, "activates debug info");
 /* TEA5757 pin mappings */
 static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
 
-#define FREQ_LO                (50 * 16000)
-#define FREQ_HI                (150 * 16000)
+#define FREQ_LO                (87 * 16000)
+#define FREQ_HI                (108 * 16000)
 
 #define FREQ_IF         171200 /* 10.7*16000   */
 #define FREQ_STEP       200    /* 12.5*16      */
index dd6bd36..7ecc8e6 100644 (file)
@@ -1407,7 +1407,7 @@ static const struct v4l2_file_operations wl1273_fops = {
        .read           = wl1273_fm_fops_read,
        .write          = wl1273_fm_fops_write,
        .poll           = wl1273_fm_fops_poll,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
        .open           = wl1273_fm_fops_open,
        .release        = wl1273_fm_fops_release,
 };
index ac76dfe..60c176f 100644 (file)
@@ -357,7 +357,8 @@ int si470x_start(struct si470x_device *radio)
                goto done;
 
        /* sysconfig 1 */
-       radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+       radio->registers[SYSCONFIG1] =
+               (de << 11) & SYSCONFIG1_DE;             /* DE*/
        retval = si470x_set_register(radio, SYSCONFIG1);
        if (retval < 0)
                goto done;
@@ -687,12 +688,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        /* driver constants */
        strcpy(tuner->name, "FM");
        tuner->type = V4L2_TUNER_RADIO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
-#else
-       tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-#endif
 
        /* range limits */
        switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
@@ -718,12 +715,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
                tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
        else
                tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
        /* If there is a reliable method of detecting an RDS channel,
           then this code should check for that before setting this
           RDS subchannel. */
        tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
-#endif
 
        /* mono/stereo selector */
        if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
index 80b3c31..1ac4913 100644 (file)
@@ -446,27 +446,27 @@ static void ene_rx_setup(struct ene_device *dev)
 
 select_timeout:
        if (dev->rx_fan_input_inuse) {
-               dev->rdev->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
+               dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
 
                /* Fan input doesn't support timeouts, it just ends the
                        input with a maximum sample */
                dev->rdev->min_timeout = dev->rdev->max_timeout =
-                       MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+                       US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
                                ENE_FW_SAMPLE_PERIOD_FAN);
        } else {
-               dev->rdev->rx_resolution = MS_TO_NS(sample_period);
+               dev->rdev->rx_resolution = US_TO_NS(sample_period);
 
                /* Theoreticly timeout is unlimited, but we cap it
                 * because it was seen that on one device, it
                 * would stop sending spaces after around 250 msec.
                 * Besides, this is close to 2^32 anyway and timeout is u32.
                 */
-               dev->rdev->min_timeout = MS_TO_NS(127 * sample_period);
-               dev->rdev->max_timeout = MS_TO_NS(200000);
+               dev->rdev->min_timeout = US_TO_NS(127 * sample_period);
+               dev->rdev->max_timeout = US_TO_NS(200000);
        }
 
        if (dev->hw_learning_and_tx_capable)
-               dev->rdev->tx_resolution = MS_TO_NS(sample_period);
+               dev->rdev->tx_resolution = US_TO_NS(sample_period);
 
        if (dev->rdev->timeout > dev->rdev->max_timeout)
                dev->rdev->timeout = dev->rdev->max_timeout;
@@ -801,7 +801,7 @@ static irqreturn_t ene_isr(int irq, void *data)
 
                dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
 
-               ev.duration = MS_TO_NS(hw_sample);
+               ev.duration = US_TO_NS(hw_sample);
                ev.pulse = pulse;
                ir_raw_event_store_with_filter(dev->rdev, &ev);
        }
@@ -821,7 +821,7 @@ static void ene_setup_default_settings(struct ene_device *dev)
        dev->learning_mode_enabled = learning_mode_force;
 
        /* Set reasonable default timeout */
-       dev->rdev->timeout = MS_TO_NS(150000);
+       dev->rdev->timeout = US_TO_NS(150000);
 }
 
 /* Upload all hardware settings at once. Used at load and resume time */
@@ -1004,6 +1004,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        /* validate resources */
        error = -ENODEV;
 
+       /* init these to -1, as 0 is valid for both */
+       dev->hw_io = -1;
+       dev->irq = -1;
+
        if (!pnp_port_valid(pnp_dev, 0) ||
            pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
                goto error;
@@ -1072,6 +1076,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
                rdev->input_name = "ENE eHome Infrared Remote Transceiver";
        }
 
+       dev->rdev = rdev;
+
        ene_rx_setup_hw_buffer(dev);
        ene_setup_default_settings(dev);
        ene_setup_hw_settings(dev);
@@ -1083,7 +1089,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        if (error < 0)
                goto error;
 
-       dev->rdev = rdev;
        ene_notice("driver has been succesfully loaded");
        return 0;
 error:
index c179baf..337a41d 100644 (file)
 #define dbg_verbose(format, ...)       __dbg(2, format, ## __VA_ARGS__)
 #define dbg_regs(format, ...)          __dbg(3, format, ## __VA_ARGS__)
 
-#define MS_TO_NS(msec) ((msec) * 1000)
-
 struct ene_device {
        struct pnp_dev *pnp_dev;
        struct rc_dev *rdev;
index 6811512..e7dc6b4 100644 (file)
@@ -988,7 +988,6 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
        int retval;
        struct imon_context *ictx = rc->priv;
        struct device *dev = ictx->dev;
-       bool pad_mouse;
        unsigned char ir_proto_packet[] = {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
 
@@ -1000,29 +999,20 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
        case RC_TYPE_RC6:
                dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
                ir_proto_packet[0] = 0x01;
-               pad_mouse = false;
                break;
        case RC_TYPE_UNKNOWN:
        case RC_TYPE_OTHER:
                dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
-               if (pad_stabilize && !nomouse)
-                       pad_mouse = true;
-               else {
+               if (!pad_stabilize)
                        dev_dbg(dev, "PAD stabilize functionality disabled\n");
-                       pad_mouse = false;
-               }
                /* ir_proto_packet[0] = 0x00; // already the default */
                rc_type = RC_TYPE_OTHER;
                break;
        default:
                dev_warn(dev, "Unsupported IR protocol specified, overriding "
                         "to iMON IR protocol\n");
-               if (pad_stabilize && !nomouse)
-                       pad_mouse = true;
-               else {
+               if (!pad_stabilize)
                        dev_dbg(dev, "PAD stabilize functionality disabled\n");
-                       pad_mouse = false;
-               }
                /* ir_proto_packet[0] = 0x00; // already the default */
                rc_type = RC_TYPE_OTHER;
                break;
@@ -1035,7 +1025,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
                goto out;
 
        ictx->rc_type = rc_type;
-       ictx->pad_mouse = pad_mouse;
+       ictx->pad_mouse = false;
 
 out:
        return retval;
@@ -1517,7 +1507,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
                        spin_unlock_irqrestore(&ictx->kc_lock, flags);
                        return;
                } else {
-                       ictx->pad_mouse = 0;
+                       ictx->pad_mouse = false;
                        dev_dbg(dev, "mouse mode disabled, passing key value\n");
                }
        }
@@ -1756,7 +1746,6 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
        printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
 
        ictx->display_type = detected_display_type;
-       ictx->rdev->allowed_protos = allowed_protos;
        ictx->rc_type = allowed_protos;
 }
 
@@ -1839,10 +1828,6 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
        rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
        rdev->change_protocol = imon_ir_change_protocol;
        rdev->driver_name = MOD_NAME;
-       if (ictx->rc_type == RC_TYPE_RC6)
-               rdev->map_name = RC_MAP_IMON_MCE;
-       else
-               rdev->map_name = RC_MAP_IMON_PAD;
 
        /* Enable front-panel buttons and/or knobs */
        memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
@@ -1851,11 +1836,18 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
        if (ret)
                dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
 
-       if (ictx->product == 0xffdc)
+       if (ictx->product == 0xffdc) {
                imon_get_ffdc_type(ictx);
+               rdev->allowed_protos = ictx->rc_type;
+       }
 
        imon_set_display_type(ictx);
 
+       if (ictx->rc_type == RC_TYPE_RC6)
+               rdev->map_name = RC_MAP_IMON_MCE;
+       else
+               rdev->map_name = RC_MAP_IMON_PAD;
+
        ret = rc_register_device(rdev);
        if (ret < 0) {
                dev_err(ictx->dev, "remote input dev register failed\n");
@@ -2108,18 +2100,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
                goto find_endpoint_failed;
        }
 
-       ictx->idev = imon_init_idev(ictx);
-       if (!ictx->idev) {
-               dev_err(dev, "%s: input device setup failed\n", __func__);
-               goto idev_setup_failed;
-       }
-
-       ictx->rdev = imon_init_rdev(ictx);
-       if (!ictx->rdev) {
-               dev_err(dev, "%s: rc device setup failed\n", __func__);
-               goto rdev_setup_failed;
-       }
-
        usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
                usb_rcvintpipe(ictx->usbdev_intf0,
                        ictx->rx_endpoint_intf0->bEndpointAddress),
@@ -2133,13 +2113,25 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
                goto urb_submit_failed;
        }
 
+       ictx->idev = imon_init_idev(ictx);
+       if (!ictx->idev) {
+               dev_err(dev, "%s: input device setup failed\n", __func__);
+               goto idev_setup_failed;
+       }
+
+       ictx->rdev = imon_init_rdev(ictx);
+       if (!ictx->rdev) {
+               dev_err(dev, "%s: rc device setup failed\n", __func__);
+               goto rdev_setup_failed;
+       }
+
        return ictx;
 
-urb_submit_failed:
-       rc_unregister_device(ictx->rdev);
 rdev_setup_failed:
        input_unregister_device(ictx->idev);
 idev_setup_failed:
+       usb_kill_urb(ictx->rx_urb_intf0);
+urb_submit_failed:
 find_endpoint_failed:
        mutex_unlock(&ictx->lock);
        usb_free_urb(tx_urb);
index f011c5d..1c5cc65 100644 (file)
@@ -1,4 +1,4 @@
-/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+/* ir-lirc-codec.c - rc-core to classic lirc interface bridge
  *
  * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
  *
@@ -47,6 +47,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
        /* Carrier reports */
        if (ev.carrier_report) {
                sample = LIRC_FREQUENCY(ev.carrier);
+               IR_dprintk(2, "carrier report (freq: %d)\n", sample);
 
        /* Packet end */
        } else if (ev.timeout) {
@@ -62,6 +63,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
                        return 0;
 
                sample = LIRC_TIMEOUT(ev.duration / 1000);
+               IR_dprintk(2, "timeout report (duration: %d)\n", sample);
 
        /* Normal sample */
        } else {
@@ -85,6 +87,8 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
                sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
                                        LIRC_SPACE(ev.duration / 1000);
+               IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
+                          TO_US(ev.duration), TO_STR(ev.pulse));
        }
 
        lirc_buffer_write(dev->raw->lirc.drv->rbuf,
index 185badd..73230ff 100644 (file)
@@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
 /* used internally by the sysfs interface */
 u64
-ir_raw_get_allowed_protocols()
+ir_raw_get_allowed_protocols(void)
 {
        u64 protocols;
        mutex_lock(&ir_raw_handler_lock);
index c59851b..7a5f530 100644 (file)
 
 static struct rc_map_table dib0700_nec_table[] = {
        /* Key codes for the Pixelview SBTVD remote */
-       { 0x8613, KEY_MUTE },
-       { 0x8612, KEY_POWER },
-       { 0x8601, KEY_1 },
-       { 0x8602, KEY_2 },
-       { 0x8603, KEY_3 },
-       { 0x8604, KEY_4 },
-       { 0x8605, KEY_5 },
-       { 0x8606, KEY_6 },
-       { 0x8607, KEY_7 },
-       { 0x8608, KEY_8 },
-       { 0x8609, KEY_9 },
-       { 0x8600, KEY_0 },
-       { 0x860d, KEY_CHANNELUP },
-       { 0x8619, KEY_CHANNELDOWN },
-       { 0x8610, KEY_VOLUMEUP },
-       { 0x860c, KEY_VOLUMEDOWN },
+       { 0x866b13, KEY_MUTE },
+       { 0x866b12, KEY_POWER },
+       { 0x866b01, KEY_1 },
+       { 0x866b02, KEY_2 },
+       { 0x866b03, KEY_3 },
+       { 0x866b04, KEY_4 },
+       { 0x866b05, KEY_5 },
+       { 0x866b06, KEY_6 },
+       { 0x866b07, KEY_7 },
+       { 0x866b08, KEY_8 },
+       { 0x866b09, KEY_9 },
+       { 0x866b00, KEY_0 },
+       { 0x866b0d, KEY_CHANNELUP },
+       { 0x866b19, KEY_CHANNELDOWN },
+       { 0x866b10, KEY_VOLUMEUP },
+       { 0x866b0c, KEY_VOLUMEDOWN },
 
-       { 0x860a, KEY_CAMERA },
-       { 0x860b, KEY_ZOOM },
-       { 0x861b, KEY_BACKSPACE },
-       { 0x8615, KEY_ENTER },
+       { 0x866b0a, KEY_CAMERA },
+       { 0x866b0b, KEY_ZOOM },
+       { 0x866b1b, KEY_BACKSPACE },
+       { 0x866b15, KEY_ENTER },
 
-       { 0x861d, KEY_UP },
-       { 0x861e, KEY_DOWN },
-       { 0x860e, KEY_LEFT },
-       { 0x860f, KEY_RIGHT },
+       { 0x866b1d, KEY_UP },
+       { 0x866b1e, KEY_DOWN },
+       { 0x866b0e, KEY_LEFT },
+       { 0x866b0f, KEY_RIGHT },
 
-       { 0x8618, KEY_RECORD },
-       { 0x861a, KEY_STOP },
+       { 0x866b18, KEY_RECORD },
+       { 0x866b1a, KEY_STOP },
 
        /* Key codes for the EvolutePC TVWay+ remote */
        { 0x7a00, KEY_MENU },
index 3bf3337..2f5dc06 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
  *
+ * See http://mediacenterguides.com/book/export/html/31 for details on
+ * key mappings.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -60,6 +63,9 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f0426, KEY_EPG },                /* Guide */
        { 0x800f0427, KEY_ZOOM },               /* Aspect */
 
+       { 0x800f0432, KEY_MODE },               /* Visualization */
+       { 0x800f0433, KEY_PRESENTATION },       /* Slide Show */
+       { 0x800f0434, KEY_EJECTCD },
        { 0x800f043a, KEY_BRIGHTNESSUP },
 
        { 0x800f0446, KEY_TV },
index 0fef6ef..6df0a49 100644 (file)
@@ -48,7 +48,6 @@
 #define USB_BUFLEN             32 /* USB reception buffer length */
 #define USB_CTRL_MSG_SZ                2  /* Size of usb ctrl msg on gen1 hw */
 #define MCE_G1_INIT_MSGS       40 /* Init messages on gen1 hw to throw out */
-#define MS_TO_NS(msec)         ((msec) * 1000)
 
 /* MCE constants */
 #define MCE_CMDBUF_SIZE                384  /* MCE Command buffer length */
@@ -817,7 +816,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
        switch (ir->buf_in[index]) {
        /* 2-byte return value commands */
        case MCE_CMD_S_TIMEOUT:
-               ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2);
+               ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2);
                break;
 
        /* 1-byte return value commands */
@@ -856,9 +855,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                        break;
                case PARSE_IRDATA:
                        ir->rem--;
+                       init_ir_raw_event(&rawir);
                        rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
                        rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
-                                        * MS_TO_NS(MCE_TIME_UNIT);
+                                        * US_TO_NS(MCE_TIME_UNIT);
 
                        dev_dbg(ir->dev, "Storing %s with duration %d\n",
                                rawir.pulse ? "pulse" : "space",
@@ -884,6 +884,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                                             i, ir->rem + 1, false);
                        if (ir->rem)
                                ir->parser_state = PARSE_IRDATA;
+                       else
+                               ir_raw_event_reset(ir->rc);
                        break;
                }
 
@@ -1061,7 +1063,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
        rc->priv = ir;
        rc->driver_type = RC_DRIVER_IR_RAW;
        rc->allowed_protos = RC_TYPE_ALL;
-       rc->timeout = MS_TO_NS(1000);
+       rc->timeout = US_TO_NS(1000);
        if (!ir->flags.no_tx) {
                rc->s_tx_mask = mceusb_set_tx_mask;
                rc->s_tx_carrier = mceusb_set_tx_carrier;
index dd4caf8..273d9d6 100644 (file)
@@ -460,7 +460,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
                return 0;
        }
 
-       carrier = (count * 1000000) / duration;
+       carrier = MS_TO_NS(count) / duration;
 
        if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
                nvt_dbg("WTF? Carrier frequency out of range!");
@@ -612,8 +612,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
                sample = nvt->buf[i];
 
                rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
-               rawir.duration = (sample & BUF_LEN_MASK)
-                                       * SAMPLE_PERIOD * 1000;
+               rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
+                                         * SAMPLE_PERIOD);
 
                if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
                        if (nvt->rawir.pulse == rawir.pulse)
index 72be8a0..512a2f4 100644 (file)
@@ -458,21 +458,27 @@ static int ir_getkeycode(struct input_dev *idev,
                index = ir_lookup_by_scancode(rc_map, scancode);
        }
 
-       if (index >= rc_map->len) {
-               if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
-                       IR_dprintk(1, "unknown key for scancode 0x%04x\n",
-                                  scancode);
+       if (index < rc_map->len) {
+               entry = &rc_map->scan[index];
+
+               ke->index = index;
+               ke->keycode = entry->keycode;
+               ke->len = sizeof(entry->scancode);
+               memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+       } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
+               /*
+                * We do not really know the valid range of scancodes
+                * so let's respond with KEY_RESERVED to anything we
+                * do not have mapping for [yet].
+                */
+               ke->index = index;
+               ke->keycode = KEY_RESERVED;
+       } else {
                retval = -EINVAL;
                goto out;
        }
 
-       entry = &rc_map->scan[index];
-
-       ke->index = index;
-       ke->keycode = entry->keycode;
-       ke->len = sizeof(entry->scancode);
-       memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
-
        retval = 0;
 
 out:
index 6e2911c..e435d94 100644 (file)
@@ -164,7 +164,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
                                sz->signal_start.tv_usec -
                                sz->signal_last.tv_usec);
                        rawir.duration -= sz->sum;
-                       rawir.duration *= 1000;
+                       rawir.duration = US_TO_NS(rawir.duration);
                        rawir.duration &= IR_MAX_DURATION;
                }
                sz_push(sz, rawir);
@@ -177,7 +177,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
        rawir.duration = ((int) value) * SZ_RESOLUTION;
        rawir.duration += SZ_RESOLUTION / 2;
        sz->sum += rawir.duration;
-       rawir.duration *= 1000;
+       rawir.duration = US_TO_NS(rawir.duration);
        rawir.duration &= IR_MAX_DURATION;
        sz_push(sz, rawir);
 }
@@ -197,7 +197,7 @@ static void sz_push_full_space(struct streamzap_ir *sz,
        rawir.duration = ((int) value) * SZ_RESOLUTION;
        rawir.duration += SZ_RESOLUTION / 2;
        sz->sum += rawir.duration;
-       rawir.duration *= 1000;
+       rawir.duration = US_TO_NS(rawir.duration);
        sz_push(sz, rawir);
 }
 
@@ -273,6 +273,7 @@ static void streamzap_callback(struct urb *urb)
                                if (sz->timeout_enabled)
                                        sz_push(sz, rawir);
                                ir_raw_event_handle(sz->rdev);
+                               ir_raw_event_reset(sz->rdev);
                        } else {
                                sz_push_full_space(sz, sz->buf_in[i]);
                        }
@@ -290,6 +291,7 @@ static void streamzap_callback(struct urb *urb)
                }
        }
 
+       ir_raw_event_handle(sz->rdev);
        usb_submit_urb(urb, GFP_ATOMIC);
 
        return;
@@ -430,13 +432,13 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
        sz->decoder_state = PulseSpace;
        /* FIXME: don't yet have a way to set this */
        sz->timeout_enabled = true;
-       sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
+       sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) &
                                IR_MAX_DURATION) | 0x03000000);
        #if 0
        /* not yet supported, depends on patches from maxim */
        /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
-       sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
-       sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+       sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
+       sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
        #endif
 
        do_gettimeofday(&sz->signal_start);
index eb875af..aa02160 100644 (file)
@@ -78,7 +78,7 @@ config VIDEO_FIXED_MINOR_RANGES
 
 config VIDEO_HELPER_CHIPS_AUTO
        bool "Autoselect pertinent encoders/decoders and other helper chips"
-       default y if !EMBEDDED
+       default y if !EXPERT
        ---help---
          Most video cards may require additional modules to encode or
          decode audio/video standards. This option will autoselect
@@ -141,15 +141,6 @@ config VIDEO_TDA9840
          To compile this driver as a module, choose M here: the
          module will be called tda9840.
 
-config VIDEO_TDA9875
-       tristate "Philips TDA9875 audio processor"
-       depends on VIDEO_V4L2 && I2C
-       ---help---
-         Support for tda9875 audio decoder chip found on some bt8xx boards.
-
-         To compile this driver as a module, choose M here: the
-         module will be called tda9875.
-
 config VIDEO_TEA6415C
        tristate "Philips TEA6415C audio processor"
        depends on I2C
index 81e38cb..a509d31 100644 (file)
@@ -27,7 +27,6 @@ obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
-obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
index f318b51..d2327db 100644 (file)
@@ -303,11 +303,22 @@ static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
 }
 
+static int adv7175_s_power(struct v4l2_subdev *sd, int on)
+{
+       if (on)
+               adv7175_write(sd, 0x01, 0x00);
+       else
+               adv7175_write(sd, 0x01, 0x78);
+
+       return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops adv7175_core_ops = {
        .g_chip_ident = adv7175_g_chip_ident,
        .init = adv7175_init,
+       .s_power = adv7175_s_power,
 };
 
 static const struct v4l2_subdev_video_ops adv7175_video_ops = {
index 49efcf6..7f58756 100644 (file)
@@ -1373,7 +1373,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x1800,
                .audio_mode_gpio= fv2000s_audio,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
@@ -1511,7 +1510,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x09,
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
@@ -1550,7 +1548,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask2      = 0x07ff,
                .muxsel         = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .muxsel_hook    = rv605_muxsel,
@@ -1686,7 +1683,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY1x0_848] = {
@@ -1699,7 +1695,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
 
@@ -1714,7 +1709,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY1x1] = {
@@ -1727,7 +1721,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY1x1_SVID] = {
@@ -1740,7 +1733,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY2xx] = {
@@ -1753,7 +1745,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
 
@@ -1768,7 +1759,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY2x0] = {
@@ -1781,7 +1771,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY500] = {
@@ -1794,7 +1783,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY540] = {
@@ -1805,7 +1793,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
 
@@ -1820,7 +1807,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
        },
        [BTTV_BOARD_IDS_EAGLE] = {
@@ -1835,7 +1821,6 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = MUXSEL(2, 2, 2, 2),
                .muxsel_hook    = eagle_muxsel,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .pll            = PLL_28,
        },
        [BTTV_BOARD_PINNACLESAT] = {
@@ -1846,7 +1831,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .muxsel         = MUXSEL(3, 1),
                .pll            = PLL_28,
@@ -1897,7 +1881,6 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = 2,
                .gpiomask       = 0,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .muxsel         = MUXSEL(2, 0, 1),
                .pll            = PLL_28,
@@ -1970,7 +1953,6 @@ struct tvcard bttv_tvcards[] = {
                /* Tuner, CVid, SVid, CVid over SVid connector */
                .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomask       = 0,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
@@ -2017,7 +1999,6 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
                .muxsel_hook    = xguard_muxsel,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
        },
@@ -2029,7 +2010,6 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = NO_SVHS,
                .muxsel         = MUXSEL(2, 3, 1, 0),
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_ABSENT,
@@ -2134,7 +2114,6 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = NO_SVHS,   /* card has no svhs */
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .gpiomask       = 0x00,
                .muxsel         = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -2156,7 +2135,6 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_TWINHAN_DST] = {
                .name           = "Twinhan DST + clones",
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
@@ -2171,7 +2149,6 @@ struct tvcard bttv_tvcards[] = {
                /* Vid In, SVid In, Vid over SVid in connector */
                .muxsel         = MUXSEL(3, 1, 1, 3),
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
@@ -2226,7 +2203,6 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = NO_SVHS,
                .muxsel         = MUXSEL(2, 3, 1, 0),
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .needs_tvaudio  = 0,
                .tuner_type     = TUNER_ABSENT,
@@ -2278,7 +2254,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0,
                .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                /*878A input is always MUX0, see above.*/
                .muxsel         = MUXSEL(2, 2, 2, 2),
@@ -2302,7 +2277,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
        },
        [BTTV_BOARD_AVDVBT_771] = {
                /* Wolfram Joost <wojo@frokaschwei.de> */
@@ -2313,7 +2287,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_addr     = ADDR_UNSET,
                .muxsel         = MUXSEL(3, 3),
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .has_dvb        = 1,
@@ -2329,7 +2302,6 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = 1,
                .muxsel         = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_ABSENT,
@@ -2393,7 +2365,6 @@ struct tvcard bttv_tvcards[] = {
                /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
                .name           = "DViCO FusionHDTV DVB-T Lite",
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .no_video       = 1,
@@ -2440,7 +2411,6 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
                .pll            = PLL_28,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
@@ -2478,7 +2448,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
-               .no_tda9875     = 1,
                .muxsel_hook    = kodicom4400r_muxsel,
        },
        [BTTV_BOARD_KODICOM_4400R_SL] = {
@@ -2500,7 +2469,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
-               .no_tda9875     = 1,
                .muxsel_hook    = kodicom4400r_muxsel,
        },
                /* ---- card 0x86---------------------------------- */
@@ -2530,7 +2498,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
                .gpiomute       = 0x00c00007,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .has_dvb        = 1,
        },
@@ -2630,7 +2597,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
                /* ---- card 0x8d ---------------------------------- */
@@ -2658,7 +2624,6 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = MUXSEL(2, 3, 1, 1),
                .gpiomux        = { 100000, 100002, 100002, 100000 },
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .tuner_type     = TUNER_TNF_5335MF,
@@ -2674,7 +2639,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0x0f, /* old: 7 */
                .muxsel         = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
@@ -2732,7 +2696,6 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
                .gpiomute       = 0x00c00007,
                .no_msp34xx     = 1,
-               .no_tda9875     = 1,
                .no_tda7432     = 1,
        },
        /* ---- card 0x95---------------------------------- */
@@ -2874,7 +2837,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
-               .no_tda9875     = 1,
                .muxsel_hook    = gv800s_muxsel,
        },
                [BTTV_BOARD_GEOVISION_GV800S_SL] = {
@@ -2899,7 +2861,6 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda7432     = 1,
-               .no_tda9875     = 1,
                .muxsel_hook    = gv800s_muxsel,
        },
        [BTTV_BOARD_PV183] = {
index fd62bf1..c633359 100644 (file)
@@ -234,7 +234,6 @@ struct tvcard {
 
        /* i2c audio flags */
        unsigned int no_msp34xx:1;
-       unsigned int no_tda9875:1;
        unsigned int no_tda7432:1;
        unsigned int needs_tvaudio:1;
        unsigned int msp34xx_alt:1;
index 49f1b8f..55ffd60 100644 (file)
@@ -2001,6 +2001,11 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                .min_width = 320,
                .min_height = 240,
        };
+       struct i2c_board_info ov7670_info = {
+               .type = "ov7670",
+               .addr = 0x42,
+               .platform_data = &sensor_cfg,
+       };
 
        /*
         * Start putting together one of our big camera structures.
@@ -2062,9 +2067,9 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        if (dmi_check_system(olpc_xo1_dmi))
                sensor_cfg.clock_speed = 45;
 
-       cam->sensor_addr = 0x42;
-       cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
-                       "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
+       cam->sensor_addr = ov7670_info.addr;
+       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter,
+                       &ov7670_info, NULL);
        if (cam->sensor == NULL) {
                ret = -ENODEV;
                goto out_smbus;
index 916c13d..6d6d184 100644 (file)
@@ -378,7 +378,7 @@ struct cpia2_fh {
 
 struct camera_data {
        /* locks */
-       struct mutex busy_lock; /* guard against SMP multithreading */
+       struct mutex v4l2_lock; /* serialize file operations */
        struct v4l2_prio_state prio;
 
        /* camera status */
index 9606bc0..aaffca8 100644 (file)
@@ -2247,7 +2247,7 @@ struct camera_data *cpia2_init_camera_struct(void)
 
 
        cam->present = 1;
-       mutex_init(&cam->busy_lock);
+       mutex_init(&cam->v4l2_lock);
        init_waitqueue_head(&cam->wq_stream);
 
        return cam;
@@ -2365,9 +2365,9 @@ long cpia2_read(struct camera_data *cam,
                char __user *buf, unsigned long count, int noblock)
 {
        struct framebuf *frame;
-       if (!count) {
+
+       if (!count)
                return 0;
-       }
 
        if (!buf) {
                ERR("%s: buffer NULL\n",__func__);
@@ -2379,17 +2379,12 @@ long cpia2_read(struct camera_data *cam,
                return -EINVAL;
        }
 
-       /* make this _really_ smp and multithread-safe */
-       if (mutex_lock_interruptible(&cam->busy_lock))
-               return -ERESTARTSYS;
-
        if (!cam->present) {
                LOG("%s: camera removed\n",__func__);
-               mutex_unlock(&cam->busy_lock);
                return 0;       /* EOF */
        }
 
-       if(!cam->streaming) {
+       if (!cam->streaming) {
                /* Start streaming */
                cpia2_usb_stream_start(cam,
                                       cam->params.camera_state.stream_mode);
@@ -2398,42 +2393,31 @@ long cpia2_read(struct camera_data *cam,
        /* Copy cam->curbuff in case it changes while we're processing */
        frame = cam->curbuff;
        if (noblock && frame->status != FRAME_READY) {
-               mutex_unlock(&cam->busy_lock);
                return -EAGAIN;
        }
 
-       if(frame->status != FRAME_READY) {
-               mutex_unlock(&cam->busy_lock);
+       if (frame->status != FRAME_READY) {
+               mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
                               !cam->present ||
                               (frame = cam->curbuff)->status == FRAME_READY);
+               mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               /* make this _really_ smp and multithread-safe */
-               if (mutex_lock_interruptible(&cam->busy_lock)) {
-                       return -ERESTARTSYS;
-               }
-               if(!cam->present) {
-                       mutex_unlock(&cam->busy_lock);
+               if (!cam->present)
                        return 0;
-               }
        }
 
        /* copy data to user space */
-       if (frame->length > count) {
-               mutex_unlock(&cam->busy_lock);
+       if (frame->length > count)
                return -EFAULT;
-       }
-       if (copy_to_user(buf, frame->data, frame->length)) {
-               mutex_unlock(&cam->busy_lock);
+       if (copy_to_user(buf, frame->data, frame->length))
                return -EFAULT;
-       }
 
        count = frame->length;
 
        frame->status = FRAME_EMPTY;
 
-       mutex_unlock(&cam->busy_lock);
        return count;
 }
 
@@ -2447,17 +2431,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
 {
        unsigned int status=0;
 
-       if(!cam) {
+       if (!cam) {
                ERR("%s: Internal error, camera_data not found!\n",__func__);
                return POLLERR;
        }
 
-       mutex_lock(&cam->busy_lock);
-
-       if(!cam->present) {
-               mutex_unlock(&cam->busy_lock);
+       if (!cam->present)
                return POLLHUP;
-       }
 
        if(!cam->streaming) {
                /* Start streaming */
@@ -2465,16 +2445,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
                                       cam->params.camera_state.stream_mode);
        }
 
-       mutex_unlock(&cam->busy_lock);
        poll_wait(filp, &cam->wq_stream, wait);
-       mutex_lock(&cam->busy_lock);
 
        if(!cam->present)
                status = POLLHUP;
        else if(cam->curbuff->status == FRAME_READY)
                status = POLLIN | POLLRDNORM;
 
-       mutex_unlock(&cam->busy_lock);
        return status;
 }
 
@@ -2496,29 +2473,19 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
 
        DBG("mmap offset:%ld size:%ld\n", start_offset, size);
 
-       /* make this _really_ smp-safe */
-       if (mutex_lock_interruptible(&cam->busy_lock))
-               return -ERESTARTSYS;
-
-       if (!cam->present) {
-               mutex_unlock(&cam->busy_lock);
+       if (!cam->present)
                return -ENODEV;
-       }
 
        if (size > cam->frame_size*cam->num_frames  ||
            (start_offset % cam->frame_size) != 0 ||
-           (start_offset+size > cam->frame_size*cam->num_frames)) {
-               mutex_unlock(&cam->busy_lock);
+           (start_offset+size > cam->frame_size*cam->num_frames))
                return -EINVAL;
-       }
 
        pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
        while (size > 0) {
                page = kvirt_to_pa(pos);
-               if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&cam->busy_lock);
+               if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
-               }
                start += PAGE_SIZE;
                pos += PAGE_SIZE;
                if (size > PAGE_SIZE)
@@ -2528,7 +2495,5 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
        }
 
        cam->mmapped = true;
-       mutex_unlock(&cam->busy_lock);
        return 0;
 }
-
index 7edf80b..9bad398 100644 (file)
@@ -238,59 +238,40 @@ static struct v4l2_queryctrl controls[] = {
 static int cpia2_open(struct file *file)
 {
        struct camera_data *cam = video_drvdata(file);
-       int retval = 0;
+       struct cpia2_fh *fh;
 
        if (!cam) {
                ERR("Internal error, camera_data not found!\n");
                return -ENODEV;
        }
 
-       if(mutex_lock_interruptible(&cam->busy_lock))
-               return -ERESTARTSYS;
-
-       if(!cam->present) {
-               retval = -ENODEV;
-               goto err_return;
-       }
+       if (!cam->present)
+               return -ENODEV;
 
-       if (cam->open_count > 0) {
-               goto skip_init;
-       }
+       if (cam->open_count == 0) {
+               if (cpia2_allocate_buffers(cam))
+                       return -ENOMEM;
 
-       if (cpia2_allocate_buffers(cam)) {
-               retval = -ENOMEM;
-               goto err_return;
-       }
+               /* reset the camera */
+               if (cpia2_reset_camera(cam) < 0)
+                       return -EIO;
 
-       /* reset the camera */
-       if (cpia2_reset_camera(cam) < 0) {
-               retval = -EIO;
-               goto err_return;
+               cam->APP_len = 0;
+               cam->COM_len = 0;
        }
 
-       cam->APP_len = 0;
-       cam->COM_len = 0;
-
-skip_init:
-       {
-               struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-               if(!fh) {
-                       retval = -ENOMEM;
-                       goto err_return;
-               }
-               file->private_data = fh;
-               fh->prio = V4L2_PRIORITY_UNSET;
-               v4l2_prio_open(&cam->prio, &fh->prio);
-               fh->mmapped = 0;
-       }
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if (!fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       fh->prio = V4L2_PRIORITY_UNSET;
+       v4l2_prio_open(&cam->prio, &fh->prio);
+       fh->mmapped = 0;
 
        ++cam->open_count;
 
        cpia2_dbg_dump_registers(cam);
-
-err_return:
-       mutex_unlock(&cam->busy_lock);
-       return retval;
+       return 0;
 }
 
 /******************************************************************************
@@ -304,15 +285,11 @@ static int cpia2_close(struct file *file)
        struct camera_data *cam = video_get_drvdata(dev);
        struct cpia2_fh *fh = file->private_data;
 
-       mutex_lock(&cam->busy_lock);
-
        if (cam->present &&
-           (cam->open_count == 1
-            || fh->prio == V4L2_PRIORITY_RECORD
-           )) {
+           (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
                cpia2_usb_stream_stop(cam);
 
-               if(cam->open_count == 1) {
+               if (cam->open_count == 1) {
                        /* save camera state for later open */
                        cpia2_save_camera_state(cam);
 
@@ -321,26 +298,21 @@ static int cpia2_close(struct file *file)
                }
        }
 
-       {
-               if(fh->mmapped)
-                       cam->mmapped = 0;
-               v4l2_prio_close(&cam->prio, fh->prio);
-               file->private_data = NULL;
-               kfree(fh);
-       }
+       if (fh->mmapped)
+               cam->mmapped = 0;
+       v4l2_prio_close(&cam->prio, fh->prio);
+       file->private_data = NULL;
+       kfree(fh);
 
        if (--cam->open_count == 0) {
                cpia2_free_buffers(cam);
                if (!cam->present) {
                        video_unregister_device(dev);
-                       mutex_unlock(&cam->busy_lock);
                        kfree(cam);
                        return 0;
                }
        }
 
-       mutex_unlock(&cam->busy_lock);
-
        return 0;
 }
 
@@ -405,11 +377,11 @@ static int sync(struct camera_data *cam, int frame_nr)
                        return 0;
                }
 
-               mutex_unlock(&cam->busy_lock);
+               mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
                                         !cam->streaming ||
                                         frame->status == FRAME_READY);
-               mutex_lock(&cam->busy_lock);
+               mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                if(!cam->present)
@@ -1293,11 +1265,11 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
        if(frame < 0) {
                /* Wait for a frame to become available */
                struct framebuf *cb=cam->curbuff;
-               mutex_unlock(&cam->busy_lock);
+               mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
                                         !cam->present ||
                                         (cb=cam->curbuff)->status == FRAME_READY);
-               mutex_lock(&cam->busy_lock);
+               mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                if(!cam->present)
@@ -1337,14 +1309,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        if (!cam)
                return -ENOTTY;
 
-       /* make this _really_ smp-safe */
-       if (mutex_lock_interruptible(&cam->busy_lock))
-               return -ERESTARTSYS;
-
-       if (!cam->present) {
-               mutex_unlock(&cam->busy_lock);
+       if (!cam->present)
                return -ENODEV;
-       }
 
        /* Priority check */
        switch (cmd) {
@@ -1352,10 +1318,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct cpia2_fh *fh = file->private_data;
                retval = v4l2_prio_check(&cam->prio, fh->prio);
-               if(retval) {
-                       mutex_unlock(&cam->busy_lock);
+               if (retval)
                        return retval;
-               }
                break;
        }
        default:
@@ -1529,7 +1493,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                break;
        }
 
-       mutex_unlock(&cam->busy_lock);
        return retval;
 }
 
@@ -1596,7 +1559,7 @@ static const struct v4l2_file_operations cpia2_fops = {
        .release        = cpia2_close,
        .read           = cpia2_v4l_read,
        .poll           = cpia2_v4l_poll,
-       .ioctl          = cpia2_ioctl,
+       .unlocked_ioctl = cpia2_ioctl,
        .mmap           = cpia2_mmap,
 };
 
@@ -1620,6 +1583,7 @@ int cpia2_register_camera(struct camera_data *cam)
 
        memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
        video_set_drvdata(cam->vdev, cam);
+       cam->vdev->lock = &cam->v4l2_lock;
 
        reset_camera_struct_v4l(cam);
 
index 133ec2b..944af8a 100644 (file)
@@ -664,7 +664,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
 {
        snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
                 cx->v4l2_dev.name);
-       cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+       cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
        if (cx->in_work_queue == NULL) {
                CX18_ERR("Unable to create incoming mailbox handler thread\n");
                return -ENOMEM;
@@ -672,18 +672,6 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
        return 0;
 }
 
-static int __devinit cx18_create_out_workq(struct cx18 *cx)
-{
-       snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
-                cx->v4l2_dev.name);
-       cx->out_work_queue = create_workqueue(cx->out_workq_name);
-       if (cx->out_work_queue == NULL) {
-               CX18_ERR("Unable to create outgoing mailbox handler threads\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
 static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
 {
        int i;
@@ -710,15 +698,9 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        mutex_init(&cx->epu2apu_mb_lock);
        mutex_init(&cx->epu2cpu_mb_lock);
 
-       ret = cx18_create_out_workq(cx);
-       if (ret)
-               return ret;
-
        ret = cx18_create_in_workq(cx);
-       if (ret) {
-               destroy_workqueue(cx->out_work_queue);
+       if (ret)
                return ret;
-       }
 
        cx18_init_in_work_orders(cx);
 
@@ -1107,7 +1089,6 @@ free_mem:
        release_mem_region(cx->base_addr, CX18_MEM_SIZE);
 free_workqueues:
        destroy_workqueue(cx->in_work_queue);
-       destroy_workqueue(cx->out_work_queue);
 err:
        if (retval == 0)
                retval = -ENODEV;
@@ -1259,7 +1240,6 @@ static void cx18_remove(struct pci_dev *pci_dev)
        cx18_halt_firmware(cx);
 
        destroy_workqueue(cx->in_work_queue);
-       destroy_workqueue(cx->out_work_queue);
 
        cx18_streams_cleanup(cx, 1);
 
index f6f3e50..306caac 100644 (file)
@@ -617,9 +617,6 @@ struct cx18 {
        struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
        char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
-       struct workqueue_struct *out_work_queue;
-       char out_workq_name[12]; /* "cx18-NN-out" */
-
        /* i2c */
        struct i2c_adapter i2c_adap[2];
        struct i2c_algo_bit_data i2c_algo[2];
index 51765eb..713b0e6 100644 (file)
@@ -42,8 +42,7 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s)
 /* Related to submission of mdls to firmware */
 static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
-       struct cx18 *cx = s->cx;
-       queue_work(cx->out_work_queue, &s->out_work_order);
+       schedule_work(&s->out_work_order);
 }
 
 static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s,
index fe59a1c..363aa60 100644 (file)
@@ -28,7 +28,6 @@
 #include <media/videobuf-vmalloc.h>
 
 #include "xc5000.h"
-#include "dvb_dummy_fe.h"
 #include "s5h1432.h"
 #include "tda18271.h"
 #include "s5h1411.h"
@@ -619,7 +618,7 @@ static int dvb_init(struct cx231xx *dev)
 
                if (dev->dvb->frontend == NULL) {
                        printk(DRIVER_NAME
-                              ": Failed to attach dummy front end\n");
+                              ": Failed to attach s5h1411 front end\n");
                        result = -EINVAL;
                        goto out_free;
                }
@@ -665,7 +664,7 @@ static int dvb_init(struct cx231xx *dev)
 
                if (dev->dvb->frontend == NULL) {
                        printk(DRIVER_NAME
-                              ": Failed to attach dummy front end\n");
+                              ": Failed to attach s5h1411 front end\n");
                        result = -EINVAL;
                        goto out_free;
                }
index f164618..6fc09dd 100644 (file)
@@ -1682,20 +1682,6 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int cx25840_s_config(struct v4l2_subdev *sd, int irq, void *platform_data)
-{
-       struct cx25840_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (platform_data) {
-               struct cx25840_platform_data *pdata = platform_data;
-
-               state->pvr150_workaround = pdata->pvr150_workaround;
-               set_input(client, state->vid_input, state->aud_input);
-       }
-       return 0;
-}
-
 static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
                               bool *handled)
 {
@@ -1787,7 +1773,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops cx25840_core_ops = {
        .log_status = cx25840_log_status,
-       .s_config = cx25840_s_config,
        .g_chip_ident = cx25840_g_chip_ident,
        .g_ctrl = v4l2_subdev_g_ctrl,
        .s_ctrl = v4l2_subdev_s_ctrl,
@@ -1974,7 +1959,6 @@ static int cx25840_probe(struct i2c_client *client,
        state->vid_input = CX25840_COMPOSITE7;
        state->aud_input = CX25840_AUDIO8;
        state->audclk_freq = 48000;
-       state->pvr150_workaround = 0;
        state->audmode = V4L2_TUNER_MODE_LANG1;
        state->vbi_line_offset = 8;
        state->id = id;
@@ -2034,6 +2018,12 @@ static int cx25840_probe(struct i2c_client *client,
        v4l2_ctrl_cluster(2, &state->volume);
        v4l2_ctrl_handler_setup(&state->hdl);
 
+       if (client->dev.platform_data) {
+               struct cx25840_platform_data *pdata = client->dev.platform_data;
+
+               state->pvr150_workaround = pdata->pvr150_workaround;
+       }
+
        cx25840_ir_probe(sd);
        return 0;
 }
index 1f532e3..9f3bfc1 100644 (file)
@@ -41,6 +41,183 @@ spinlock_t vpif_lock;
 
 void __iomem *vpif_base;
 
+/**
+ * ch_params: video standard configuration parameters for vpif
+ * The table must include all presets from supported subdevices.
+ */
+const struct vpif_channel_config_params ch_params[] = {
+       /* HDTV formats */
+       {
+               .name = "480p59_94",
+               .width = 720,
+               .height = 480,
+               .frm_fmt = 1,
+               .ycmux_mode = 0,
+               .eav2sav = 138-8,
+               .sav2eav = 720,
+               .l1 = 1,
+               .l3 = 43,
+               .l5 = 523,
+               .vsize = 525,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_480P59_94,
+       },
+       {
+               .name = "576p50",
+               .width = 720,
+               .height = 576,
+               .frm_fmt = 1,
+               .ycmux_mode = 0,
+               .eav2sav = 144-8,
+               .sav2eav = 720,
+               .l1 = 1,
+               .l3 = 45,
+               .l5 = 621,
+               .vsize = 625,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_576P50,
+       },
+       {
+               .name = "720p50",
+               .width = 1280,
+               .height = 720,
+               .frm_fmt = 1,
+               .ycmux_mode = 0,
+               .eav2sav = 700-8,
+               .sav2eav = 1280,
+               .l1 = 1,
+               .l3 = 26,
+               .l5 = 746,
+               .vsize = 750,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_720P50,
+       },
+       {
+               .name = "720p60",
+               .width = 1280,
+               .height = 720,
+               .frm_fmt = 1,
+               .ycmux_mode = 0,
+               .eav2sav = 370 - 8,
+               .sav2eav = 1280,
+               .l1 = 1,
+               .l3 = 26,
+               .l5 = 746,
+               .vsize = 750,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_720P60,
+       },
+       {
+               .name = "1080I50",
+               .width = 1920,
+               .height = 1080,
+               .frm_fmt = 0,
+               .ycmux_mode = 0,
+               .eav2sav = 720 - 8,
+               .sav2eav = 1920,
+               .l1 = 1,
+               .l3 = 21,
+               .l5 = 561,
+               .l7 = 563,
+               .l9 = 584,
+               .l11 = 1124,
+               .vsize = 1125,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_1080I50,
+       },
+       {
+               .name = "1080I60",
+               .width = 1920,
+               .height = 1080,
+               .frm_fmt = 0,
+               .ycmux_mode = 0,
+               .eav2sav = 280 - 8,
+               .sav2eav = 1920,
+               .l1 = 1,
+               .l3 = 21,
+               .l5 = 561,
+               .l7 = 563,
+               .l9 = 584,
+               .l11 = 1124,
+               .vsize = 1125,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_1080I60,
+       },
+       {
+               .name = "1080p60",
+               .width = 1920,
+               .height = 1080,
+               .frm_fmt = 1,
+               .ycmux_mode = 0,
+               .eav2sav = 280 - 8,
+               .sav2eav = 1920,
+               .l1 = 1,
+               .l3 = 42,
+               .l5 = 1122,
+               .vsize = 1125,
+               .capture_format = 0,
+               .vbi_supported = 0,
+               .hd_sd = 1,
+               .dv_preset = V4L2_DV_1080P60,
+       },
+
+       /* SDTV formats */
+       {
+               .name = "NTSC_M",
+               .width = 720,
+               .height = 480,
+               .frm_fmt = 0,
+               .ycmux_mode = 1,
+               .eav2sav = 268,
+               .sav2eav = 1440,
+               .l1 = 1,
+               .l3 = 23,
+               .l5 = 263,
+               .l7 = 266,
+               .l9 = 286,
+               .l11 = 525,
+               .vsize = 525,
+               .capture_format = 0,
+               .vbi_supported = 1,
+               .hd_sd = 0,
+               .stdid = V4L2_STD_525_60,
+       },
+       {
+               .name = "PAL_BDGHIK",
+               .width = 720,
+               .height = 576,
+               .frm_fmt = 0,
+               .ycmux_mode = 1,
+               .eav2sav = 280,
+               .sav2eav = 1440,
+               .l1 = 1,
+               .l3 = 23,
+               .l5 = 311,
+               .l7 = 313,
+               .l9 = 336,
+               .l11 = 624,
+               .vsize = 625,
+               .capture_format = 0,
+               .vbi_supported = 1,
+               .hd_sd = 0,
+               .stdid = V4L2_STD_625_50,
+       },
+};
+
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+
 static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
 {
        if (val)
index ebd5c43..10550bd 100644 (file)
@@ -577,12 +577,10 @@ struct vpif_channel_config_params {
        char name[VPIF_MAX_NAME];       /* Name of the mode */
        u16 width;                      /* Indicates width of the image */
        u16 height;                     /* Indicates height of the image */
-       u8 fps;
-       u8 frm_fmt;                     /* Indicates whether this is interlaced
-                                        * or progressive format */
-       u8 ycmux_mode;                  /* Indicates whether this mode requires
-                                        * single or two channels */
-       u16 eav2sav;                    /* length of sav 2 eav */
+       u8 frm_fmt;                     /* Interlaced (0) or progressive (1) */
+       u8 ycmux_mode;                  /* This mode requires one (0) or two (1)
+                                          channels */
+       u16 eav2sav;                    /* length of eav 2 sav */
        u16 sav2eav;                    /* length of sav 2 eav */
        u16 l1, l3, l5, l7, l9, l11;    /* Other parameter configurations */
        u16 vsize;                      /* Vertical size of the image */
@@ -590,10 +588,14 @@ struct vpif_channel_config_params {
                                         * is in BT or in CCD/CMOS */
        u8  vbi_supported;              /* Indicates whether this mode
                                         * supports capturing vbi or not */
-       u8 hd_sd;
-       v4l2_std_id stdid;
+       u8 hd_sd;                       /* HDTV (1) or SDTV (0) format */
+       v4l2_std_id stdid;              /* SDTV format */
+       u32 dv_preset;                  /* HDTV format */
 };
 
+extern const unsigned int vpif_ch_params_count;
+extern const struct vpif_channel_config_params ch_params[];
+
 struct vpif_video_params;
 struct vpif_params;
 struct vpif_vbi_params;
index 193abab..d93ad74 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
 
 #include "vpif_capture.h"
 #include "vpif.h"
@@ -81,20 +82,6 @@ static struct vpif_device vpif_obj = { {NULL} };
 static struct device *vpif_dev;
 
 /**
- * ch_params: video standard configuration parameters for vpif
- */
-static const struct vpif_channel_config_params ch_params[] = {
-       {
-               "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
-               286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
-       },
-       {
-               "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
-               336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
-       },
-};
-
-/**
  * vpif_uservirt_to_phys : translate user/virtual address to phy address
  * @virtp: user/virtual address
  *
@@ -342,7 +329,7 @@ static void vpif_schedule_next_buffer(struct common_obj *common)
  * @dev_id: dev_id ptr
  *
  * It changes status of the captured buffer, takes next buffer from the queue
- * and sets its address in VPIF  registers
+ * and sets its address in VPIF registers
  */
 static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
 {
@@ -435,24 +422,31 @@ static int vpif_update_std_info(struct channel_obj *ch)
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
        struct vpif_params *vpifparams = &ch->vpifparams;
        const struct vpif_channel_config_params *config;
-       struct vpif_channel_config_params *std_info;
+       struct vpif_channel_config_params *std_info = &vpifparams->std_info;
        struct video_obj *vid_ch = &ch->video;
        int index;
 
        vpif_dbg(2, debug, "vpif_update_std_info\n");
 
-       std_info = &vpifparams->std_info;
-
-       for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
+       for (index = 0; index < vpif_ch_params_count; index++) {
                config = &ch_params[index];
-               if (config->stdid & vid_ch->stdid) {
-                       memcpy(std_info, config, sizeof(*config));
-                       break;
+               if (config->hd_sd == 0) {
+                       vpif_dbg(2, debug, "SD format\n");
+                       if (config->stdid & vid_ch->stdid) {
+                               memcpy(std_info, config, sizeof(*config));
+                               break;
+                       }
+               } else {
+                       vpif_dbg(2, debug, "HD format\n");
+                       if (config->dv_preset == vid_ch->dv_preset) {
+                               memcpy(std_info, config, sizeof(*config));
+                               break;
+                       }
                }
        }
 
        /* standard not found */
-       if (index == ARRAY_SIZE(ch_params))
+       if (index == vpif_ch_params_count)
                return -EINVAL;
 
        common->fmt.fmt.pix.width = std_info->width;
@@ -462,6 +456,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
        common->fmt.fmt.pix.bytesperline = std_info->width;
        vpifparams->video_params.hpitch = std_info->width;
        vpifparams->video_params.storage_mode = std_info->frm_fmt;
+
        return 0;
 }
 
@@ -757,7 +752,7 @@ static int vpif_open(struct file *filep)
        struct video_obj *vid_ch;
        struct channel_obj *ch;
        struct vpif_fh *fh;
-       int i, ret = 0;
+       int i;
 
        vpif_dbg(2, debug, "vpif_open\n");
 
@@ -766,9 +761,6 @@ static int vpif_open(struct file *filep)
        vid_ch = &ch->video;
        common = &ch->common[VPIF_VIDEO_INDEX];
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        if (NULL == ch->curr_subdev_info) {
                /**
                 * search through the sub device to see a registered
@@ -785,8 +777,7 @@ static int vpif_open(struct file *filep)
                }
                if (i == config->subdev_count) {
                        vpif_err("No sub device registered\n");
-                       ret = -ENOENT;
-                       goto exit;
+                       return -ENOENT;
                }
        }
 
@@ -794,8 +785,7 @@ static int vpif_open(struct file *filep)
        fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
        if (NULL == fh) {
                vpif_err("unable to allocate memory for file handle object\n");
-               ret = -ENOMEM;
-               goto exit;
+               return -ENOMEM;
        }
 
        /* store pointer to fh in private_data member of filep */
@@ -815,9 +805,7 @@ static int vpif_open(struct file *filep)
        /* Initialize priority of this instance to default priority */
        fh->prio = V4L2_PRIORITY_UNSET;
        v4l2_prio_open(&ch->prio, &fh->prio);
-exit:
-       mutex_unlock(&common->lock);
-       return ret;
+       return 0;
 }
 
 /**
@@ -837,9 +825,6 @@ static int vpif_release(struct file *filep)
 
        common = &ch->common[VPIF_VIDEO_INDEX];
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* if this instance is doing IO */
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
@@ -863,9 +848,6 @@ static int vpif_release(struct file *filep)
        /* Decrement channel usrs counter */
        ch->usrs--;
 
-       /* unlock mutex on channel object */
-       mutex_unlock(&common->lock);
-
        /* Close the priority */
        v4l2_prio_close(&ch->prio, fh->prio);
 
@@ -890,7 +872,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
        struct channel_obj *ch = fh->channel;
        struct common_obj *common;
        u8 index = 0;
-       int ret = 0;
 
        vpif_dbg(2, debug, "vpif_reqbufs\n");
 
@@ -913,13 +894,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
 
        common = &ch->common[index];
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
-       if (0 != common->io_usrs) {
-               ret = -EBUSY;
-               goto reqbuf_exit;
-       }
+       if (0 != common->io_usrs)
+               return -EBUSY;
 
        /* Initialize videobuf queue as per the buffer type */
        videobuf_queue_dma_contig_init(&common->buffer_queue,
@@ -928,7 +904,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
                                            reqbuf->type,
                                            common->fmt.fmt.pix.field,
                                            sizeof(struct videobuf_buffer), fh,
-                                           NULL);
+                                           &common->lock);
 
        /* Set io allowed member of file handle to TRUE */
        fh->io_allowed[index] = 1;
@@ -939,11 +915,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
        INIT_LIST_HEAD(&common->dma_queue);
 
        /* Allocate buffers */
-       ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
-       mutex_unlock(&common->lock);
-       return ret;
+       return videobuf_reqbufs(&common->buffer_queue, reqbuf);
 }
 
 /**
@@ -1157,11 +1129,6 @@ static int vpif_streamon(struct file *file, void *priv,
                return ret;
        }
 
-       if (mutex_lock_interruptible(&common->lock)) {
-               ret = -ERESTARTSYS;
-               goto streamoff_exit;
-       }
-
        /* If buffer queue is empty, return error */
        if (list_empty(&common->dma_queue)) {
                vpif_dbg(1, debug, "buffer queue is empty\n");
@@ -1240,13 +1207,10 @@ static int vpif_streamon(struct file *file, void *priv,
                enable_channel1(1);
        }
        channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
-       mutex_unlock(&common->lock);
        return ret;
 
 exit:
-       mutex_unlock(&common->lock);
-streamoff_exit:
-       ret = videobuf_streamoff(&common->buffer_queue);
+       videobuf_streamoff(&common->buffer_queue);
        return ret;
 }
 
@@ -1284,9 +1248,6 @@ static int vpif_streamoff(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* disable channel */
        if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
                enable_channel0(0);
@@ -1304,8 +1265,6 @@ static int vpif_streamoff(struct file *file, void *priv,
        if (ret && (ret != -ENOIOCTLCMD))
                vpif_dbg(1, debug, "stream off failed in subdev\n");
 
-       mutex_unlock(&common->lock);
-
        return videobuf_streamoff(&common->buffer_queue);
 }
 
@@ -1381,21 +1340,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
 {
        struct vpif_fh *fh = priv;
        struct channel_obj *ch = fh->channel;
-       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
        int ret = 0;
 
        vpif_dbg(2, debug, "vpif_querystd\n");
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* Call querystd function of decoder device */
        ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
                                querystd, std_id);
        if (ret < 0)
                vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
 
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1451,16 +1405,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
        fh->initialized = 1;
 
        /* Call encoder subdevice function to set the standard */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        ch->video.stdid = *std_id;
+       ch->video.dv_preset = V4L2_DV_INVALID;
+       memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
 
        /* Get the information about the standard */
        if (vpif_update_std_info(ch)) {
-               ret = -EINVAL;
                vpif_err("Error getting the standard info\n");
-               goto s_std_exit;
+               return -EINVAL;
        }
 
        /* Configure the default format information */
@@ -1471,9 +1423,6 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
                                s_std, *std_id);
        if (ret < 0)
                vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
-
-s_std_exit:
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1567,9 +1516,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
                return -EINVAL;
        }
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* first setup input path from sub device to vpif */
        if (config->setup_input_path) {
                ret = config->setup_input_path(ch->channel_id,
@@ -1578,7 +1524,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
                        vpif_dbg(1, debug, "couldn't setup input path for the"
                                " sub device %s, for input index %d\n",
                                subdev_info->name, index);
-                       goto exit;
+                       return ret;
                }
        }
 
@@ -1589,7 +1535,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
                                        input, output, 0);
                if (ret < 0) {
                        vpif_dbg(1, debug, "Failed to set input\n");
-                       goto exit;
+                       return ret;
                }
        }
        vid_ch->input_idx = index;
@@ -1600,9 +1546,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
 
        /* update tvnorms from the sub device input info */
        ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
-
-exit:
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1671,11 +1614,7 @@ static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
 
        /* Fill in the information about format */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        *fmt = common->fmt;
-       mutex_unlock(&common->lock);
        return 0;
 }
 
@@ -1694,7 +1633,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_pix_format *pixfmt;
        int ret = 0;
 
-       vpif_dbg(2, debug, "VIDIOC_S_FMT\n");
+       vpif_dbg(2, debug, "%s\n", __func__);
 
        /* If streaming is started, return error */
        if (common->started) {
@@ -1723,12 +1662,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
        if (ret)
                return ret;
        /* store the format in the channel object */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        common->fmt = *fmt;
-       mutex_unlock(&common->lock);
-
        return 0;
 }
 
@@ -1807,6 +1741,306 @@ static int vpif_cropcap(struct file *file, void *priv,
        return 0;
 }
 
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+               struct v4l2_dv_enum_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+                       video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_query_dv_presets() - QUERY_DV_PRESET handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_query_dv_preset(struct file *file, void *priv,
+               struct v4l2_dv_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+                      video, query_dv_preset, preset);
+}
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+               struct v4l2_dv_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       int ret = 0;
+
+       if (common->started) {
+               vpif_dbg(1, debug, "streaming in progress\n");
+               return -EBUSY;
+       }
+
+       if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+           (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+               if (!fh->initialized) {
+                       vpif_dbg(1, debug, "Channel Busy\n");
+                       return -EBUSY;
+               }
+       }
+
+       ret = v4l2_prio_check(&ch->prio, fh->prio);
+       if (ret)
+               return ret;
+
+       fh->initialized = 1;
+
+       /* Call encoder subdevice function to set the standard */
+       if (mutex_lock_interruptible(&common->lock))
+               return -ERESTARTSYS;
+
+       ch->video.dv_preset = preset->preset;
+       ch->video.stdid = V4L2_STD_UNKNOWN;
+       memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+       /* Get the information about the standard */
+       if (vpif_update_std_info(ch)) {
+               vpif_dbg(1, debug, "Error getting the standard info\n");
+               ret = -EINVAL;
+       } else {
+               /* Configure the default format information */
+               vpif_config_format(ch);
+
+               ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+                               video, s_dv_preset, preset);
+       }
+
+       mutex_unlock(&common->lock);
+
+       return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+               struct v4l2_dv_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       preset->preset = ch->video.dv_preset;
+
+       return 0;
+}
+
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+               struct v4l2_dv_timings *timings)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct vpif_params *vpifparams = &ch->vpifparams;
+       struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+       struct video_obj *vid_ch = &ch->video;
+       struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+       int ret;
+
+       if (timings->type != V4L2_DV_BT_656_1120) {
+               vpif_dbg(2, debug, "Timing type not defined\n");
+               return -EINVAL;
+       }
+
+       /* Configure subdevice timings, if any */
+       ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+                       video, s_dv_timings, timings);
+       if (ret == -ENOIOCTLCMD) {
+               vpif_dbg(2, debug, "Custom DV timings not supported by "
+                               "subdevice\n");
+               return -EINVAL;
+       }
+       if (ret < 0) {
+               vpif_dbg(2, debug, "Error setting custom DV timings\n");
+               return ret;
+       }
+
+       if (!(timings->bt.width && timings->bt.height &&
+                               (timings->bt.hbackporch ||
+                                timings->bt.hfrontporch ||
+                                timings->bt.hsync) &&
+                               timings->bt.vfrontporch &&
+                               (timings->bt.vbackporch ||
+                                timings->bt.vsync))) {
+               vpif_dbg(2, debug, "Timings for width, height, "
+                               "horizontal back porch, horizontal sync, "
+                               "horizontal front porch, vertical back porch, "
+                               "vertical sync and vertical back porch "
+                               "must be defined\n");
+               return -EINVAL;
+       }
+
+       *bt = timings->bt;
+
+       /* Configure video port timings */
+
+       std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+               bt->hsync - 8;
+       std_info->sav2eav = bt->width;
+
+       std_info->l1 = 1;
+       std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+       if (bt->interlaced) {
+               if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+                       std_info->vsize = bt->height * 2 +
+                               bt->vfrontporch + bt->vsync + bt->vbackporch +
+                               bt->il_vfrontporch + bt->il_vsync +
+                               bt->il_vbackporch;
+                       std_info->l5 = std_info->vsize/2 -
+                               (bt->vfrontporch - 1);
+                       std_info->l7 = std_info->vsize/2 + 1;
+                       std_info->l9 = std_info->l7 + bt->il_vsync +
+                               bt->il_vbackporch + 1;
+                       std_info->l11 = std_info->vsize -
+                               (bt->il_vfrontporch - 1);
+               } else {
+                       vpif_dbg(2, debug, "Required timing values for "
+                                       "interlaced BT format missing\n");
+                       return -EINVAL;
+               }
+       } else {
+               std_info->vsize = bt->height + bt->vfrontporch +
+                       bt->vsync + bt->vbackporch;
+               std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+       }
+       strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+       std_info->width = bt->width;
+       std_info->height = bt->height;
+       std_info->frm_fmt = bt->interlaced ? 0 : 1;
+       std_info->ycmux_mode = 0;
+       std_info->capture_format = 0;
+       std_info->vbi_supported = 0;
+       std_info->hd_sd = 1;
+       std_info->stdid = 0;
+       std_info->dv_preset = V4L2_DV_INVALID;
+
+       vid_ch->stdid = 0;
+       vid_ch->dv_preset = V4L2_DV_INVALID;
+       return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+               struct v4l2_dv_timings *timings)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct video_obj *vid_ch = &ch->video;
+       struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+       timings->bt = *bt;
+
+       return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+               vpif_dbg(2, debug, "match_type is invalid.\n");
+               return -EINVAL;
+       }
+
+       return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+                       g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg){
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+                       g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg){
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+                       s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+       /* status for sub devices */
+       v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+       return 0;
+}
+
 /* vpif capture ioctl operations */
 static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_querycap                = vpif_querycap,
@@ -1829,6 +2063,18 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_streamon                = vpif_streamon,
        .vidioc_streamoff               = vpif_streamoff,
        .vidioc_cropcap                 = vpif_cropcap,
+       .vidioc_enum_dv_presets         = vpif_enum_dv_presets,
+       .vidioc_s_dv_preset             = vpif_s_dv_preset,
+       .vidioc_g_dv_preset             = vpif_g_dv_preset,
+       .vidioc_query_dv_preset         = vpif_query_dv_preset,
+       .vidioc_s_dv_timings            = vpif_s_dv_timings,
+       .vidioc_g_dv_timings            = vpif_g_dv_timings,
+       .vidioc_g_chip_ident            = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = vpif_dbg_g_register,
+       .vidioc_s_register              = vpif_dbg_s_register,
+#endif
+       .vidioc_log_status              = vpif_log_status,
 };
 
 /* vpif file operations */
@@ -1836,7 +2082,7 @@ static struct v4l2_file_operations vpif_fops = {
        .owner = THIS_MODULE,
        .open = vpif_open,
        .release = vpif_release,
-       .ioctl = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
        .mmap = vpif_mmap,
        .poll = vpif_poll
 };
@@ -1979,6 +2225,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                common = &(ch->common[VPIF_VIDEO_INDEX]);
                spin_lock_init(&common->irqlock);
                mutex_init(&common->lock);
+               ch->video_dev->lock = &common->lock;
                /* Initialize prio member of channel object */
                v4l2_prio_init(&ch->prio);
                err = video_register_device(ch->video_dev,
@@ -2026,9 +2273,9 @@ static __init int vpif_probe(struct platform_device *pdev)
                if (vpif_obj.sd[i])
                        vpif_obj.sd[i]->grp_id = 1 << i;
        }
-       v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver"
-                 " initialized\n");
 
+       v4l2_info(&vpif_obj.v4l2_dev,
+                       "DM646x VPIF capture driver initialized\n");
        return 0;
 
 probe_subdev_out:
index 4e12ec8..7a4196d 100644 (file)
@@ -59,6 +59,8 @@ struct video_obj {
        enum v4l2_field buf_field;
        /* Currently selected or default standard */
        v4l2_std_id stdid;
+       u32 dv_preset;
+       struct v4l2_bt_timings bt_timings;
        /* This is to track the last input that is passed to application */
        u32 input_idx;
 };
index 412c65d..cdf659a 100644 (file)
@@ -38,6 +38,7 @@
 #include <media/adv7343.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
 
 #include <mach/dm646x.h>
 
@@ -84,17 +85,6 @@ static struct vpif_config_params config_params = {
 static struct vpif_device vpif_obj = { {NULL} };
 static struct device *vpif_dev;
 
-static const struct vpif_channel_config_params ch_params[] = {
-       {
-               "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
-               286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
-       },
-       {
-               "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
-               336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
-       },
-};
-
 /*
  * vpif_uservirt_to_phys: This function is used to convert user
  * space virtual address to physical address.
@@ -373,30 +363,54 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int vpif_get_std_info(struct channel_obj *ch)
+static int vpif_update_std_info(struct channel_obj *ch)
 {
-       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
        struct video_obj *vid_ch = &ch->video;
        struct vpif_params *vpifparams = &ch->vpifparams;
        struct vpif_channel_config_params *std_info = &vpifparams->std_info;
        const struct vpif_channel_config_params *config;
 
-       int index;
-
-       std_info->stdid = vid_ch->stdid;
-       if (!std_info->stdid)
-               return -1;
+       int i;
 
-       for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
-               config = &ch_params[index];
-               if (config->stdid & std_info->stdid) {
-                       memcpy(std_info, config, sizeof(*config));
-                       break;
+       for (i = 0; i < vpif_ch_params_count; i++) {
+               config = &ch_params[i];
+               if (config->hd_sd == 0) {
+                       vpif_dbg(2, debug, "SD format\n");
+                       if (config->stdid & vid_ch->stdid) {
+                               memcpy(std_info, config, sizeof(*config));
+                               break;
+                       }
+               } else {
+                       vpif_dbg(2, debug, "HD format\n");
+                       if (config->dv_preset == vid_ch->dv_preset) {
+                               memcpy(std_info, config, sizeof(*config));
+                               break;
+                       }
                }
        }
 
-       if (index == ARRAY_SIZE(ch_params))
-               return -1;
+       if (i == vpif_ch_params_count) {
+               vpif_dbg(1, debug, "Format not found\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vpif_update_resolution(struct channel_obj *ch)
+{
+       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       struct video_obj *vid_ch = &ch->video;
+       struct vpif_params *vpifparams = &ch->vpifparams;
+       struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+
+       if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
+               return -EINVAL;
+
+       if (vid_ch->stdid || vid_ch->dv_preset) {
+               if (vpif_update_std_info(ch))
+                       return -EINVAL;
+       }
 
        common->fmt.fmt.pix.width = std_info->width;
        common->fmt.fmt.pix.height = std_info->height;
@@ -404,8 +418,8 @@ static int vpif_get_std_info(struct channel_obj *ch)
                        common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
 
        /* Set height and width paramateres */
-       ch->common[VPIF_VIDEO_INDEX].height = std_info->height;
-       ch->common[VPIF_VIDEO_INDEX].width = std_info->width;
+       common->height = std_info->height;
+       common->width = std_info->width;
 
        return 0;
 }
@@ -516,10 +530,8 @@ static int vpif_check_format(struct channel_obj *ch,
        else
                sizeimage = config_params.channel_bufsize[ch->channel_id];
 
-       if (vpif_get_std_info(ch)) {
-               vpif_err("Error getting the standard info\n");
+       if (vpif_update_resolution(ch))
                return -EINVAL;
-       }
 
        hpitch = pixfmt->bytesperline;
        vpitch = sizeimage / (hpitch * 2);
@@ -568,7 +580,10 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode)
 static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
 {
        struct vpif_fh *fh = filep->private_data;
-       struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX];
+       struct channel_obj *ch = fh->channel;
+       struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+
+       vpif_dbg(2, debug, "vpif_mmap\n");
 
        return videobuf_mmap_mapper(&common->buffer_queue, vma);
 }
@@ -637,9 +652,6 @@ static int vpif_release(struct file *filep)
        struct channel_obj *ch = fh->channel;
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* if this instance is doing IO */
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
@@ -662,8 +674,6 @@ static int vpif_release(struct file *filep)
                    config_params.numbuffers[ch->channel_id];
        }
 
-       mutex_unlock(&common->lock);
-
        /* Decrement channel usrs counter */
        atomic_dec(&ch->usrs);
        /* If this file handle has initialize encoder device, reset it */
@@ -680,7 +690,12 @@ static int vpif_release(struct file *filep)
 }
 
 /* functions implementing ioctls */
-
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
 static int vpif_querycap(struct file *file, void  *priv,
                                struct v4l2_capability *cap)
 {
@@ -722,17 +737,9 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv,
        if (common->fmt.type != fmt->type)
                return -EINVAL;
 
-       /* Fill in the information about format */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
-       if (vpif_get_std_info(ch)) {
-               vpif_err("Error getting the standard info\n");
+       if (vpif_update_resolution(ch))
                return -EINVAL;
-       }
-
        *fmt = common->fmt;
-       mutex_unlock(&common->lock);
        return 0;
 }
 
@@ -773,12 +780,7 @@ static int vpif_s_fmt_vid_out(struct file *file, void *priv,
        /* store the pix format in the channel object */
        common->fmt.fmt.pix = *pixfmt;
        /* store the format in the channel object */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        common->fmt = *fmt;
-       mutex_unlock(&common->lock);
-
        return 0;
 }
 
@@ -808,7 +810,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
        struct common_obj *common;
        enum v4l2_field field;
        u8 index = 0;
-       int ret = 0;
 
        /* This file handle has not initialized the channel,
           It is not allowed to do settings */
@@ -826,18 +827,12 @@ static int vpif_reqbufs(struct file *file, void *priv,
        index = VPIF_VIDEO_INDEX;
 
        common = &ch->common[index];
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
 
-       if (common->fmt.type != reqbuf->type) {
-               ret = -EINVAL;
-               goto reqbuf_exit;
-       }
+       if (common->fmt.type != reqbuf->type)
+               return -EINVAL;
 
-       if (0 != common->io_usrs) {
-               ret = -EBUSY;
-               goto reqbuf_exit;
-       }
+       if (0 != common->io_usrs)
+               return -EBUSY;
 
        if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
@@ -854,7 +849,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
                                            &common->irqlock,
                                            reqbuf->type, field,
                                            sizeof(struct videobuf_buffer), fh,
-                                           NULL);
+                                           &common->lock);
 
        /* Set io allowed member of file handle to TRUE */
        fh->io_allowed[index] = 1;
@@ -865,11 +860,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
        INIT_LIST_HEAD(&common->dma_queue);
 
        /* Allocate buffers */
-       ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
-       mutex_unlock(&common->lock);
-       return ret;
+       return videobuf_reqbufs(&common->buffer_queue, reqbuf);
 }
 
 static int vpif_querybuf(struct file *file, void *priv,
@@ -990,22 +981,19 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
        }
 
        /* Call encoder subdevice function to set the standard */
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        ch->video.stdid = *std_id;
+       ch->video.dv_preset = V4L2_DV_INVALID;
+       memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
        /* Get the information about the standard */
-       if (vpif_get_std_info(ch)) {
-               vpif_err("Error getting the standard info\n");
+       if (vpif_update_resolution(ch))
                return -EINVAL;
-       }
 
        if ((ch->vpifparams.std_info.width *
                ch->vpifparams.std_info.height * 2) >
                config_params.channel_bufsize[ch->channel_id]) {
                vpif_err("invalid std for this size\n");
-               ret = -EINVAL;
-               goto s_std_exit;
+               return -EINVAL;
        }
 
        common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
@@ -1016,16 +1004,13 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
                                                s_std_output, *std_id);
        if (ret < 0) {
                vpif_err("Failed to set output standard\n");
-               goto s_std_exit;
+               return ret;
        }
 
        ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
                                                        s_std, *std_id);
        if (ret < 0)
                vpif_err("Failed to set standard for sub devices\n");
-
-s_std_exit:
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1090,21 +1075,17 @@ static int vpif_streamon(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       /* Call videobuf_streamon to start streaming  in videobuf */
+       /* Call videobuf_streamon to start streaming in videobuf */
        ret = videobuf_streamon(&common->buffer_queue);
        if (ret < 0) {
                vpif_err("videobuf_streamon\n");
                return ret;
        }
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        /* If buffer queue is empty, return error */
        if (list_empty(&common->dma_queue)) {
                vpif_err("buffer queue is empty\n");
-               ret = -EIO;
-               goto streamon_exit;
+               return -EIO;
        }
 
        /* Get the next frame from the buffer queue */
@@ -1130,8 +1111,7 @@ static int vpif_streamon(struct file *file, void *priv,
                        || (!ch->vpifparams.std_info.frm_fmt
                        && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
                        vpif_err("conflict in field format and std format\n");
-                       ret = -EINVAL;
-                       goto streamon_exit;
+                       return -EINVAL;
                }
 
                /* clock settings */
@@ -1140,13 +1120,13 @@ static int vpif_streamon(struct file *file, void *priv,
                                                ch->vpifparams.std_info.hd_sd);
                if (ret < 0) {
                        vpif_err("can't set clock\n");
-                       goto streamon_exit;
+                       return ret;
                }
 
                /* set the parameters and addresses */
                ret = vpif_set_video_params(vpif, ch->channel_id + 2);
                if (ret < 0)
-                       goto streamon_exit;
+                       return ret;
 
                common->started = ret;
                vpif_config_addr(ch, ret);
@@ -1171,9 +1151,6 @@ static int vpif_streamon(struct file *file, void *priv,
                }
                channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
        }
-
-streamon_exit:
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1199,9 +1176,6 @@ static int vpif_streamoff(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                /* disable channel */
                if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
@@ -1216,8 +1190,6 @@ static int vpif_streamoff(struct file *file, void *priv,
        }
 
        common->started = 0;
-       mutex_unlock(&common->lock);
-
        return videobuf_streamoff(&common->buffer_queue);
 }
 
@@ -1264,13 +1236,9 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
        int ret = 0;
 
-       if (mutex_lock_interruptible(&common->lock))
-               return -ERESTARTSYS;
-
        if (common->started) {
                vpif_err("Streaming in progress\n");
-               ret = -EBUSY;
-               goto s_output_exit;
+               return -EBUSY;
        }
 
        ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
@@ -1280,9 +1248,6 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
                vpif_err("Failed to set output standard\n");
 
        vid_ch->output_id = i;
-
-s_output_exit:
-       mutex_unlock(&common->lock);
        return ret;
 }
 
@@ -1315,6 +1280,287 @@ static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
        return v4l2_prio_change(&ch->prio, &fh->prio, p);
 }
 
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+               struct v4l2_dv_enum_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct video_obj *vid_ch = &ch->video;
+
+       return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+                       video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+               struct v4l2_dv_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       struct video_obj *vid_ch = &ch->video;
+       int ret = 0;
+
+       if (common->started) {
+               vpif_dbg(1, debug, "streaming in progress\n");
+               return -EBUSY;
+       }
+
+       ret = v4l2_prio_check(&ch->prio, fh->prio);
+       if (ret != 0)
+               return ret;
+
+       fh->initialized = 1;
+
+       /* Call encoder subdevice function to set the standard */
+       if (mutex_lock_interruptible(&common->lock))
+               return -ERESTARTSYS;
+
+       ch->video.dv_preset = preset->preset;
+       ch->video.stdid = V4L2_STD_UNKNOWN;
+       memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+       /* Get the information about the standard */
+       if (vpif_update_resolution(ch)) {
+               ret = -EINVAL;
+       } else {
+               /* Configure the default format information */
+               vpif_config_format(ch);
+
+               ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+                               video, s_dv_preset, preset);
+       }
+
+       mutex_unlock(&common->lock);
+
+       return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+               struct v4l2_dv_preset *preset)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+
+       preset->preset = ch->video.dv_preset;
+
+       return 0;
+}
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+               struct v4l2_dv_timings *timings)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct vpif_params *vpifparams = &ch->vpifparams;
+       struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+       struct video_obj *vid_ch = &ch->video;
+       struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+       int ret;
+
+       if (timings->type != V4L2_DV_BT_656_1120) {
+               vpif_dbg(2, debug, "Timing type not defined\n");
+               return -EINVAL;
+       }
+
+       /* Configure subdevice timings, if any */
+       ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+                       video, s_dv_timings, timings);
+       if (ret == -ENOIOCTLCMD) {
+               vpif_dbg(2, debug, "Custom DV timings not supported by "
+                               "subdevice\n");
+               return -EINVAL;
+       }
+       if (ret < 0) {
+               vpif_dbg(2, debug, "Error setting custom DV timings\n");
+               return ret;
+       }
+
+       if (!(timings->bt.width && timings->bt.height &&
+                               (timings->bt.hbackporch ||
+                                timings->bt.hfrontporch ||
+                                timings->bt.hsync) &&
+                               timings->bt.vfrontporch &&
+                               (timings->bt.vbackporch ||
+                                timings->bt.vsync))) {
+               vpif_dbg(2, debug, "Timings for width, height, "
+                               "horizontal back porch, horizontal sync, "
+                               "horizontal front porch, vertical back porch, "
+                               "vertical sync and vertical back porch "
+                               "must be defined\n");
+               return -EINVAL;
+       }
+
+       *bt = timings->bt;
+
+       /* Configure video port timings */
+
+       std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+               bt->hsync - 8;
+       std_info->sav2eav = bt->width;
+
+       std_info->l1 = 1;
+       std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+       if (bt->interlaced) {
+               if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+                       std_info->vsize = bt->height * 2 +
+                               bt->vfrontporch + bt->vsync + bt->vbackporch +
+                               bt->il_vfrontporch + bt->il_vsync +
+                               bt->il_vbackporch;
+                       std_info->l5 = std_info->vsize/2 -
+                               (bt->vfrontporch - 1);
+                       std_info->l7 = std_info->vsize/2 + 1;
+                       std_info->l9 = std_info->l7 + bt->il_vsync +
+                               bt->il_vbackporch + 1;
+                       std_info->l11 = std_info->vsize -
+                               (bt->il_vfrontporch - 1);
+               } else {
+                       vpif_dbg(2, debug, "Required timing values for "
+                                       "interlaced BT format missing\n");
+                       return -EINVAL;
+               }
+       } else {
+               std_info->vsize = bt->height + bt->vfrontporch +
+                       bt->vsync + bt->vbackporch;
+               std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+       }
+       strncpy(std_info->name, "Custom timings BT656/1120",
+                       VPIF_MAX_NAME);
+       std_info->width = bt->width;
+       std_info->height = bt->height;
+       std_info->frm_fmt = bt->interlaced ? 0 : 1;
+       std_info->ycmux_mode = 0;
+       std_info->capture_format = 0;
+       std_info->vbi_supported = 0;
+       std_info->hd_sd = 1;
+       std_info->stdid = 0;
+       std_info->dv_preset = V4L2_DV_INVALID;
+
+       vid_ch->stdid = 0;
+       vid_ch->dv_preset = V4L2_DV_INVALID;
+
+       return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+               struct v4l2_dv_timings *timings)
+{
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct video_obj *vid_ch = &ch->video;
+       struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+       timings->bt = *bt;
+
+       return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+               vpif_dbg(2, debug, "match_type is invalid.\n");
+               return -EINVAL;
+       }
+
+       return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+                       g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg){
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct video_obj *vid_ch = &ch->video;
+
+       return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+                       g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg){
+       struct vpif_fh *fh = priv;
+       struct channel_obj *ch = fh->channel;
+       struct video_obj *vid_ch = &ch->video;
+
+       return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+                       s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+       /* status for sub devices */
+       v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+       return 0;
+}
+
 /* vpif display ioctl operations */
 static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_querycap                = vpif_querycap,
@@ -1336,13 +1582,24 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_s_output                = vpif_s_output,
        .vidioc_g_output                = vpif_g_output,
        .vidioc_cropcap                 = vpif_cropcap,
+       .vidioc_enum_dv_presets         = vpif_enum_dv_presets,
+       .vidioc_s_dv_preset             = vpif_s_dv_preset,
+       .vidioc_g_dv_preset             = vpif_g_dv_preset,
+       .vidioc_s_dv_timings            = vpif_s_dv_timings,
+       .vidioc_g_dv_timings            = vpif_g_dv_timings,
+       .vidioc_g_chip_ident            = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = vpif_dbg_g_register,
+       .vidioc_s_register              = vpif_dbg_s_register,
+#endif
+       .vidioc_log_status              = vpif_log_status,
 };
 
 static const struct v4l2_file_operations vpif_fops = {
        .owner          = THIS_MODULE,
        .open           = vpif_open,
        .release        = vpif_release,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
        .mmap           = vpif_mmap,
        .poll           = vpif_poll
 };
@@ -1526,6 +1783,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                v4l2_prio_init(&ch->prio);
                ch->common[VPIF_VIDEO_INDEX].fmt.type =
                                                V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               ch->video_dev->lock = &common->lock;
 
                /* register video device */
                vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
@@ -1565,6 +1823,8 @@ static __init int vpif_probe(struct platform_device *pdev)
                        vpif_obj.sd[i]->grp_id = 1 << i;
        }
 
+       v4l2_info(&vpif_obj.v4l2_dev,
+                       "DM646x VPIF display driver initialized\n");
        return 0;
 
 probe_subdev_out:
index a2a7cd1..b53aaa8 100644 (file)
@@ -67,6 +67,8 @@ struct video_obj {
                                         * most recent displayed frame only */
        v4l2_std_id stdid;              /* Currently selected or default
                                         * standard */
+       u32 dv_preset;
+       struct v4l2_bt_timings bt_timings;
        u32 output_id;                  /* Current output id */
 };
 
index 099d5df..87f77a3 100644 (file)
@@ -33,6 +33,7 @@
 #include <media/saa7115.h>
 #include <media/tvp5150.h>
 #include <media/tvaudio.h>
+#include <media/mt9v011.h>
 #include <media/i2c-addr.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
@@ -1917,11 +1918,6 @@ static unsigned short tvp5150_addrs[] = {
        I2C_CLIENT_END
 };
 
-static unsigned short mt9v011_addrs[] = {
-       0xba >> 1,
-       I2C_CLIENT_END
-};
-
 static unsigned short msp3400_addrs[] = {
        0x80 >> 1,
        0x88 >> 1,
@@ -2437,6 +2433,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
                dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW;
                dev->init_data.get_key = em28xx_get_key_em_haup;
                dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+               break;
        case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
                dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
                dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
@@ -2623,11 +2620,17 @@ void em28xx_card_setup(struct em28xx *dev)
                        "tvp5150", 0, tvp5150_addrs);
 
        if (dev->em28xx_sensor == EM28XX_MT9V011) {
+               struct mt9v011_platform_data pdata;
+               struct i2c_board_info mt9v011_info = {
+                       .type = "mt9v011",
+                       .addr = 0xba >> 1,
+                       .platform_data = &pdata,
+               };
                struct v4l2_subdev *sd;
 
-               sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                        &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs);
-               v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+               pdata.xtal = dev->sensor_xtal;
+               sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+                               &mt9v011_info, NULL);
        }
 
 
index cc77d14..bf66189 100644 (file)
 /*****************************************************************************/
 
 static const struct usb_device_id et61x251_id_table[] = {
-       { USB_DEVICE(0x102c, 0x6151), },
        { USB_DEVICE(0x102c, 0x6251), },
-       { USB_DEVICE(0x102c, 0x6253), },
-       { USB_DEVICE(0x102c, 0x6254), },
-       { USB_DEVICE(0x102c, 0x6255), },
-       { USB_DEVICE(0x102c, 0x6256), },
-       { USB_DEVICE(0x102c, 0x6257), },
-       { USB_DEVICE(0x102c, 0x6258), },
-       { USB_DEVICE(0x102c, 0x6259), },
-       { USB_DEVICE(0x102c, 0x625a), },
-       { USB_DEVICE(0x102c, 0x625b), },
-       { USB_DEVICE(0x102c, 0x625c), },
-       { USB_DEVICE(0x102c, 0x625d), },
-       { USB_DEVICE(0x102c, 0x625e), },
-       { USB_DEVICE(0x102c, 0x625f), },
-       { USB_DEVICE(0x102c, 0x6260), },
-       { USB_DEVICE(0x102c, 0x6261), },
-       { USB_DEVICE(0x102c, 0x6262), },
-       { USB_DEVICE(0x102c, 0x6263), },
-       { USB_DEVICE(0x102c, 0x6264), },
-       { USB_DEVICE(0x102c, 0x6265), },
-       { USB_DEVICE(0x102c, 0x6266), },
-       { USB_DEVICE(0x102c, 0x6267), },
-       { USB_DEVICE(0x102c, 0x6268), },
-       { USB_DEVICE(0x102c, 0x6269), },
        { }
 };
 
index 6290439..a09c470 100644 (file)
@@ -276,7 +276,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x04a5, 0x3035)},
        {}
 };
index 1eacb6c..8b39849 100644 (file)
@@ -1040,14 +1040,14 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0572, 0x0041)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
index c1ae05f..4bf2cab 100644 (file)
@@ -2088,7 +2088,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0553, 0x0002)},
        {USB_DEVICE(0x0813, 0x0001)},
        {}
index a594b36..4b2c483 100644 (file)
@@ -864,7 +864,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
 #if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
        {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
@@ -875,7 +875,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
                    const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
index d782264..987b4b6 100644 (file)
@@ -229,7 +229,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 /* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x04cb, 0x0104)},
        {USB_DEVICE(0x04cb, 0x0109)},
        {USB_DEVICE(0x04cb, 0x010b)},
index b05bec7..9908303 100644 (file)
@@ -488,7 +488,7 @@ static void sd_callback(struct gspca_dev *gspca_dev)
 
 /*=================== USB driver structure initialisation ==================*/
 
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x05e3, 0x0503)},
        {USB_DEVICE(0x05e3, 0xf191)},
        {}
index 4429700..f21f2a2 100644 (file)
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 11, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 12, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -508,8 +508,8 @@ static int gspca_is_compressed(__u32 format)
        return 0;
 }
 
-static int frame_alloc(struct gspca_dev *gspca_dev,
-                       unsigned int count)
+static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
+                       enum v4l2_memory memory, unsigned int count)
 {
        struct gspca_frame *frame;
        unsigned int frsz;
@@ -519,7 +519,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
        frsz = gspca_dev->cam.cam_mode[i].sizeimage;
        PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
        frsz = PAGE_ALIGN(frsz);
-       gspca_dev->frsz = frsz;
        if (count >= GSPCA_MAX_FRAMES)
                count = GSPCA_MAX_FRAMES - 1;
        gspca_dev->frbuf = vmalloc_32(frsz * count);
@@ -527,6 +526,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
                err("frame alloc failed");
                return -ENOMEM;
        }
+       gspca_dev->capt_file = file;
+       gspca_dev->memory = memory;
+       gspca_dev->frsz = frsz;
        gspca_dev->nframes = count;
        for (i = 0; i < count; i++) {
                frame = &gspca_dev->frame[i];
@@ -535,7 +537,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
                frame->v4l2_buf.flags = 0;
                frame->v4l2_buf.field = V4L2_FIELD_NONE;
                frame->v4l2_buf.length = frsz;
-               frame->v4l2_buf.memory = gspca_dev->memory;
+               frame->v4l2_buf.memory = memory;
                frame->v4l2_buf.sequence = 0;
                frame->data = gspca_dev->frbuf + i * frsz;
                frame->v4l2_buf.m.offset = i * frsz;
@@ -558,6 +560,9 @@ static void frame_free(struct gspca_dev *gspca_dev)
                        gspca_dev->frame[i].data = NULL;
        }
        gspca_dev->nframes = 0;
+       gspca_dev->frsz = 0;
+       gspca_dev->capt_file = NULL;
+       gspca_dev->memory = GSPCA_MEMORY_NO;
 }
 
 static void destroy_urbs(struct gspca_dev *gspca_dev)
@@ -1210,29 +1215,15 @@ static void gspca_release(struct video_device *vfd)
 static int dev_open(struct file *file)
 {
        struct gspca_dev *gspca_dev;
-       int ret;
 
        PDEBUG(D_STREAM, "[%s] open", current->comm);
        gspca_dev = (struct gspca_dev *) video_devdata(file);
-       if (mutex_lock_interruptible(&gspca_dev->queue_lock))
-               return -ERESTARTSYS;
-       if (!gspca_dev->present) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (gspca_dev->users > 4) {     /* (arbitrary value) */
-               ret = -EBUSY;
-               goto out;
-       }
+       if (!gspca_dev->present)
+               return -ENODEV;
 
        /* protect the subdriver against rmmod */
-       if (!try_module_get(gspca_dev->module)) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       gspca_dev->users++;
+       if (!try_module_get(gspca_dev->module))
+               return -ENODEV;
 
        file->private_data = gspca_dev;
 #ifdef GSPCA_DEBUG
@@ -1244,14 +1235,7 @@ static int dev_open(struct file *file)
                gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
                                        | V4L2_DEBUG_IOCTL_ARG);
 #endif
-       ret = 0;
-out:
-       mutex_unlock(&gspca_dev->queue_lock);
-       if (ret != 0)
-               PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
-       else
-               PDEBUG(D_STREAM, "open done");
-       return ret;
+       return 0;
 }
 
 static int dev_close(struct file *file)
@@ -1261,7 +1245,6 @@ static int dev_close(struct file *file)
        PDEBUG(D_STREAM, "[%s] close", current->comm);
        if (mutex_lock_interruptible(&gspca_dev->queue_lock))
                return -ERESTARTSYS;
-       gspca_dev->users--;
 
        /* if the file did the capture, free the streaming resources */
        if (gspca_dev->capt_file == file) {
@@ -1272,8 +1255,6 @@ static int dev_close(struct file *file)
                        mutex_unlock(&gspca_dev->usb_lock);
                }
                frame_free(gspca_dev);
-               gspca_dev->capt_file = NULL;
-               gspca_dev->memory = GSPCA_MEMORY_NO;
        }
        file->private_data = NULL;
        module_put(gspca_dev->module);
@@ -1516,6 +1497,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                return -ERESTARTSYS;
 
        if (gspca_dev->memory != GSPCA_MEMORY_NO
+           && gspca_dev->memory != GSPCA_MEMORY_READ
            && gspca_dev->memory != rb->memory) {
                ret = -EBUSY;
                goto out;
@@ -1544,19 +1526,18 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                gspca_stream_off(gspca_dev);
                mutex_unlock(&gspca_dev->usb_lock);
        }
+       /* Don't restart the stream when switching from read to mmap mode */
+       if (gspca_dev->memory == GSPCA_MEMORY_READ)
+               streaming = 0;
 
        /* free the previous allocated buffers, if any */
-       if (gspca_dev->nframes != 0) {
+       if (gspca_dev->nframes != 0)
                frame_free(gspca_dev);
-               gspca_dev->capt_file = NULL;
-       }
        if (rb->count == 0)                     /* unrequest */
                goto out;
-       gspca_dev->memory = rb->memory;
-       ret = frame_alloc(gspca_dev, rb->count);
+       ret = frame_alloc(gspca_dev, file, rb->memory, rb->count);
        if (ret == 0) {
                rb->count = gspca_dev->nframes;
-               gspca_dev->capt_file = file;
                if (streaming)
                        ret = gspca_init_transfer(gspca_dev);
        }
@@ -1630,11 +1611,15 @@ static int vidioc_streamoff(struct file *file, void *priv,
 
        if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       if (!gspca_dev->streaming)
-               return 0;
+
        if (mutex_lock_interruptible(&gspca_dev->queue_lock))
                return -ERESTARTSYS;
 
+       if (!gspca_dev->streaming) {
+               ret = 0;
+               goto out;
+       }
+
        /* check the capture file */
        if (gspca_dev->capt_file != file) {
                ret = -EBUSY;
@@ -1649,6 +1634,8 @@ static int vidioc_streamoff(struct file *file, void *priv,
        gspca_dev->usb_err = 0;
        gspca_stream_off(gspca_dev);
        mutex_unlock(&gspca_dev->usb_lock);
+       /* In case another thread is waiting in dqbuf */
+       wake_up_interruptible(&gspca_dev->wq);
 
        /* empty the transfer queues */
        atomic_set(&gspca_dev->fr_q, 0);
@@ -1827,33 +1814,77 @@ out:
        return ret;
 }
 
+static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file,
+                               enum v4l2_memory memory)
+{
+       if (!gspca_dev->present)
+               return -ENODEV;
+       if (gspca_dev->capt_file != file || gspca_dev->memory != memory ||
+                       !gspca_dev->streaming)
+               return -EINVAL;
+
+       /* check if a frame is ready */
+       return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i);
+}
+
+static int frame_ready(struct gspca_dev *gspca_dev, struct file *file,
+                       enum v4l2_memory memory)
+{
+       int ret;
+
+       if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+               return -ERESTARTSYS;
+       ret = frame_ready_nolock(gspca_dev, file, memory);
+       mutex_unlock(&gspca_dev->queue_lock);
+       return ret;
+}
+
 /*
- * wait for a video frame
+ * dequeue a video buffer
  *
- * If a frame is ready, its index is returned.
+ * If nonblock_ing is false, block until a buffer is available.
  */
-static int frame_wait(struct gspca_dev *gspca_dev,
-                       int nonblock_ing)
+static int vidioc_dqbuf(struct file *file, void *priv,
+                       struct v4l2_buffer *v4l2_buf)
 {
-       int i, ret;
+       struct gspca_dev *gspca_dev = priv;
+       struct gspca_frame *frame;
+       int i, j, ret;
 
-       /* check if a frame is ready */
-       i = gspca_dev->fr_o;
-       if (i == atomic_read(&gspca_dev->fr_i)) {
-               if (nonblock_ing)
+       PDEBUG(D_FRAM, "dqbuf");
+
+       if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+               return -ERESTARTSYS;
+
+       for (;;) {
+               ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory);
+               if (ret < 0)
+                       goto out;
+               if (ret > 0)
+                       break;
+
+               mutex_unlock(&gspca_dev->queue_lock);
+
+               if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
 
                /* wait till a frame is ready */
                ret = wait_event_interruptible_timeout(gspca_dev->wq,
-                       i != atomic_read(&gspca_dev->fr_i) ||
-                       !gspca_dev->streaming || !gspca_dev->present,
+                       frame_ready(gspca_dev, file, v4l2_buf->memory),
                        msecs_to_jiffies(3000));
                if (ret < 0)
                        return ret;
-               if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present)
+               if (ret == 0)
                        return -EIO;
+
+               if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+                       return -ERESTARTSYS;
        }
 
+       i = gspca_dev->fr_o;
+       j = gspca_dev->fr_queue[i];
+       frame = &gspca_dev->frame[j];
+
        gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
 
        if (gspca_dev->sd_desc->dq_callback) {
@@ -1863,46 +1894,12 @@ static int frame_wait(struct gspca_dev *gspca_dev,
                        gspca_dev->sd_desc->dq_callback(gspca_dev);
                mutex_unlock(&gspca_dev->usb_lock);
        }
-       return gspca_dev->fr_queue[i];
-}
-
-/*
- * dequeue a video buffer
- *
- * If nonblock_ing is false, block until a buffer is available.
- */
-static int vidioc_dqbuf(struct file *file, void *priv,
-                       struct v4l2_buffer *v4l2_buf)
-{
-       struct gspca_dev *gspca_dev = priv;
-       struct gspca_frame *frame;
-       int i, ret;
-
-       PDEBUG(D_FRAM, "dqbuf");
-       if (v4l2_buf->memory != gspca_dev->memory)
-               return -EINVAL;
-
-       if (!gspca_dev->present)
-               return -ENODEV;
-
-       /* if not streaming, be sure the application will not loop forever */
-       if (!(file->f_flags & O_NONBLOCK)
-           && !gspca_dev->streaming && gspca_dev->users == 1)
-               return -EINVAL;
 
-       /* only the capturing file may dequeue */
-       if (gspca_dev->capt_file != file)
-               return -EINVAL;
-
-       /* only one dequeue / read at a time */
-       if (mutex_lock_interruptible(&gspca_dev->read_lock))
-               return -ERESTARTSYS;
+       frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+       memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+       PDEBUG(D_FRAM, "dqbuf %d", j);
+       ret = 0;
 
-       ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
-       if (ret < 0)
-               goto out;
-       i = ret;                                /* frame index */
-       frame = &gspca_dev->frame[i];
        if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
                if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
                                 frame->data,
@@ -1910,15 +1907,10 @@ static int vidioc_dqbuf(struct file *file, void *priv,
                        PDEBUG(D_ERR|D_STREAM,
                                "dqbuf cp to user failed");
                        ret = -EFAULT;
-                       goto out;
                }
        }
-       frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
-       memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
-       PDEBUG(D_FRAM, "dqbuf %d", i);
-       ret = 0;
 out:
-       mutex_unlock(&gspca_dev->read_lock);
+       mutex_unlock(&gspca_dev->queue_lock);
        return ret;
 }
 
@@ -2033,9 +2025,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
        poll_wait(file, &gspca_dev->wq, wait);
 
        /* if reqbufs is not done, the user would use read() */
-       if (gspca_dev->nframes == 0) {
-               if (gspca_dev->memory != GSPCA_MEMORY_NO)
-                       return POLLERR;         /* not the 1st time */
+       if (gspca_dev->memory == GSPCA_MEMORY_NO) {
                ret = read_alloc(gspca_dev, file);
                if (ret != 0)
                        return POLLERR;
@@ -2067,18 +2057,10 @@ static ssize_t dev_read(struct file *file, char __user *data,
        PDEBUG(D_FRAM, "read (%zd)", count);
        if (!gspca_dev->present)
                return -ENODEV;
-       switch (gspca_dev->memory) {
-       case GSPCA_MEMORY_NO:                   /* first time */
+       if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
                ret = read_alloc(gspca_dev, file);
                if (ret != 0)
                        return ret;
-               break;
-       case GSPCA_MEMORY_READ:
-               if (gspca_dev->capt_file == file)
-                       break;
-               /* fall thru */
-       default:
-               return -EINVAL;
        }
 
        /* get a frame */
@@ -2266,7 +2248,6 @@ int gspca_dev_probe2(struct usb_interface *intf,
                goto out;
 
        mutex_init(&gspca_dev->usb_lock);
-       mutex_init(&gspca_dev->read_lock);
        mutex_init(&gspca_dev->queue_lock);
        init_waitqueue_head(&gspca_dev->wq);
 
@@ -2341,12 +2322,11 @@ void gspca_disconnect(struct usb_interface *intf)
        PDEBUG(D_PROBE, "%s disconnect",
                video_device_node_name(&gspca_dev->vdev));
        mutex_lock(&gspca_dev->usb_lock);
+
        gspca_dev->present = 0;
+       wake_up_interruptible(&gspca_dev->wq);
 
-       if (gspca_dev->streaming) {
-               destroy_urbs(gspca_dev);
-               wake_up_interruptible(&gspca_dev->wq);
-       }
+       destroy_urbs(gspca_dev);
 
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        gspca_input_destroy_urb(gspca_dev);
index 97b77a2..4175522 100644 (file)
@@ -205,14 +205,12 @@ struct gspca_dev {
 
        wait_queue_head_t wq;           /* wait queue */
        struct mutex usb_lock;          /* usb exchange protection */
-       struct mutex read_lock;         /* read protection */
        struct mutex queue_lock;        /* ISOC queue protection */
        int usb_err;                    /* USB error - protected by usb_lock */
        u16 pkt_size;                   /* ISOC packet size */
 #ifdef CONFIG_PM
        char frozen;                    /* suspend - resume */
 #endif
-       char users;                     /* number of opens */
        char present;                   /* device connected */
        char nbufread;                  /* number of buffers for read() */
        char memory;                    /* memory type (V4L2_MEMORY_xxx) */
index a35e87b..06b777f 100644 (file)
@@ -314,7 +314,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 }
 
 /* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0979, 0x0280)},
        {}
 };
index de63c36..ab54910 100644 (file)
@@ -141,9 +141,9 @@ static void jpeg_define(u8 *jpeg_hdr,
        memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
 #ifndef CONEX_CAM
        jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
-       jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height;
        jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
-       jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+       jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width;
        jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
 #endif
 }
index d2ce65d..5964691 100644 (file)
@@ -607,7 +607,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */
        {}
 };
index c872b93..a7722b1 100644 (file)
@@ -28,7 +28,7 @@ int force_sensor;
 static int dump_bridge;
 int dump_sensor;
 
-static const __devinitdata struct usb_device_id m5602_table[] = {
+static const struct usb_device_id m5602_table[] = {
        {USB_DEVICE(0x0402, 0x5602)},
        {}
 };
index a81536e..cb4d0bf 100644 (file)
@@ -490,7 +490,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x050f)},
        {}
 };
index 7607a28..3884c9d 100644 (file)
@@ -1229,7 +1229,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x08ca, 0x0110)},   /* Trust Spyc@m 100 */
        {USB_DEVICE(0x08ca, 0x0111)},   /* Aiptek Pencam VGA+ */
        {USB_DEVICE(0x093a, 0x010f)},   /* All other known MR97310A VGA cams */
index e1c3b93..8ab2c45 100644 (file)
@@ -488,7 +488,6 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
 #define R511_SNAP_PXDIV                        0x1c
 #define R511_SNAP_LNDIV                        0x1d
 #define R511_SNAP_UV_EN                        0x1e
-#define R511_SNAP_UV_EN                        0x1e
 #define R511_SNAP_OPTS                 0x1f
 
 #define R511_DRAM_FLOW_CTL             0x20
@@ -1847,8 +1846,7 @@ static const struct ov_i2c_regvals norm_7670[] = {
        { 0x6c, 0x0a },
        { 0x6d, 0x55 },
        { 0x6e, 0x11 },
-       { 0x6f, 0x9f },
-                                       /* "9e for advance AWB" */
+       { 0x6f, 0x9f },                 /* "9e for advance AWB" */
        { 0x6a, 0x40 },
        { OV7670_R01_BLUE, 0x40 },
        { OV7670_R02_RED, 0x60 },
@@ -3054,7 +3052,7 @@ static void ov519_configure(struct sd *sd)
 {
        static const struct ov_regvals init_519[] = {
                { 0x5a, 0x6d }, /* EnableSystem */
-               { 0x53, 0x9b },
+               { 0x53, 0x9b }, /* don't enable the microcontroller */
                { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */
                { 0x5d, 0x03 },
                { 0x49, 0x01 },
@@ -4747,7 +4745,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
        {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
index 0edf939..04da228 100644 (file)
@@ -479,15 +479,20 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
        struct usb_device *udev = gspca_dev->dev;
        int ret;
 
-       PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val);
        gspca_dev->usb_buf[0] = val;
        ret = usb_control_msg(udev,
                              usb_sndctrlpipe(udev, 0),
                              0x01,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
-       if (ret < 0)
+       if (ret < 0) {
                err("write failed %d", ret);
+               gspca_dev->usb_err = ret;
+       }
 }
 
 static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -495,14 +500,18 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
        struct usb_device *udev = gspca_dev->dev;
        int ret;
 
+       if (gspca_dev->usb_err < 0)
+               return 0;
        ret = usb_control_msg(udev,
                              usb_rcvctrlpipe(udev, 0),
                              0x01,
                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
-       PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
-       if (ret < 0)
+       PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]);
+       if (ret < 0) {
                err("read failed %d", ret);
+               gspca_dev->usb_err = ret;
+       }
        return gspca_dev->usb_buf[0];
 }
 
@@ -558,13 +567,15 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
 
 static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
-       PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
+       PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val);
        ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
        ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
        ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
 
-       if (!sccb_check_status(gspca_dev))
+       if (!sccb_check_status(gspca_dev)) {
                err("sccb_reg_write failed");
+               gspca_dev->usb_err = -EIO;
+       }
 }
 
 static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -885,7 +896,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        ov534_set_led(gspca_dev, 0);
        set_frame_rate(gspca_dev);
 
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
@@ -920,7 +931,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        ov534_set_led(gspca_dev, 1);
        ov534_reg_write(gspca_dev, 0xe0, 0x00);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1289,7 +1300,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x1415, 0x2000)},
        {}
 };
index c5244b4..aaf5428 100644 (file)
@@ -1429,7 +1429,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x06f8, 0x3003)},
        {}
 };
index 96f9986..81739a2 100644 (file)
@@ -530,7 +530,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4028)},
        {USB_DEVICE(0x093a, 0x2460)},
        {USB_DEVICE(0x093a, 0x2461)},
index 2700975..5615d7b 100644 (file)
@@ -1184,7 +1184,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x06f8, 0x3009)},
        {USB_DEVICE(0x093a, 0x2620)},
        {USB_DEVICE(0x093a, 0x2621)},
@@ -1201,7 +1201,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
index 6820f5d..f8801b5 100644 (file)
@@ -837,7 +837,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2600)},
        {USB_DEVICE(0x093a, 0x2601)},
        {USB_DEVICE(0x093a, 0x2603)},
@@ -849,7 +849,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
index 40a0668..4271f86 100644 (file)
@@ -703,7 +703,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
        /* The Genius Smart is untested. I can't find an owner ! */
        /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
index cb08d00..fcf2989 100644 (file)
@@ -2470,7 +2470,7 @@ static const struct sd_desc sd_desc = {
                        | (SENSOR_ ## sensor << 8) \
                        | (i2c_addr)
 
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
        {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
        {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
index 73504a3..c6cd68d 100644 (file)
 /* Some documentation on known sonixb registers:
 
 Reg    Use
+sn9c101 / sn9c102:
 0x10   high nibble red gain low nibble blue gain
 0x11   low nibble green gain
+sn9c103:
+0x05   red gain 0-127
+0x06   blue gain 0-127
+0x07   green gain 0-127
+all:
+0x08-0x0f i2c / 3wire registers
 0x12   hstart
 0x13   vstart
 0x15   hsize (hsize = register-value * 16)
@@ -88,12 +95,9 @@ struct sd {
 typedef const __u8 sensor_init_t[8];
 
 struct sensor_data {
-       const __u8 *bridge_init[2];
-       int bridge_init_size[2];
+       const __u8 *bridge_init;
        sensor_init_t *sensor_init;
        int sensor_init_size;
-       sensor_init_t *sensor_bridge_init[2];
-       int sensor_bridge_init_size[2];
        int flags;
        unsigned ctrl_dis;
        __u8 sensor_addr;
@@ -114,7 +118,6 @@ struct sensor_data {
 #define NO_FREQ (1 << FREQ_IDX)
 #define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
 
-#define COMP2 0x8f
 #define COMP 0xc7              /* 0x87 //0x07 */
 #define COMP1 0xc9             /* 0x89 //0x09 */
 
@@ -123,15 +126,11 @@ struct sensor_data {
 
 #define SYS_CLK 0x04
 
-#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
-       sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \
 { \
-       .bridge_init = { bridge_1, bridge_3 }, \
-       .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+       .bridge_init = bridge, \
        .sensor_init = sensor, \
        .sensor_init_size = sizeof(sensor), \
-       .sensor_bridge_init = { sensor_1, sensor_3,}, \
-       .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
        .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
 }
 
@@ -311,7 +310,6 @@ static const __u8 initHv7131d[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
        0x28, 0x1e, 0x60, 0x8e, 0x42,
-       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
 };
 static const __u8 hv7131d_sensor_init[][8] = {
        {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17},
@@ -326,7 +324,6 @@ static const __u8 initHv7131r[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
        0x28, 0x1e, 0x60, 0x8a, 0x20,
-       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
 };
 static const __u8 hv7131r_sensor_init[][8] = {
        {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
@@ -339,7 +336,7 @@ static const __u8 initOv6650[] = {
        0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
        0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
-       0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
+       0x10,
 };
 static const __u8 ov6650_sensor_init[][8] = {
        /* Bright, contrast, etc are set through SCBB interface.
@@ -378,24 +375,13 @@ static const __u8 initOv7630[] = {
        0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
        0x00, 0x01, 0x01, 0x0a,                         /* r11 .. r14 */
        0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
-       0x68, COMP2, MCK_INIT1,                         /* r17 .. r19 */
-       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c              /* r1a .. r1f */
-};
-static const __u8 initOv7630_3[] = {
-       0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
-       0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
-       0x00, 0x02, 0x01, 0x0a,                         /* r11 .. r14 */
-       0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
        0x68, 0x8f, MCK_INIT1,                          /* r17 .. r19 */
-       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00,       /* r1a .. r20 */
-       0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
-       0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff  /* r29 .. r30 */
 };
 static const __u8 ov7630_sensor_init[][8] = {
        {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
        {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
 /*     {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10},          jfm */
-       {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10},       /* jfm */
+       {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10},       /* jfm */
        {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
        {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
        {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
@@ -413,16 +399,11 @@ static const __u8 ov7630_sensor_init[][8] = {
        {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
 };
 
-static const __u8 ov7630_sensor_init_3[][8] = {
-       {0xa0, 0x21, 0x13, 0x80, 0x00,  0x00, 0x00, 0x10},
-};
-
 static const __u8 initPas106[] = {
        0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
        0x16, 0x12, 0x24, COMP1, MCK_INIT1,
-       0x18, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 /* compression 0x86 mckinit1 0x2b */
 
@@ -496,7 +477,6 @@ static const __u8 initPas202[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
        0x28, 0x1e, 0x20, 0x89, 0x20,
-       0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
 };
 
 /* "Known" PAS202BCB registers:
@@ -537,7 +517,6 @@ static const __u8 initTas5110c[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x45, 0x09, 0x0a,
        0x16, 0x12, 0x60, 0x86, 0x2b,
-       0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
 };
 /* Same as above, except a different hstart */
 static const __u8 initTas5110d[] = {
@@ -545,12 +524,19 @@ static const __u8 initTas5110d[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x41, 0x09, 0x0a,
        0x16, 0x12, 0x60, 0x86, 0x2b,
-       0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
 };
-static const __u8 tas5110_sensor_init[][8] = {
+/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */
+static const __u8 tas5110c_sensor_init[][8] = {
        {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
        {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
-       {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+/* Known TAS5110D registers
+ * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain
+ * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted)
+ *        Note: writing reg03 seems to only work when written together with 02
+ */
+static const __u8 tas5110d_sensor_init[][8] = {
+       {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */
 };
 
 static const __u8 initTas5130[] = {
@@ -558,7 +544,6 @@ static const __u8 initTas5130[] = {
        0x00, 0x00,
        0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a,
        0x28, 0x1e, 0x60, COMP, MCK_INIT,
-       0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
 };
 static const __u8 tas5130_sensor_init[][8] = {
 /*     {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
@@ -569,21 +554,18 @@ static const __u8 tas5130_sensor_init[][8] = {
 };
 
 static struct sensor_data sensor_data[] = {
-SENS(initHv7131d, NULL, hv7131d_sensor_init, NULL, NULL, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initHv7131r, NULL, hv7131r_sensor_init, NULL, NULL, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
-SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
-SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
-       F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
-       0),
-SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
-       NO_FREQ, 0),
-SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL,
-       F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL,
-       F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
-       0),
+SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21),
+SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0),
+SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0),
+SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+       NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+       NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, tas5130_sensor_init, F_GAIN,
+       NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
 };
 
 /* get one byte in gspca_dev->usb_buf */
@@ -655,7 +637,6 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev,
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 value;
 
        switch (sd->sensor) {
        case  SENSOR_OV6650:
@@ -697,17 +678,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
-       case SENSOR_TAS5130CXX: {
-               __u8 i2c[] =
-                       {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
-
-               value = 0xff - sd->brightness;
-               i2c[4] = value;
-               PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
-               if (i2c_w(gspca_dev, i2c) < 0)
-                       goto err;
-               break;
-           }
        }
        return;
 err:
@@ -733,7 +703,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
                break;
            }
        case SENSOR_TAS5110C:
-       case SENSOR_TAS5110D: {
+       case SENSOR_TAS5130CXX: {
                __u8 i2c[] =
                        {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
 
@@ -742,6 +712,23 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
+       case SENSOR_TAS5110D: {
+               __u8 i2c[] = {
+                       0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 };
+               gain = 255 - gain;
+               /* The bits in the register are the wrong way around!! */
+               i2c[3] |= (gain & 0x80) >> 7;
+               i2c[3] |= (gain & 0x40) >> 5;
+               i2c[3] |= (gain & 0x20) >> 3;
+               i2c[3] |= (gain & 0x10) >> 1;
+               i2c[3] |= (gain & 0x08) << 1;
+               i2c[3] |= (gain & 0x04) << 3;
+               i2c[3] |= (gain & 0x02) << 5;
+               i2c[3] |= (gain & 0x01) << 7;
+               if (i2c_w(gspca_dev, i2c) < 0)
+                       goto err;
+               break;
+           }
 
        case SENSOR_OV6650:
                gain >>= 1;
@@ -796,7 +783,7 @@ static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 gain;
-       __u8 buf[2] = { 0, 0 };
+       __u8 buf[3] = { 0, 0, 0 };
 
        if (sensor_data[sd->sensor].flags & F_GAIN) {
                /* Use the sensor gain to do the actual gain */
@@ -804,13 +791,18 @@ static void setgain(struct gspca_dev *gspca_dev)
                return;
        }
 
-       gain = sd->gain >> 4;
-
-       /* red and blue gain */
-       buf[0] = gain << 4 | gain;
-       /* green gain */
-       buf[1] = gain;
-       reg_w(gspca_dev, 0x10, buf, 2);
+       if (sd->bridge == BRIDGE_103) {
+               gain = sd->gain >> 1;
+               buf[0] = gain; /* Red */
+               buf[1] = gain; /* Green */
+               buf[2] = gain; /* Blue */
+               reg_w(gspca_dev, 0x05, buf, 3);
+       } else {
+               gain = sd->gain >> 4;
+               buf[0] = gain << 4 | gain; /* Red and blue */
+               buf[1] = gain; /* Green */
+               reg_w(gspca_dev, 0x10, buf, 2);
+       }
 }
 
 static void setexposure(struct gspca_dev *gspca_dev)
@@ -1049,7 +1041,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                desired_avg_lum = 5000;
        } else {
                deadzone = 1500;
-               desired_avg_lum = 18000;
+               desired_avg_lum = 13000;
        }
 
        if (sensor_data[sd->sensor].flags & F_COARSE_EXPO)
@@ -1127,53 +1119,91 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam = &gspca_dev->cam;
-       int mode, l;
-       const __u8 *sn9c10x;
-       __u8 reg12_19[8];
+       int i, mode;
+       __u8 regs[0x31];
 
        mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
-       sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
-       l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
-       memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
-       reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
-       /* Special cases where reg 17 and or 19 value depends on mode */
+       /* Copy registers 0x01 - 0x19 from the template */
+       memcpy(&regs[0x01], sensor_data[sd->sensor].bridge_init, 0x19);
+       /* Set the mode */
+       regs[0x18] |= mode << 4;
+
+       /* Set bridge gain to 1.0 */
+       if (sd->bridge == BRIDGE_103) {
+               regs[0x05] = 0x20; /* Red */
+               regs[0x06] = 0x20; /* Green */
+               regs[0x07] = 0x20; /* Blue */
+       } else {
+               regs[0x10] = 0x00; /* Red and blue */
+               regs[0x11] = 0x00; /* Green */
+       }
+
+       /* Setup pixel numbers and auto exposure window */
+       if (sensor_data[sd->sensor].flags & F_SIF) {
+               regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */
+               regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */
+               regs[0x1c] = 0x02; /* AE H-start 64 */
+               regs[0x1d] = 0x02; /* AE V-start 64 */
+               regs[0x1e] = 0x09; /* AE H-end 288 */
+               regs[0x1f] = 0x07; /* AE V-end 224 */
+       } else {
+               regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */
+               regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */
+               regs[0x1c] = 0x05; /* AE H-start 160 */
+               regs[0x1d] = 0x03; /* AE V-start 96 */
+               regs[0x1e] = 0x0f; /* AE H-end 480 */
+               regs[0x1f] = 0x0c; /* AE V-end 384 */
+       }
+
+       /* Setup the gamma table (only used with the sn9c103 bridge) */
+       for (i = 0; i < 16; i++)
+               regs[0x20 + i] = i * 16;
+       regs[0x20 + i] = 255;
+
+       /* Special cases where some regs depend on mode or bridge */
        switch (sd->sensor) {
        case SENSOR_TAS5130CXX:
-               /* probably not mode specific at all most likely the upper
+               /* FIXME / TESTME
+                  probably not mode specific at all most likely the upper
                   nibble of 0x19 is exposure (clock divider) just as with
                   the tas5110, we need someone to test this. */
-               reg12_19[7] = mode ? 0x23 : 0x43;
+               regs[0x19] = mode ? 0x23 : 0x43;
                break;
+       case SENSOR_OV7630:
+               /* FIXME / TESTME for some reason with the 101/102 bridge the
+                  clock is set to 12 Mhz (reg1 == 0x04), rather then 24.
+                  Also the hstart needs to go from 1 to 2 when using a 103,
+                  which is likely related. This does not seem right. */
+               if (sd->bridge == BRIDGE_103) {
+                       regs[0x01] = 0x44; /* Select 24 Mhz clock */
+                       regs[0x12] = 0x02; /* Set hstart to 2 */
+               }
        }
        /* Disable compression when the raw bayer format has been selected */
        if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
-               reg12_19[6] &= ~0x80;
+               regs[0x18] &= ~0x80;
 
        /* Vga mode emulation on SIF sensor? */
        if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
-               reg12_19[0] += 16; /* 0x12: hstart adjust */
-               reg12_19[1] += 24; /* 0x13: vstart adjust */
-               reg12_19[3] = 320 / 16; /* 0x15: hsize */
-               reg12_19[4] = 240 / 16; /* 0x16: vsize */
+               regs[0x12] += 16;       /* hstart adjust */
+               regs[0x13] += 24;       /* vstart adjust */
+               regs[0x15]  = 320 / 16; /* hsize */
+               regs[0x16]  = 240 / 16; /* vsize */
        }
 
        /* reg 0x01 bit 2 video transfert on */
-       reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
+       reg_w(gspca_dev, 0x01, &regs[0x01], 1);
        /* reg 0x17 SensorClk enable inv Clk 0x60 */
-       reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
+       reg_w(gspca_dev, 0x17, &regs[0x17], 1);
        /* Set the registers from the template */
-       reg_w(gspca_dev, 0x01, sn9c10x, l);
+       reg_w(gspca_dev, 0x01, &regs[0x01],
+             (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f);
 
        /* Init the sensor */
        i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
                        sensor_data[sd->sensor].sensor_init_size);
-       if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
-               i2c_w_vector(gspca_dev,
-                       sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
-                       sensor_data[sd->sensor].sensor_bridge_init_size[
-                               sd->bridge]);
 
-       /* Mode specific sensor setup */
+       /* Mode / bridge specific sensor setup */
        switch (sd->sensor) {
        case SENSOR_PAS202: {
                const __u8 i2cpclockdiv[] =
@@ -1181,27 +1211,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
                /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
                if (mode)
                        i2c_w(gspca_dev, i2cpclockdiv);
+               break;
            }
+       case SENSOR_OV7630:
+               /* FIXME / TESTME We should be able to handle this identical
+                  for the 101/102 and the 103 case */
+               if (sd->bridge == BRIDGE_103) {
+                       const __u8 i2c[] = { 0xa0, 0x21, 0x13,
+                                            0x80, 0x00, 0x00, 0x00, 0x10 };
+                       i2c_w(gspca_dev, i2c);
+               }
+               break;
        }
        /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
-       reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
+       reg_w(gspca_dev, 0x15, &regs[0x15], 2);
        /* compression register */
-       reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
+       reg_w(gspca_dev, 0x18, &regs[0x18], 1);
        /* H_start */
-       reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
+       reg_w(gspca_dev, 0x12, &regs[0x12], 1);
        /* V_START */
-       reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
+       reg_w(gspca_dev, 0x13, &regs[0x13], 1);
        /* reset 0x17 SensorClk enable inv Clk 0x60 */
                                /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
-       reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
+       reg_w(gspca_dev, 0x17, &regs[0x17], 1);
        /*MCKSIZE ->3 */        /*fixme: not ov7630*/
-       reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
+       reg_w(gspca_dev, 0x19, &regs[0x19], 1);
        /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
-       reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+       reg_w(gspca_dev, 0x1c, &regs[0x1c], 4);
        /* Enable video transfert */
-       reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
+       reg_w(gspca_dev, 0x01, &regs[0x01], 1);
        /* Compression */
-       reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
+       reg_w(gspca_dev, 0x18, &regs[0x18], 2);
        msleep(20);
 
        sd->reg11 = -1;
@@ -1525,15 +1565,15 @@ static const struct sd_desc sd_desc = {
        .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
 
 
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
        {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
        {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
        {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
        {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
        {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
        {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
 #endif
@@ -1544,18 +1584,22 @@ static const struct usb_device_id device_table[] __devinitconst = {
        {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
        {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
        {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
-       /* {USB_DEVICE(0x0c45, 0x602b), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
+       /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
+       /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */
+       {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)},
+       {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)},
+       /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */
        {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)},
+       {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)},
        {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
-#endif
        {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
index 2d0bb17..d6f39ce 100644 (file)
 #include "gspca.h"
 #include "jpeg.h"
 
-#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
-
 MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+static int starcam;
+
 /* controls */
 enum e_ctrl {
        BRIGHTNESS,
@@ -43,7 +43,7 @@ enum e_ctrl {
        HFLIP,
        VFLIP,
        SHARPNESS,
-       INFRARED,
+       ILLUM,
        FREQ,
        NCTRLS          /* number of controls */
 };
@@ -100,7 +100,8 @@ enum sensors {
 };
 
 /* device flags */
-#define PDN_INV        1               /* inverse pin S_PWR_DN / sn_xxx tables */
+#define F_PDN_INV      0x01    /* inverse pin S_PWR_DN / sn_xxx tables */
+#define F_ILLUM                0x02    /* presence of illuminator */
 
 /* sn9c1xx definitions */
 /* register 0x01 */
@@ -124,7 +125,7 @@ static void setgamma(struct gspca_dev *gspca_dev);
 static void setautogain(struct gspca_dev *gspca_dev);
 static void sethvflip(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
-static void setinfrared(struct gspca_dev *gspca_dev);
+static void setillum(struct gspca_dev *gspca_dev);
 static void setfreq(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[NCTRLS] = {
@@ -251,18 +252,17 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
            },
            .set_control = setsharpness
        },
-/* mt9v111 only */
-[INFRARED] = {
+[ILLUM] = {
            {
-               .id      = V4L2_CID_INFRARED,
+               .id      = V4L2_CID_ILLUMINATORS_1,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
-               .name    = "Infrared",
+               .name    = "Illuminator / infrared",
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
                .default_value = 0,
            },
-           .set_control = setinfrared
+           .set_control = setillum
        },
 /* ov7630/ov7648/ov7660 only */
 [FREQ] = {
@@ -282,32 +282,26 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
 /* table of the disabled controls */
 static const __u32 ctrl_dis[] = {
 [SENSOR_ADCM1700] =    (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_GC0307] =      (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_GC0307] =      (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_HV7131R] =     (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_HV7131R] =     (1 << HFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MI0360] =      (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_MI0360] =      (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MI0360B] =     (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_MI0360B] =     (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MO4000] =      (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_MO4000] =      (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
@@ -315,40 +309,32 @@ static const __u32 ctrl_dis[] = {
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_OM6802] =      (1 << INFRARED) |
-                       (1 << HFLIP) |
+[SENSOR_OM6802] =      (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_OV7630] =      (1 << INFRARED) |
-                       (1 << HFLIP),
+[SENSOR_OV7630] =      (1 << HFLIP),
 
-[SENSOR_OV7648] =      (1 << INFRARED) |
-                       (1 << HFLIP),
+[SENSOR_OV7648] =      (1 << HFLIP),
 
 [SENSOR_OV7660] =      (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << HFLIP) |
                        (1 << VFLIP),
 
 [SENSOR_PO1030] =      (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
 [SENSOR_PO2030N] =     (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << FREQ),
 
 [SENSOR_SOI768] =      (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
 [SENSOR_SP80708] =     (1 << AUTOGAIN) |
-                       (1 << INFRARED) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
@@ -1822,44 +1808,46 @@ static int sd_init(struct gspca_dev *gspca_dev)
        PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
        switch (sd->bridge) {
        case BRIDGE_SN9C102P:
+       case BRIDGE_SN9C105:
                if (regF1 != 0x11)
                        return -ENODEV;
+               break;
+       default:
+/*     case BRIDGE_SN9C110: */
+/*     case BRIDGE_SN9C120: */
+               if (regF1 != 0x12)
+                       return -ENODEV;
+       }
+
+       switch (sd->sensor) {
+       case SENSOR_MI0360:
+               mi0360_probe(gspca_dev);
+               break;
+       case SENSOR_OV7630:
+               ov7630_probe(gspca_dev);
+               break;
+       case SENSOR_OV7648:
+               ov7648_probe(gspca_dev);
+               break;
+       case SENSOR_PO2030N:
+               po2030n_probe(gspca_dev);
+               break;
+       }
+
+       switch (sd->bridge) {
+       case BRIDGE_SN9C102P:
                reg_w1(gspca_dev, 0x02, regGpio[1]);
                break;
        case BRIDGE_SN9C105:
-               if (regF1 != 0x11)
-                       return -ENODEV;
-               if (sd->sensor == SENSOR_MI0360)
-                       mi0360_probe(gspca_dev);
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
+       case BRIDGE_SN9C110:
+               reg_w1(gspca_dev, 0x02, 0x62);
+               break;
        case BRIDGE_SN9C120:
-               if (regF1 != 0x12)
-                       return -ENODEV;
-               switch (sd->sensor) {
-               case SENSOR_MI0360:
-                       mi0360_probe(gspca_dev);
-                       break;
-               case SENSOR_OV7630:
-                       ov7630_probe(gspca_dev);
-                       break;
-               case SENSOR_OV7648:
-                       ov7648_probe(gspca_dev);
-                       break;
-               case SENSOR_PO2030N:
-                       po2030n_probe(gspca_dev);
-                       break;
-               }
                regGpio[1] = 0x70;              /* no audio */
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
-       default:
-/*     case BRIDGE_SN9C110: */
-/*     case BRIDGE_SN9C325: */
-               if (regF1 != 0x12)
-                       return -ENODEV;
-               reg_w1(gspca_dev, 0x02, 0x62);
-               break;
        }
 
        if (sd->sensor == SENSOR_OM6802)
@@ -1874,6 +1862,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
        sd->i2c_addr = sn9c1xx[9];
 
        gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+       if (!(sd->flags & F_ILLUM))
+               gspca_dev->ctrl_dis |= (1 << ILLUM);
 
        return gspca_dev->usb_err;
 }
@@ -2197,16 +2187,28 @@ static void setsharpness(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val);
 }
 
-static void setinfrared(struct gspca_dev *gspca_dev)
+static void setillum(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (gspca_dev->ctrl_dis & (1 << INFRARED))
+       if (gspca_dev->ctrl_dis & (1 << ILLUM))
                return;
-/*fixme: different sequence for StarCam Clip and StarCam 370i */
-/* Clip */
-       i2c_w1(gspca_dev, 0x02,                         /* gpio */
-               sd->ctrls[INFRARED].val ? 0x66 : 0x64);
+       switch (sd->sensor) {
+       case SENSOR_ADCM1700:
+               reg_w1(gspca_dev, 0x02,                         /* gpio */
+                       sd->ctrls[ILLUM].val ? 0x64 : 0x60);
+               break;
+       case SENSOR_MT9V111:
+               if (starcam)
+                       reg_w1(gspca_dev, 0x02,
+                               sd->ctrls[ILLUM].val ?
+                                               0x55 : 0x54);   /* 370i */
+               else
+                       reg_w1(gspca_dev, 0x02,
+                               sd->ctrls[ILLUM].val ?
+                                               0x66 : 0x64);   /* Clip */
+               break;
+       }
 }
 
 static void setfreq(struct gspca_dev *gspca_dev)
@@ -2344,7 +2346,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* sensor clock already enabled in sd_init */
        /* reg_w1(gspca_dev, 0xf1, 0x00); */
        reg01 = sn9c1xx[1];
-       if (sd->flags & PDN_INV)
+       if (sd->flags & F_PDN_INV)
                reg01 ^= S_PDN_INV;             /* power down inverted */
        reg_w1(gspca_dev, 0x01, reg01);
 
@@ -2907,13 +2909,11 @@ static const struct sd_desc sd_desc = {
        .driver_info = (BRIDGE_ ## bridge << 16) \
                        | (SENSOR_ ## sensor << 8) \
                        | (flags)
-static const __devinitdata struct usb_device_id device_table[] = {
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
        {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
-#endif
-       {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)},
-       {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)},
+       {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)},
+       {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)},
        {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
        {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
        {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
@@ -2925,7 +2925,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */
        {USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)},
 /*     {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */
-       {USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)},
+       {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)},
                                                /* or MT9V111 */
 /*     {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
 /*     {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
@@ -2936,10 +2936,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */
 /*     {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */
        {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)},
        {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
-#endif
        {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)},      /*sn9c128*/
        {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)},     /* /GC0305*/
 /*     {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
@@ -2962,16 +2960,15 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */
        {USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)},
        {USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)},
-#endif
        {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
        {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
        {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)},     /*sn9c120b*/
                                                /* or GC0305 / GC0307 */
        {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)},     /*sn9c120b*/
        {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)},      /*sn9c120b*/
-       {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)},    /*sn9c120b*/
+       {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)},
+/*     {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */   /*sn9c120b*/
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -3007,3 +3004,7 @@ static void __exit sd_mod_exit(void)
 
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
+
+module_param(starcam, int, 0644);
+MODULE_PARM_DESC(starcam,
+       "StarCam model. 0: Clip, 1: 370i");
index e643386..76c006b 100644 (file)
@@ -555,7 +555,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x04fc, 0x1528)},
        {}
 };
index 8e202b9..45552c3 100644 (file)
@@ -1051,7 +1051,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
        {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
        {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
index 642839a..f7ef282 100644 (file)
@@ -2155,7 +2155,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325},
        {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera},
        {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite},
index bc9dd90..e5bf865 100644 (file)
@@ -786,7 +786,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra},
        {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro},
 /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
index 7307638..3483193 100644 (file)
@@ -1509,7 +1509,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam},
        {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista},
        {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110},
index 3a162c6..e836e77 100644 (file)
@@ -1061,7 +1061,7 @@ static const struct sd_desc *sd_desc[2] = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
        {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
        {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
index 4040677..2e9c061 100644 (file)
@@ -396,7 +396,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 }
 
 /* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x2770, 0x9120)},
        {}
 };
index 8ba1995..457563b 100644 (file)
@@ -298,7 +298,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 }
 
 /* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x2770, 0x905c)},
        {USB_DEVICE(0x2770, 0x9050)},
        {USB_DEVICE(0x2770, 0x9051)},
index a4a9881..8215d5d 100644 (file)
@@ -1163,7 +1163,7 @@ static const struct sd_desc sd_desc = {
 #define ST(sensor, type) \
        .driver_info = (SENSOR_ ## sensor << 8) \
                        | (type)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
        {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
        {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
index 11a192b..87be52b 100644 (file)
@@ -495,7 +495,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x05e1, 0x0893)},
        {}
 };
index b199ad4..e2ef41c 100644 (file)
@@ -327,7 +327,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0553, 0x0202)},
        {USB_DEVICE(0x041e, 0x4007)},
        {}
index 28ea417..7e06614 100644 (file)
@@ -564,7 +564,7 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
 
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        /* QuickCam Express */
        {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },
        /* LEGO cam / QuickCam Web */
index a9cbcd6..543542a 100644 (file)
@@ -1162,7 +1162,7 @@ static const struct sd_desc sd_desc = {
 #define BS(bridge, subtype) \
        .driver_info = (BRIDGE_ ## bridge << 8) \
                        | (subtype)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
        {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
        {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
index 8f0c331..a3eccd8 100644 (file)
@@ -1416,7 +1416,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x17a1, 0x0128)},
        {}
 };
index 38c22f0..933ef2c 100644 (file)
@@ -388,7 +388,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x046d, 0x0920)},
        {USB_DEVICE(0x046d, 0x0921)},
        {USB_DEVICE(0x0545, 0x808b)},
index 9b2ae1b..6caed73 100644 (file)
@@ -4192,7 +4192,7 @@ static const struct sd_desc sd_desc = {
 #define BF(bridge, flags) \
        .driver_info = (BRIDGE_ ## bridge << 8) \
                | (flags)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
        {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
        {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
index 5b5039a..c089a0f 100644 (file)
@@ -3270,7 +3270,7 @@ static const struct sd_desc sd_desc_isoc_nego = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 },
        { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 },
        { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
index 14b85d4..47236a5 100644 (file)
@@ -5793,7 +5793,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
                        break;
                default:
 /*             case 0xdd:       * delay */
-                       msleep(action->val / 64 + 10);
+                       msleep(action->idx);
                        break;
                }
                action++;
@@ -5830,7 +5830,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
                [SENSOR_GC0305] =       gc0305_matrix,
                [SENSOR_HDCS2020b] =    NULL,
                [SENSOR_HV7131B] =      NULL,
-               [SENSOR_HV7131R] =      NULL,
+               [SENSOR_HV7131R] =      po2030_matrix,
                [SENSOR_ICM105A] =      po2030_matrix,
                [SENSOR_MC501CB] =      NULL,
                [SENSOR_MT9V111_1] =    gc0305_matrix,
@@ -5936,6 +5936,7 @@ static void setquality(struct gspca_dev *gspca_dev)
        case SENSOR_ADCM2700:
        case SENSOR_GC0305:
        case SENSOR_HV7131B:
+       case SENSOR_HV7131R:
        case SENSOR_OV7620:
        case SENSOR_PAS202B:
        case SENSOR_PO2030:
@@ -6108,11 +6109,13 @@ static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
                reg_w(gspca_dev, 0x02, 0x003b);
                reg_w(gspca_dev, 0x00, 0x0038);
                break;
+       case SENSOR_HV7131R:
        case SENSOR_PAS202B:
                reg_w(gspca_dev, 0x03, 0x003b);
                reg_w(gspca_dev, 0x0c, 0x003a);
                reg_w(gspca_dev, 0x0b, 0x0039);
-               reg_w(gspca_dev, 0x0b, 0x0038);
+               if (sensor == SENSOR_PAS202B)
+                       reg_w(gspca_dev, 0x0b, 0x0038);
                break;
        }
 }
@@ -6704,10 +6707,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x02, 0x003b);
                reg_w(gspca_dev, 0x00, 0x0038);
                break;
+       case SENSOR_HV7131R:
        case SENSOR_PAS202B:
                reg_w(gspca_dev, 0x03, 0x003b);
                reg_w(gspca_dev, 0x0c, 0x003a);
                reg_w(gspca_dev, 0x0b, 0x0039);
+               if (sd->sensor == SENSOR_HV7131R)
+                       reg_w(gspca_dev, 0x50, ZC3XX_R11D_GLOBALGAIN);
                break;
        }
 
@@ -6720,6 +6726,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_PAS202B:
        case SENSOR_GC0305:
+       case SENSOR_HV7131R:
        case SENSOR_TAS5130C:
                reg_r(gspca_dev, 0x0008);
                /* fall thru */
@@ -6760,6 +6767,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                                /* ms-win + */
                reg_w(gspca_dev, 0x40, 0x0117);
                break;
+       case SENSOR_HV7131R:
+               i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */
+               i2c_write(gspca_dev, 0x26, 0x93, 0x00);
+               i2c_write(gspca_dev, 0x27, 0xe0, 0x00);
+               reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
+               break;
        case SENSOR_GC0305:
        case SENSOR_TAS5130C:
                reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
@@ -6808,9 +6821,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (data[0] == 0xff && data[1] == 0xd8) {       /* start of frame */
+       /* check the JPEG end of frame */
+       if (len >= 3
+        && data[len - 3] == 0xff && data[len - 2] == 0xd9) {
+/*fixme: what does the last byte mean?*/
                gspca_frame_add(gspca_dev, LAST_PACKET,
-                                       NULL, 0);
+                                       data, len - 1);
+               return;
+       }
+
+       /* check the JPEG start of a frame */
+       if (data[0] == 0xff && data[1] == 0xd8) {
                /* put the JPEG header in the new frame */
                gspca_frame_add(gspca_dev, FIRST_PACKET,
                        sd->jpeg_hdr, JPEG_HDR_SZ);
@@ -6909,7 +6930,7 @@ static const struct sd_desc sd_desc = {
 #endif
 };
 
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x041e)},
        {USB_DEVICE(0x041e, 0x4017)},
        {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
index e0230fc..3baa9f6 100644 (file)
@@ -1,6 +1,4 @@
-hdpvr-objs     := hdpvr-control.o hdpvr-core.o hdpvr-video.o
-
-hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
+hdpvr-objs     := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
 
 obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
 
index f7d1ee5..a27d93b 100644 (file)
@@ -283,6 +283,7 @@ static int hdpvr_probe(struct usb_interface *interface,
        struct hdpvr_device *dev;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
+       struct i2c_client *client;
        size_t buffer_size;
        int i;
        int retval = -ENOMEM;
@@ -378,25 +379,35 @@ static int hdpvr_probe(struct usb_interface *interface,
                goto error;
        }
 
-#ifdef CONFIG_I2C
-       /* until i2c is working properly */
-       retval = 0; /* hdpvr_register_i2c_adapter(dev); */
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       retval = hdpvr_register_i2c_adapter(dev);
        if (retval < 0) {
-               v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
+               v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
                goto error;
        }
 
-       /* until i2c is working properly */
-       retval = 0; /* hdpvr_register_i2c_ir(dev); */
-       if (retval < 0)
-               v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
-#endif /* CONFIG_I2C */
+       client = hdpvr_register_ir_rx_i2c(dev);
+       if (!client) {
+               v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n");
+               goto reg_fail;
+       }
+
+       client = hdpvr_register_ir_tx_i2c(dev);
+       if (!client) {
+               v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n");
+               goto reg_fail;
+       }
+#endif
 
        /* let the user know what node this device is now attached to */
        v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
                  video_device_node_name(dev->video_dev));
        return 0;
 
+reg_fail:
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_adapter(&dev->i2c_adapter);
+#endif
 error:
        if (dev) {
                /* Destroy single thread */
@@ -426,6 +437,9 @@ static void hdpvr_disconnect(struct usb_interface *interface)
        mutex_lock(&dev->io_mutex);
        hdpvr_cancel_queue(dev);
        mutex_unlock(&dev->io_mutex);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_adapter(&dev->i2c_adapter);
+#endif
        video_unregister_device(dev->video_dev);
        atomic_dec(&dev_nr);
 }
index 24966aa..e53fa55 100644 (file)
@@ -13,6 +13,8 @@
  *
  */
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
 #include <linux/i2c.h>
 #include <linux/slab.h>
 
 #define Z8F0811_IR_TX_I2C_ADDR 0x70
 #define Z8F0811_IR_RX_I2C_ADDR 0x71
 
-static const u8 ir_i2c_addrs[] = {
-       Z8F0811_IR_TX_I2C_ADDR,
-       Z8F0811_IR_RX_I2C_ADDR,
-};
-
-static const char * const ir_devicenames[] = {
-       "ir_tx_z8f0811_hdpvr",
-       "ir_rx_z8f0811_hdpvr",
-};
 
-static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,
-                           const char *type, u8 addr)
+struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev)
 {
-       struct i2c_board_info info;
        struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
-       unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+       struct i2c_board_info hdpvr_ir_tx_i2c_board_info = {
+               I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
+       };
 
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       strlcpy(info.type, type, I2C_NAME_SIZE);
-
-       /* Our default information for ir-kbd-i2c.c to use */
-       switch (addr) {
-       case Z8F0811_IR_RX_I2C_ADDR:
-               init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
-               init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
-               init_data->type = RC_TYPE_RC5;
-               init_data->name = "HD PVR";
-               info.platform_data = init_data;
-               break;
-       }
+       init_data->name = "HD-PVR";
+       hdpvr_ir_tx_i2c_board_info.platform_data = init_data;
 
-       return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
-              -1 : 0;
+       return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info);
 }
 
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
+struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev)
 {
-       int i;
-       int ret = 0;
+       struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
+       struct i2c_board_info hdpvr_ir_rx_i2c_board_info = {
+               I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
+       };
 
-       for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++)
-               ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter,
-                                       ir_devicenames[i], ir_i2c_addrs[i]);
+       /* Our default information for ir-kbd-i2c.c to use */
+       init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+       init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+       init_data->type = RC_TYPE_RC5;
+       init_data->name = "HD-PVR";
+       hdpvr_ir_rx_i2c_board_info.platform_data = init_data;
 
-       return ret;
+       return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info);
 }
 
-static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
-                         char *data, int len)
+static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
+                         unsigned char addr, char *data, int len)
 {
        int ret;
-       char *buf = kmalloc(len, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
+
+       if (len > sizeof(dev->i2c_buf))
+               return -EINVAL;
 
        ret = usb_control_msg(dev->udev,
                              usb_rcvctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_READ, CTRL_READ_REQUEST,
-                             0x100|addr, 0, buf, len, 1000);
+                             (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
 
        if (ret == len) {
-               memcpy(data, buf, len);
+               memcpy(data, &dev->i2c_buf, len);
                ret = 0;
        } else if (ret >= 0)
                ret = -EIO;
 
-       kfree(buf);
-
        return ret;
 }
 
-static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
-                          char *data, int len)
+static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
+                          unsigned char addr, char *data, int len)
 {
        int ret;
-       char *buf = kmalloc(len, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
 
-       memcpy(buf, data, len);
+       if (len > sizeof(dev->i2c_buf))
+               return -EINVAL;
+
+       memcpy(&dev->i2c_buf, data, len);
        ret = usb_control_msg(dev->udev,
                              usb_sndctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
-                             0x100|addr, 0, buf, len, 1000);
+                             (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
 
        if (ret < 0)
-               goto error;
+               return ret;
 
        ret = usb_control_msg(dev->udev,
                              usb_rcvctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
-                             0, 0, buf, 2, 1000);
+                             0, 0, &dev->i2c_buf, 2, 1000);
 
-       if (ret == 2)
+       if ((ret == 2) && (dev->i2c_buf[1] == (len - 1)))
                ret = 0;
        else if (ret >= 0)
                ret = -EIO;
 
-error:
-       kfree(buf);
        return ret;
 }
 
@@ -146,10 +128,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
                addr = msgs[i].addr << 1;
 
                if (msgs[i].flags & I2C_M_RD)
-                       retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
+                       retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf,
                                                msgs[i].len);
                else
-                       retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
+                       retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf,
                                                 msgs[i].len);
        }
 
@@ -168,30 +150,47 @@ static struct i2c_algorithm hdpvr_algo = {
        .functionality = hdpvr_functionality,
 };
 
+static struct i2c_adapter hdpvr_i2c_adapter_template = {
+       .name   = "Hauppage HD PVR I2C",
+       .owner  = THIS_MODULE,
+       .algo   = &hdpvr_algo,
+};
+
+static int hdpvr_activate_ir(struct hdpvr_device *dev)
+{
+       char buffer[8];
+
+       mutex_lock(&dev->i2c_mutex);
+
+       hdpvr_i2c_read(dev, 0, 0x54, buffer, 1);
+
+       buffer[0] = 0;
+       buffer[1] = 0x8;
+       hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+       buffer[1] = 0x18;
+       hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+       mutex_unlock(&dev->i2c_mutex);
+
+       return 0;
+}
+
 int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
 {
-       struct i2c_adapter *i2c_adap;
        int retval = -ENOMEM;
 
-       i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-       if (i2c_adap == NULL)
-               goto error;
-
-       strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
-               sizeof(i2c_adap->name));
-       i2c_adap->algo  = &hdpvr_algo;
-       i2c_adap->owner = THIS_MODULE;
-       i2c_adap->dev.parent = &dev->udev->dev;
+       hdpvr_activate_ir(dev);
 
-       i2c_set_adapdata(i2c_adap, dev);
+       memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template,
+              sizeof(struct i2c_adapter));
+       dev->i2c_adapter.dev.parent = &dev->udev->dev;
 
-       retval = i2c_add_adapter(i2c_adap);
+       i2c_set_adapdata(&dev->i2c_adapter, dev);
 
-       if (!retval)
-               dev->i2c_adapter = i2c_adap;
-       else
-               kfree(i2c_adap);
+       retval = i2c_add_adapter(&dev->i2c_adapter);
 
-error:
        return retval;
 }
+
+#endif
index d38fe10..514aea7 100644 (file)
@@ -1220,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev)
        v4l2_device_unregister(&dev->v4l2_dev);
 
        /* deregister I2C adapter */
-#ifdef CONFIG_I2C
+#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
        mutex_lock(&dev->i2c_mutex);
-       if (dev->i2c_adapter)
-               i2c_del_adapter(dev->i2c_adapter);
-       kfree(dev->i2c_adapter);
-       dev->i2c_adapter = NULL;
+       i2c_del_adapter(&dev->i2c_adapter);
        mutex_unlock(&dev->i2c_mutex);
 #endif /* CONFIG_I2C */
 
index 37f1e4c..072f23c 100644 (file)
@@ -25,6 +25,7 @@
        KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
 
 #define HDPVR_MAX 8
+#define HDPVR_I2C_MAX_SIZE 128
 
 /* Define these values to match your devices */
 #define HD_PVR_VENDOR_ID       0x2040
@@ -106,9 +107,11 @@ struct hdpvr_device {
        struct work_struct      worker;
 
        /* I2C adapter */
-       struct i2c_adapter      *i2c_adapter;
+       struct i2c_adapter      i2c_adapter;
        /* I2C lock */
        struct mutex            i2c_mutex;
+       /* I2C message buffer space */
+       char                    i2c_buf[HDPVR_I2C_MAX_SIZE];
 
        /* For passing data to ir-kbd-i2c */
        struct IR_i2c_init_data ir_i2c_init_data;
@@ -310,7 +313,8 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev);
 /* i2c adapter registration */
 int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
 
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev);
+struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev);
+struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev);
 
 /*========================================================================*/
 /* buffer management */
index c87b6bc..a221ad6 100644 (file)
@@ -128,6 +128,19 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
 static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
+       int ret;
+       unsigned char buf[1] = { 0 };
+
+       /*
+        * This is the same apparent "are you ready?" poll command observed
+        * watching Windows driver traffic and implemented in lirc_zilog. With
+        * this added, we get far saner remote behavior with z8 chips on usb
+        * connected devices, even with the default polling interval of 100ms.
+        */
+       ret = i2c_master_send(ir->c, buf, 1);
+       if (ret != 1)
+               return (ret < 0) ? ret : -EINVAL;
+
        return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
 }
 
@@ -244,15 +257,17 @@ static void ir_key_poll(struct IR_i2c *ir)
        static u32 ir_key, ir_raw;
        int rc;
 
-       dprintk(2,"ir_poll_key\n");
+       dprintk(3, "%s\n", __func__);
        rc = ir->get_key(ir, &ir_key, &ir_raw);
        if (rc < 0) {
                dprintk(2,"error\n");
                return;
        }
 
-       if (rc)
+       if (rc) {
+               dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
                rc_keydown(ir->rc, ir_key, 0);
+       }
 }
 
 static void ir_work(struct work_struct *work)
@@ -321,6 +336,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                rc_type     = RC_TYPE_OTHER;
                ir_codes    = RC_MAP_AVERMEDIA_CARDBUS;
                break;
+       case 0x71:
+               name        = "Hauppauge/Zilog Z8";
+               ir->get_key = get_key_haup_xvr;
+               rc_type     = RC_TYPE_RC5;
+               ir_codes    = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV;
+               break;
        }
 
        /* Let the caller override settings */
index e103b8f..9fb86a0 100644 (file)
@@ -300,10 +300,15 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
                                adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
        } else if (hw == IVTV_HW_CX25840) {
                struct cx25840_platform_data pdata;
+               struct i2c_board_info cx25840_info = {
+                       .type = "cx25840",
+                       .addr = hw_addrs[idx],
+                       .platform_data = &pdata,
+               };
 
                pdata.pvr150_workaround = itv->pvr150_workaround;
-               sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
-                               adap, type, 0, &pdata, hw_addrs[idx], NULL);
+               sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap,
+                               &cx25840_info, NULL);
        } else {
                sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
                                adap, type, hw_addrs[idx], NULL);
index 209ff97..4904d25 100644 (file)
 #include <asm/div64.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-#include "mt9v011.h"
+#include <media/mt9v011.h>
 
 MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 MODULE_LICENSE("GPL");
 
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
+#define R00_MT9V011_CHIP_VERSION       0x00
+#define R01_MT9V011_ROWSTART           0x01
+#define R02_MT9V011_COLSTART           0x02
+#define R03_MT9V011_HEIGHT             0x03
+#define R04_MT9V011_WIDTH              0x04
+#define R05_MT9V011_HBLANK             0x05
+#define R06_MT9V011_VBLANK             0x06
+#define R07_MT9V011_OUT_CTRL           0x07
+#define R09_MT9V011_SHUTTER_WIDTH      0x09
+#define R0A_MT9V011_CLK_SPEED          0x0a
+#define R0B_MT9V011_RESTART            0x0b
+#define R0C_MT9V011_SHUTTER_DELAY      0x0c
+#define R0D_MT9V011_RESET              0x0d
+#define R1E_MT9V011_DIGITAL_ZOOM       0x1e
+#define R20_MT9V011_READ_MODE          0x20
+#define R2B_MT9V011_GREEN_1_GAIN       0x2b
+#define R2C_MT9V011_BLUE_GAIN          0x2c
+#define R2D_MT9V011_RED_GAIN           0x2d
+#define R2E_MT9V011_GREEN_2_GAIN       0x2e
+#define R35_MT9V011_GLOBAL_GAIN                0x35
+#define RF1_MT9V011_CHIP_ENABLE                0xf1
+
+#define MT9V011_VERSION                        0x8232
+#define MT9V011_REV_B_VERSION          0x8243
+
 /* supported controls */
 static struct v4l2_queryctrl mt9v011_qctrl[] = {
        {
@@ -469,23 +493,6 @@ static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
        return 0;
 }
 
-static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
-{
-       struct mt9v011 *core = to_mt9v011(sd);
-       unsigned *xtal = data;
-
-       v4l2_dbg(1, debug, sd, "s_config called\n");
-
-       if (xtal) {
-               core->xtal = *xtal;
-               v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
-                        *xtal / 1000000, (*xtal / 1000) % 1000);
-       }
-
-       return 0;
-}
-
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9v011_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
@@ -536,7 +543,6 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
        .g_ctrl = mt9v011_g_ctrl,
        .s_ctrl = mt9v011_s_ctrl,
        .reset = mt9v011_reset,
-       .s_config = mt9v011_s_config,
        .g_chip_ident = mt9v011_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = mt9v011_g_register,
@@ -596,6 +602,14 @@ static int mt9v011_probe(struct i2c_client *c,
        core->height = 480;
        core->xtal = 27000000;  /* Hz */
 
+       if (c->dev.platform_data) {
+               struct mt9v011_platform_data *pdata = c->dev.platform_data;
+
+               core->xtal = pdata->xtal;
+               v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+                       core->xtal / 1000000, (core->xtal / 1000) % 1000);
+       }
+
        v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
                 c->addr << 1, c->adapter->name, version);
 
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h
deleted file mode 100644 (file)
index 3350fd6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
- *
- * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#ifndef MT9V011_H_
-#define MT9V011_H_
-
-#define R00_MT9V011_CHIP_VERSION       0x00
-#define R01_MT9V011_ROWSTART           0x01
-#define R02_MT9V011_COLSTART           0x02
-#define R03_MT9V011_HEIGHT             0x03
-#define R04_MT9V011_WIDTH              0x04
-#define R05_MT9V011_HBLANK             0x05
-#define R06_MT9V011_VBLANK             0x06
-#define R07_MT9V011_OUT_CTRL           0x07
-#define R09_MT9V011_SHUTTER_WIDTH      0x09
-#define R0A_MT9V011_CLK_SPEED          0x0a
-#define R0B_MT9V011_RESTART            0x0b
-#define R0C_MT9V011_SHUTTER_DELAY      0x0c
-#define R0D_MT9V011_RESET              0x0d
-#define R1E_MT9V011_DIGITAL_ZOOM       0x1e
-#define R20_MT9V011_READ_MODE          0x20
-#define R2B_MT9V011_GREEN_1_GAIN       0x2b
-#define R2C_MT9V011_BLUE_GAIN          0x2c
-#define R2D_MT9V011_RED_GAIN           0x2d
-#define R2E_MT9V011_GREEN_2_GAIN       0x2e
-#define R35_MT9V011_GLOBAL_GAIN                0x35
-#define RF1_MT9V011_CHIP_ENABLE                0xf1
-
-#define MT9V011_VERSION                        0x8232
-#define MT9V011_REV_B_VERSION          0x8243
-
-#endif
index c881a64..d4e7c11 100644 (file)
@@ -1449,47 +1449,6 @@ static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
 }
 
-static int ov7670_s_config(struct v4l2_subdev *sd, int dumb, void *data)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov7670_config *config = data;
-       struct ov7670_info *info = to_state(sd);
-       int ret;
-
-       info->clock_speed = 30; /* default: a guess */
-
-       /*
-        * Must apply configuration before initializing device, because it
-        * selects I/O method.
-        */
-       if (config) {
-               info->min_width = config->min_width;
-               info->min_height = config->min_height;
-               info->use_smbus = config->use_smbus;
-
-               if (config->clock_speed)
-                       info->clock_speed = config->clock_speed;
-       }
-
-       /* Make sure it's an ov7670 */
-       ret = ov7670_detect(sd);
-       if (ret) {
-               v4l_dbg(1, debug, client,
-                       "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
-                       client->addr << 1, client->adapter->name);
-               kfree(info);
-               return ret;
-       }
-       v4l_info(client, "chip found @ 0x%02x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-
-       info->fmt = &ov7670_formats[0];
-       info->sat = 128;        /* Review this */
-       info->clkrc = info->clock_speed / 30;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
@@ -1528,7 +1487,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
        .s_ctrl = ov7670_s_ctrl,
        .queryctrl = ov7670_queryctrl,
        .reset = ov7670_reset,
-       .s_config = ov7670_s_config,
        .init = ov7670_init,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ov7670_g_register,
@@ -1558,6 +1516,7 @@ static int ov7670_probe(struct i2c_client *client,
 {
        struct v4l2_subdev *sd;
        struct ov7670_info *info;
+       int ret;
 
        info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
        if (info == NULL)
@@ -1565,6 +1524,37 @@ static int ov7670_probe(struct i2c_client *client,
        sd = &info->sd;
        v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
 
+       info->clock_speed = 30; /* default: a guess */
+       if (client->dev.platform_data) {
+               struct ov7670_config *config = client->dev.platform_data;
+
+               /*
+                * Must apply configuration before initializing device, because it
+                * selects I/O method.
+                */
+               info->min_width = config->min_width;
+               info->min_height = config->min_height;
+               info->use_smbus = config->use_smbus;
+
+               if (config->clock_speed)
+                       info->clock_speed = config->clock_speed;
+       }
+
+       /* Make sure it's an ov7670 */
+       ret = ov7670_detect(sd);
+       if (ret) {
+               v4l_dbg(1, debug, client,
+                       "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+                       client->addr << 1, client->adapter->name);
+               kfree(info);
+               return ret;
+       }
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       info->fmt = &ov7670_formats[0];
+       info->sat = 128;        /* Review this */
+       info->clkrc = info->clock_speed / 30;
        return 0;
 }
 
index ac94a8b..305e6aa 100644 (file)
@@ -40,6 +40,7 @@
 #include "pvrusb2-io.h"
 #include <media/v4l2-device.h>
 #include <media/cx2341x.h>
+#include <media/ir-kbd-i2c.h>
 #include "pvrusb2-devattr.h"
 
 /* Legal values for PVR2_CID_HSM */
@@ -202,6 +203,7 @@ struct pvr2_hdw {
 
        /* IR related */
        unsigned int ir_scheme_active; /* IR scheme as seen from the outside */
+       struct IR_i2c_init_data ir_init_data; /* params passed to IR modules */
 
        /* Frequency table */
        unsigned int freqTable[FREQTABLE_SIZE];
index 7cbe18c..451ecd4 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
 #include "pvrusb2-i2c-core.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
@@ -48,13 +49,6 @@ module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
 MODULE_PARM_DESC(disable_autoload_ir_video,
                 "1=do not try to autoload ir_video IR receiver");
 
-/* Mapping of IR schemes to known I2C addresses - if any */
-static const unsigned char ir_video_addresses[] = {
-       [PVR2_IR_SCHEME_ZILOG] = 0x71,
-       [PVR2_IR_SCHEME_29XXX] = 0x18,
-       [PVR2_IR_SCHEME_24XXX] = 0x18,
-};
-
 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
                          u8 i2c_addr,      /* I2C address we're talking to */
                          u8 *data,         /* Data to write */
@@ -574,26 +568,55 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
 static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
 {
        struct i2c_board_info info;
-       unsigned char addr = 0;
+       struct IR_i2c_init_data *init_data = &hdw->ir_init_data;
        if (pvr2_disable_ir_video) {
                pvr2_trace(PVR2_TRACE_INFO,
                           "Automatic binding of ir_video has been disabled.");
                return;
        }
-       if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
-               addr = ir_video_addresses[hdw->ir_scheme_active];
-       }
-       if (!addr) {
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       switch (hdw->ir_scheme_active) {
+       case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
+       case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
+               init_data->ir_codes              = RC_MAP_HAUPPAUGE_NEW;
+               init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
+               init_data->type                  = RC_TYPE_RC5;
+               init_data->name                  = hdw->hdw_desc->description;
+               init_data->polling_interval      = 100; /* ms From ir-kbd-i2c */
+               /* IR Receiver */
+               info.addr          = 0x18;
+               info.platform_data = init_data;
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+                          info.type, info.addr);
+               i2c_new_device(&hdw->i2c_adap, &info);
+               break;
+       case PVR2_IR_SCHEME_ZILOG:     /* HVR-1950 style */
+       case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
+               init_data->ir_codes              = RC_MAP_HAUPPAUGE_NEW;
+               init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+               init_data->type                  = RC_TYPE_RC5;
+               init_data->name                  = hdw->hdw_desc->description;
+               /* IR Receiver */
+               info.addr          = 0x71;
+               info.platform_data = init_data;
+               strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE);
+               pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+                          info.type, info.addr);
+               i2c_new_device(&hdw->i2c_adap, &info);
+               /* IR Trasmitter */
+               info.addr          = 0x70;
+               info.platform_data = init_data;
+               strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE);
+               pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+                          info.type, info.addr);
+               i2c_new_device(&hdw->i2c_adap, &info);
+               break;
+       default:
                /* The device either doesn't support I2C-based IR or we
                   don't know (yet) how to operate IR on the device. */
-               return;
+               break;
        }
-       pvr2_trace(PVR2_TRACE_INFO,
-                  "Binding ir_video to i2c address 0x%02x.", addr);
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-       info.addr = addr;
-       i2c_new_device(&hdw->i2c_adap, &info);
 }
 
 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
index f35459d..0db9092 100644 (file)
@@ -1565,7 +1565,7 @@ static int saa711x_probe(struct i2c_client *client,
        chip_id = name[5];
 
        /* Check whether this chip is part of the saa711x series */
-       if (memcmp(name, "1f711", 5)) {
+       if (memcmp(name + 1, "f711", 4)) {
                v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
                        client->addr << 1, name);
                return -ENODEV;
index e7aa588..deb8fcf 100644 (file)
@@ -5179,18 +5179,8 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
                .name           = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
                .audio_clock    = 0x00187de7,
-#if 0
-       /*
-        * FIXME: Analog mode doesn't work, if digital is enabled. The proper
-        * fix is to use tda8290 driver, but Kworld seems to use an
-        * unsupported version of tda8295.
-        */
-               .tuner_type     = TUNER_NXP_TDA18271,   /* TUNER_PHILIPS_TDA8290 */
-               .tuner_addr     = 0x60,
-#else
-               .tuner_type     = UNSET,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
                .tuner_addr     = ADDR_UNSET,
-#endif
                .radio_type     = UNSET,
                .radio_addr     = ADDR_UNSET,
                .gpiomask       = 0x8e054000,
@@ -6932,10 +6922,17 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
        /* toggle AGC switch through GPIO 27 */
        switch (mode) {
        case TDA18271_ANALOG:
-               saa7134_set_gpio(dev, 27, 0);
+               saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+               saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+               msleep(20);
                break;
        case TDA18271_DIGITAL:
-               saa7134_set_gpio(dev, 27, 1);
+               saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+               saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+               msleep(20);
+               saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+               saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+               msleep(30);
                break;
        default:
                return -EINVAL;
@@ -6993,6 +6990,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
 int saa7134_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct saa7134_dev *dev = priv;
+
        if (dev != NULL) {
                switch (dev->tuner_type) {
                case TUNER_PHILIPS_TDA8290:
@@ -7659,36 +7657,11 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                break;
        }
        case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
-       {
-               struct i2c_msg msg = { .addr = 0x4b, .flags = 0 };
-               int i;
-               static u8 buffer[][2] = {
-                       {0x30, 0x31},
-                       {0xff, 0x00},
-                       {0x41, 0x03},
-                       {0x41, 0x1a},
-                       {0xff, 0x02},
-                       {0x34, 0x00},
-                       {0x45, 0x97},
-                       {0x45, 0xc1},
-               };
                saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
                saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
 
-               /*
-                * FIXME: identify what device is at addr 0x4b and what means
-                * this initialization
-                */
-               for (i = 0; i < ARRAY_SIZE(buffer); i++) {
-                       msg.buf = &buffer[i][0];
-                       msg.len = ARRAY_SIZE(buffer[0]);
-                       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-                               printk(KERN_WARNING
-                                      "%s: Unable to enable tuner(%i).\n",
-                                      dev->name, i);
-               }
+               saa7134_set_gpio(dev, 27, 0);
                break;
-       }
        } /* switch() */
 
        /* initialize tuner */
index 3315a48..f65cad2 100644 (file)
@@ -237,12 +237,39 @@ static struct tda18271_std_map mb86a20s_tda18271_std_map = {
 static struct tda18271_config kworld_tda18271_config = {
        .std_map = &mb86a20s_tda18271_std_map,
        .gate    = TDA18271_GATE_DIGITAL,
+       .config  = 3,   /* Use tuner callback for AGC */
+
 };
 
 static const struct mb86a20s_config kworld_mb86a20s_config = {
        .demod_address = 0x10,
 };
 
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+
+       unsigned char initmsg[] = {0x45, 0x97};
+       unsigned char msg_enable[] = {0x45, 0xc1};
+       unsigned char msg_disable[] = {0x45, 0x81};
+       struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+               wprintk("could not access the I2C gate\n");
+               return -EIO;
+       }
+       if (enable)
+               msg.buf = msg_enable;
+       else
+               msg.buf = msg_disable;
+       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+               wprintk("could not access the I2C gate\n");
+               return -EIO;
+       }
+       msleep(20);
+       return 0;
+}
+
 /* ==================================================================
  * tda1004x based DVB-T cards, helper functions
  */
@@ -623,37 +650,6 @@ static struct tda827x_config tda827x_cfg_2_sw42 = {
 
 /* ------------------------------------------------------------------ */
 
-static int __kworld_sbtvd_i2c_gate_ctrl(struct saa7134_dev *dev, int enable)
-{
-       unsigned char initmsg[] = {0x45, 0x97};
-       unsigned char msg_enable[] = {0x45, 0xc1};
-       unsigned char msg_disable[] = {0x45, 0x81};
-       struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
-
-       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
-               wprintk("could not access the I2C gate\n");
-               return -EIO;
-       }
-       if (enable)
-               msg.buf = msg_enable;
-       else
-               msg.buf = msg_disable;
-       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
-               wprintk("could not access the I2C gate\n");
-               return -EIO;
-       }
-       msleep(20);
-       return 0;
-}
-static int kworld_sbtvd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-
-       return __kworld_sbtvd_i2c_gate_ctrl(dev, enable);
-}
-
-/* ------------------------------------------------------------------ */
-
 static struct tda1004x_config tda827x_lifeview_config = {
        .demod_address = 0x08,
        .invert        = 1,
@@ -1660,27 +1656,23 @@ static int dvb_init(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
-               __kworld_sbtvd_i2c_gate_ctrl(dev, 0);
-               saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
-               saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
-               msleep(20);
-               saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
-               saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
-               msleep(20);
+               /* Switch to digital mode */
+               saa7134_tuner_callback(dev, 0,
+                                      TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
                fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
                                               &kworld_mb86a20s_config,
                                               &dev->i2c_adap);
-               __kworld_sbtvd_i2c_gate_ctrl(dev, 1);
                if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
                        dvb_attach(tda18271_attach, fe0->dvb.frontend,
                                   0x60, &dev->i2c_adap,
                                   &kworld_tda18271_config);
-                       /*
-                        * Only after success, it can initialize the gate, otherwise
-                        * an OOPS will hit, due to kfree(fe0->dvb.frontend)
-                        */
-                       fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_i2c_gate_ctrl;
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
                }
+
+               /* mb86a20s need to use the I2C gateway */
                break;
        default:
                wprintk("Huh? unknown DVB card?\n");
index 41064c7..b3d2cc7 100644 (file)
@@ -47,8 +47,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
-#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
 #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
@@ -56,78 +56,68 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
 #endif
-       { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */
 #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
        { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
 #endif
-       { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */
        /* SN9C103 */
-       { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */
+       { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
-       { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */
        { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
-#endif
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
-/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */
        { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */
 #endif
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
        /* SN9C105 */
 #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
-#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */
        { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
        /* SN9C120 */
        { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
-       { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
-#endif
-       { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */
        { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
-#endif
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
-#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
 #endif
index 864696b..c901721 100644 (file)
@@ -714,15 +714,6 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd)
        return ret;
 }
 
-static int sr030pc30_s_config(struct v4l2_subdev *sd,
-                             int irq, void *platform_data)
-{
-       struct sr030pc30_info *info = to_sr030pc30(sd);
-
-       info->pdata = platform_data;
-       return 0;
-}
-
 static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable)
 {
        return 0;
@@ -763,7 +754,6 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
 }
 
 static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
-       .s_config       = sr030pc30_s_config,
        .s_power        = sr030pc30_s_power,
        .queryctrl      = sr030pc30_queryctrl,
        .s_ctrl         = sr030pc30_s_ctrl,
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
deleted file mode 100644 (file)
index 35b6ff5..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * For the TDA9875 chip
- * (The TDA9875 is used on the Diamond DTV2000 french version
- * Other cards probably use these chips as well.)
- * This driver will not complain if used with any
- * other i2c device with the same address.
- *
- * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
- * Eric Sandeen
- * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- * This code is placed under the terms of the GNU General Public License
- * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * Which was based on tda8425.c by Greg Alexander (c) 1998
- *
- * OPTIONS:
- * debug   - set to 1 if you'd like to see debug messages
- *
- *  Revision: 0.1 - original version
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/i2c-addr.h>
-
-static int debug; /* insmod parameter */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_LICENSE("GPL");
-
-
-/* This is a superset of the TDA9875 */
-struct tda9875 {
-       struct v4l2_subdev sd;
-       int rvol, lvol;
-       int bass, treble;
-};
-
-static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct tda9875, sd);
-}
-
-#define dprintk  if (debug) printk
-
-/* The TDA9875 is made by Philips Semiconductor
- * http://www.semiconductors.philips.com
- * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
- *
- */
-
-               /* subaddresses for TDA9875 */
-#define TDA9875_MUT         0x12  /*General mute  (value --> 0b11001100*/
-#define TDA9875_CFG         0x01  /* Config register (value --> 0b00000000 */
-#define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
-#define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
-
-#define TDA9875_CH1V        0x0c  /*Channel 1 volume (mute)*/
-#define TDA9875_CH2V        0x0d  /*Channel 2 volume (mute)*/
-#define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
-#define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
-
-#define TDA9875_ADCIS       0x17  /*ADC input select (mono) 0b0110 000*/
-#define TDA9875_AER         0x19  /*Audio effect (AVL+Pseudo) 0b0000 0110*/
-#define TDA9875_MCS         0x18  /*Main channel select (DAC) 0b0000100*/
-#define TDA9875_MVL         0x1a  /* Main volume gauche */
-#define TDA9875_MVR         0x1b  /* Main volume droite */
-#define TDA9875_MBA         0x1d  /* Main Basse */
-#define TDA9875_MTR         0x1e  /* Main treble */
-#define TDA9875_ACS         0x1f  /* Auxilary channel select (FM) 0b0000000*/
-#define TDA9875_AVL         0x20  /* Auxilary volume gauche */
-#define TDA9875_AVR         0x21  /* Auxilary volume droite */
-#define TDA9875_ABA         0x22  /* Auxilary Basse */
-#define TDA9875_ATR         0x23  /* Auxilary treble */
-
-#define TDA9875_MSR         0x02  /* Monitor select register */
-#define TDA9875_C1MSB       0x03  /* Carrier 1 (FM) frequency register MSB */
-#define TDA9875_C1MIB       0x04  /* Carrier 1 (FM) frequency register (16-8]b */
-#define TDA9875_C1LSB       0x05  /* Carrier 1 (FM) frequency register LSB */
-#define TDA9875_C2MSB       0x06  /* Carrier 2 (nicam) frequency register MSB */
-#define TDA9875_C2MIB       0x07  /* Carrier 2 (nicam) frequency register (16-8]b */
-#define TDA9875_C2LSB       0x08  /* Carrier 2 (nicam) frequency register LSB */
-#define TDA9875_DCR         0x09  /* Demodulateur configuration regirter*/
-#define TDA9875_DEEM        0x0a  /* FM de-emphasis regirter*/
-#define TDA9875_FMAT        0x0b  /* FM Matrix regirter*/
-
-/* values */
-#define TDA9875_MUTE_ON            0xff /* general mute */
-#define TDA9875_MUTE_OFF    0xcc /* general no mute */
-
-
-
-/* Begin code */
-
-static int tda9875_write(struct v4l2_subdev *sd, int subaddr, unsigned char val)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       unsigned char buffer[2];
-
-       v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
-       buffer[0] = subaddr;
-       buffer[1] = val;
-       if (2 != i2c_master_send(client, buffer, 2)) {
-               v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n",
-                      subaddr, val);
-               return -1;
-       }
-       return 0;
-}
-
-
-static int i2c_read_register(struct i2c_client *client, int addr, int reg)
-{
-       unsigned char write[1];
-       unsigned char read[1];
-       struct i2c_msg msgs[2] = {
-               { addr, 0,        1, write },
-               { addr, I2C_M_RD, 1, read  }
-       };
-
-       write[0] = reg;
-
-       if (2 != i2c_transfer(client->adapter, msgs, 2)) {
-               v4l_warn(client, "I/O error (read2)\n");
-               return -1;
-       }
-       v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]);
-       return read[0];
-}
-
-static void tda9875_set(struct v4l2_subdev *sd)
-{
-       struct tda9875 *tda = to_state(sd);
-       unsigned char a;
-
-       v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n",
-               tda->lvol, tda->rvol, tda->bass, tda->treble);
-
-       a = tda->lvol & 0xff;
-       tda9875_write(sd, TDA9875_MVL, a);
-       a =tda->rvol & 0xff;
-       tda9875_write(sd, TDA9875_MVR, a);
-       a =tda->bass & 0xff;
-       tda9875_write(sd, TDA9875_MBA, a);
-       a =tda->treble  & 0xff;
-       tda9875_write(sd, TDA9875_MTR, a);
-}
-
-static void do_tda9875_init(struct v4l2_subdev *sd)
-{
-       struct tda9875 *t = to_state(sd);
-
-       v4l2_dbg(1, debug, sd, "In tda9875_init\n");
-       tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
-       tda9875_write(sd, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
-       tda9875_write(sd, TDA9875_C1MSB, 0x00);  /*Car1(FM) MSB XMHz*/
-       tda9875_write(sd, TDA9875_C1MIB, 0x00);  /*Car1(FM) MIB XMHz*/
-       tda9875_write(sd, TDA9875_C1LSB, 0x00);  /*Car1(FM) LSB XMHz*/
-       tda9875_write(sd, TDA9875_C2MSB, 0x00);  /*Car2(NICAM) MSB XMHz*/
-       tda9875_write(sd, TDA9875_C2MIB, 0x00);  /*Car2(NICAM) MIB XMHz*/
-       tda9875_write(sd, TDA9875_C2LSB, 0x00);  /*Car2(NICAM) LSB XMHz*/
-       tda9875_write(sd, TDA9875_DCR, 0x00);    /*Demod config 0x00*/
-       tda9875_write(sd, TDA9875_DEEM, 0x44);   /*DE-Emph 0b0100 0100*/
-       tda9875_write(sd, TDA9875_FMAT, 0x00);   /*FM Matrix reg 0x00*/
-       tda9875_write(sd, TDA9875_SC1, 0x00);    /* SCART 1 (SC1)*/
-       tda9875_write(sd, TDA9875_SC2, 0x01);    /* SCART 2 (sc2)*/
-
-       tda9875_write(sd, TDA9875_CH1V, 0x10);  /* Channel volume 1 mute*/
-       tda9875_write(sd, TDA9875_CH2V, 0x10);  /* Channel volume 2 mute */
-       tda9875_write(sd, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
-       tda9875_write(sd, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
-       tda9875_write(sd, TDA9875_LOSR, 0x00);  /* line out (in:mono)*/
-       tda9875_write(sd, TDA9875_AER, 0x00);   /*06 Effect (AVL+PSEUDO) */
-       tda9875_write(sd, TDA9875_MCS, 0x44);   /* Main ch select (DAC) */
-       tda9875_write(sd, TDA9875_MVL, 0x03);   /* Vol Main left 10dB */
-       tda9875_write(sd, TDA9875_MVR, 0x03);   /* Vol Main right 10dB*/
-       tda9875_write(sd, TDA9875_MBA, 0x00);   /* Main Bass Main 0dB*/
-       tda9875_write(sd, TDA9875_MTR, 0x00);   /* Main Treble Main 0dB*/
-       tda9875_write(sd, TDA9875_ACS, 0x44);   /* Aux chan select (dac)*/
-       tda9875_write(sd, TDA9875_AVL, 0x00);   /* Vol Aux left 0dB*/
-       tda9875_write(sd, TDA9875_AVR, 0x00);   /* Vol Aux right 0dB*/
-       tda9875_write(sd, TDA9875_ABA, 0x00);   /* Aux Bass Main 0dB*/
-       tda9875_write(sd, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
-
-       tda9875_write(sd, TDA9875_MUT, 0xcc);   /* General mute  */
-
-       t->lvol = t->rvol = 0;          /* 0dB */
-       t->bass = 0;                    /* 0dB */
-       t->treble = 0;                  /* 0dB */
-       tda9875_set(sd);
-}
-
-
-static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct tda9875 *t = to_state(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-       {
-               int left = (t->lvol+84)*606;
-               int right = (t->rvol+84)*606;
-
-               ctrl->value=max(left,right);
-               return 0;
-       }
-       case V4L2_CID_AUDIO_BALANCE:
-       {
-               int left = (t->lvol+84)*606;
-               int right = (t->rvol+84)*606;
-               int volume = max(left,right);
-               int balance = (32768*min(left,right))/
-                             (volume ? volume : 1);
-               ctrl->value=(left<right)?
-                       (65535-balance) : balance;
-               return 0;
-       }
-       case V4L2_CID_AUDIO_BASS:
-               ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
-               return 0;
-       case V4L2_CID_AUDIO_TREBLE:
-               ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct tda9875 *t = to_state(sd);
-       int chvol = 0, volume = 0, balance = 0, left, right;
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               left = (t->lvol+84)*606;
-               right = (t->rvol+84)*606;
-
-               volume = max(left,right);
-               balance = (32768*min(left,right))/
-                             (volume ? volume : 1);
-               balance =(left<right)?
-                       (65535-balance) : balance;
-
-               volume = ctrl->value;
-
-               chvol=1;
-               break;
-       case V4L2_CID_AUDIO_BALANCE:
-               left = (t->lvol+84)*606;
-               right = (t->rvol+84)*606;
-
-               volume=max(left,right);
-
-               balance = ctrl->value;
-
-               chvol=1;
-               break;
-       case V4L2_CID_AUDIO_BASS:
-               t->bass = ((ctrl->value/2400)-12) & 0xff;
-               if (t->bass > 15)
-                       t->bass = 15;
-               if (t->bass < -12)
-                       t->bass = -12 & 0xff;
-               break;
-       case V4L2_CID_AUDIO_TREBLE:
-               t->treble = ((ctrl->value/2700)-12) & 0xff;
-               if (t->treble > 12)
-                       t->treble = 12;
-               if (t->treble < -12)
-                       t->treble = -12 & 0xff;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (chvol) {
-               left = (min(65536 - balance,32768) *
-                       volume) / 32768;
-               right = (min(balance,32768) *
-                               volume) / 32768;
-               t->lvol = ((left/606)-84) & 0xff;
-               if (t->lvol > 24)
-                       t->lvol = 24;
-               if (t->lvol < -84)
-                       t->lvol = -84 & 0xff;
-
-               t->rvol = ((right/606)-84) & 0xff;
-               if (t->rvol > 24)
-                       t->rvol = 24;
-               if (t->rvol < -84)
-                       t->rvol = -84 & 0xff;
-       }
-
-       tda9875_set(sd);
-       return 0;
-}
-
-static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
-       }
-       return -EINVAL;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops tda9875_core_ops = {
-       .queryctrl = tda9875_queryctrl,
-       .g_ctrl = tda9875_g_ctrl,
-       .s_ctrl = tda9875_s_ctrl,
-};
-
-static const struct v4l2_subdev_ops tda9875_ops = {
-       .core = &tda9875_core_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9875_checkit(struct i2c_client *client, int addr)
-{
-       int dic, rev;
-
-       dic = i2c_read_register(client, addr, 254);
-       rev = i2c_read_register(client, addr, 255);
-
-       if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
-               v4l_info(client, "tda9875%s rev. %d detected at 0x%02x\n",
-                       dic == 0 ? "" : "A", rev, addr << 1);
-               return 1;
-       }
-       v4l_info(client, "no such chip at 0x%02x (dic=0x%x rev=0x%x)\n",
-                       addr << 1, dic, rev);
-       return 0;
-}
-
-static int tda9875_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct tda9875 *t;
-       struct v4l2_subdev *sd;
-
-       v4l_info(client, "chip found @ 0x%02x (%s)\n",
-                       client->addr << 1, client->adapter->name);
-
-       if (!tda9875_checkit(client, client->addr))
-               return -ENODEV;
-
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
-       if (!t)
-               return -ENOMEM;
-       sd = &t->sd;
-       v4l2_i2c_subdev_init(sd, client, &tda9875_ops);
-
-       do_tda9875_init(sd);
-       return 0;
-}
-
-static int tda9875_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
-       do_tda9875_init(sd);
-       v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
-       return 0;
-}
-
-static const struct i2c_device_id tda9875_id[] = {
-       { "tda9875", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, tda9875_id);
-
-static struct i2c_driver tda9875_driver = {
-       .driver = {
-               .owner  = THIS_MODULE,
-               .name   = "tda9875",
-       },
-       .probe          = tda9875_probe,
-       .remove         = tda9875_remove,
-       .id_table       = tda9875_id,
-};
-
-static __init int init_tda9875(void)
-{
-       return i2c_add_driver(&tda9875_driver);
-}
-
-static __exit void exit_tda9875(void)
-{
-       i2c_del_driver(&tda9875_driver);
-}
-
-module_init(init_tda9875);
-module_exit(exit_tda9875);
index a1ffe18..df33a1d 100644 (file)
@@ -512,19 +512,20 @@ int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
                        int buf_size, gfp_t gfp_flags,
                        usb_complete_t complete_fn, void *context)
 {
-       struct urb *urb;
-       void *mem;
-       int i;
+       int i = 0;
 
-       for (i = 0; i < num; i++) {
-               urb = usb_alloc_urb(0, gfp_flags);
+       for (; i < num; i++) {
+               void *mem;
+               struct urb *urb = usb_alloc_urb(0, gfp_flags);
                if (urb == NULL)
                        return i;
 
                mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
                                         &urb->transfer_dma);
-               if (mem == NULL)
+               if (mem == NULL) {
+                       usb_free_urb(urb);
                        return i;
+               }
 
                usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
                                mem, buf_size, complete_fn, context);
index 3f0871b..810eef4 100644 (file)
@@ -407,18 +407,6 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
        /* Decrease the module use count to match the first try_module_get. */
        module_put(client->driver->driver.owner);
 
-       if (sd) {
-               /* We return errors from v4l2_subdev_call only if we have the
-                  callback as the .s_config is not mandatory */
-               int err = v4l2_subdev_call(sd, core, s_config,
-                               info->irq, info->platform_data);
-
-               if (err && err != -ENOIOCTLCMD) {
-                       v4l2_device_unregister_subdev(sd);
-                       sd = NULL;
-               }
-       }
-
 error:
        /* If we have a client but no subdev, then something went wrong and
           we must unregister the client. */
@@ -428,9 +416,8 @@ error:
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
 
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
                struct i2c_adapter *adapter, const char *client_type,
-               int irq, void *platform_data,
                u8 addr, const unsigned short *probe_addrs)
 {
        struct i2c_board_info info;
@@ -440,12 +427,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
        memset(&info, 0, sizeof(info));
        strlcpy(info.type, client_type, sizeof(info.type));
        info.addr = addr;
-       info.irq = irq;
-       info.platform_data = platform_data;
 
        return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
 }
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
 
 /* Return i2c client address of v4l2_subdev. */
 unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
index 8f81efc..ef66d2a 100644 (file)
@@ -569,7 +569,7 @@ static int user_to_new(struct v4l2_ext_control *c,
        int ret;
        u32 size;
 
-       ctrl->has_new = 1;
+       ctrl->is_new = 1;
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_INTEGER64:
                ctrl->val64 = c->value64;
@@ -1280,8 +1280,12 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
                if (ctrl->done)
                        continue;
 
-               for (i = 0; i < master->ncontrols; i++)
-                       cur_to_new(master->cluster[i]);
+               for (i = 0; i < master->ncontrols; i++) {
+                       if (master->cluster[i]) {
+                               cur_to_new(master->cluster[i]);
+                               master->cluster[i]->is_new = 1;
+                       }
+               }
 
                /* Skip button controls and read-only controls. */
                if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
@@ -1340,12 +1344,15 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 
        ctrl = ref->ctrl;
        memset(qc, 0, sizeof(*qc));
-       qc->id = ctrl->id;
+       if (id >= V4L2_CID_PRIVATE_BASE)
+               qc->id = id;
+       else
+               qc->id = ctrl->id;
        strlcpy(qc->name, ctrl->name, sizeof(qc->name));
        qc->minimum = ctrl->minimum;
        qc->maximum = ctrl->maximum;
        qc->default_value = ctrl->default_value;
-       if (qc->type == V4L2_CTRL_TYPE_MENU)
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU)
                qc->step = 1;
        else
                qc->step = ctrl->step;
@@ -1645,7 +1652,7 @@ static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
                if (ctrl == NULL)
                        continue;
 
-               if (ctrl->has_new) {
+               if (ctrl->is_new) {
                        /* Double check this: it may have changed since the
                           last check in try_or_set_ext_ctrls(). */
                        if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
@@ -1719,13 +1726,13 @@ static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 
                v4l2_ctrl_lock(ctrl);
 
-               /* Reset the 'has_new' flags of the cluster */
+               /* Reset the 'is_new' flags of the cluster */
                for (j = 0; j < master->ncontrols; j++)
                        if (master->cluster[j])
-                               master->cluster[j]->has_new = 0;
+                               master->cluster[j]->is_new = 0;
 
                /* Copy the new caller-supplied control values.
-                  user_to_new() sets 'has_new' to 1. */
+                  user_to_new() sets 'is_new' to 1. */
                ret = cluster_walk(i, cs, helpers, user_to_new);
 
                if (!ret)
@@ -1820,15 +1827,18 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
        int ret;
        int i;
 
+       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+               return -EACCES;
+
        v4l2_ctrl_lock(ctrl);
 
-       /* Reset the 'has_new' flags of the cluster */
+       /* Reset the 'is_new' flags of the cluster */
        for (i = 0; i < master->ncontrols; i++)
                if (master->cluster[i])
-                       master->cluster[i]->has_new = 0;
+                       master->cluster[i]->is_new = 0;
 
        ctrl->val = *val;
-       ctrl->has_new = 1;
+       ctrl->is_new = 1;
        ret = try_or_set_control_cluster(master, false);
        if (!ret)
                ret = try_or_set_control_cluster(master, true);
index 359e232..341764a 100644 (file)
@@ -419,6 +419,10 @@ static int get_index(struct video_device *vdev)
  *     The registration code assigns minor numbers and device node numbers
  *     based on the requested type and registers the new device node with
  *     the kernel.
+ *
+ *     This function assumes that struct video_device was zeroed when it
+ *     was allocated and does not contain any stale date.
+ *
  *     An error is returned if no free minor or device node number could be
  *     found, or if the registration of the device node failed.
  *
@@ -440,7 +444,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
        int minor_offset = 0;
        int minor_cnt = VIDEO_NUM_DEVICES;
        const char *name_base;
-       void *priv = vdev->dev.p;
 
        /* A minor value of -1 marks this video device as never
           having been registered */
@@ -559,10 +562,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
        }
 
        /* Part 4: register the device with sysfs */
-       memset(&vdev->dev, 0, sizeof(vdev->dev));
-       /* The memset above cleared the device's device_private, so
-          put back the copy we made earlier. */
-       vdev->dev.p = priv;
        vdev->dev.class = &video_class;
        vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
        if (vdev->parent)
index 7fe6f92..ce64fe1 100644 (file)
@@ -100,6 +100,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
                           is a platform bus, then it is never deleted. */
                        if (client)
                                i2c_unregister_device(client);
+                       continue;
                }
 #endif
 #if defined(CONFIG_SPI)
@@ -108,6 +109,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 
                        if (spi)
                                spi_unregister_device(spi);
+                       continue;
                }
 #endif
        }
@@ -126,11 +128,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
        WARN_ON(sd->v4l2_dev != NULL);
        if (!try_module_get(sd->owner))
                return -ENODEV;
+       sd->v4l2_dev = v4l2_dev;
+       if (sd->internal_ops && sd->internal_ops->registered) {
+               err = sd->internal_ops->registered(sd);
+               if (err)
+                       return err;
+       }
        /* This just returns 0 if either of the two args is NULL */
        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
-       if (err)
+       if (err) {
+               if (sd->internal_ops && sd->internal_ops->unregistered)
+                       sd->internal_ops->unregistered(sd);
                return err;
-       sd->v4l2_dev = v4l2_dev;
+       }
        spin_lock(&v4l2_dev->lock);
        list_add_tail(&sd->list, &v4l2_dev->subdevs);
        spin_unlock(&v4l2_dev->lock);
@@ -146,6 +156,8 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
        spin_lock(&sd->v4l2_dev->lock);
        list_del(&sd->list);
        spin_unlock(&sd->v4l2_dev->lock);
+       if (sd->internal_ops && sd->internal_ops->unregistered)
+               sd->internal_ops->unregistered(sd);
        sd->v4l2_dev = NULL;
        module_put(sd->owner);
 }
index 7e47f15..f51327e 100644 (file)
@@ -1659,20 +1659,24 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_dbg_register *p = arg;
 
-               if (!capable(CAP_SYS_ADMIN))
-                       ret = -EPERM;
-               else if (ops->vidioc_g_register)
-                       ret = ops->vidioc_g_register(file, fh, p);
+               if (ops->vidioc_g_register) {
+                       if (!capable(CAP_SYS_ADMIN))
+                               ret = -EPERM;
+                       else
+                               ret = ops->vidioc_g_register(file, fh, p);
+               }
                break;
        }
        case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_dbg_register *p = arg;
 
-               if (!capable(CAP_SYS_ADMIN))
-                       ret = -EPERM;
-               else if (ops->vidioc_s_register)
-                       ret = ops->vidioc_s_register(file, fh, p);
+               if (ops->vidioc_s_register) {
+                       if (!capable(CAP_SYS_ADMIN))
+                               ret = -EPERM;
+                       else
+                               ret = ops->vidioc_s_register(file, fh, p);
+               }
                break;
        }
 #endif
index 019ee20..fa35639 100644 (file)
@@ -937,6 +937,7 @@ static void w9966_term(struct w9966 *cam)
                parport_unregister_device(cam->pdev);
                w9966_set_state(cam, W9966_STATE_PDEV, 0);
        }
+       memset(cam, 0, sizeof(*cam));
 }
 
 
index 9cdc3bb..9f2bac5 100644 (file)
@@ -1041,7 +1041,7 @@ zr36057_init (struct zoran *zr)
        /* allocate memory *before* doing anything to the hardware
         * in case allocation fails */
        zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
-       zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+       zr->video_dev = video_device_alloc();
        if (!zr->stat_com || !zr->video_dev) {
                dprintk(1,
                        KERN_ERR
index e9a3eab..8c1d85e 100644 (file)
@@ -621,7 +621,7 @@ static int __init memstick_init(void)
 {
        int rc;
 
-       workqueue = create_freezeable_workqueue("kmemstick");
+       workqueue = create_freezable_workqueue("kmemstick");
        if (!workqueue)
                return -ENOMEM;
 
index f71f229..1735c84 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.17"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.17"
+#define MPT_LINUX_VERSION_COMMON       "3.04.18"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.18"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
index a3856ed..e8deb8e 100644 (file)
@@ -597,6 +597,13 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 }
 
 static int
+mptctl_release(struct inode *inode, struct file *filep)
+{
+       fasync_helper(-1, filep, 0, &async_queue);
+       return 0;
+}
+
+static int
 mptctl_fasync(int fd, struct file *filep, int mode)
 {
        MPT_ADAPTER     *ioc;
@@ -2815,6 +2822,7 @@ static const struct file_operations mptctl_fops = {
        .llseek =       no_llseek,
        .fasync =       mptctl_fasync,
        .unlocked_ioctl = mptctl_ioctl,
+       .release =      mptctl_release,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = compat_mpctl_ioctl,
 #endif
index 59b8f53..0d9b82a 100644 (file)
@@ -1873,8 +1873,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
        }
 
  out:
-       printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
-           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
+       printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n",
+           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
+           SCpnt, SCpnt->serial_number);
 
        return retval;
 }
@@ -1911,7 +1912,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
 
        vdevice = SCpnt->device->hostdata;
        if (!vdevice || !vdevice->vtarget) {
-               retval = SUCCESS;
+               retval = 0;
                goto out;
        }
 
index 6a1f940..c45e630 100644 (file)
@@ -143,9 +143,9 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
        unsigned long flags;
        struct asic3 *asic;
 
-       desc->chip->ack(irq);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-       asic = desc->handler_data;
+       asic = get_irq_data(irq);
 
        for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
                u32 status;
index 33c923d..fdd8a1b 100644 (file)
@@ -118,12 +118,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
 
        /* Voice codec interface client */
        cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
-       cell->name = "davinci_vcif";
+       cell->name = "davinci-vcif";
        cell->driver_data = davinci_vc;
 
        /* Voice codec CQ93VC client */
        cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
-       cell->name = "cq93vc";
+       cell->name = "cq93vc-codec";
        cell->driver_data = davinci_vc;
 
        ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
index 627cf57..e9018d1 100644 (file)
@@ -150,12 +150,12 @@ static inline int __tps6586x_write(struct i2c_client *client,
 static inline int __tps6586x_writes(struct i2c_client *client, int reg,
                                  int len, uint8_t *val)
 {
-       int ret;
+       int ret, i;
 
-       ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
-       if (ret < 0) {
-               dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
-               return ret;
+       for (i = 0; i < len; i++) {
+               ret = __tps6586x_write(client, reg + i, *(val + i));
+               if (ret < 0)
+                       return ret;
        }
 
        return 0;
index 000cb41..92b85e2 100644 (file)
@@ -385,12 +385,18 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        idev->close      = ucb1x00_ts_close;
 
        __set_bit(EV_ABS, idev->evbit);
-       __set_bit(ABS_X, idev->absbit);
-       __set_bit(ABS_Y, idev->absbit);
-       __set_bit(ABS_PRESSURE, idev->absbit);
 
        input_set_drvdata(idev, ts);
 
+       ucb1x00_adc_enable(ts->ucb);
+       ts->x_res = ucb1x00_ts_read_xres(ts);
+       ts->y_res = ucb1x00_ts_read_yres(ts);
+       ucb1x00_adc_disable(ts->ucb);
+
+       input_set_abs_params(idev, ABS_X, 0, ts->x_res, 0, 0);
+       input_set_abs_params(idev, ABS_Y, 0, ts->y_res, 0, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0);
+
        err = input_register_device(idev);
        if (err)
                goto fail;
index 41233c7..f4016a0 100644 (file)
@@ -246,6 +246,16 @@ static int wm8994_suspend(struct device *dev)
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
 
+       /* Don't actually go through with the suspend if the CODEC is
+        * still active (eg, for audio passthrough from CP. */
+       ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read power status: %d\n", ret);
+       } else if (ret & WM8994_VMID_SEL_MASK) {
+               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+               return 0;
+       }
+
        /* GPIO configuration state is saved here since we may be configuring
         * the GPIO alternate functions even if we're not using the gpiolib
         * driver for them.
@@ -261,6 +271,8 @@ static int wm8994_suspend(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to save LDO registers: %d\n", ret);
 
+       wm8994->suspended = true;
+
        ret = regulator_bulk_disable(wm8994->num_supplies,
                                     wm8994->supplies);
        if (ret != 0) {
@@ -276,6 +288,10 @@ static int wm8994_resume(struct device *dev)
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
 
+       /* We may have lied to the PM core about suspending */
+       if (!wm8994->suspended)
+               return 0;
+
        ret = regulator_bulk_enable(wm8994->num_supplies,
                                    wm8994->supplies);
        if (ret != 0) {
@@ -298,6 +314,8 @@ static int wm8994_resume(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
 
+       wm8994->suspended = false;
+
        return 0;
 }
 #endif
index 63ee4c1..b6e1c9a 100644 (file)
@@ -449,6 +449,7 @@ static const struct i2c_device_id bmp085_id[] = {
        { "bmp085", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
 
 static struct i2c_driver bmp085_driver = {
        .driver = {
index 5f6852d..44d4475 100644 (file)
@@ -329,7 +329,7 @@ static int __init tifm_init(void)
 {
        int rc;
 
-       workqueue = create_freezeable_workqueue("tifm");
+       workqueue = create_freezable_workqueue("tifm");
        if (!workqueue)
                return -ENOMEM;
 
index 4d2ea8e..6df5a55 100644 (file)
@@ -785,7 +785,7 @@ static int __init vmballoon_init(void)
        if (x86_hyper != &x86_hyper_vmware)
                return -ENODEV;
 
-       vmballoon_wq = create_freezeable_workqueue("vmmemctl");
+       vmballoon_wq = create_freezable_workqueue("vmmemctl");
        if (!vmballoon_wq) {
                pr_err("failed to create workqueue\n");
                return -ENOMEM;
index bac7d62..0371bf5 100644 (file)
@@ -462,7 +462,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
                goto out;
        }
 
-       mmc = mmc_alloc_host(sizeof(*mmc), &pdev->dev);
+       mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev);
        if (!mmc) {
                ret = -ENOMEM;
                goto out;
index b3a0ab0..74218ad 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/mmc/host.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
@@ -827,8 +828,8 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
        }
 
        host->clk = clk_get(&pdev->dev, "mmc");
-       if (!host->clk) {
-               ret = -ENOENT;
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
                dev_err(&pdev->dev, "Failed to get mmc clock\n");
                goto err_free_host;
        }
index 5630228..2d6de3e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/highmem.h>
@@ -46,10 +47,6 @@ static unsigned int fmax = 515633;
  *           is asserted (likewise for RX)
  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
  *               is asserted (likewise for RX)
- * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
- *             and will not work at all.
- * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
- *             using DMA.
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  */
@@ -59,8 +56,6 @@ struct variant_data {
        unsigned int            datalength_bits;
        unsigned int            fifosize;
        unsigned int            fifohalfsize;
-       bool                    broken_blockend;
-       bool                    broken_blockend_dma;
        bool                    sdio;
        bool                    st_clkdiv;
 };
@@ -76,7 +71,6 @@ static struct variant_data variant_u300 = {
        .fifohalfsize           = 8 * 4,
        .clkreg_enable          = 1 << 13, /* HWFCEN */
        .datalength_bits        = 16,
-       .broken_blockend_dma    = true,
        .sdio                   = true,
 };
 
@@ -86,7 +80,6 @@ static struct variant_data variant_ux500 = {
        .clkreg                 = MCI_CLK_ENABLE,
        .clkreg_enable          = 1 << 14, /* HWFCEN */
        .datalength_bits        = 24,
-       .broken_blockend        = true,
        .sdio                   = true,
        .st_clkdiv              = true,
 };
@@ -210,8 +203,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        host->data = data;
        host->size = data->blksz * data->blocks;
        host->data_xfered = 0;
-       host->blockend = false;
-       host->dataend = false;
 
        mmci_init_sg(host, data);
 
@@ -288,21 +279,26 @@ static void
 mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
 {
-       struct variant_data *variant = host->variant;
-
        /* First check for errors */
        if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+               u32 remain, success;
+
+               /* Calculate how far we are into the transfer */
+               remain = readl(host->base + MMCIDATACNT);
+               success = data->blksz * data->blocks - remain;
+
                dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
-               if (status & MCI_DATACRCFAIL)
+               if (status & MCI_DATACRCFAIL) {
+                       /* Last block was not successful */
+                       host->data_xfered = round_down(success - 1, data->blksz);
                        data->error = -EILSEQ;
-               else if (status & MCI_DATATIMEOUT)
+               } else if (status & MCI_DATATIMEOUT) {
+                       host->data_xfered = round_down(success, data->blksz);
                        data->error = -ETIMEDOUT;
-               else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
+               } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+                       host->data_xfered = round_down(success, data->blksz);
                        data->error = -EIO;
-
-               /* Force-complete the transaction */
-               host->blockend = true;
-               host->dataend = true;
+               }
 
                /*
                 * We hit an error condition.  Ensure that any data
@@ -321,61 +317,14 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                }
        }
 
-       /*
-        * On ARM variants in PIO mode, MCI_DATABLOCKEND
-        * is always sent first, and we increase the
-        * transfered number of bytes for that IRQ. Then
-        * MCI_DATAEND follows and we conclude the transaction.
-        *
-        * On the Ux500 single-IRQ variant MCI_DATABLOCKEND
-        * doesn't seem to immediately clear from the status,
-        * so we can't use it keep count when only one irq is
-        * used because the irq will hit for other reasons, and
-        * then the flag is still up. So we use the MCI_DATAEND
-        * IRQ at the end of the entire transfer because
-        * MCI_DATABLOCKEND is broken.
-        *
-        * In the U300, the IRQs can arrive out-of-order,
-        * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
-        * so for this case we use the flags "blockend" and
-        * "dataend" to make sure both IRQs have arrived before
-        * concluding the transaction. (This does not apply
-        * to the Ux500 which doesn't fire MCI_DATABLOCKEND
-        * at all.) In DMA mode it suffers from the same problem
-        * as the Ux500.
-        */
-       if (status & MCI_DATABLOCKEND) {
-               /*
-                * Just being a little over-cautious, we do not
-                * use this progressive update if the hardware blockend
-                * flag is unreliable: since it can stay high between
-                * IRQs it will corrupt the transfer counter.
-                */
-               if (!variant->broken_blockend)
-                       host->data_xfered += data->blksz;
-               host->blockend = true;
-       }
-
-       if (status & MCI_DATAEND)
-               host->dataend = true;
+       if (status & MCI_DATABLOCKEND)
+               dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
 
-       /*
-        * On variants with broken blockend we shall only wait for dataend,
-        * on others we must sync with the blockend signal since they can
-        * appear out-of-order.
-        */
-       if (host->dataend && (host->blockend || variant->broken_blockend)) {
+       if (status & MCI_DATAEND || data->error) {
                mmci_stop_data(host);
 
-               /* Reset these flags */
-               host->blockend = false;
-               host->dataend = false;
-
-               /*
-                * Variants with broken blockend flags need to handle the
-                * end of the entire transfer here.
-                */
-               if (variant->broken_blockend && !data->error)
+               if (!data->error)
+                       /* The error clause is handled above, success! */
                        host->data_xfered += data->blksz * data->blocks;
 
                if (!data->stop) {
@@ -394,15 +343,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 
        host->cmd = NULL;
 
-       cmd->resp[0] = readl(base + MMCIRESPONSE0);
-       cmd->resp[1] = readl(base + MMCIRESPONSE1);
-       cmd->resp[2] = readl(base + MMCIRESPONSE2);
-       cmd->resp[3] = readl(base + MMCIRESPONSE3);
-
        if (status & MCI_CMDTIMEOUT) {
                cmd->error = -ETIMEDOUT;
        } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
                cmd->error = -EILSEQ;
+       } else {
+               cmd->resp[0] = readl(base + MMCIRESPONSE0);
+               cmd->resp[1] = readl(base + MMCIRESPONSE1);
+               cmd->resp[2] = readl(base + MMCIRESPONSE2);
+               cmd->resp[3] = readl(base + MMCIRESPONSE3);
        }
 
        if (!cmd->data || cmd->error) {
@@ -770,7 +719,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        struct variant_data *variant = id->data;
        struct mmci_host *host;
        struct mmc_host *mmc;
-       unsigned int mask;
        int ret;
 
        /* must have platform data */
@@ -951,12 +899,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        goto irq0_free;
        }
 
-       mask = MCI_IRQENABLE;
-       /* Don't use the datablockend flag if it's broken */
-       if (variant->broken_blockend)
-               mask &= ~MCI_DATABLOCKEND;
-
-       writel(mask, host->base + MMCIMASK0);
+       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
 
        amba_set_drvdata(dev, mmc);
 
index df06f01..c1df7b8 100644 (file)
 #define MCI_IRQENABLE  \
        (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|     \
        MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
-       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK)
 
 /* These interrupts are directed to IRQ1 when two IRQ lines are available */
 #define MCI_IRQ1MASK \
@@ -177,9 +177,6 @@ struct mmci_host {
        struct timer_list       timer;
        unsigned int            oldstat;
 
-       bool                    blockend;
-       bool                    dataend;
-
        /* pio stuff */
        struct sg_mapping_iter  sg_miter;
        unsigned int            size;
index 5decfd0..153ab97 100644 (file)
@@ -383,14 +383,30 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
        host->curr.user_pages = 0;
 
        box = &nc->cmd[0];
-       for (i = 0; i < host->dma.num_ents; i++) {
-               box->cmd = CMD_MODE_BOX;
 
-       /* Initialize sg dma address */
-       sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
-                               + sg->offset;
+       /* location of command block must be 64 bit aligned */
+       BUG_ON(host->dma.cmd_busaddr & 0x07);
 
-       if (i == (host->dma.num_ents - 1))
+       nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
+       host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
+                              DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
+       host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
+
+       n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
+                       host->dma.num_ents, host->dma.dir);
+       if (n == 0) {
+               printk(KERN_ERR "%s: Unable to map in all sg elements\n",
+                       mmc_hostname(host->mmc));
+               host->dma.sg = NULL;
+               host->dma.num_ents = 0;
+               return -ENOMEM;
+       }
+
+       for_each_sg(host->dma.sg, sg, n, i) {
+
+               box->cmd = CMD_MODE_BOX;
+
+               if (i == n - 1)
                        box->cmd |= CMD_LC;
                rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
                        (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
@@ -418,27 +434,6 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
                        box->cmd |= CMD_DST_CRCI(crci);
                }
                box++;
-               sg++;
-       }
-
-       /* location of command block must be 64 bit aligned */
-       BUG_ON(host->dma.cmd_busaddr & 0x07);
-
-       nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
-       host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
-                              DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
-       host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
-
-       n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
-                       host->dma.num_ents, host->dma.dir);
-/* dsb inside dma_map_sg will write nc out to mem as well */
-
-       if (n != host->dma.num_ents) {
-               printk(KERN_ERR "%s: Unable to map in all sg elements\n",
-                       mmc_hostname(host->mmc));
-               host->dma.sg = NULL;
-               host->dma.num_ents = 0;
-               return -ENOMEM;
        }
 
        return 0;
@@ -1331,9 +1326,6 @@ msmsdcc_probe(struct platform_device *pdev)
        if (host->timer.function)
                pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
 
-#if BUSCLK_PWRSAVE
-       msmsdcc_disable_clocks(host, 1);
-#endif
        return 0;
  cmd_irq_free:
        free_irq(cmd_irqres->start, host);
index 1720358..5309ab9 100644 (file)
@@ -277,10 +277,43 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
        host->clock = clock;
 }
 
+/**
+ * sdhci_s3c_platform_8bit_width - support 8bit buswidth
+ * @host: The SDHCI host being queried
+ * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
+ *
+ * We have 8-bit width support but is not a v3 controller.
+ * So we add platform_8bit_width() and support 8bit width.
+ */
+static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width)
+{
+       u8 ctrl;
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+       switch (width) {
+       case MMC_BUS_WIDTH_8:
+               ctrl |= SDHCI_CTRL_8BITBUS;
+               ctrl &= ~SDHCI_CTRL_4BITBUS;
+               break;
+       case MMC_BUS_WIDTH_4:
+               ctrl |= SDHCI_CTRL_4BITBUS;
+               ctrl &= ~SDHCI_CTRL_8BITBUS;
+               break;
+       default:
+               break;
+       }
+
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+       return 0;
+}
+
 static struct sdhci_ops sdhci_s3c_ops = {
        .get_max_clock          = sdhci_s3c_get_max_clk,
        .set_clock              = sdhci_s3c_set_clock,
        .get_min_clock          = sdhci_s3c_get_min_clock,
+       .platform_8bit_width    = sdhci_s3c_platform_8bit_width,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
@@ -473,6 +506,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->mmc->caps = MMC_CAP_NONREMOVABLE;
 
+       if (pdata->host_caps)
+               host->mmc->caps |= pdata->host_caps;
+
        host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
                         SDHCI_QUIRK_32BIT_DMA_SIZE);
 
index f8f65df..f08f944 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
-#include <linux/usb.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/mmc/host.h>
index d9d7efb..6322d1f 100644 (file)
@@ -930,7 +930,7 @@ int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 
        init_completion(&dev->dma_done);
 
-       dev->card_workqueue = create_freezeable_workqueue(DRV_NAME);
+       dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
 
        if (!dev->card_workqueue)
                goto error9;
index 67822cf..ac0d6a8 100644 (file)
@@ -1258,7 +1258,7 @@ static struct mtd_blktrans_ops sm_ftl_ops = {
 static __init int sm_module_init(void)
 {
        int error = 0;
-       cache_flush_workqueue = create_freezeable_workqueue("smflush");
+       cache_flush_workqueue = create_freezable_workqueue("smflush");
 
        if (IS_ERR(cache_flush_workqueue))
                return PTR_ERR(cache_flush_workqueue);
index f49e49d..5ebe280 100644 (file)
@@ -672,33 +672,7 @@ static int io_init(struct ubi_device *ubi)
                ubi->nor_flash = 1;
        }
 
-       /*
-        * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize
-        * for these purposes, not @mtd->writesize. At the moment this does not
-        * matter for NAND, because currently @mtd->writebufsize is equivalent to
-        * @mtd->writesize for all NANDs. However, some CFI NOR flashes may
-        * have @mtd->writebufsize which is multiple of @mtd->writesize.
-        *
-        * The reason we use @mtd->writebufsize for @ubi->min_io_size is that
-        * UBI and UBIFS recovery algorithms rely on the fact that if there was
-        * an unclean power cut, then we can find offset of the last corrupted
-        * node, align the offset to @ubi->min_io_size, read the rest of the
-        * eraseblock starting from this offset, and check whether there are
-        * only 0xFF bytes. If yes, then we are probably dealing with a
-        * corruption caused by a power cut, if not, then this is probably some
-        * severe corruption.
-        *
-        * Thus, we have to use the maximum write unit size of the flash, which
-        * is @mtd->writebufsize, because @mtd->writesize is the minimum write
-        * size, not the maximum.
-        */
-       if (ubi->mtd->type == MTD_NANDFLASH)
-               ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize);
-       else if (ubi->mtd->type == MTD_NORFLASH)
-               ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0);
-
-       ubi->min_io_size = ubi->mtd->writebufsize;
-
+       ubi->min_io_size = ubi->mtd->writesize;
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
        /*
index 16fe4f9..0382332 100644 (file)
@@ -2864,7 +2864,7 @@ config MLX4_CORE
        default n
 
 config MLX4_DEBUG
-       bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED)
+       bool "Verbose debugging output" if (MLX4_CORE && EXPERT)
        depends on MLX4_CORE
        default y
        ---help---
index 62d6f88..aa07657 100644 (file)
@@ -1644,7 +1644,7 @@ ks8695_cleanup(void)
 module_init(ks8695_init);
 module_exit(ks8695_cleanup);
 
-MODULE_AUTHOR("Simtec Electronics")
+MODULE_AUTHOR("Simtec Electronics");
 MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" MODULENAME);
index a699bbf..3824382 100644 (file)
@@ -48,6 +48,7 @@ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D_2_0)},
        /* required last entry */
        { 0 }
 };
index 0c7811f..a179cc6 100644 (file)
@@ -1786,6 +1786,10 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
        spin_lock_bh(&adapter->mcc_lock);
 
        wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
        req = nonemb_cmd->va;
        sge = nonembedded_sgl(wrb);
 
@@ -1801,6 +1805,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
 
        status = be_mcc_notify_wait(adapter);
 
+err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
index de40d3b..28a32a6 100644 (file)
@@ -312,11 +312,9 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up)
        if (adapter->link_up != link_up) {
                adapter->link_speed = -1;
                if (link_up) {
-                       netif_start_queue(netdev);
                        netif_carrier_on(netdev);
                        printk(KERN_INFO "%s: Link up\n", netdev->name);
                } else {
-                       netif_stop_queue(netdev);
                        netif_carrier_off(netdev);
                        printk(KERN_INFO "%s: Link down\n", netdev->name);
                }
@@ -2628,8 +2626,6 @@ static void be_netdev_init(struct net_device *netdev)
 
        netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
                BE_NAPI_WEIGHT);
-
-       netif_stop_queue(netdev);
 }
 
 static void be_unmap_pci_bars(struct be_adapter *adapter)
index df99edf..0ba59d5 100644 (file)
@@ -7553,6 +7553,10 @@ bnx2_set_flags(struct net_device *dev, u32 data)
            !(data & ETH_FLAG_RXVLAN))
                return -EINVAL;
 
+       /* TSO with VLAN tag won't work with current firmware */
+       if (!(data & ETH_FLAG_TXVLAN))
+               return -EINVAL;
+
        rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
                                  ETH_FLAG_TXVLAN);
        if (rc)
@@ -7962,11 +7966,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
                /* AER (Advanced Error Reporting) hooks */
                err = pci_enable_pcie_error_reporting(pdev);
-               if (err) {
-                       dev_err(&pdev->dev, "pci_enable_pcie_error_reporting "
-                                           "failed 0x%x\n", err);
-                       /* non-fatal, continue */
-               }
+               if (!err)
+                       bp->flags |= BNX2_FLAG_AER_ENABLED;
 
        } else {
                bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
@@ -8229,8 +8230,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        return 0;
 
 err_out_unmap:
-       if (bp->flags & BNX2_FLAG_PCIE)
+       if (bp->flags & BNX2_FLAG_AER_ENABLED) {
                pci_disable_pcie_error_reporting(pdev);
+               bp->flags &= ~BNX2_FLAG_AER_ENABLED;
+       }
 
        if (bp->regview) {
                iounmap(bp->regview);
@@ -8418,8 +8421,10 @@ bnx2_remove_one(struct pci_dev *pdev)
 
        kfree(bp->temp_stats_blk);
 
-       if (bp->flags & BNX2_FLAG_PCIE)
+       if (bp->flags & BNX2_FLAG_AER_ENABLED) {
                pci_disable_pcie_error_reporting(pdev);
+               bp->flags &= ~BNX2_FLAG_AER_ENABLED;
+       }
 
        free_netdev(dev);
 
@@ -8535,7 +8540,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
        }
        rtnl_unlock();
 
-       if (!(bp->flags & BNX2_FLAG_PCIE))
+       if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
                return result;
 
        err = pci_cleanup_aer_uncorrect_error_status(pdev);
index 5488a2e..f459fb2 100644 (file)
@@ -6741,6 +6741,7 @@ struct bnx2 {
 #define BNX2_FLAG_JUMBO_BROKEN         0x00000800
 #define BNX2_FLAG_CAN_KEEP_VLAN                0x00001000
 #define BNX2_FLAG_BROKEN_STATS         0x00002000
+#define BNX2_FLAG_AER_ENABLED          0x00004000
 
        struct bnx2_napi        bnx2_napi[BNX2_MAX_MSIX_VEC];
 
index a6cd335..7897d11 100644 (file)
@@ -22,8 +22,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.62.00-3"
-#define DRV_MODULE_RELDATE      "2010/12/21"
+#define DRV_MODULE_VERSION      "1.62.00-6"
+#define DRV_MODULE_RELDATE      "2011/01/30"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
@@ -1613,19 +1613,23 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_BTR                      4
 #define MAX_SPQ_PENDING                        8
 
-
-/* CMNG constants
-   derived from lab experiments, and not from system spec calculations !!! */
-#define DEF_MIN_RATE                   100
+/* CMNG constants, as derived from system spec calculations */
+/* default MIN rate in case VNIC min rate is configured to zero - 100Mbps */
+#define DEF_MIN_RATE                                   100
 /* resolution of the rate shaping timer - 100 usec */
-#define RS_PERIODIC_TIMEOUT_USEC       100
-/* resolution of fairness algorithm in usecs -
-   coefficient for calculating the actual t fair */
-#define T_FAIR_COEF                    10000000
+#define RS_PERIODIC_TIMEOUT_USEC                       100
 /* number of bytes in single QM arbitration cycle -
-   coefficient for calculating the fairness timer */
-#define QM_ARB_BYTES                   40000
-#define FAIR_MEM                       2
+ * coefficient for calculating the fairness timer */
+#define QM_ARB_BYTES                                   160000
+/* resolution of Min algorithm 1:100 */
+#define MIN_RES                                                100
+/* how many bytes above threshold for the minimal credit of Min algorithm*/
+#define MIN_ABOVE_THRESH                               32768
+/* Fairness algorithm integration time coefficient -
+ * for calculating the actual Tfair */
+#define T_FAIR_COEF    ((MIN_ABOVE_THRESH +  QM_ARB_BYTES) * 8 * MIN_RES)
+/* Memory of fairness algorithm . 2 cycles */
+#define FAIR_MEM                                       2
 
 
 #define ATTN_NIG_FOR_FUNC              (1L << 8)
index 710ce5d..9379812 100644 (file)
@@ -259,10 +259,44 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 #endif
 }
 
+/* Timestamp option length allowed for TPA aggregation:
+ *
+ *             nop nop kind length echo val
+ */
+#define TPA_TSTAMP_OPT_LEN     12
+/**
+ * Calculate the approximate value of the MSS for this
+ * aggregation using the first packet of it.
+ *
+ * @param bp
+ * @param parsing_flags Parsing flags from the START CQE
+ * @param len_on_bd Total length of the first packet for the
+ *                  aggregation.
+ */
+static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
+                                   u16 len_on_bd)
+{
+       /* TPA arrgregation won't have an IP options and TCP options
+        * other than timestamp.
+        */
+       u16 hdrs_len = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct tcphdr);
+
+
+       /* Check if there was a TCP timestamp, if there is it's will
+        * always be 12 bytes length: nop nop kind length echo val.
+        *
+        * Otherwise FW would close the aggregation.
+        */
+       if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
+               hdrs_len += TPA_TSTAMP_OPT_LEN;
+
+       return len_on_bd - hdrs_len;
+}
+
 static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                               struct sk_buff *skb,
                               struct eth_fast_path_rx_cqe *fp_cqe,
-                              u16 cqe_idx)
+                              u16 cqe_idx, u16 parsing_flags)
 {
        struct sw_rx_page *rx_pg, old_rx_pg;
        u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
@@ -275,8 +309,8 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 
        /* This is needed in order to enable forwarding support */
        if (frag_size)
-               skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
-                                              max(frag_size, (u32)len_on_bd));
+               skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp, parsing_flags,
+                                                             len_on_bd);
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
@@ -344,6 +378,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        if (likely(new_skb)) {
                /* fix ip xsum and give it to the stack */
                /* (no need to map the new skb) */
+               u16 parsing_flags =
+                       le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags);
 
                prefetch(skb);
                prefetch(((char *)(skb)) + L1_CACHE_BYTES);
@@ -373,9 +409,9 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
                if (!bnx2x_fill_frag_skb(bp, fp, skb,
-                                        &cqe->fast_path_cqe, cqe_idx)) {
-                       if ((le16_to_cpu(cqe->fast_path_cqe.
-                           pars_flags.flags) & PARSING_FLAGS_VLAN))
+                                        &cqe->fast_path_cqe, cqe_idx,
+                                        parsing_flags)) {
+                       if (parsing_flags & PARSING_FLAGS_VLAN)
                                __vlan_hwaccel_put_tag(skb,
                                                 le16_to_cpu(cqe->fast_path_cqe.
                                                             vlan_tag));
@@ -703,19 +739,20 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
 {
        u16 line_speed = bp->link_vars.line_speed;
        if (IS_MF(bp)) {
-               u16 maxCfg = (bp->mf_config[BP_VN(bp)] &
-                                               FUNC_MF_CFG_MAX_BW_MASK) >>
-                                               FUNC_MF_CFG_MAX_BW_SHIFT;
-               /* Calculate the current MAX line speed limit for the DCC
-                * capable devices
+               u16 maxCfg = bnx2x_extract_max_cfg(bp,
+                                                  bp->mf_config[BP_VN(bp)]);
+
+               /* Calculate the current MAX line speed limit for the MF
+                * devices
                 */
-               if (IS_MF_SD(bp)) {
+               if (IS_MF_SI(bp))
+                       line_speed = (line_speed * maxCfg) / 100;
+               else { /* SD mode */
                        u16 vn_max_rate = maxCfg * 100;
 
                        if (vn_max_rate < line_speed)
                                line_speed = vn_max_rate;
-               } else /* IS_MF_SI(bp)) */
-                       line_speed = (line_speed * maxCfg) / 100;
+               }
        }
 
        return line_speed;
index 03eb4d6..326ba44 100644 (file)
@@ -1044,4 +1044,24 @@ static inline void storm_memset_cmng(struct bnx2x *bp,
 void bnx2x_acquire_phy_lock(struct bnx2x *bp);
 void bnx2x_release_phy_lock(struct bnx2x *bp);
 
+/**
+ * Extracts MAX BW part from MF configuration.
+ *
+ * @param bp
+ * @param mf_cfg
+ *
+ * @return u16
+ */
+static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
+{
+       u16 max_cfg = (mf_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
+                             FUNC_MF_CFG_MAX_BW_SHIFT;
+       if (!max_cfg) {
+               BNX2X_ERR("Illegal configuration detected for Max BW - "
+                         "using 100 instead\n");
+               max_cfg = 100;
+       }
+       return max_cfg;
+}
+
 #endif /* BNX2X_CMN_H */
index 5b44a8b..ef29199 100644 (file)
@@ -238,7 +238,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        speed |= (cmd->speed_hi << 16);
 
        if (IS_MF_SI(bp)) {
-               u32 param = 0;
+               u32 param = 0, part;
                u32 line_speed = bp->link_vars.line_speed;
 
                /* use 10G if no link detected */
@@ -251,9 +251,11 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                       REQ_BC_VER_4_SET_MF_BW);
                        return -EINVAL;
                }
-               if (line_speed < speed) {
-                       BNX2X_DEV_INFO("New speed should be less or equal "
-                                      "to actual line speed\n");
+               part = (speed * 100) / line_speed;
+               if (line_speed < speed || !part) {
+                       BNX2X_DEV_INFO("Speed setting should be in a range "
+                                      "from 1%% to 100%% "
+                                      "of actual line speed\n");
                        return -EINVAL;
                }
                /* load old values */
@@ -263,8 +265,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                param &= FUNC_MF_CFG_MIN_BW_MASK;
 
                /* set new MAX value */
-               param |= (((speed * 100) / line_speed)
-                                << FUNC_MF_CFG_MAX_BW_SHIFT)
+               param |= (part << FUNC_MF_CFG_MAX_BW_SHIFT)
                                  & FUNC_MF_CFG_MAX_BW_MASK;
 
                bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, param);
@@ -1781,9 +1782,7 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
                { 0x100, 0x350 }, /* manuf_info */
                { 0x450,  0xf0 }, /* feature_info */
                { 0x640,  0x64 }, /* upgrade_key_info */
-               { 0x6a4,  0x64 },
                { 0x708,  0x70 }, /* manuf_key_info */
-               { 0x778,  0x70 },
                {     0,     0 }
        };
        __be32 buf[0x350 / 4];
@@ -1933,11 +1932,11 @@ static void bnx2x_self_test(struct net_device *dev,
                buf[4] = 1;
                etest->flags |= ETH_TEST_FL_FAILED;
        }
-       if (bp->port.pmf)
-               if (bnx2x_link_test(bp, is_serdes) != 0) {
-                       buf[5] = 1;
-                       etest->flags |= ETH_TEST_FL_FAILED;
-               }
+
+       if (bnx2x_link_test(bp, is_serdes) != 0) {
+               buf[5] = 1;
+               etest->flags |= ETH_TEST_FL_FAILED;
+       }
 
 #ifdef BNX2X_EXTRA_DEBUG
        bnx2x_panic_dump(bp);
index 6238d4f..548f563 100644 (file)
@@ -352,6 +352,10 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_LANE_SWAP_CFG_31203120         0x0000d8d8
        /* forced only */
 #define PORT_HW_CFG_LANE_SWAP_CFG_32103210         0x0000e4e4
+    /* Indicate whether to swap the external phy polarity */
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_MASK            0x00010000
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_DISABLED     0x00000000
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED      0x00010000
 
        u32 external_phy_config;
 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK       0xff000000
index 5a268e9..fa6dbe3 100644 (file)
@@ -241,7 +241,7 @@ static const struct {
        /* Block IGU, MISC, PXP and PXP2 parity errors as long as we don't
         * want to handle "system kill" flow at the moment.
         */
-       BLOCK_PRTY_INFO(PXP, 0x3ffffff, 0x3ffffff, 0x3ffffff, 0x3ffffff),
+       BLOCK_PRTY_INFO(PXP, 0x7ffffff, 0x3ffffff, 0x3ffffff, 0x7ffffff),
        BLOCK_PRTY_INFO_0(PXP2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff),
        BLOCK_PRTY_INFO_1(PXP2, 0x7ff, 0x7f, 0x7f, 0x7ff),
        BLOCK_PRTY_INFO(HC, 0x7, 0x7, 0x7, 0),
index 43b0de2..dd1210f 100644 (file)
@@ -1573,7 +1573,7 @@ static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
 
        offset = phy->addr + ser_lane;
        if (CHIP_IS_E2(bp))
-               aer_val = 0x2800 + offset - 1;
+               aer_val = 0x3800 + offset - 1;
        else
                aer_val = 0x3800 + offset;
        CL45_WR_OVER_CL22(bp, phy,
@@ -3166,7 +3166,23 @@ u8 bnx2x_set_led(struct link_params *params,
                if (!vars->link_up)
                        break;
        case LED_MODE_ON:
-               if (SINGLE_MEDIA_DIRECT(params)) {
+               if (params->phy[EXT_PHY1].type ==
+                   PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 &&
+                   CHIP_IS_E2(bp) && params->num_phys == 2) {
+                       /**
+                       * This is a work-around for E2+8727 Configurations
+                       */
+                       if (mode == LED_MODE_ON ||
+                               speed == SPEED_10000){
+                               REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+                               REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+
+                               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+                               EMAC_WR(bp, EMAC_REG_EMAC_LED,
+                                       (tmp | EMAC_LED_OVERRIDE));
+                               return rc;
+                       }
+               } else if (SINGLE_MEDIA_DIRECT(params)) {
                        /**
                        * This is a work-around for HW issue found when link
                        * is up in CL73
@@ -3854,11 +3870,14 @@ static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
                           pause_result);
        }
 }
-
-static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
+static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
                                              struct bnx2x_phy *phy,
                                              u8 port)
 {
+       u32 count = 0;
+       u16 fw_ver1, fw_msgout;
+       u8 rc = 0;
+
        /* Boot port from external ROM  */
        /* EDC grst */
        bnx2x_cl45_write(bp, phy,
@@ -3888,56 +3907,45 @@ static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
                       MDIO_PMA_REG_GEN_CTRL,
                       MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
 
-       /* wait for 120ms for code download via SPI port */
-       msleep(120);
+       /* Delay 100ms per the PHY specifications */
+       msleep(100);
+
+       /* 8073 sometimes taking longer to download */
+       do {
+               count++;
+               if (count > 300) {
+                       DP(NETIF_MSG_LINK,
+                                "bnx2x_8073_8727_external_rom_boot port %x:"
+                                "Download failed. fw version = 0x%x\n",
+                                port, fw_ver1);
+                       rc = -EINVAL;
+                       break;
+               }
+
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
+
+               msleep(1);
+       } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
+                       ((fw_msgout & 0xff) != 0x03 && (phy->type ==
+                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
 
        /* Clear ser_boot_ctl bit */
        bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_MISC_CTRL1, 0x0000);
        bnx2x_save_bcm_spirom_ver(bp, phy, port);
-}
 
-static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
-                                              struct bnx2x_phy *phy)
-{
-       u16 val;
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
-
-       if (val == 0) {
-               /* Mustn't set low power mode in 8073 A0 */
-               return;
-       }
-
-       /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
-       val &= ~(1<<13);
-       bnx2x_cl45_write(bp, phy,
-                      MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-
-       /* PLL controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
-
-       /* Tx Controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
-
-       /* Rx Controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
+       DP(NETIF_MSG_LINK,
+                "bnx2x_8073_8727_external_rom_boot port %x:"
+                "Download complete. fw version = 0x%x\n",
+                port, fw_ver1);
 
-       /* Enable PLL sequencer  (use read-modify-write to set bit 13) */
-       bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
-       val |= (1<<13);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
+       return rc;
 }
 
 /******************************************************************/
@@ -4098,8 +4106,6 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
 
        bnx2x_8073_set_pause_cl37(params, phy, vars);
 
-       bnx2x_8073_set_xaui_low_power_mode(bp, phy);
-
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
 
@@ -4108,6 +4114,25 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
 
        DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
+       /**
+        * If this is forced speed, set to KR or KX (all other are not
+        * supported)
+        */
+       /* Swap polarity if required - Must be done only in non-1G mode */
+       if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
+               /* Configure the 8073 to swap _P and _N of the KR lines */
+               DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
+               /* 10G Rx/Tx and 1G Tx signal polarity swap */
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
+                                (val | (3<<9)));
+       }
+
+
        /* Enable CL37 BAM */
        if (REG_RD(bp, params->shmem_base +
                         offsetof(struct shmem_region, dev_info.
@@ -4314,8 +4339,32 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
        }
 
        if (link_up) {
+               /* Swap polarity if required */
+               if (params->lane_config &
+                   PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
+                       /* Configure the 8073 to swap P and N of the KR lines */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_XS_DEVAD,
+                                       MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
+                       /**
+                       * Set bit 3 to invert Rx in 1G mode and clear this bit
+                       * when it`s in 10G mode.
+                       */
+                       if (vars->line_speed == SPEED_1000) {
+                               DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
+                                             "the 8073\n");
+                               val1 |= (1<<3);
+                       } else
+                               val1 &= ~(1<<3);
+
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_XS_DEVAD,
+                                        MDIO_XS_REG_8073_RX_CTRL_PCIE,
+                                        val1);
+               }
                bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
                bnx2x_8073_resolve_fc(phy, params, vars);
+               vars->duplex = DUPLEX_FULL;
        }
        return link_up;
 }
@@ -5062,6 +5111,7 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
                else
                        vars->line_speed = SPEED_10000;
                bnx2x_ext_phy_resolve_fc(phy, params, vars);
+               vars->duplex = DUPLEX_FULL;
        }
        return link_up;
 }
@@ -5758,8 +5808,11 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
                DP(NETIF_MSG_LINK, "port %x: External link is down\n",
                           params->port);
        }
-       if (link_up)
+       if (link_up) {
                bnx2x_ext_phy_resolve_fc(phy, params, vars);
+               vars->duplex = DUPLEX_FULL;
+               DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
+       }
 
        if ((DUAL_MEDIA(params)) &&
            (phy->req_line_speed == SPEED_1000)) {
@@ -5875,10 +5928,26 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
                         MDIO_PMA_REG_8481_LED2_MASK,
                         0x18);
 
+       /* Select activity source by Tx and Rx, as suggested by PHY AE */
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
                         MDIO_PMA_REG_8481_LED3_MASK,
-                        0x0040);
+                        0x0006);
+
+       /* Select the closest activity blink rate to that in 10/100/1000 */
+       bnx2x_cl45_write(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_8481_LED3_BLINK,
+                       0);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
+       val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
 
        /* 'Interrupt Mask' */
        bnx2x_cl45_write(bp, phy,
@@ -6126,6 +6195,7 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
        /* Check link 10G */
        if (val2 & (1<<11)) {
                vars->line_speed = SPEED_10000;
+               vars->duplex = DUPLEX_FULL;
                link_up = 1;
                bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
        } else { /* Check Legacy speed link */
@@ -6405,6 +6475,18 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                         MDIO_PMA_DEVAD,
                                         MDIO_PMA_REG_8481_LED1_MASK,
                                         0x80);
+
+                       /* Tell LED3 to blink on source */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                       &val);
+                       val &= ~(7<<6);
+                       val |= (1<<6); /* A83B[8:6]= 1 */
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                        val);
                }
                break;
        }
@@ -6489,6 +6571,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
                                MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
                                &val2);
                vars->line_speed = SPEED_10000;
+               vars->duplex = DUPLEX_FULL;
                DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
                           val2, (val2 & (1<<14)));
                bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
@@ -7605,10 +7688,13 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        struct bnx2x_phy phy[PORT_MAX];
        struct bnx2x_phy *phy_blk[PORT_MAX];
        u16 val;
-       s8 port;
+       s8 port = 0;
        s8 port_of_path = 0;
-
-       bnx2x_ext_phy_hw_reset(bp, 0);
+       u32 swap_val, swap_override;
+       swap_val = REG_RD(bp,  NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp,  NIG_REG_STRAP_OVERRIDE);
+       port ^= (swap_val && swap_override);
+       bnx2x_ext_phy_hw_reset(bp, port);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
@@ -7663,7 +7749,6 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
 
        /* PART2 - Download firmware to both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
-               u16 fw_ver1;
                if (CHIP_IS_E2(bp))
                        port_of_path = 0;
                else
@@ -7671,19 +7756,9 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
 
                DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
                           phy_blk[port]->addr);
-               bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
-                                                 port_of_path);
-
-               bnx2x_cl45_read(bp, phy_blk[port],
-                             MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_ROM_VER1, &fw_ver1);
-               if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
-                       DP(NETIF_MSG_LINK,
-                                "bnx2x_8073_common_init_phy port %x:"
-                                "Download failed. fw version = 0x%x\n",
-                                port, fw_ver1);
+               if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+                                                     port_of_path))
                        return -EINVAL;
-               }
 
                /* Only set bit 10 = 1 (Tx power down) */
                bnx2x_cl45_read(bp, phy_blk[port],
@@ -7848,27 +7923,17 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
        }
        /* PART2 - Download firmware to both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
-               u16 fw_ver1;
                 if (CHIP_IS_E2(bp))
                        port_of_path = 0;
                else
                        port_of_path = port;
                DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
                           phy_blk[port]->addr);
-               bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
-                                                 port_of_path);
-               bnx2x_cl45_read(bp, phy_blk[port],
-                             MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_ROM_VER1, &fw_ver1);
-               if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
-                       DP(NETIF_MSG_LINK,
-                                "bnx2x_8727_common_init_phy port %x:"
-                                "Download failed. fw version = 0x%x\n",
-                                port, fw_ver1);
+               if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+                                                     port_of_path))
                        return -EINVAL;
-               }
-       }
 
+       }
        return 0;
 }
 
@@ -7916,6 +7981,7 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
                         u32 shmem2_base_path[], u32 chip_id)
 {
        u8 rc = 0;
+       u32 phy_ver;
        u8 phy_index;
        u32 ext_phy_type, ext_phy_config;
        DP(NETIF_MSG_LINK, "Begin common phy init\n");
@@ -7923,6 +7989,16 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
        if (CHIP_REV_IS_EMUL(bp))
                return 0;
 
+       /* Check if common init was already done */
+       phy_ver = REG_RD(bp, shmem_base_path[0] +
+                        offsetof(struct shmem_region,
+                                 port_mb[PORT_0].ext_phy_fw_version));
+       if (phy_ver) {
+               DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
+                              phy_ver);
+               return 0;
+       }
+
        /* Read the ext_phy_type for arbitrary port(0) */
        for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
              phy_index++) {
index 8cdcf5b..032ae18 100644 (file)
@@ -1974,13 +1974,22 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
                vn_max_rate = 0;
 
        } else {
+               u32 maxCfg = bnx2x_extract_max_cfg(bp, vn_cfg);
+
                vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
                                FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-               /* If min rate is zero - set it to 1 */
+               /* If fairness is enabled (not all min rates are zeroes) and
+                  if current min rate is zero - set it to 1.
+                  This is a requirement of the algorithm. */
                if (bp->vn_weight_sum && (vn_min_rate == 0))
                        vn_min_rate = DEF_MIN_RATE;
-               vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
-                               FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+
+               if (IS_MF_SI(bp))
+                       /* maxCfg in percents of linkspeed */
+                       vn_max_rate = (bp->link_vars.line_speed * maxCfg) / 100;
+               else
+                       /* maxCfg is absolute in 100Mb units */
+                       vn_max_rate = maxCfg * 100;
        }
 
        DP(NETIF_MSG_IFUP,
@@ -2006,7 +2015,8 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
                m_fair_vn.vn_credit_delta =
                        max_t(u32, (vn_min_rate * (T_FAIR_COEF /
                                                   (8 * bp->vn_weight_sum))),
-                             (bp->cmng.fair_vars.fair_threshold * 2));
+                             (bp->cmng.fair_vars.fair_threshold +
+                                                       MIN_ABOVE_THRESH));
                DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
                   m_fair_vn.vn_credit_delta);
        }
@@ -2301,15 +2311,10 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
                /* accept matched ucast */
                drop_all_ucast = 0;
        }
-       if (filters & BNX2X_ACCEPT_MULTICAST) {
+       if (filters & BNX2X_ACCEPT_MULTICAST)
                /* accept matched mcast */
                drop_all_mcast = 0;
-               if (IS_MF_SI(bp))
-                       /* since mcast addresses won't arrive with ovlan,
-                        * fw needs to accept all of them in
-                        * switch-independent mode */
-                       accp_all_mcast = 1;
-       }
+
        if (filters & BNX2X_ACCEPT_ALL_UNICAST) {
                /* accept all mcast */
                drop_all_ucast = 0;
@@ -4281,9 +4286,12 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
                                BNX2X_ACCEPT_MULTICAST;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id,
+                                                 BNX2X_ACCEPT_UNICAST |
+                                                 BNX2X_ACCEPT_MULTICAST);
+               }
 #endif
                break;
 
@@ -4291,18 +4299,29 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
                                BNX2X_ACCEPT_ALL_MULTICAST;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               /*
+                *  Prevent duplication of multicast packets by configuring FCoE
+                *  L2 Client to receive only matched unicast frames.
+                */
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id,
+                                                 BNX2X_ACCEPT_UNICAST);
+               }
 #endif
                break;
 
        case BNX2X_RX_MODE_PROMISC:
                def_q_filters |= BNX2X_PROMISCUOUS_MODE;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               /*
+                *  Prevent packets duplication by configuring DROP_ALL for FCoE
+                *  L2 Client.
+                */
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE);
+               }
 #endif
                /* pass management unicast packets as well */
                llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
@@ -5296,10 +5315,6 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
                }
        }
 
-       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
-                                                      bp->common.shmem_base,
-                                                      bp->common.shmem2_base);
-
        bnx2x_setup_fan_failure_detection(bp);
 
        /* clear PXP2 attentions */
@@ -5503,9 +5518,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
 
        bnx2x_init_block(bp, MCP_BLOCK, init_stage);
        bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
-       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
-                                                      bp->common.shmem_base,
-                                                      bp->common.shmem2_base);
        if (bnx2x_fan_failure_det_req(bp, bp->common.shmem_base,
                                      bp->common.shmem2_base, port)) {
                u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
@@ -8379,6 +8391,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
                 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
                bp->mdio.prtad =
                        XGXS_EXT_PHY_ADDR(ext_phy_config);
+
+       /*
+        * Check if hw lock is required to access MDC/MDIO bus to the PHY(s)
+        * In MF mode, it is set to cover self test cases
+        */
+       if (IS_MF(bp))
+               bp->port.need_hw_lock = 1;
+       else
+               bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+                                                       bp->common.shmem_base,
+                                                       bp->common.shmem2_base);
 }
 
 static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
index c939683..e01330b 100644 (file)
@@ -6194,7 +6194,11 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER       0x0000
 #define MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER                0x0100
 #define MDIO_CTL_REG_84823_MEDIA_FIBER_1G                      0x1000
+#define MDIO_CTL_REG_84823_USER_CTRL_REG               0x4005
+#define MDIO_CTL_REG_84823_USER_CTRL_CMS               0x0080
 
+#define MDIO_PMA_REG_84823_CTL_LED_CTL_1               0xa8e3
+#define MDIO_PMA_REG_84823_LED3_STRETCH_EN             0x0080
 
 #define IGU_FUNC_BASE                  0x0400
 
index bda60d5..3445ded 100644 (file)
@@ -1239,14 +1239,14 @@ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
        if (unlikely(bp->panic))
                return;
 
+       bnx2x_stats_stm[bp->stats_state][event].action(bp);
+
        /* Protect a state change flow */
        spin_lock_bh(&bp->stats_lock);
        state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
        spin_unlock_bh(&bp->stats_lock);
 
-       bnx2x_stats_stm[state][event].action(bp);
-
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
                   state, event, bp->stats_state);
index 171782e..1024ae1 100644 (file)
@@ -2470,6 +2470,10 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
        if (!(dev->flags & IFF_MASTER))
                goto out;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
        if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
                goto out;
 
index f4e638c..5c6fba8 100644 (file)
@@ -326,6 +326,10 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
                goto out;
        }
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
        if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
                goto out;
 
index b1025b8..163e0b0 100644 (file)
@@ -2733,6 +2733,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
        if (!slave || !slave_do_arp_validate(bond, slave))
                goto out_unlock;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out_unlock;
+
        if (!pskb_may_pull(skb, arp_hdr_len(dev)))
                goto out_unlock;
 
index d5a9db6..5dec456 100644 (file)
@@ -23,7 +23,7 @@ config CAN_SLCAN
 
          As only the sending and receiving of CAN frames is implemented, this
          driver should work with the (serial/USB) CAN hardware from:
-         www.canusb.com / www.can232.com / www.mictronic.com / www.canhack.de
+         www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
 
          Userspace tools to attach the SLCAN line discipline (slcan_attach,
          slcand) can be found in the can-utils at the SocketCAN SVN, see
@@ -117,6 +117,8 @@ source "drivers/net/can/sja1000/Kconfig"
 
 source "drivers/net/can/usb/Kconfig"
 
+source "drivers/net/can/softing/Kconfig"
+
 config CAN_DEBUG_DEVICES
        bool "CAN devices debugging messages"
        depends on CAN
index 07ca159..53c82a7 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_DEV)           += can-dev.o
 can-dev-y                      := dev.o
 
 obj-y                          += usb/
+obj-y                          += softing/
 
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
index 7ef83d0..57d2ffb 100644 (file)
@@ -2,7 +2,7 @@
  * at91_can.c - CAN network driver for AT91 SoC CAN controller
  *
  * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
- * (C) 2008, 2009, 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
+ * (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde <kernel@pengutronix.de>
  *
  * This software may be distributed under the terms of the GNU General
  * Public License ("GPL") version 2 as distributed in the 'COPYING'
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/platform_device.h>
+#include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
 #include <mach/board.h>
 
-#define AT91_NAPI_WEIGHT       12
+#define AT91_NAPI_WEIGHT       11
 
 /*
  * RX/TX Mailbox split
  * don't dare to touch
  */
-#define AT91_MB_RX_NUM         12
+#define AT91_MB_RX_NUM         11
 #define AT91_MB_TX_SHIFT       2
 
-#define AT91_MB_RX_FIRST       0
+#define AT91_MB_RX_FIRST       1
 #define AT91_MB_RX_LAST                (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
 
 #define AT91_MB_RX_MASK(i)     ((1 << (i)) - 1)
 #define AT91_MB_RX_SPLIT       8
 #define AT91_MB_RX_LOW_LAST    (AT91_MB_RX_SPLIT - 1)
-#define AT91_MB_RX_LOW_MASK    (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT))
+#define AT91_MB_RX_LOW_MASK    (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \
+                                ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST))
 
 #define AT91_MB_TX_NUM         (1 << AT91_MB_TX_SHIFT)
 #define AT91_MB_TX_FIRST       (AT91_MB_RX_LAST + 1)
@@ -168,6 +170,8 @@ struct at91_priv {
 
        struct clk              *clk;
        struct at91_can_data    *pdata;
+
+       canid_t                 mb0_id;
 };
 
 static struct can_bittiming_const at91_bittiming_const = {
@@ -220,6 +224,18 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb,
        set_mb_mode_prio(priv, mb, mode, 0);
 }
 
+static inline u32 at91_can_id_to_reg_mid(canid_t can_id)
+{
+       u32 reg_mid;
+
+       if (can_id & CAN_EFF_FLAG)
+               reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
+       else
+               reg_mid = (can_id & CAN_SFF_MASK) << 18;
+
+       return reg_mid;
+}
+
 /*
  * Swtich transceiver on or off
  */
@@ -233,12 +249,22 @@ static void at91_setup_mailboxes(struct net_device *dev)
 {
        struct at91_priv *priv = netdev_priv(dev);
        unsigned int i;
+       u32 reg_mid;
 
        /*
-        * The first 12 mailboxes are used as a reception FIFO. The
-        * last mailbox is configured with overwrite option. The
-        * overwrite flag indicates a FIFO overflow.
+        * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
+        * mailbox is disabled. The next 11 mailboxes are used as a
+        * reception FIFO. The last mailbox is configured with
+        * overwrite option. The overwrite flag indicates a FIFO
+        * overflow.
         */
+       reg_mid = at91_can_id_to_reg_mid(priv->mb0_id);
+       for (i = 0; i < AT91_MB_RX_FIRST; i++) {
+               set_mb_mode(priv, i, AT91_MB_MODE_DISABLED);
+               at91_write(priv, AT91_MID(i), reg_mid);
+               at91_write(priv, AT91_MCR(i), 0x0);     /* clear dlc */
+       }
+
        for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++)
                set_mb_mode(priv, i, AT91_MB_MODE_RX);
        set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
@@ -254,7 +280,8 @@ static void at91_setup_mailboxes(struct net_device *dev)
                set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
 
        /* Reset tx and rx helper pointers */
-       priv->tx_next = priv->tx_echo = priv->rx_next = 0;
+       priv->tx_next = priv->tx_echo = 0;
+       priv->rx_next = AT91_MB_RX_FIRST;
 }
 
 static int at91_set_bittiming(struct net_device *dev)
@@ -372,12 +399,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netdev_err(dev, "BUG! TX buffer full when queue awake!\n");
                return NETDEV_TX_BUSY;
        }
-
-       if (cf->can_id & CAN_EFF_FLAG)
-               reg_mid = (cf->can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
-       else
-               reg_mid = (cf->can_id & CAN_SFF_MASK) << 18;
-
+       reg_mid = at91_can_id_to_reg_mid(cf->can_id);
        reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
                (cf->can_dlc << 16) | AT91_MCR_MTCR;
 
@@ -539,27 +561,31 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
  *
  * Theory of Operation:
  *
- * 12 of the 16 mailboxes on the chip are reserved for RX. we split
- * them into 2 groups. The lower group holds 8 and upper 4 mailboxes.
+ * 11 of the 16 mailboxes on the chip are reserved for RX. we split
+ * them into 2 groups. The lower group holds 7 and upper 4 mailboxes.
  *
  * Like it or not, but the chip always saves a received CAN message
  * into the first free mailbox it finds (starting with the
  * lowest). This makes it very difficult to read the messages in the
  * right order from the chip. This is how we work around that problem:
  *
- * The first message goes into mb nr. 0 and issues an interrupt. All
+ * The first message goes into mb nr. 1 and issues an interrupt. All
  * rx ints are disabled in the interrupt handler and a napi poll is
  * scheduled. We read the mailbox, but do _not_ reenable the mb (to
  * receive another message).
  *
  *    lower mbxs      upper
- *   ______^______    __^__
- *  /             \  /     \
+ *     ____^______    __^__
+ *    /           \  /     \
  * +-+-+-+-+-+-+-+-++-+-+-+-+
- * |x|x|x|x|x|x|x|x|| | | | |
+ * | |x|x|x|x|x|x|x|| | | | |
  * +-+-+-+-+-+-+-+-++-+-+-+-+
  *  0 0 0 0 0 0  0 0 0 0 1 1  \ mail
  *  0 1 2 3 4 5  6 7 8 9 0 1  / box
+ *  ^
+ *  |
+ *   \
+ *     unused, due to chip bug
  *
  * The variable priv->rx_next points to the next mailbox to read a
  * message from. As long we're in the lower mailboxes we just read the
@@ -590,10 +616,10 @@ static int at91_poll_rx(struct net_device *dev, int quota)
                        "order of incoming frames cannot be guaranteed\n");
 
  again:
-       for (mb = find_next_bit(addr, AT91_MB_RX_NUM, priv->rx_next);
-            mb < AT91_MB_RX_NUM && quota > 0;
+       for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
+            mb < AT91_MB_RX_LAST + 1 && quota > 0;
             reg_sr = at91_read(priv, AT91_SR),
-            mb = find_next_bit(addr, AT91_MB_RX_NUM, ++priv->rx_next)) {
+            mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) {
                at91_read_msg(dev, mb);
 
                /* reactivate mailboxes */
@@ -610,8 +636,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
 
        /* upper group completed, look again in lower */
        if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
-           quota > 0 && mb >= AT91_MB_RX_NUM) {
-               priv->rx_next = 0;
+           quota > 0 && mb > AT91_MB_RX_LAST) {
+               priv->rx_next = AT91_MB_RX_FIRST;
                goto again;
        }
 
@@ -1037,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = {
        .ndo_start_xmit = at91_start_xmit,
 };
 
+static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct at91_priv *priv = netdev_priv(to_net_dev(dev));
+
+       if (priv->mb0_id & CAN_EFF_FLAG)
+               return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id);
+       else
+               return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id);
+}
+
+static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct at91_priv *priv = netdev_priv(ndev);
+       unsigned long can_id;
+       ssize_t ret;
+       int err;
+
+       rtnl_lock();
+
+       if (ndev->flags & IFF_UP) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       err = strict_strtoul(buf, 0, &can_id);
+       if (err) {
+               ret = err;
+               goto out;
+       }
+
+       if (can_id & CAN_EFF_FLAG)
+               can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
+       else
+               can_id &= CAN_SFF_MASK;
+
+       priv->mb0_id = can_id;
+       ret = count;
+
+ out:
+       rtnl_unlock();
+       return ret;
+}
+
+static DEVICE_ATTR(mb0_id, S_IWUSR | S_IRUGO,
+       at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id);
+
+static struct attribute *at91_sysfs_attrs[] = {
+       &dev_attr_mb0_id.attr,
+       NULL,
+};
+
+static struct attribute_group at91_sysfs_attr_group = {
+       .attrs = at91_sysfs_attrs,
+};
+
 static int __devinit at91_can_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
@@ -1082,6 +1166,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        dev->netdev_ops = &at91_netdev_ops;
        dev->irq = irq;
        dev->flags |= IFF_ECHO;
+       dev->sysfs_groups[0] = &at91_sysfs_attr_group;
 
        priv = netdev_priv(dev);
        priv->can.clock.freq = clk_get_rate(clk);
@@ -1093,6 +1178,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        priv->dev = dev;
        priv->clk = clk;
        priv->pdata = pdev->dev.platform_data;
+       priv->mb0_id = 0x7ff;
 
        netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);
 
index b9a6d7a..366f5cc 100644 (file)
@@ -1618,7 +1618,7 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(termination, S_IWUGO | S_IRUGO, ican3_sysfs_show_term,
+static DEVICE_ATTR(termination, S_IWUSR | S_IRUGO, ican3_sysfs_show_term,
                                                   ican3_sysfs_set_term);
 
 static struct attribute *ican3_sysfs_attrs[] = {
index 7ab534a..7513c45 100644 (file)
@@ -940,7 +940,7 @@ static int mcp251x_open(struct net_device *net)
                goto open_unlock;
        }
 
-       priv->wq = create_freezeable_workqueue("mcp251x_wq");
+       priv->wq = create_freezable_workqueue("mcp251x_wq");
        INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
        INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
 
index 27d1d39..d387069 100644 (file)
@@ -1,5 +1,5 @@
 config CAN_MSCAN
-       depends on CAN_DEV && (PPC || M68K || M68KNOMMU)
+       depends on CAN_DEV && (PPC || M68K)
        tristate "Support for Freescale MSCAN based chips"
        ---help---
          The Motorola Scalable Controller Area Network (MSCAN) definition
index c42e972..e54712b 100644 (file)
@@ -185,7 +185,7 @@ struct pch_can_priv {
 
 static struct can_bittiming_const pch_can_bittiming_const = {
        .name = KBUILD_MODNAME,
-       .tseg1_min = 1,
+       .tseg1_min = 2,
        .tseg1_max = 16,
        .tseg2_min = 1,
        .tseg2_max = 8,
@@ -959,13 +959,13 @@ static void __devexit pch_can_remove(struct pci_dev *pdev)
        struct pch_can_priv *priv = netdev_priv(ndev);
 
        unregister_candev(priv->ndev);
-       pci_iounmap(pdev, priv->regs);
        if (priv->use_msi)
                pci_disable_msi(priv->dev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        pch_can_reset(priv);
+       pci_iounmap(pdev, priv->regs);
        free_candev(priv->ndev);
 }
 
@@ -1238,6 +1238,7 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
                priv->use_msi = 0;
        } else {
                netdev_err(ndev, "PCH CAN opened with MSI\n");
+               pci_set_master(pdev);
                priv->use_msi = 1;
        }
 
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
new file mode 100644 (file)
index 0000000..5de46a9
--- /dev/null
@@ -0,0 +1,30 @@
+config CAN_SOFTING
+       tristate "Softing Gmbh CAN generic support"
+       depends on CAN_DEV && HAS_IOMEM
+       ---help---
+         Support for CAN cards from Softing Gmbh & some cards
+         from Vector Gmbh.
+         Softing Gmbh CAN cards come with 1 or 2 physical busses.
+         Those cards typically use Dual Port RAM to communicate
+         with the host CPU. The interface is then identical for PCI
+         and PCMCIA cards. This driver operates on a platform device,
+         which has been created by softing_cs or softing_pci driver.
+         Warning:
+         The API of the card does not allow fine control per bus, but
+         controls the 2 busses on the card together.
+         As such, some actions (start/stop/busoff recovery) on 1 bus
+         must bring down the other bus too temporarily.
+
+config CAN_SOFTING_CS
+       tristate "Softing Gmbh CAN pcmcia cards"
+       depends on PCMCIA
+       depends on CAN_SOFTING
+       ---help---
+         Support for PCMCIA cards from Softing Gmbh & some cards
+         from Vector Gmbh.
+         You need firmware for these, which you can get at
+         http://developer.berlios.de/projects/socketcan/
+         This version of the driver is written against
+         firmware version 4.6 (softing-fw-4.6-binaries.tar.gz)
+         In order to use the card as CAN device, you need the Softing generic
+         support too.
diff --git a/drivers/net/can/softing/Makefile b/drivers/net/can/softing/Makefile
new file mode 100644 (file)
index 0000000..c5e5016
--- /dev/null
@@ -0,0 +1,6 @@
+
+softing-y := softing_main.o softing_fw.o
+obj-$(CONFIG_CAN_SOFTING) += softing.o
+obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h
new file mode 100644 (file)
index 0000000..7ec9f4d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * softing common interfaces
+ *
+ * by Kurt Van Dijck, 2008-2010
+ */
+
+#include <linux/atomic.h>
+#include <linux/netdevice.h>
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include "softing_platform.h"
+
+struct softing;
+
+struct softing_priv {
+       struct can_priv can; /* must be the first member! */
+       struct net_device *netdev;
+       struct softing *card;
+       struct {
+               int pending;
+               /* variables wich hold the circular buffer */
+               int echo_put;
+               int echo_get;
+       } tx;
+       struct can_bittiming_const btr_const;
+       int index;
+       uint8_t output;
+       uint16_t chip;
+};
+#define netdev2softing(netdev) ((struct softing_priv *)netdev_priv(netdev))
+
+struct softing {
+       const struct softing_platform_data *pdat;
+       struct platform_device *pdev;
+       struct net_device *net[2];
+       spinlock_t spin; /* protect this structure & DPRAM access */
+       ktime_t ts_ref;
+       ktime_t ts_overflow; /* timestamp overflow value, in ktime */
+
+       struct {
+               /* indication of firmware status */
+               int up;
+               /* protection of the 'up' variable */
+               struct mutex lock;
+       } fw;
+       struct {
+               int nr;
+               int requested;
+               int svc_count;
+               unsigned int dpram_position;
+       } irq;
+       struct {
+               int pending;
+               int last_bus;
+               /*
+                * keep the bus that last tx'd a message,
+                * in order to let every netdev queue resume
+                */
+       } tx;
+       __iomem uint8_t *dpram;
+       unsigned long dpram_phys;
+       unsigned long dpram_size;
+       struct {
+               uint16_t fw_version, hw_version, license, serial;
+               uint16_t chip[2];
+               unsigned int freq; /* remote cpu's operating frequency */
+       } id;
+};
+
+extern int softing_default_output(struct net_device *netdev);
+
+extern ktime_t softing_raw2ktime(struct softing *card, u32 raw);
+
+extern int softing_chip_poweron(struct softing *card);
+
+extern int softing_bootloader_command(struct softing *card, int16_t cmd,
+               const char *msg);
+
+/* Load firmware after reset */
+extern int softing_load_fw(const char *file, struct softing *card,
+                       __iomem uint8_t *virt, unsigned int size, int offset);
+
+/* Load final application firmware after bootloader */
+extern int softing_load_app_fw(const char *file, struct softing *card);
+
+/*
+ * enable or disable irq
+ * only called with fw.lock locked
+ */
+extern int softing_enable_irq(struct softing *card, int enable);
+
+/* start/stop 1 bus on card */
+extern int softing_startstop(struct net_device *netdev, int up);
+
+/* netif_rx() */
+extern int softing_netdev_rx(struct net_device *netdev,
+               const struct can_frame *msg, ktime_t ktime);
+
+/* SOFTING DPRAM mappings */
+#define DPRAM_RX               0x0000
+       #define DPRAM_RX_SIZE   32
+       #define DPRAM_RX_CNT    16
+#define DPRAM_RX_RD            0x0201  /* uint8_t */
+#define DPRAM_RX_WR            0x0205  /* uint8_t */
+#define DPRAM_RX_LOST          0x0207  /* uint8_t */
+
+#define DPRAM_FCT_PARAM                0x0300  /* int16_t [20] */
+#define DPRAM_FCT_RESULT       0x0328  /* int16_t */
+#define DPRAM_FCT_HOST         0x032b  /* uint16_t */
+
+#define DPRAM_INFO_BUSSTATE    0x0331  /* uint16_t */
+#define DPRAM_INFO_BUSSTATE2   0x0335  /* uint16_t */
+#define DPRAM_INFO_ERRSTATE    0x0339  /* uint16_t */
+#define DPRAM_INFO_ERRSTATE2   0x033d  /* uint16_t */
+#define DPRAM_RESET            0x0341  /* uint16_t */
+#define DPRAM_CLR_RECV_FIFO    0x0345  /* uint16_t */
+#define DPRAM_RESET_TIME       0x034d  /* uint16_t */
+#define DPRAM_TIME             0x0350  /* uint64_t */
+#define DPRAM_WR_START         0x0358  /* uint8_t */
+#define DPRAM_WR_END           0x0359  /* uint8_t */
+#define DPRAM_RESET_RX_FIFO    0x0361  /* uint16_t */
+#define DPRAM_RESET_TX_FIFO    0x0364  /* uint8_t */
+#define DPRAM_READ_FIFO_LEVEL  0x0365  /* uint8_t */
+#define DPRAM_RX_FIFO_LEVEL    0x0366  /* uint16_t */
+#define DPRAM_TX_FIFO_LEVEL    0x0366  /* uint16_t */
+
+#define DPRAM_TX               0x0400  /* uint16_t */
+       #define DPRAM_TX_SIZE   16
+       #define DPRAM_TX_CNT    32
+#define DPRAM_TX_RD            0x0601  /* uint8_t */
+#define DPRAM_TX_WR            0x0605  /* uint8_t */
+
+#define DPRAM_COMMAND          0x07e0  /* uint16_t */
+#define DPRAM_RECEIPT          0x07f0  /* uint16_t */
+#define DPRAM_IRQ_TOHOST       0x07fe  /* uint8_t */
+#define DPRAM_IRQ_TOCARD       0x07ff  /* uint8_t */
+
+#define DPRAM_V2_RESET         0x0e00  /* uint8_t */
+#define DPRAM_V2_IRQ_TOHOST    0x0e02  /* uint8_t */
+
+#define TXMAX  (DPRAM_TX_CNT - 1)
+
+/* DPRAM return codes */
+#define RES_NONE       0
+#define RES_OK         1
+#define RES_NOK                2
+#define RES_UNKNOWN    3
+/* DPRAM flags */
+#define CMD_TX         0x01
+#define CMD_ACK                0x02
+#define CMD_XTD                0x04
+#define CMD_RTR                0x08
+#define CMD_ERR                0x10
+#define CMD_BUS2       0x80
+
+/* returned fifo entry bus state masks */
+#define SF_MASK_BUSOFF         0x80
+#define SF_MASK_EPASSIVE       0x60
+
+/* bus states */
+#define STATE_BUSOFF   2
+#define STATE_EPASSIVE 1
+#define STATE_EACTIVE  0
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
new file mode 100644 (file)
index 0000000..c11bb4d
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "softing_platform.h"
+
+static int softingcs_index;
+static spinlock_t softingcs_index_lock;
+
+static int softingcs_reset(struct platform_device *pdev, int v);
+static int softingcs_enable_irq(struct platform_device *pdev, int v);
+
+/*
+ * platform_data descriptions
+ */
+#define MHZ (1000*1000)
+static const struct softing_platform_data softingcs_platform_data[] = {
+{
+       .name = "CANcard",
+       .manf = 0x0168, .prod = 0x001,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-NEC",
+       .manf = 0x0168, .prod = 0x002,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-SJA",
+       .manf = 0x0168, .prod = 0x004,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-2",
+       .manf = 0x0168, .prod = 0x005,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       .name = "Vector-CANcard",
+       .manf = 0x0168, .prod = 0x081,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "Vector-CANcard-SJA",
+       .manf = 0x0168, .prod = 0x084,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "Vector-CANcard-2",
+       .manf = 0x0168, .prod = 0x085,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       .name = "EDICcard-NEC",
+       .manf = 0x0168, .prod = 0x102,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "EDICcard-2",
+       .manf = 0x0168, .prod = 0x105,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       0, 0,
+},
+};
+
+MODULE_FIRMWARE(fw_dir "bcard.bin");
+MODULE_FIRMWARE(fw_dir "ldcard.bin");
+MODULE_FIRMWARE(fw_dir "cancard.bin");
+MODULE_FIRMWARE(fw_dir "cansja.bin");
+
+MODULE_FIRMWARE(fw_dir "bcard2.bin");
+MODULE_FIRMWARE(fw_dir "ldcard2.bin");
+MODULE_FIRMWARE(fw_dir "cancrd2.bin");
+
+static __devinit const struct softing_platform_data
+*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
+{
+       const struct softing_platform_data *lp;
+
+       for (lp = softingcs_platform_data; lp->manf; ++lp) {
+               if ((lp->manf == manf) && (lp->prod == prod))
+                       return lp;
+       }
+       return NULL;
+}
+
+/*
+ * platformdata callbacks
+ */
+static int softingcs_reset(struct platform_device *pdev, int v)
+{
+       struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
+
+       dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
+       return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
+}
+
+static int softingcs_enable_irq(struct platform_device *pdev, int v)
+{
+       struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
+
+       dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
+       return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
+}
+
+/*
+ * pcmcia check
+ */
+static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia,
+               void *priv_data)
+{
+       struct softing_platform_data *pdat = priv_data;
+       struct resource *pres;
+       int memspeed = 0;
+
+       WARN_ON(!pdat);
+       pres = pcmcia->resource[PCMCIA_IOMEM_0];
+       if (resource_size(pres) < 0x1000)
+               return -ERANGE;
+
+       pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+       if (pdat->generation < 2) {
+               pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
+               memspeed = 3;
+       } else {
+               pres->flags |= WIN_DATA_WIDTH_16;
+       }
+       return pcmcia_request_window(pcmcia, pres, memspeed);
+}
+
+static __devexit void softingcs_remove(struct pcmcia_device *pcmcia)
+{
+       struct platform_device *pdev = pcmcia->priv;
+
+       /* free bits */
+       platform_device_unregister(pdev);
+       /* release pcmcia stuff */
+       pcmcia_disable_device(pcmcia);
+}
+
+/*
+ * platform_device wrapper
+ * pdev->resource has 2 entries: io & irq
+ */
+static void softingcs_pdev_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       kfree(pdev);
+}
+
+static __devinit int softingcs_probe(struct pcmcia_device *pcmcia)
+{
+       int ret;
+       struct platform_device *pdev;
+       const struct softing_platform_data *pdat;
+       struct resource *pres;
+       struct dev {
+               struct platform_device pdev;
+               struct resource res[2];
+       } *dev;
+
+       /* find matching platform_data */
+       pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
+       if (!pdat)
+               return -ENOTTY;
+
+       /* setup pcmcia device */
+       pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
+               CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
+       ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
+       if (ret)
+               goto pcmcia_failed;
+
+       ret = pcmcia_enable_device(pcmcia);
+       if (ret < 0)
+               goto pcmcia_failed;
+
+       pres = pcmcia->resource[PCMCIA_IOMEM_0];
+       if (!pres) {
+               ret = -EBADF;
+               goto pcmcia_bad;
+       }
+
+       /* create softing platform device */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto mem_failed;
+       }
+       dev->pdev.resource = dev->res;
+       dev->pdev.num_resources = ARRAY_SIZE(dev->res);
+       dev->pdev.dev.release = softingcs_pdev_release;
+
+       pdev = &dev->pdev;
+       pdev->dev.platform_data = (void *)pdat;
+       pdev->dev.parent = &pcmcia->dev;
+       pcmcia->priv = pdev;
+
+       /* platform device resources */
+       pdev->resource[0].flags = IORESOURCE_MEM;
+       pdev->resource[0].start = pres->start;
+       pdev->resource[0].end = pres->end;
+
+       pdev->resource[1].flags = IORESOURCE_IRQ;
+       pdev->resource[1].start = pcmcia->irq;
+       pdev->resource[1].end = pdev->resource[1].start;
+
+       /* platform device setup */
+       spin_lock(&softingcs_index_lock);
+       pdev->id = softingcs_index++;
+       spin_unlock(&softingcs_index_lock);
+       pdev->name = "softing";
+       dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
+       ret = platform_device_register(pdev);
+       if (ret < 0)
+               goto platform_failed;
+
+       dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
+       return 0;
+
+platform_failed:
+       kfree(dev);
+mem_failed:
+pcmcia_bad:
+pcmcia_failed:
+       pcmcia_disable_device(pcmcia);
+       pcmcia->priv = NULL;
+       return ret ?: -ENODEV;
+}
+
+static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
+       /* softing */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
+       /* vector, manufacturer? */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
+       /* EDIC */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
+       PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
+
+static struct pcmcia_driver softingcs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "softingcs",
+       .id_table       = softingcs_ids,
+       .probe          = softingcs_probe,
+       .remove         = __devexit_p(softingcs_remove),
+};
+
+static int __init softingcs_start(void)
+{
+       spin_lock_init(&softingcs_index_lock);
+       return pcmcia_register_driver(&softingcs_driver);
+}
+
+static void __exit softingcs_stop(void)
+{
+       pcmcia_unregister_driver(&softingcs_driver);
+}
+
+module_init(softingcs_start);
+module_exit(softingcs_stop);
+
+MODULE_DESCRIPTION("softing CANcard driver"
+               ", links PCMCIA card to softing driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
new file mode 100644 (file)
index 0000000..b520784
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <asm/div64.h>
+
+#include "softing.h"
+
+/*
+ * low level DPRAM command.
+ * Make sure that card->dpram[DPRAM_FCT_HOST] is preset
+ */
+static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
+               const char *msg)
+{
+       int ret;
+       unsigned long stamp;
+
+       iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
+       iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
+       iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
+       /* be sure to flush this to the card */
+       wmb();
+       stamp = jiffies + 1 * HZ;
+       /* wait for card */
+       do {
+               /* DPRAM_FCT_HOST is _not_ aligned */
+               ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
+                       (ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
+               /* don't have any cached variables */
+               rmb();
+               if (ret == RES_OK)
+                       /* read return-value now */
+                       return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
+
+               if ((ret != vector) || time_after(jiffies, stamp))
+                       break;
+               /* process context => relax */
+               usleep_range(500, 10000);
+       } while (1);
+
+       ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
+       dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
+       return ret;
+}
+
+static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
+{
+       int ret;
+
+       ret = _softing_fct_cmd(card, cmd, 0, msg);
+       if (ret > 0) {
+               dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
+               ret = -EIO;
+       }
+       return ret;
+}
+
+int softing_bootloader_command(struct softing *card, int16_t cmd,
+               const char *msg)
+{
+       int ret;
+       unsigned long stamp;
+
+       iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
+       iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
+       /* be sure to flush this to the card */
+       wmb();
+       stamp = jiffies + 3 * HZ;
+       /* wait for card */
+       do {
+               ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
+               /* don't have any cached variables */
+               rmb();
+               if (ret == RES_OK)
+                       return 0;
+               if (time_after(jiffies, stamp))
+                       break;
+               /* process context => relax */
+               usleep_range(500, 10000);
+       } while (!signal_pending(current));
+
+       ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
+       dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
+       return ret;
+}
+
+static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
+               uint16_t *plen, const uint8_t **pdat)
+{
+       uint16_t checksum[2];
+       const uint8_t *mem;
+       const uint8_t *end;
+
+       /*
+        * firmware records are a binary, unaligned stream composed of:
+        * uint16_t type;
+        * uint32_t addr;
+        * uint16_t len;
+        * uint8_t dat[len];
+        * uint16_t checksum;
+        * all values in little endian.
+        * We could define a struct for this, with __attribute__((packed)),
+        * but would that solve the alignment in _all_ cases (cfr. the
+        * struct itself may be an odd address)?
+        *
+        * I chose to use leXX_to_cpup() since this solves both
+        * endianness & alignment.
+        */
+       mem = *pmem;
+       *ptype = le16_to_cpup((void *)&mem[0]);
+       *paddr = le32_to_cpup((void *)&mem[2]);
+       *plen = le16_to_cpup((void *)&mem[6]);
+       *pdat = &mem[8];
+       /* verify checksum */
+       end = &mem[8 + *plen];
+       checksum[0] = le16_to_cpup((void *)end);
+       for (checksum[1] = 0; mem < end; ++mem)
+               checksum[1] += *mem;
+       if (checksum[0] != checksum[1])
+               return -EINVAL;
+       /* increment */
+       *pmem += 10 + *plen;
+       return 0;
+}
+
+int softing_load_fw(const char *file, struct softing *card,
+               __iomem uint8_t *dpram, unsigned int size, int offset)
+{
+       const struct firmware *fw;
+       int ret;
+       const uint8_t *mem, *end, *dat;
+       uint16_t type, len;
+       uint32_t addr;
+       uint8_t *buf = NULL;
+       int buflen = 0;
+       int8_t type_end = 0;
+
+       ret = request_firmware(&fw, file, &card->pdev->dev);
+       if (ret < 0)
+               return ret;
+       dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
+               ", offset %c0x%04x\n",
+               card->pdat->name, file, (unsigned int)fw->size,
+               (offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
+       /* parse the firmware */
+       mem = fw->data;
+       end = &mem[fw->size];
+       /* look for header record */
+       ret = fw_parse(&mem, &type, &addr, &len, &dat);
+       if (ret < 0)
+               goto failed;
+       if (type != 0xffff)
+               goto failed;
+       if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
+               ret = -EINVAL;
+               goto failed;
+       }
+       /* ok, we had a header */
+       while (mem < end) {
+               ret = fw_parse(&mem, &type, &addr, &len, &dat);
+               if (ret < 0)
+                       goto failed;
+               if (type == 3) {
+                       /* start address, not used here */
+                       continue;
+               } else if (type == 1) {
+                       /* eof */
+                       type_end = 1;
+                       break;
+               } else if (type != 0) {
+                       ret = -EINVAL;
+                       goto failed;
+               }
+
+               if ((addr + len + offset) > size)
+                       goto failed;
+               memcpy_toio(&dpram[addr + offset], dat, len);
+               /* be sure to flush caches from IO space */
+               mb();
+               if (len > buflen) {
+                       /* align buflen */
+                       buflen = (len + (1024-1)) & ~(1024-1);
+                       buf = krealloc(buf, buflen, GFP_KERNEL);
+                       if (!buf) {
+                               ret = -ENOMEM;
+                               goto failed;
+                       }
+               }
+               /* verify record data */
+               memcpy_fromio(buf, &dpram[addr + offset], len);
+               if (memcmp(buf, dat, len)) {
+                       /* is not ok */
+                       dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
+                       ret = -EIO;
+                       goto failed;
+               }
+       }
+       if (!type_end)
+               /* no end record seen */
+               goto failed;
+       ret = 0;
+failed:
+       kfree(buf);
+       release_firmware(fw);
+       if (ret < 0)
+               dev_info(&card->pdev->dev, "firmware %s failed\n", file);
+       return ret;
+}
+
+int softing_load_app_fw(const char *file, struct softing *card)
+{
+       const struct firmware *fw;
+       const uint8_t *mem, *end, *dat;
+       int ret, j;
+       uint16_t type, len;
+       uint32_t addr, start_addr = 0;
+       unsigned int sum, rx_sum;
+       int8_t type_end = 0, type_entrypoint = 0;
+
+       ret = request_firmware(&fw, file, &card->pdev->dev);
+       if (ret) {
+               dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
+                       file, ret);
+               return ret;
+       }
+       dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
+               file, (unsigned long)fw->size);
+       /* parse the firmware */
+       mem = fw->data;
+       end = &mem[fw->size];
+       /* look for header record */
+       ret = fw_parse(&mem, &type, &addr, &len, &dat);
+       if (ret)
+               goto failed;
+       ret = -EINVAL;
+       if (type != 0xffff) {
+               dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
+                       type);
+               goto failed;
+       }
+       if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
+               dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
+                               len, dat);
+               goto failed;
+       }
+       /* ok, we had a header */
+       while (mem < end) {
+               ret = fw_parse(&mem, &type, &addr, &len, &dat);
+               if (ret)
+                       goto failed;
+
+               if (type == 3) {
+                       /* start address */
+                       start_addr = addr;
+                       type_entrypoint = 1;
+                       continue;
+               } else if (type == 1) {
+                       /* eof */
+                       type_end = 1;
+                       break;
+               } else if (type != 0) {
+                       dev_alert(&card->pdev->dev,
+                                       "unknown record type 0x%04x\n", type);
+                       ret = -EINVAL;
+                       goto failed;
+               }
+
+               /* regualar data */
+               for (sum = 0, j = 0; j < len; ++j)
+                       sum += dat[j];
+               /* work in 16bit (target) */
+               sum &= 0xffff;
+
+               memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
+               iowrite32(card->pdat->app.offs + card->pdat->app.addr,
+                               &card->dpram[DPRAM_COMMAND + 2]);
+               iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
+               iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
+               iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
+               ret = softing_bootloader_command(card, 1, "loading app.");
+               if (ret < 0)
+                       goto failed;
+               /* verify checksum */
+               rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
+               if (rx_sum != sum) {
+                       dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
+                               ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
+                       ret = -EIO;
+                       goto failed;
+               }
+       }
+       if (!type_end || !type_entrypoint)
+               goto failed;
+       /* start application in card */
+       iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
+       iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
+       ret = softing_bootloader_command(card, 3, "start app.");
+       if (ret < 0)
+               goto failed;
+       ret = 0;
+failed:
+       release_firmware(fw);
+       if (ret < 0)
+               dev_info(&card->pdev->dev, "firmware %s failed\n", file);
+       return ret;
+}
+
+static int softing_reset_chip(struct softing *card)
+{
+       int ret;
+
+       do {
+               /* reset chip */
+               iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
+               iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
+               iowrite8(1, &card->dpram[DPRAM_RESET]);
+               iowrite8(0, &card->dpram[DPRAM_RESET+1]);
+
+               ret = softing_fct_cmd(card, 0, "reset_can");
+               if (!ret)
+                       break;
+               if (signal_pending(current))
+                       /* don't wait any longer */
+                       break;
+       } while (1);
+       card->tx.pending = 0;
+       return ret;
+}
+
+int softing_chip_poweron(struct softing *card)
+{
+       int ret;
+       /* sync */
+       ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
+       if (ret < 0)
+               goto failed;
+
+       ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
+       if (ret < 0)
+               goto failed;
+
+       ret = softing_reset_chip(card);
+       if (ret < 0)
+               goto failed;
+       /* get_serial */
+       ret = softing_fct_cmd(card, 43, "get_serial_number");
+       if (ret < 0)
+               goto failed;
+       card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
+       /* get_version */
+       ret = softing_fct_cmd(card, 12, "get_version");
+       if (ret < 0)
+               goto failed;
+       card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
+       card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
+       card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
+       card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
+       card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
+       return 0;
+failed:
+       return ret;
+}
+
+static void softing_initialize_timestamp(struct softing *card)
+{
+       uint64_t ovf;
+
+       card->ts_ref = ktime_get();
+
+       /* 16MHz is the reference */
+       ovf = 0x100000000ULL * 16;
+       do_div(ovf, card->pdat->freq ?: 16);
+
+       card->ts_overflow = ktime_add_us(ktime_set(0, 0), ovf);
+}
+
+ktime_t softing_raw2ktime(struct softing *card, u32 raw)
+{
+       uint64_t rawl;
+       ktime_t now, real_offset;
+       ktime_t target;
+       ktime_t tmp;
+
+       now = ktime_get();
+       real_offset = ktime_sub(ktime_get_real(), now);
+
+       /* find nsec from card */
+       rawl = raw * 16;
+       do_div(rawl, card->pdat->freq ?: 16);
+       target = ktime_add_us(card->ts_ref, rawl);
+       /* test for overflows */
+       tmp = ktime_add(target, card->ts_overflow);
+       while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
+               card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
+               target = tmp;
+               tmp = ktime_add(target, card->ts_overflow);
+       }
+       return ktime_add(target, real_offset);
+}
+
+static inline int softing_error_reporting(struct net_device *netdev)
+{
+       struct softing_priv *priv = netdev_priv(netdev);
+
+       return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+               ? 1 : 0;
+}
+
+int softing_startstop(struct net_device *dev, int up)
+{
+       int ret;
+       struct softing *card;
+       struct softing_priv *priv;
+       struct net_device *netdev;
+       int bus_bitmask_start;
+       int j, error_reporting;
+       struct can_frame msg;
+       const struct can_bittiming *bt;
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       if (!card->fw.up)
+               return -EIO;
+
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
+               return ret;
+
+       bus_bitmask_start = 0;
+       if (dev && up)
+               /* prepare to start this bus as well */
+               bus_bitmask_start |= (1 << priv->index);
+       /* bring netdevs down */
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+
+               if (dev != netdev)
+                       netif_stop_queue(netdev);
+
+               if (netif_running(netdev)) {
+                       if (dev != netdev)
+                               bus_bitmask_start |= (1 << j);
+                       priv->tx.pending = 0;
+                       priv->tx.echo_put = 0;
+                       priv->tx.echo_get = 0;
+                       /*
+                        * this bus' may just have called open_candev()
+                        * which is rather stupid to call close_candev()
+                        * already
+                        * but we may come here from busoff recovery too
+                        * in which case the echo_skb _needs_ flushing too.
+                        * just be sure to call open_candev() again
+                        */
+                       close_candev(netdev);
+               }
+               priv->can.state = CAN_STATE_STOPPED;
+       }
+       card->tx.pending = 0;
+
+       softing_enable_irq(card, 0);
+       ret = softing_reset_chip(card);
+       if (ret)
+               goto failed;
+       if (!bus_bitmask_start)
+               /* no busses to be brought up */
+               goto card_done;
+
+       if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
+                       && (softing_error_reporting(card->net[0])
+                               != softing_error_reporting(card->net[1]))) {
+               dev_alert(&card->pdev->dev,
+                               "err_reporting flag differs for busses\n");
+               goto invalid;
+       }
+       error_reporting = 0;
+       if (bus_bitmask_start & 1) {
+               netdev = card->net[0];
+               priv = netdev_priv(netdev);
+               error_reporting += softing_error_reporting(netdev);
+               /* init chip 1 */
+               bt = &priv->can.bittiming;
+               iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               iowrite16(bt->phase_seg1 + bt->prop_seg,
+                               &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
+                               &card->dpram[DPRAM_FCT_PARAM + 10]);
+               ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set mode */
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               ret = softing_fct_cmd(card, 3, "set_mode[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set filter */
+               /* 11bit id & mask */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               /* 29bit id.lo & mask.lo & id.hi & mask.hi */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
+               iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
+               ret = softing_fct_cmd(card, 7, "set_filter[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set output control */
+               iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               ret = softing_fct_cmd(card, 5, "set_output[0]");
+               if (ret < 0)
+                       goto failed;
+       }
+       if (bus_bitmask_start & 2) {
+               netdev = card->net[1];
+               priv = netdev_priv(netdev);
+               error_reporting += softing_error_reporting(netdev);
+               /* init chip2 */
+               bt = &priv->can.bittiming;
+               iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               iowrite16(bt->phase_seg1 + bt->prop_seg,
+                               &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
+                               &card->dpram[DPRAM_FCT_PARAM + 10]);
+               ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set mode2 */
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               ret = softing_fct_cmd(card, 4, "set_mode[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set filter2 */
+               /* 11bit id & mask */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               /* 29bit id.lo & mask.lo & id.hi & mask.hi */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
+               iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
+               ret = softing_fct_cmd(card, 8, "set_filter[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set output control2 */
+               iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               ret = softing_fct_cmd(card, 6, "set_output[1]");
+               if (ret < 0)
+                       goto failed;
+       }
+       /* enable_error_frame */
+       /*
+        * Error reporting is switched off at the moment since
+        * the receiving of them is not yet 100% verified
+        * This should be enabled sooner or later
+        *
+       if (error_reporting) {
+               ret = softing_fct_cmd(card, 51, "enable_error_frame");
+               if (ret < 0)
+                       goto failed;
+       }
+       */
+       /* initialize interface */
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
+       ret = softing_fct_cmd(card, 17, "initialize_interface");
+       if (ret < 0)
+               goto failed;
+       /* enable_fifo */
+       ret = softing_fct_cmd(card, 36, "enable_fifo");
+       if (ret < 0)
+               goto failed;
+       /* enable fifo tx ack */
+       ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
+       if (ret < 0)
+               goto failed;
+       /* enable fifo tx ack2 */
+       ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
+       if (ret < 0)
+               goto failed;
+       /* start_chip */
+       ret = softing_fct_cmd(card, 11, "start_chip");
+       if (ret < 0)
+               goto failed;
+       iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
+       iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
+       if (card->pdat->generation < 2) {
+               iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
+               /* flush the DPRAM caches */
+               wmb();
+       }
+
+       softing_initialize_timestamp(card);
+
+       /*
+        * do socketcan notifications/status changes
+        * from here, no errors should occur, or the failed: part
+        * must be reviewed
+        */
+       memset(&msg, 0, sizeof(msg));
+       msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
+       msg.can_dlc = CAN_ERR_DLC;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!(bus_bitmask_start & (1 << j)))
+                       continue;
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               open_candev(netdev);
+               if (dev != netdev) {
+                       /* notify other busses on the restart */
+                       softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
+                       ++priv->can.can_stats.restarts;
+               }
+               netif_wake_queue(netdev);
+       }
+
+       /* enable interrupts */
+       ret = softing_enable_irq(card, 1);
+       if (ret)
+               goto failed;
+card_done:
+       mutex_unlock(&card->fw.lock);
+       return 0;
+invalid:
+       ret = -EINVAL;
+failed:
+       softing_enable_irq(card, 0);
+       softing_reset_chip(card);
+       mutex_unlock(&card->fw.lock);
+       /* bring all other interfaces down */
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               dev_close(netdev);
+       }
+       return ret;
+}
+
+int softing_default_output(struct net_device *netdev)
+{
+       struct softing_priv *priv = netdev_priv(netdev);
+       struct softing *card = priv->card;
+
+       switch (priv->chip) {
+       case 1000:
+               return (card->pdat->generation < 2) ? 0xfb : 0xfa;
+       case 5:
+               return 0x60;
+       default:
+               return 0x40;
+       }
+}
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
new file mode 100644 (file)
index 0000000..aeea9f9
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "softing.h"
+
+#define TX_ECHO_SKB_MAX (((TXMAX+1)/2)-1)
+
+/*
+ * test is a specific CAN netdev
+ * is online (ie. up 'n running, not sleeping, not busoff
+ */
+static inline int canif_is_active(struct net_device *netdev)
+{
+       struct can_priv *can = netdev_priv(netdev);
+
+       if (!netif_running(netdev))
+               return 0;
+       return (can->state <= CAN_STATE_ERROR_PASSIVE);
+}
+
+/* reset DPRAM */
+static inline void softing_set_reset_dpram(struct softing *card)
+{
+       if (card->pdat->generation >= 2) {
+               spin_lock_bh(&card->spin);
+               iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) & ~1,
+                               &card->dpram[DPRAM_V2_RESET]);
+               spin_unlock_bh(&card->spin);
+       }
+}
+
+static inline void softing_clr_reset_dpram(struct softing *card)
+{
+       if (card->pdat->generation >= 2) {
+               spin_lock_bh(&card->spin);
+               iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) | 1,
+                               &card->dpram[DPRAM_V2_RESET]);
+               spin_unlock_bh(&card->spin);
+       }
+}
+
+/* trigger the tx queue-ing */
+static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
+               struct net_device *dev)
+{
+       struct softing_priv *priv = netdev_priv(dev);
+       struct softing *card = priv->card;
+       int ret;
+       uint8_t *ptr;
+       uint8_t fifo_wr, fifo_rd;
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       uint8_t buf[DPRAM_TX_SIZE];
+
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
+       spin_lock(&card->spin);
+
+       ret = NETDEV_TX_BUSY;
+       if (!card->fw.up ||
+                       (card->tx.pending >= TXMAX) ||
+                       (priv->tx.pending >= TX_ECHO_SKB_MAX))
+               goto xmit_done;
+       fifo_wr = ioread8(&card->dpram[DPRAM_TX_WR]);
+       fifo_rd = ioread8(&card->dpram[DPRAM_TX_RD]);
+       if (fifo_wr == fifo_rd)
+               /* fifo full */
+               goto xmit_done;
+       memset(buf, 0, sizeof(buf));
+       ptr = buf;
+       *ptr = CMD_TX;
+       if (cf->can_id & CAN_RTR_FLAG)
+               *ptr |= CMD_RTR;
+       if (cf->can_id & CAN_EFF_FLAG)
+               *ptr |= CMD_XTD;
+       if (priv->index)
+               *ptr |= CMD_BUS2;
+       ++ptr;
+       *ptr++ = cf->can_dlc;
+       *ptr++ = (cf->can_id >> 0);
+       *ptr++ = (cf->can_id >> 8);
+       if (cf->can_id & CAN_EFF_FLAG) {
+               *ptr++ = (cf->can_id >> 16);
+               *ptr++ = (cf->can_id >> 24);
+       } else {
+               /* increment 1, not 2 as you might think */
+               ptr += 1;
+       }
+       if (!(cf->can_id & CAN_RTR_FLAG))
+               memcpy(ptr, &cf->data[0], cf->can_dlc);
+       memcpy_toio(&card->dpram[DPRAM_TX + DPRAM_TX_SIZE * fifo_wr],
+                       buf, DPRAM_TX_SIZE);
+       if (++fifo_wr >= DPRAM_TX_CNT)
+               fifo_wr = 0;
+       iowrite8(fifo_wr, &card->dpram[DPRAM_TX_WR]);
+       card->tx.last_bus = priv->index;
+       ++card->tx.pending;
+       ++priv->tx.pending;
+       can_put_echo_skb(skb, dev, priv->tx.echo_put);
+       ++priv->tx.echo_put;
+       if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
+               priv->tx.echo_put = 0;
+       /* can_put_echo_skb() saves the skb, safe to return TX_OK */
+       ret = NETDEV_TX_OK;
+xmit_done:
+       spin_unlock(&card->spin);
+       if (card->tx.pending >= TXMAX) {
+               int j;
+               for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+                       if (card->net[j])
+                               netif_stop_queue(card->net[j]);
+               }
+       }
+       if (ret != NETDEV_TX_OK)
+               netif_stop_queue(dev);
+
+       return ret;
+}
+
+/*
+ * shortcut for skb delivery
+ */
+int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
+               ktime_t ktime)
+{
+       struct sk_buff *skb;
+       struct can_frame *cf;
+
+       skb = alloc_can_skb(netdev, &cf);
+       if (!skb)
+               return -ENOMEM;
+       memcpy(cf, msg, sizeof(*msg));
+       skb->tstamp = ktime;
+       return netif_rx(skb);
+}
+
+/*
+ * softing_handle_1
+ * pop 1 entry from the DPRAM queue, and process
+ */
+static int softing_handle_1(struct softing *card)
+{
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       ktime_t ktime;
+       struct can_frame msg;
+       int cnt = 0, lost_msg;
+       uint8_t fifo_rd, fifo_wr, cmd;
+       uint8_t *ptr;
+       uint32_t tmp_u32;
+       uint8_t buf[DPRAM_RX_SIZE];
+
+       memset(&msg, 0, sizeof(msg));
+       /* test for lost msgs */
+       lost_msg = ioread8(&card->dpram[DPRAM_RX_LOST]);
+       if (lost_msg) {
+               int j;
+               /* reset condition */
+               iowrite8(0, &card->dpram[DPRAM_RX_LOST]);
+               /* prepare msg */
+               msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
+               msg.can_dlc = CAN_ERR_DLC;
+               msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+               /*
+                * service to all busses, we don't know which it was applicable
+                * but only service busses that are online
+                */
+               for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+                       netdev = card->net[j];
+                       if (!netdev)
+                               continue;
+                       if (!canif_is_active(netdev))
+                               /* a dead bus has no overflows */
+                               continue;
+                       ++netdev->stats.rx_over_errors;
+                       softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
+               }
+               /* prepare for other use */
+               memset(&msg, 0, sizeof(msg));
+               ++cnt;
+       }
+
+       fifo_rd = ioread8(&card->dpram[DPRAM_RX_RD]);
+       fifo_wr = ioread8(&card->dpram[DPRAM_RX_WR]);
+
+       if (++fifo_rd >= DPRAM_RX_CNT)
+               fifo_rd = 0;
+       if (fifo_wr == fifo_rd)
+               return cnt;
+
+       memcpy_fromio(buf, &card->dpram[DPRAM_RX + DPRAM_RX_SIZE*fifo_rd],
+                       DPRAM_RX_SIZE);
+       mb();
+       /* trigger dual port RAM */
+       iowrite8(fifo_rd, &card->dpram[DPRAM_RX_RD]);
+
+       ptr = buf;
+       cmd = *ptr++;
+       if (cmd == 0xff)
+               /* not quite usefull, probably the card has got out */
+               return 0;
+       netdev = card->net[0];
+       if (cmd & CMD_BUS2)
+               netdev = card->net[1];
+       priv = netdev_priv(netdev);
+
+       if (cmd & CMD_ERR) {
+               uint8_t can_state, state;
+
+               state = *ptr++;
+
+               msg.can_id = CAN_ERR_FLAG;
+               msg.can_dlc = CAN_ERR_DLC;
+
+               if (state & SF_MASK_BUSOFF) {
+                       can_state = CAN_STATE_BUS_OFF;
+                       msg.can_id |= CAN_ERR_BUSOFF;
+                       state = STATE_BUSOFF;
+               } else if (state & SF_MASK_EPASSIVE) {
+                       can_state = CAN_STATE_ERROR_PASSIVE;
+                       msg.can_id |= CAN_ERR_CRTL;
+                       msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
+                       state = STATE_EPASSIVE;
+               } else {
+                       can_state = CAN_STATE_ERROR_ACTIVE;
+                       msg.can_id |= CAN_ERR_CRTL;
+                       state = STATE_EACTIVE;
+               }
+               /* update DPRAM */
+               iowrite8(state, &card->dpram[priv->index ?
+                               DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
+               /* timestamp */
+               tmp_u32 = le32_to_cpup((void *)ptr);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp_u32);
+
+               ++netdev->stats.rx_errors;
+               /* update internal status */
+               if (can_state != priv->can.state) {
+                       priv->can.state = can_state;
+                       if (can_state == CAN_STATE_ERROR_PASSIVE)
+                               ++priv->can.can_stats.error_passive;
+                       else if (can_state == CAN_STATE_BUS_OFF) {
+                               /* this calls can_close_cleanup() */
+                               can_bus_off(netdev);
+                               netif_stop_queue(netdev);
+                       }
+                       /* trigger socketcan */
+                       softing_netdev_rx(netdev, &msg, ktime);
+               }
+
+       } else {
+               if (cmd & CMD_RTR)
+                       msg.can_id |= CAN_RTR_FLAG;
+               msg.can_dlc = get_can_dlc(*ptr++);
+               if (cmd & CMD_XTD) {
+                       msg.can_id |= CAN_EFF_FLAG;
+                       msg.can_id |= le32_to_cpup((void *)ptr);
+                       ptr += 4;
+               } else {
+                       msg.can_id |= le16_to_cpup((void *)ptr);
+                       ptr += 2;
+               }
+               /* timestamp */
+               tmp_u32 = le32_to_cpup((void *)ptr);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp_u32);
+               if (!(msg.can_id & CAN_RTR_FLAG))
+                       memcpy(&msg.data[0], ptr, 8);
+               ptr += 8;
+               /* update socket */
+               if (cmd & CMD_ACK) {
+                       /* acknowledge, was tx msg */
+                       struct sk_buff *skb;
+                       skb = priv->can.echo_skb[priv->tx.echo_get];
+                       if (skb)
+                               skb->tstamp = ktime;
+                       can_get_echo_skb(netdev, priv->tx.echo_get);
+                       ++priv->tx.echo_get;
+                       if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
+                               priv->tx.echo_get = 0;
+                       if (priv->tx.pending)
+                               --priv->tx.pending;
+                       if (card->tx.pending)
+                               --card->tx.pending;
+                       ++netdev->stats.tx_packets;
+                       if (!(msg.can_id & CAN_RTR_FLAG))
+                               netdev->stats.tx_bytes += msg.can_dlc;
+               } else {
+                       int ret;
+
+                       ret = softing_netdev_rx(netdev, &msg, ktime);
+                       if (ret == NET_RX_SUCCESS) {
+                               ++netdev->stats.rx_packets;
+                               if (!(msg.can_id & CAN_RTR_FLAG))
+                                       netdev->stats.rx_bytes += msg.can_dlc;
+                       } else {
+                               ++netdev->stats.rx_dropped;
+                       }
+               }
+       }
+       ++cnt;
+       return cnt;
+}
+
+/*
+ * real interrupt handler
+ */
+static irqreturn_t softing_irq_thread(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       int j, offset, work_done;
+
+       work_done = 0;
+       spin_lock_bh(&card->spin);
+       while (softing_handle_1(card) > 0) {
+               ++card->irq.svc_count;
+               ++work_done;
+       }
+       spin_unlock_bh(&card->spin);
+       /* resume tx queue's */
+       offset = card->tx.last_bus;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (card->tx.pending >= TXMAX)
+                       break;
+               netdev = card->net[(j + offset + 1) % card->pdat->nbus];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+               if (!canif_is_active(netdev))
+                       /* it makes no sense to wake dead busses */
+                       continue;
+               if (priv->tx.pending >= TX_ECHO_SKB_MAX)
+                       continue;
+               ++work_done;
+               netif_wake_queue(netdev);
+       }
+       return work_done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * interrupt routines:
+ * schedule the 'real interrupt handler'
+ */
+static irqreturn_t softing_irq_v2(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       uint8_t ir;
+
+       ir = ioread8(&card->dpram[DPRAM_V2_IRQ_TOHOST]);
+       iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
+       return (1 == ir) ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t softing_irq_v1(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       uint8_t ir;
+
+       ir = ioread8(&card->dpram[DPRAM_IRQ_TOHOST]);
+       iowrite8(0, &card->dpram[DPRAM_IRQ_TOHOST]);
+       return ir ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+/*
+ * netdev/candev inter-operability
+ */
+static int softing_netdev_open(struct net_device *ndev)
+{
+       int ret;
+
+       /* check or determine and set bittime */
+       ret = open_candev(ndev);
+       if (!ret)
+               ret = softing_startstop(ndev, 1);
+       return ret;
+}
+
+static int softing_netdev_stop(struct net_device *ndev)
+{
+       int ret;
+
+       netif_stop_queue(ndev);
+
+       /* softing cycle does close_candev() */
+       ret = softing_startstop(ndev, 0);
+       return ret;
+}
+
+static int softing_candev_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+       int ret;
+
+       switch (mode) {
+       case CAN_MODE_START:
+               /* softing_startstop does close_candev() */
+               ret = softing_startstop(ndev, 1);
+               return ret;
+       case CAN_MODE_STOP:
+       case CAN_MODE_SLEEP:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+/*
+ * Softing device management helpers
+ */
+int softing_enable_irq(struct softing *card, int enable)
+{
+       int ret;
+
+       if (!card->irq.nr) {
+               return 0;
+       } else if (card->irq.requested && !enable) {
+               free_irq(card->irq.nr, card);
+               card->irq.requested = 0;
+       } else if (!card->irq.requested && enable) {
+               ret = request_threaded_irq(card->irq.nr,
+                               (card->pdat->generation >= 2) ?
+                                       softing_irq_v2 : softing_irq_v1,
+                               softing_irq_thread, IRQF_SHARED,
+                               dev_name(&card->pdev->dev), card);
+               if (ret) {
+                       dev_alert(&card->pdev->dev,
+                                       "request_threaded_irq(%u) failed\n",
+                                       card->irq.nr);
+                       return ret;
+               }
+               card->irq.requested = 1;
+       }
+       return 0;
+}
+
+static void softing_card_shutdown(struct softing *card)
+{
+       int fw_up = 0;
+
+       if (mutex_lock_interruptible(&card->fw.lock))
+               /* return -ERESTARTSYS */;
+       fw_up = card->fw.up;
+       card->fw.up = 0;
+
+       if (card->irq.requested && card->irq.nr) {
+               free_irq(card->irq.nr, card);
+               card->irq.requested = 0;
+       }
+       if (fw_up) {
+               if (card->pdat->enable_irq)
+                       card->pdat->enable_irq(card->pdev, 0);
+               softing_set_reset_dpram(card);
+               if (card->pdat->reset)
+                       card->pdat->reset(card->pdev, 1);
+       }
+       mutex_unlock(&card->fw.lock);
+}
+
+static __devinit int softing_card_boot(struct softing *card)
+{
+       int ret, j;
+       static const uint8_t stream[] = {
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
+       unsigned char back[sizeof(stream)];
+
+       if (mutex_lock_interruptible(&card->fw.lock))
+               return -ERESTARTSYS;
+       if (card->fw.up) {
+               mutex_unlock(&card->fw.lock);
+               return 0;
+       }
+       /* reset board */
+       if (card->pdat->enable_irq)
+               card->pdat->enable_irq(card->pdev, 1);
+       /* boot card */
+       softing_set_reset_dpram(card);
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 1);
+       for (j = 0; (j + sizeof(stream)) < card->dpram_size;
+                       j += sizeof(stream)) {
+
+               memcpy_toio(&card->dpram[j], stream, sizeof(stream));
+               /* flush IO cache */
+               mb();
+               memcpy_fromio(back, &card->dpram[j], sizeof(stream));
+
+               if (!memcmp(back, stream, sizeof(stream)))
+                       continue;
+               /* memory is not equal */
+               dev_alert(&card->pdev->dev, "dpram failed at 0x%04x\n", j);
+               ret = -EIO;
+               goto failed;
+       }
+       wmb();
+       /* load boot firmware */
+       ret = softing_load_fw(card->pdat->boot.fw, card, card->dpram,
+                               card->dpram_size,
+                               card->pdat->boot.offs - card->pdat->boot.addr);
+       if (ret < 0)
+               goto failed;
+       /* load loader firmware */
+       ret = softing_load_fw(card->pdat->load.fw, card, card->dpram,
+                               card->dpram_size,
+                               card->pdat->load.offs - card->pdat->load.addr);
+       if (ret < 0)
+               goto failed;
+
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 0);
+       softing_clr_reset_dpram(card);
+       ret = softing_bootloader_command(card, 0, "card boot");
+       if (ret < 0)
+               goto failed;
+       ret = softing_load_app_fw(card->pdat->app.fw, card);
+       if (ret < 0)
+               goto failed;
+
+       ret = softing_chip_poweron(card);
+       if (ret < 0)
+               goto failed;
+
+       card->fw.up = 1;
+       mutex_unlock(&card->fw.lock);
+       return 0;
+failed:
+       card->fw.up = 0;
+       if (card->pdat->enable_irq)
+               card->pdat->enable_irq(card->pdev, 0);
+       softing_set_reset_dpram(card);
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 1);
+       mutex_unlock(&card->fw.lock);
+       return ret;
+}
+
+/*
+ * netdev sysfs
+ */
+static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "%i\n", priv->index);
+}
+
+static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "%i\n", priv->chip);
+}
+
+static ssize_t show_output(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "0x%02x\n", priv->output);
+}
+
+static ssize_t store_output(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+       struct softing *card = priv->card;
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       val &= 0xFF;
+
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
+               return -ERESTARTSYS;
+       if (netif_running(ndev)) {
+               mutex_unlock(&card->fw.lock);
+               return -EBUSY;
+       }
+       priv->output = val;
+       mutex_unlock(&card->fw.lock);
+       return count;
+}
+
+static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
+static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
+
+static const struct attribute *const netdev_sysfs_attrs[] = {
+       &dev_attr_channel.attr,
+       &dev_attr_chip.attr,
+       &dev_attr_output.attr,
+       NULL,
+};
+static const struct attribute_group netdev_sysfs_group = {
+       .name = NULL,
+       .attrs = (struct attribute **)netdev_sysfs_attrs,
+};
+
+static const struct net_device_ops softing_netdev_ops = {
+       .ndo_open = softing_netdev_open,
+       .ndo_stop = softing_netdev_stop,
+       .ndo_start_xmit = softing_netdev_start_xmit,
+};
+
+static const struct can_bittiming_const softing_btr_const = {
+       .name = "softing",
+       .tseg1_min = 1,
+       .tseg1_max = 16,
+       .tseg2_min = 1,
+       .tseg2_max = 8,
+       .sjw_max = 4, /* overruled */
+       .brp_min = 1,
+       .brp_max = 32, /* overruled */
+       .brp_inc = 1,
+};
+
+
+static __devinit struct net_device *softing_netdev_create(struct softing *card,
+               uint16_t chip_id)
+{
+       struct net_device *netdev;
+       struct softing_priv *priv;
+
+       netdev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
+       if (!netdev) {
+               dev_alert(&card->pdev->dev, "alloc_candev failed\n");
+               return NULL;
+       }
+       priv = netdev_priv(netdev);
+       priv->netdev = netdev;
+       priv->card = card;
+       memcpy(&priv->btr_const, &softing_btr_const, sizeof(priv->btr_const));
+       priv->btr_const.brp_max = card->pdat->max_brp;
+       priv->btr_const.sjw_max = card->pdat->max_sjw;
+       priv->can.bittiming_const = &priv->btr_const;
+       priv->can.clock.freq = 8000000;
+       priv->chip = chip_id;
+       priv->output = softing_default_output(netdev);
+       SET_NETDEV_DEV(netdev, &card->pdev->dev);
+
+       netdev->flags |= IFF_ECHO;
+       netdev->netdev_ops = &softing_netdev_ops;
+       priv->can.do_set_mode = softing_candev_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+
+       return netdev;
+}
+
+static __devinit int softing_netdev_register(struct net_device *netdev)
+{
+       int ret;
+
+       netdev->sysfs_groups[0] = &netdev_sysfs_group;
+       ret = register_candev(netdev);
+       if (ret) {
+               dev_alert(&netdev->dev, "register failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+static void softing_netdev_cleanup(struct net_device *netdev)
+{
+       unregister_candev(netdev);
+       free_candev(netdev);
+}
+
+/*
+ * sysfs for Platform device
+ */
+#define DEV_ATTR_RO(name, member) \
+static ssize_t show_##name(struct device *dev, \
+               struct device_attribute *attr, char *buf) \
+{ \
+       struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+       return sprintf(buf, "%u\n", card->member); \
+} \
+static DEVICE_ATTR(name, 0444, show_##name, NULL)
+
+#define DEV_ATTR_RO_STR(name, member) \
+static ssize_t show_##name(struct device *dev, \
+               struct device_attribute *attr, char *buf) \
+{ \
+       struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+       return sprintf(buf, "%s\n", card->member); \
+} \
+static DEVICE_ATTR(name, 0444, show_##name, NULL)
+
+DEV_ATTR_RO(serial, id.serial);
+DEV_ATTR_RO_STR(firmware, pdat->app.fw);
+DEV_ATTR_RO(firmware_version, id.fw_version);
+DEV_ATTR_RO_STR(hardware, pdat->name);
+DEV_ATTR_RO(hardware_version, id.hw_version);
+DEV_ATTR_RO(license, id.license);
+DEV_ATTR_RO(frequency, id.freq);
+DEV_ATTR_RO(txpending, tx.pending);
+
+static struct attribute *softing_pdev_attrs[] = {
+       &dev_attr_serial.attr,
+       &dev_attr_firmware.attr,
+       &dev_attr_firmware_version.attr,
+       &dev_attr_hardware.attr,
+       &dev_attr_hardware_version.attr,
+       &dev_attr_license.attr,
+       &dev_attr_frequency.attr,
+       &dev_attr_txpending.attr,
+       NULL,
+};
+
+static const struct attribute_group softing_pdev_group = {
+       .name = NULL,
+       .attrs = softing_pdev_attrs,
+};
+
+/*
+ * platform driver
+ */
+static __devexit int softing_pdev_remove(struct platform_device *pdev)
+{
+       struct softing *card = platform_get_drvdata(pdev);
+       int j;
+
+       /* first, disable card*/
+       softing_card_shutdown(card);
+
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!card->net[j])
+                       continue;
+               softing_netdev_cleanup(card->net[j]);
+               card->net[j] = NULL;
+       }
+       sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
+
+       iounmap(card->dpram);
+       kfree(card);
+       return 0;
+}
+
+static __devinit int softing_pdev_probe(struct platform_device *pdev)
+{
+       const struct softing_platform_data *pdat = pdev->dev.platform_data;
+       struct softing *card;
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       struct resource *pres;
+       int ret;
+       int j;
+
+       if (!pdat) {
+               dev_warn(&pdev->dev, "no platform data\n");
+               return -EINVAL;
+       }
+       if (pdat->nbus > ARRAY_SIZE(card->net)) {
+               dev_warn(&pdev->dev, "%u nets??\n", pdat->nbus);
+               return -EINVAL;
+       }
+
+       card = kzalloc(sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+       card->pdat = pdat;
+       card->pdev = pdev;
+       platform_set_drvdata(pdev, card);
+       mutex_init(&card->fw.lock);
+       spin_lock_init(&card->spin);
+
+       ret = -EINVAL;
+       pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!pres)
+               goto platform_resource_failed;;
+       card->dpram_phys = pres->start;
+       card->dpram_size = pres->end - pres->start + 1;
+       card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size);
+       if (!card->dpram) {
+               dev_alert(&card->pdev->dev, "dpram ioremap failed\n");
+               goto ioremap_failed;
+       }
+
+       pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (pres)
+               card->irq.nr = pres->start;
+
+       /* reset card */
+       ret = softing_card_boot(card);
+       if (ret < 0) {
+               dev_alert(&pdev->dev, "failed to boot\n");
+               goto boot_failed;
+       }
+
+       /* only now, the chip's are known */
+       card->id.freq = card->pdat->freq;
+
+       ret = sysfs_create_group(&pdev->dev.kobj, &softing_pdev_group);
+       if (ret < 0) {
+               dev_alert(&card->pdev->dev, "sysfs failed\n");
+               goto sysfs_failed;
+       }
+
+       ret = -ENOMEM;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               card->net[j] = netdev =
+                       softing_netdev_create(card, card->id.chip[j]);
+               if (!netdev) {
+                       dev_alert(&pdev->dev, "failed to make can[%i]", j);
+                       goto netdev_failed;
+               }
+               priv = netdev_priv(card->net[j]);
+               priv->index = j;
+               ret = softing_netdev_register(netdev);
+               if (ret) {
+                       free_candev(netdev);
+                       card->net[j] = NULL;
+                       dev_alert(&card->pdev->dev,
+                                       "failed to register can[%i]\n", j);
+                       goto netdev_failed;
+               }
+       }
+       dev_info(&card->pdev->dev, "%s ready.\n", card->pdat->name);
+       return 0;
+
+netdev_failed:
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!card->net[j])
+                       continue;
+               softing_netdev_cleanup(card->net[j]);
+       }
+       sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
+sysfs_failed:
+       softing_card_shutdown(card);
+boot_failed:
+       iounmap(card->dpram);
+ioremap_failed:
+platform_resource_failed:
+       kfree(card);
+       return ret;
+}
+
+static struct platform_driver softing_driver = {
+       .driver = {
+               .name = "softing",
+               .owner = THIS_MODULE,
+       },
+       .probe = softing_pdev_probe,
+       .remove = __devexit_p(softing_pdev_remove),
+};
+
+MODULE_ALIAS("platform:softing");
+
+static int __init softing_start(void)
+{
+       return platform_driver_register(&softing_driver);
+}
+
+static void __exit softing_stop(void)
+{
+       platform_driver_unregister(&softing_driver);
+}
+
+module_init(softing_start);
+module_exit(softing_stop);
+
+MODULE_DESCRIPTION("Softing DPRAM CAN driver");
+MODULE_AUTHOR("Kurt Van Dijck <kurt.van.dijck@eia.be>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_platform.h b/drivers/net/can/softing/softing_platform.h
new file mode 100644 (file)
index 0000000..ebbf698
--- /dev/null
@@ -0,0 +1,40 @@
+
+#include <linux/platform_device.h>
+
+#ifndef _SOFTING_DEVICE_H_
+#define _SOFTING_DEVICE_H_
+
+/* softing firmware directory prefix */
+#define fw_dir "softing-4.6/"
+
+struct softing_platform_data {
+       unsigned int manf;
+       unsigned int prod;
+       /*
+        * generation
+        * 1st with NEC or SJA1000
+        * 8bit, exclusive interrupt, ...
+        * 2nd only SJA1000
+        * 16bit, shared interrupt
+        */
+       int generation;
+       int nbus; /* # busses on device */
+       unsigned int freq; /* operating frequency in Hz */
+       unsigned int max_brp;
+       unsigned int max_sjw;
+       unsigned long dpram_size;
+       const char *name;
+       struct {
+               unsigned long offs;
+               unsigned long addr;
+               const char *fw;
+       } boot, load, app;
+       /*
+        * reset() function
+        * bring pdev in or out of reset, depending on value
+        */
+       int (*reset)(struct platform_device *pdev, int value);
+       int (*enable_irq)(struct platform_device *pdev, int value);
+};
+
+#endif
index 263a294..302be4a 100644 (file)
@@ -699,13 +699,13 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in big endian format. */
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
-               *page_table = (u32) dma->pg_map_arr[i];
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
        }
 }
@@ -713,13 +713,13 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in little endian format. */
-               *page_table = dma->pg_map_arr[i] & 0xffffffff;
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
        }
 }
@@ -2760,6 +2760,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
        u32 status_idx = (u16) *cp->kcq1.status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading other fields */
+       rmb();
        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
 
        while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) {
@@ -2770,6 +2772,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
                barrier();
                if (status_idx != *cp->kcq1.status_idx_ptr) {
                        status_idx = (u16) *cp->kcq1.status_idx_ptr;
+                       /* status block index must be read first */
+                       rmb();
                        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
                } else
                        break;
@@ -2888,6 +2892,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
        u32 last_status = *info->status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading the KCQ */
+       rmb();
        while ((kcqe_cnt = cnic_get_kcqes(dev, info))) {
 
                service_kcqes(dev, kcqe_cnt);
@@ -2898,6 +2904,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
                        break;
 
                last_status = *info->status_idx_ptr;
+               /* status block index must be read before reading the KCQ */
+               rmb();
        }
        return last_status;
 }
@@ -2906,26 +2914,35 @@ static void cnic_service_bnx2x_bh(unsigned long data)
 {
        struct cnic_dev *dev = (struct cnic_dev *) data;
        struct cnic_local *cp = dev->cnic_priv;
-       u32 status_idx;
+       u32 status_idx, new_status_idx;
 
        if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
                return;
 
-       status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
+       while (1) {
+               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
 
-       CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
+               CNIC_WR16(dev, cp->kcq1.io_addr,
+                         cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
-               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+               if (!BNX2X_CHIP_IS_E2(cp->chip_id)) {
+                       cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
+                                          status_idx, IGU_INT_ENABLE, 1);
+                       break;
+               }
+
+               new_status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+
+               if (new_status_idx != status_idx)
+                       continue;
 
                CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx +
                          MAX_KCQ_IDX);
 
                cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
                                status_idx, IGU_INT_ENABLE, 1);
-       } else {
-               cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
-                                  status_idx, IGU_INT_ENABLE, 1);
+
+               break;
        }
 }
 
index 059c1ee..ec35d45 100644 (file)
@@ -2710,6 +2710,8 @@ static int cxgb_open(struct net_device *dev)
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
+       netif_carrier_off(dev);
+
        if (!(adapter->flags & FULL_INIT_DONE)) {
                err = cxgb_up(adapter);
                if (err < 0)
@@ -3661,7 +3663,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                pi->port_id = i;
-               netif_carrier_off(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features |= NETIF_F_SG | TSO_FLAGS;
index 56166ae..6aad64d 100644 (file)
@@ -2040,7 +2040,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
 {
        int i;
 
-       BUG_ON(adapter->debugfs_root == NULL);
+       BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root));
 
        /*
         * Debugfs support is best effort.
@@ -2061,7 +2061,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
  */
 static void cleanup_debugfs(struct adapter *adapter)
 {
-       BUG_ON(adapter->debugfs_root == NULL);
+       BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root));
 
        /*
         * Unlike our sister routine cleanup_proc(), we don't need to remove
@@ -2489,17 +2489,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
        struct net_device *netdev;
 
        /*
-        * Vet our module parameters.
-        */
-       if (msi != MSI_MSIX && msi != MSI_MSI) {
-               dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d"
-                       " (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX,
-                       MSI_MSI);
-               err = -EINVAL;
-               goto err_out;
-       }
-
-       /*
         * Print our driver banner the first time we're called to initialize a
         * device.
         */
@@ -2711,11 +2700,11 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
        /*
         * Set up our debugfs entries.
         */
-       if (cxgb4vf_debugfs_root) {
+       if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) {
                adapter->debugfs_root =
                        debugfs_create_dir(pci_name(pdev),
                                           cxgb4vf_debugfs_root);
-               if (adapter->debugfs_root == NULL)
+               if (IS_ERR_OR_NULL(adapter->debugfs_root))
                        dev_warn(&pdev->dev, "could not create debugfs"
                                 " directory");
                else
@@ -2770,7 +2759,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
         */
 
 err_free_debugfs:
-       if (adapter->debugfs_root) {
+       if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
                cleanup_debugfs(adapter);
                debugfs_remove_recursive(adapter->debugfs_root);
        }
@@ -2802,7 +2791,6 @@ err_release_regions:
 err_disable_device:
        pci_disable_device(pdev);
 
-err_out:
        return err;
 }
 
@@ -2840,7 +2828,7 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
                /*
                 * Tear down our debugfs entries.
                 */
-               if (adapter->debugfs_root) {
+               if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
                        cleanup_debugfs(adapter);
                        debugfs_remove_recursive(adapter->debugfs_root);
                }
@@ -2874,6 +2862,46 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
 }
 
 /*
+ * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt
+ * delivery.
+ */
+static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev)
+{
+       struct adapter *adapter;
+       int pidx;
+
+       adapter = pci_get_drvdata(pdev);
+       if (!adapter)
+               return;
+
+       /*
+        * Disable all Virtual Interfaces.  This will shut down the
+        * delivery of all ingress packets into the chip for these
+        * Virtual Interfaces.
+        */
+       for_each_port(adapter, pidx) {
+               struct net_device *netdev;
+               struct port_info *pi;
+
+               if (!test_bit(pidx, &adapter->registered_device_map))
+                       continue;
+
+               netdev = adapter->port[pidx];
+               if (!netdev)
+                       continue;
+
+               pi = netdev_priv(netdev);
+               t4vf_enable_vi(adapter, pi->viid, false, false);
+       }
+
+       /*
+        * Free up all Queues which will prevent further DMA and
+        * Interrupts allowing various internal pathways to drain.
+        */
+       t4vf_free_sge_resources(adapter);
+}
+
+/*
  * PCI Device registration data structures.
  */
 #define CH_DEVICE(devid, idx) \
@@ -2906,6 +2934,7 @@ static struct pci_driver cxgb4vf_driver = {
        .id_table       = cxgb4vf_pci_tbl,
        .probe          = cxgb4vf_pci_probe,
        .remove         = __devexit_p(cxgb4vf_pci_remove),
+       .shutdown       = __devexit_p(cxgb4vf_pci_shutdown),
 };
 
 /*
@@ -2915,14 +2944,25 @@ static int __init cxgb4vf_module_init(void)
 {
        int ret;
 
+       /*
+        * Vet our module parameters.
+        */
+       if (msi != MSI_MSIX && msi != MSI_MSI) {
+               printk(KERN_WARNING KBUILD_MODNAME
+                      ": bad module parameter msi=%d; must be %d"
+                      " (MSI-X or MSI) or %d (MSI)\n",
+                      msi, MSI_MSIX, MSI_MSI);
+               return -EINVAL;
+       }
+
        /* Debugfs support is optional, just warn if this fails */
        cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!cxgb4vf_debugfs_root)
+       if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
                printk(KERN_WARNING KBUILD_MODNAME ": could not create"
                       " debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4vf_driver);
-       if (ret < 0)
+       if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
                debugfs_remove(cxgb4vf_debugfs_root);
        return ret;
 }
index 0f51c80..192db22 100644 (file)
@@ -171,7 +171,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
        delay_idx = 0;
        ms = delay[0];
 
-       for (i = 0; i < 500; i += ms) {
+       for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
                if (sleep_ok) {
                        ms = delay[delay_idx];
                        if (delay_idx < ARRAY_SIZE(delay) - 1)
index 2a628d1..7018bfe 100644 (file)
@@ -1008,7 +1008,7 @@ static void emac_rx_handler(void *token, int len, int status)
        int                     ret;
 
        /* free and bail if we are shutting down */
-       if (unlikely(!netif_running(ndev))) {
+       if (unlikely(!netif_running(ndev) || !netif_carrier_ok(ndev))) {
                dev_kfree_skb_any(skb);
                return;
        }
index 1b48b68..8b0084d 100644 (file)
@@ -1094,7 +1094,7 @@ static int depca_rx(struct net_device *dev)
                                }
                        }
                        /* Change buffer ownership for this last frame, back to the adapter */
-                       for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) {
+                       for (; lp->rx_old != entry; lp->rx_old = (lp->rx_old + 1) & lp->rxRingMask) {
                                writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
                        }
                        writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
@@ -1103,7 +1103,7 @@ static int depca_rx(struct net_device *dev)
                /*
                   ** Update entry information
                 */
-               lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+               lp->rx_new = (lp->rx_new + 1) & lp->rxRingMask;
        }
 
        return 0;
@@ -1148,7 +1148,7 @@ static int depca_tx(struct net_device *dev)
                }
 
                /* Update all the pointers */
-               lp->tx_old = (++lp->tx_old) & lp->txRingMask;
+               lp->tx_old = (lp->tx_old + 1) & lp->txRingMask;
        }
 
        return 0;
index e1a8216..c05db60 100644 (file)
@@ -1753,8 +1753,6 @@ rio_close (struct net_device *dev)
 
        /* Free all the skbuffs in the queue. */
        for (i = 0; i < RX_RING_SIZE; i++) {
-               np->rx_ring[i].status = 0;
-               np->rx_ring[i].fraginfo = 0;
                skb = np->rx_skbuff[i];
                if (skb) {
                        pci_unmap_single(np->pdev,
@@ -1763,6 +1761,8 @@ rio_close (struct net_device *dev)
                        dev_kfree_skb (skb);
                        np->rx_skbuff[i] = NULL;
                }
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
        }
        for (i = 0; i < TX_RING_SIZE; i++) {
                skb = np->tx_skbuff[i];
index 2d4c4fc..461dd6f 100644 (file)
@@ -802,10 +802,7 @@ dm9000_init_dm9000(struct net_device *dev)
        /* Checksum mode */
        dm9000_set_rx_csum_unlocked(dev, db->rx_csum);
 
-       /* GPIO0 on pre-activate PHY */
-       iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
-       iow(db, DM9000_GPR, 0); /* Enable PHY */
 
        ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
 
@@ -852,8 +849,8 @@ static void dm9000_timeout(struct net_device *dev)
        unsigned long flags;
 
        /* Save previous register address */
-       reg_save = readb(db->io_addr);
        spin_lock_irqsave(&db->lock, flags);
+       reg_save = readb(db->io_addr);
 
        netif_stop_queue(dev);
        dm9000_reset(db);
@@ -1194,6 +1191,10 @@ dm9000_open(struct net_device *dev)
        if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
                return -EAGAIN;
 
+       /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
+       iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
+       mdelay(1); /* delay needs by DM9000B */
+
        /* Initialize DM9000 board */
        dm9000_reset(db);
        dm9000_init_dm9000(dev);
index 9d8a20b..8318ea0 100644 (file)
@@ -337,8 +337,6 @@ static int dnet_mii_init(struct dnet *bp)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                bp->mii_bus->irq[i] = PHY_POLL;
 
-       platform_set_drvdata(bp->dev, bp->mii_bus);
-
        if (mdiobus_register(bp->mii_bus)) {
                err = -ENXIO;
                goto err_out_free_mdio_irq;
@@ -863,6 +861,7 @@ static int __devinit dnet_probe(struct platform_device *pdev)
        bp = netdev_priv(dev);
        bp->dev = dev;
 
+       platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        spin_lock_init(&bp->lock);
index aed223b..7501d97 100644 (file)
@@ -124,6 +124,7 @@ static s32 e1000_set_phy_type(struct e1000_hw *hw)
        case M88E1000_I_PHY_ID:
        case M88E1011_I_PHY_ID:
        case M88E1111_I_PHY_ID:
+       case M88E1118_E_PHY_ID:
                hw->phy_type = e1000_phy_m88;
                break;
        case IGP01E1000_I_PHY_ID:
@@ -3222,7 +3223,8 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
                break;
        case e1000_ce4100:
                if ((hw->phy_id == RTL8211B_PHY_ID) ||
-                   (hw->phy_id == RTL8201N_PHY_ID))
+                   (hw->phy_id == RTL8201N_PHY_ID) ||
+                   (hw->phy_id == M88E1118_E_PHY_ID))
                        match = true;
                break;
        case e1000_82541:
index 196eeda..c70b23d 100644 (file)
@@ -2917,6 +2917,7 @@ struct e1000_host_command_info {
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
 #define M88E1011_I_REV_4   0x04
 #define M88E1111_I_PHY_ID  0x01410CC0
+#define M88E1118_E_PHY_ID  0x01410E40
 #define L1LXT971A_PHY_ID   0x001378E0
 
 #define RTL8211B_PHY_ID    0x001CC910
index 55c1711..33e7c45 100644 (file)
@@ -42,7 +42,8 @@
 #define GBE_CONFIG_RAM_BASE \
        ((unsigned int)(CONFIG_RAM_BASE + GBE_CONFIG_OFFSET))
 
-#define GBE_CONFIG_BASE_VIRT    phys_to_virt(GBE_CONFIG_RAM_BASE)
+#define GBE_CONFIG_BASE_VIRT \
+       ((void __iomem *)phys_to_virt(GBE_CONFIG_RAM_BASE))
 
 #define GBE_CONFIG_FLASH_WRITE(base, offset, count, data) \
        (iowrite16_rep(base + offset, data, count))
index 1c18f26..2e50228 100644 (file)
@@ -937,6 +937,9 @@ static void e1000_print_hw_hang(struct work_struct *work)
        u16 phy_status, phy_1000t_status, phy_ext_status;
        u16 pci_status;
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1e_rphy(hw, PHY_STATUS, &phy_status);
        e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status);
        e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status);
@@ -1506,6 +1509,9 @@ static void e1000e_downshift_workaround(struct work_struct *work)
        struct e1000_adapter *adapter = container_of(work,
                                        struct e1000_adapter, downshift_task);
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
 }
 
@@ -3338,6 +3344,21 @@ int e1000e_up(struct e1000_adapter *adapter)
        return 0;
 }
 
+static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!(adapter->flags2 & FLAG2_DMA_BURST))
+               return;
+
+       /* flush pending descriptor writebacks to memory */
+       ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
+       ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
+
+       /* execute the writes immediately */
+       e1e_flush();
+}
+
 void e1000e_down(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -3377,6 +3398,9 @@ void e1000e_down(struct e1000_adapter *adapter)
 
        if (!pci_channel_offline(adapter->pdev))
                e1000e_reset(adapter);
+
+       e1000e_flush_descriptors(adapter);
+
        e1000_clean_tx_ring(adapter);
        e1000_clean_rx_ring(adapter);
 
@@ -3765,6 +3789,10 @@ static void e1000e_update_phy_task(struct work_struct *work)
 {
        struct e1000_adapter *adapter = container_of(work,
                                        struct e1000_adapter, update_phy_task);
+
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1000_get_phy_info(&adapter->hw);
 }
 
@@ -3775,6 +3803,10 @@ static void e1000e_update_phy_task(struct work_struct *work)
 static void e1000_update_phy_info(unsigned long data)
 {
        struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        schedule_work(&adapter->update_phy_task);
 }
 
@@ -4149,6 +4181,9 @@ static void e1000_watchdog_task(struct work_struct *work)
        u32 link, tctl;
        int tx_pending = 0;
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        link = e1000e_has_link(adapter);
        if ((netif_carrier_ok(netdev)) && link) {
                /* Cancel scheduled suspend requests. */
@@ -4309,7 +4344,6 @@ link_up:
                         * to get done, so reset controller to flush Tx.
                         * (Do the reset outside of interrupt context).
                         */
-                       adapter->tx_timeout_count++;
                        schedule_work(&adapter->reset_task);
                        /* return immediately since reset is imminent */
                        return;
@@ -4338,19 +4372,12 @@ link_up:
        else
                ew32(ICS, E1000_ICS_RXDMT0);
 
+       /* flush pending descriptors to memory before detecting Tx hang */
+       e1000e_flush_descriptors(adapter);
+
        /* Force detection of hung controller every watchdog period */
        adapter->detect_tx_hung = 1;
 
-       /* flush partial descriptors to memory before detecting Tx hang */
-       if (adapter->flags2 & FLAG2_DMA_BURST) {
-               ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
-               ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
-               /*
-                * no need to flush the writes because the timeout code does
-                * an er32 first thing
-                */
-       }
-
        /*
         * With 82571 controllers, LAA may be overwritten due to controller
         * reset from the other port. Set the appropriate LAA in RAR[0]
@@ -4888,6 +4915,10 @@ static void e1000_reset_task(struct work_struct *work)
        struct e1000_adapter *adapter;
        adapter = container_of(work, struct e1000_adapter, reset_task);
 
+       /* don't run the task if already down */
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
              (adapter->flags & FLAG_RX_RESTART_NOW))) {
                e1000e_dump(adapter);
@@ -5936,7 +5967,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                /* APME bit in EEPROM is mapped to WUC.APME */
                eeprom_data = er32(WUC);
                eeprom_apme_mask = E1000_WUC_APME;
-               if (eeprom_data & E1000_WUC_PHY_WAKE)
+               if ((hw->mac.type > e1000_ich10lan) &&
+                   (eeprom_data & E1000_WUC_PHY_WAKE))
                        adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP;
        } else if (adapter->flags & FLAG_APME_IN_CTRL3) {
                if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
index 112c5aa..907b05a 100644 (file)
@@ -812,7 +812,7 @@ static void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE])
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": reading TSV at addr:0x%04x\n",
                         endptr + 1);
-       enc28j60_mem_read(priv, endptr + 1, sizeof(tsv), tsv);
+       enc28j60_mem_read(priv, endptr + 1, TSV_SIZE, tsv);
 }
 
 static void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg,
index 2a71373..cd0282d 100644 (file)
@@ -74,7 +74,8 @@ static struct platform_device_id fec_devtype[] = {
        }, {
                .name = "imx28-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
-       }
+       },
+       { }
 };
 
 static unsigned char macaddr[ETH_ALEN];
index af09296..9c0b1ba 100644 (file)
@@ -5645,6 +5645,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                goto out_error;
        }
 
+       netif_carrier_off(dev);
+
        dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
                 dev->name, np->phy_oui, np->phyaddr, dev->dev_addr);
 
index 119aa20..5ed8f9f 100644 (file)
@@ -1920,7 +1920,7 @@ int startup_gfar(struct net_device *ndev)
                if (err) {
                        for (j = 0; j < i; j++)
                                free_grp_irqs(&priv->gfargrp[j]);
-                               goto irq_fail;
+                       goto irq_fail;
                }
        }
 
index 74486a8..af3822f 100644 (file)
@@ -220,7 +220,7 @@ static u32 e1000_hash_mc_addr_vf(struct e1000_hw *hw, u8 *mc_addr)
  *  The parameter rar_count will usually be hw->mac.rar_entry_count
  *  unless there are workarounds that change this.
  **/
-void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
+static void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
                                   u8 *mc_addr_list, u32 mc_addr_count,
                                   u32 rar_used_count, u32 rar_count)
 {
index 9e3f4f5..4488bd5 100644 (file)
@@ -635,7 +635,7 @@ static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        ret = sh_irda_set_baudrate(self, speed);
        if (ret < 0)
-               return ret;
+               goto sh_irda_hard_xmit_end;
 
        self->tx_buff.len = 0;
        if (skb->len) {
@@ -652,11 +652,21 @@ static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
 
                sh_irda_write(self, IRTFLR, self->tx_buff.len);
                sh_irda_write(self, IRTCTR, ARMOD | TE);
-       }
+       } else
+               goto sh_irda_hard_xmit_end;
 
        dev_kfree_skb(skb);
 
        return 0;
+
+sh_irda_hard_xmit_end:
+       sh_irda_set_baudrate(self, 9600);
+       netif_wake_queue(self->ndev);
+       sh_irda_rcv_ctrl(self, 1);
+       dev_kfree_skb(skb);
+
+       return ret;
+
 }
 
 static int sh_irda_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
index d5ede2d..ebbda7d 100644 (file)
@@ -1370,6 +1370,9 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
                hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
 
                hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+
+               /*  clear VMDq pool/queue selection for RAR 0 */
+               hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL);
        }
        hw->addr_ctrl.overflow_promisc = 0;
 
index 6342d48..c54a882 100644 (file)
@@ -159,13 +159,13 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
        struct scatterlist *sg;
        unsigned int i, j, dmacount;
        unsigned int len;
-       static const unsigned int bufflen = 4096;
+       static const unsigned int bufflen = IXGBE_FCBUFF_MIN;
        unsigned int firstoff = 0;
        unsigned int lastsize;
        unsigned int thisoff = 0;
        unsigned int thislen = 0;
        u32 fcbuff, fcdmarw, fcfltrw;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
 
        if (!netdev || !sgl)
                return 0;
@@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
        /* only the last buffer may have non-full bufflen */
        lastsize = thisoff + thislen;
 
+       /*
+        * lastsize can not be buffer len.
+        * If it is then adding another buffer with lastsize = 1.
+        */
+       if (lastsize == bufflen) {
+               if (j >= IXGBE_BUFFCNT_MAX) {
+                       e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
+                               "not enough user buffers. We need an extra "
+                               "buffer because lastsize is bufflen.\n",
+                               xid, i, j, dmacount, (u64)addr);
+                       goto out_noddp_free;
+               }
+
+               ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
+               j++;
+               lastsize = 1;
+       }
+
        fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT);
        fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);
        fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT);
@@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
                        e_err(drv, "failed to allocated FCoE DDP pool\n");
 
                spin_lock_init(&fcoe->lock);
+
+               /* Extra buffer to be shared by all DDPs for HW work around */
+               fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
+               if (fcoe->extra_ddp_buffer == NULL) {
+                       e_err(drv, "failed to allocated extra DDP buffer\n");
+                       goto out_extra_ddp_buffer_alloc;
+               }
+
+               fcoe->extra_ddp_buffer_dma =
+                       dma_map_single(&adapter->pdev->dev,
+                                      fcoe->extra_ddp_buffer,
+                                      IXGBE_FCBUFF_MIN,
+                                      DMA_FROM_DEVICE);
+               if (dma_mapping_error(&adapter->pdev->dev,
+                                     fcoe->extra_ddp_buffer_dma)) {
+                       e_err(drv, "failed to map extra DDP buffer\n");
+                       goto out_extra_ddp_buffer_dma;
+               }
        }
 
        /* Enable L2 eth type filter for FCoE */
@@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
                }
        }
 #endif
+
+       return;
+
+out_extra_ddp_buffer_dma:
+       kfree(fcoe->extra_ddp_buffer);
+out_extra_ddp_buffer_alloc:
+       pci_pool_destroy(fcoe->pool);
+       fcoe->pool = NULL;
 }
 
 /**
@@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter)
        if (fcoe->pool) {
                for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++)
                        ixgbe_fcoe_ddp_put(adapter->netdev, i);
+               dma_unmap_single(&adapter->pdev->dev,
+                                fcoe->extra_ddp_buffer_dma,
+                                IXGBE_FCBUFF_MIN,
+                                DMA_FROM_DEVICE);
+               kfree(fcoe->extra_ddp_buffer);
                pci_pool_destroy(fcoe->pool);
                fcoe->pool = NULL;
        }
index 4bc2c55..65cc8fb 100644 (file)
@@ -70,6 +70,8 @@ struct ixgbe_fcoe {
        spinlock_t lock;
        struct pci_pool *pool;
        struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX];
+       unsigned char *extra_ddp_buffer;
+       dma_addr_t extra_ddp_buffer_dma;
 };
 
 #endif /* _IXGBE_FCOE_H */
index 602078b..30f9ccf 100644 (file)
@@ -52,7 +52,7 @@ char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
                              "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "3.0.12-k2"
+#define DRV_VERSION "3.2.9-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
 
@@ -3176,9 +3176,16 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
        u32 mhadd, hlreg0;
 
        /* Decide whether to use packet split mode or not */
+       /* On by default */
+       adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+
        /* Do not use packet split if we're in SR-IOV Mode */
-       if (!adapter->num_vfs)
-               adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+       if (adapter->num_vfs)
+               adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+
+       /* Disable packet split due to 82599 erratum #45 */
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
 
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
@@ -3721,7 +3728,8 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
                         * We need to try and force an autonegotiation
                         * session, then bring up link.
                         */
-                       hw->mac.ops.setup_sfp(hw);
+                       if (hw->mac.ops.setup_sfp)
+                               hw->mac.ops.setup_sfp(hw);
                        if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
                                schedule_work(&adapter->multispeed_fiber_task);
                } else {
@@ -4863,16 +4871,13 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
 {
        int q_idx, num_q_vectors;
        struct ixgbe_q_vector *q_vector;
-       int napi_vectors;
        int (*poll)(struct napi_struct *, int);
 
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
                num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
-               napi_vectors = adapter->num_rx_queues;
                poll = &ixgbe_clean_rxtx_many;
        } else {
                num_q_vectors = 1;
-               napi_vectors = 1;
                poll = &ixgbe_poll;
        }
 
@@ -5964,7 +5969,8 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
                unregister_netdev(adapter->netdev);
                return;
        }
-       hw->mac.ops.setup_sfp(hw);
+       if (hw->mac.ops.setup_sfp)
+               hw->mac.ops.setup_sfp(hw);
 
        if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
                /* This will also work for DA Twinax connections */
index 47b1573..187b3a1 100644 (file)
@@ -110,12 +110,10 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
        return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
 }
 
-
 static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
 {
        u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
        vmolr |= (IXGBE_VMOLR_ROMPE |
-                 IXGBE_VMOLR_ROPE |
                  IXGBE_VMOLR_BAM);
        if (aupe)
                vmolr |= IXGBE_VMOLR_AUPE;
index 3a89239..f2518b0 100644 (file)
@@ -133,17 +133,17 @@ static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
        }
 
        ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
-       IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | reset_bit));
        IXGBE_WRITE_FLUSH(hw);
 
        /* Poll for reset bit to self-clear indicating reset is complete */
        for (i = 0; i < 10; i++) {
                udelay(1);
                ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
-               if (!(ctrl & IXGBE_CTRL_RST))
+               if (!(ctrl & reset_bit))
                        break;
        }
-       if (ctrl & IXGBE_CTRL_RST) {
+       if (ctrl & reset_bit) {
                status = IXGBE_ERR_RESET_FAILED;
                hw_dbg(hw, "Reset polling failed to complete.\n");
        }
index f69e73e..79ccb54 100644 (file)
@@ -260,7 +260,7 @@ static int macb_mii_init(struct macb *bp)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                bp->mii_bus->irq[i] = PHY_POLL;
 
-       platform_set_drvdata(bp->dev, bp->mii_bus);
+       dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
 
        if (mdiobus_register(bp->mii_bus))
                goto err_out_free_mdio_irq;
index 4ffdc18..2765a3c 100644 (file)
@@ -1286,6 +1286,21 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
        { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
        { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */
        { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX2 40GigE PCIe gen2 */
+       { PCI_VDEVICE(MELLANOX, 0x1002) }, /* MT25400 Family [ConnectX-2 Virtual Function] */
+       { PCI_VDEVICE(MELLANOX, 0x1003) }, /* MT27500 Family [ConnectX-3] */
+       { PCI_VDEVICE(MELLANOX, 0x1004) }, /* MT27500 Family [ConnectX-3 Virtual Function] */
+       { PCI_VDEVICE(MELLANOX, 0x1005) }, /* MT27510 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1006) }, /* MT27511 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1007) }, /* MT27520 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1008) }, /* MT27521 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1009) }, /* MT27530 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100a) }, /* MT27531 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100b) }, /* MT27540 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100c) }, /* MT27541 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100d) }, /* MT27550 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100e) }, /* MT27551 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100f) }, /* MT27560 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1010) }, /* MT27561 Family */
        { 0, }
 };
 
index 2541321..9fb59d3 100644 (file)
@@ -4489,6 +4489,9 @@ static int niu_alloc_channels(struct niu *np)
 {
        struct niu_parent *parent = np->parent;
        int first_rx_channel, first_tx_channel;
+       int num_rx_rings, num_tx_rings;
+       struct rx_ring_info *rx_rings;
+       struct tx_ring_info *tx_rings;
        int i, port, err;
 
        port = np->port;
@@ -4498,18 +4501,21 @@ static int niu_alloc_channels(struct niu *np)
                first_tx_channel += parent->txchan_per_port[i];
        }
 
-       np->num_rx_rings = parent->rxchan_per_port[port];
-       np->num_tx_rings = parent->txchan_per_port[port];
+       num_rx_rings = parent->rxchan_per_port[port];
+       num_tx_rings = parent->txchan_per_port[port];
 
-       netif_set_real_num_rx_queues(np->dev, np->num_rx_rings);
-       netif_set_real_num_tx_queues(np->dev, np->num_tx_rings);
-
-       np->rx_rings = kcalloc(np->num_rx_rings, sizeof(struct rx_ring_info),
-                              GFP_KERNEL);
+       rx_rings = kcalloc(num_rx_rings, sizeof(struct rx_ring_info),
+                          GFP_KERNEL);
        err = -ENOMEM;
-       if (!np->rx_rings)
+       if (!rx_rings)
                goto out_err;
 
+       np->num_rx_rings = num_rx_rings;
+       smp_wmb();
+       np->rx_rings = rx_rings;
+
+       netif_set_real_num_rx_queues(np->dev, num_rx_rings);
+
        for (i = 0; i < np->num_rx_rings; i++) {
                struct rx_ring_info *rp = &np->rx_rings[i];
 
@@ -4538,12 +4544,18 @@ static int niu_alloc_channels(struct niu *np)
                        return err;
        }
 
-       np->tx_rings = kcalloc(np->num_tx_rings, sizeof(struct tx_ring_info),
-                              GFP_KERNEL);
+       tx_rings = kcalloc(num_tx_rings, sizeof(struct tx_ring_info),
+                          GFP_KERNEL);
        err = -ENOMEM;
-       if (!np->tx_rings)
+       if (!tx_rings)
                goto out_err;
 
+       np->num_tx_rings = num_tx_rings;
+       smp_wmb();
+       np->tx_rings = tx_rings;
+
+       netif_set_real_num_tx_queues(np->dev, num_tx_rings);
+
        for (i = 0; i < np->num_tx_rings; i++) {
                struct tx_ring_info *rp = &np->tx_rings[i];
 
@@ -6246,11 +6258,17 @@ static void niu_sync_mac_stats(struct niu *np)
 static void niu_get_rx_stats(struct niu *np)
 {
        unsigned long pkts, dropped, errors, bytes;
+       struct rx_ring_info *rx_rings;
        int i;
 
        pkts = dropped = errors = bytes = 0;
+
+       rx_rings = ACCESS_ONCE(np->rx_rings);
+       if (!rx_rings)
+               goto no_rings;
+
        for (i = 0; i < np->num_rx_rings; i++) {
-               struct rx_ring_info *rp = &np->rx_rings[i];
+               struct rx_ring_info *rp = &rx_rings[i];
 
                niu_sync_rx_discard_stats(np, rp, 0);
 
@@ -6259,6 +6277,8 @@ static void niu_get_rx_stats(struct niu *np)
                dropped += rp->rx_dropped;
                errors += rp->rx_errors;
        }
+
+no_rings:
        np->dev->stats.rx_packets = pkts;
        np->dev->stats.rx_bytes = bytes;
        np->dev->stats.rx_dropped = dropped;
@@ -6268,16 +6288,24 @@ static void niu_get_rx_stats(struct niu *np)
 static void niu_get_tx_stats(struct niu *np)
 {
        unsigned long pkts, errors, bytes;
+       struct tx_ring_info *tx_rings;
        int i;
 
        pkts = errors = bytes = 0;
+
+       tx_rings = ACCESS_ONCE(np->tx_rings);
+       if (!tx_rings)
+               goto no_rings;
+
        for (i = 0; i < np->num_tx_rings; i++) {
-               struct tx_ring_info *rp = &np->tx_rings[i];
+               struct tx_ring_info *rp = &tx_rings[i];
 
                pkts += rp->tx_packets;
                bytes += rp->tx_bytes;
                errors += rp->tx_errors;
        }
+
+no_rings:
        np->dev->stats.tx_packets = pkts;
        np->dev->stats.tx_bytes = bytes;
        np->dev->stats.tx_errors = errors;
@@ -6287,9 +6315,10 @@ static struct net_device_stats *niu_get_stats(struct net_device *dev)
 {
        struct niu *np = netdev_priv(dev);
 
-       niu_get_rx_stats(np);
-       niu_get_tx_stats(np);
-
+       if (netif_running(dev)) {
+               niu_get_rx_stats(np);
+               niu_get_tx_stats(np);
+       }
        return &dev->stats;
 }
 
index 84134c7..a41b2cf 100644 (file)
@@ -1988,12 +1988,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
        }
 
        ndev = alloc_etherdev(sizeof(struct ns83820));
-       dev = PRIV(ndev);
-
        err = -ENOMEM;
-       if (!dev)
+       if (!ndev)
                goto out;
 
+       dev = PRIV(ndev);
        dev->ndev = ndev;
 
        spin_lock_init(&dev->rx_info.lock);
index a0c26a9..e1e33c8 100644 (file)
@@ -73,7 +73,7 @@ struct pch_gbe_regs {
        struct pch_gbe_regs_mac_adr mac_adr[16];
        u32 ADDR_MASK;
        u32 MIIM;
-       u32 reserve2;
+       u32 MAC_ADDR_LOAD;
        u32 RGMII_ST;
        u32 RGMII_CTRL;
        u32 reserve3[3];
index d735530..b99e90a 100644 (file)
@@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION;
 #define PCH_GBE_SHORT_PKT              64
 #define DSC_INIT16                     0xC000
 #define PCH_GBE_DMA_ALIGN              0
+#define PCH_GBE_DMA_PADDING            2
 #define PCH_GBE_WATCHDOG_PERIOD                (1 * HZ)        /* watchdog time */
 #define PCH_GBE_COPYBREAK_DEFAULT      256
 #define PCH_GBE_PCI_BAR                        1
@@ -88,6 +89,12 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
 static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
 static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
                               int data);
+
+inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw)
+{
+       iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD);
+}
+
 /**
  * pch_gbe_mac_read_mac_addr - Read MAC address
  * @hw:                    Pointer to the HW structure
@@ -519,7 +526,9 @@ static void pch_gbe_reset_task(struct work_struct *work)
        struct pch_gbe_adapter *adapter;
        adapter = container_of(work, struct pch_gbe_adapter, reset_task);
 
+       rtnl_lock();
        pch_gbe_reinit_locked(adapter);
+       rtnl_unlock();
 }
 
 /**
@@ -528,14 +537,8 @@ static void pch_gbe_reset_task(struct work_struct *work)
  */
 void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
-
-       rtnl_lock();
-       if (netif_running(netdev)) {
-               pch_gbe_down(adapter);
-               pch_gbe_up(adapter);
-       }
-       rtnl_unlock();
+       pch_gbe_down(adapter);
+       pch_gbe_up(adapter);
 }
 
 /**
@@ -1369,16 +1372,13 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
        struct pch_gbe_buffer *buffer_info;
        struct pch_gbe_rx_desc *rx_desc;
        u32 length;
-       unsigned char tmp_packet[ETH_HLEN];
        unsigned int i;
        unsigned int cleaned_count = 0;
        bool cleaned = false;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *new_skb;
        u8 dma_status;
        u16 gbec_status;
        u32 tcp_ip_status;
-       u8 skb_copy_flag = 0;
-       u8 skb_padding_flag = 0;
 
        i = rx_ring->next_to_clean;
 
@@ -1422,55 +1422,70 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
                        pr_err("Receive CRC Error\n");
                } else {
                        /* get receive length */
-                       /* length convert[-3], padding[-2] */
-                       length = (rx_desc->rx_words_eob) - 3 - 2;
+                       /* length convert[-3] */
+                       length = (rx_desc->rx_words_eob) - 3;
 
                        /* Decide the data conversion method */
                        if (!adapter->rx_csum) {
                                /* [Header:14][payload] */
-                               skb_padding_flag = 0;
-                               skb_copy_flag = 1;
+                               if (NET_IP_ALIGN) {
+                                       /* Because alignment differs,
+                                        * the new_skb is newly allocated,
+                                        * and data is copied to new_skb.*/
+                                       new_skb = netdev_alloc_skb(netdev,
+                                                        length + NET_IP_ALIGN);
+                                       if (!new_skb) {
+                                               /* dorrop error */
+                                               pr_err("New skb allocation "
+                                                       "Error\n");
+                                               goto dorrop;
+                                       }
+                                       skb_reserve(new_skb, NET_IP_ALIGN);
+                                       memcpy(new_skb->data, skb->data,
+                                              length);
+                                       skb = new_skb;
+                               } else {
+                                       /* DMA buffer is used as SKB as it is.*/
+                                       buffer_info->skb = NULL;
+                               }
                        } else {
                                /* [Header:14][padding:2][payload] */
-                               skb_padding_flag = 1;
-                               if (length < copybreak)
-                                       skb_copy_flag = 1;
-                               else
-                                       skb_copy_flag = 0;
-                       }
-
-                       /* Data conversion */
-                       if (skb_copy_flag) {    /* recycle  skb */
-                               struct sk_buff *new_skb;
-                               new_skb =
-                                   netdev_alloc_skb(netdev,
-                                                    length + NET_IP_ALIGN);
-                               if (new_skb) {
-                                       if (!skb_padding_flag) {
-                                               skb_reserve(new_skb,
-                                                               NET_IP_ALIGN);
+                               /* The length includes padding length */
+                               length = length - PCH_GBE_DMA_PADDING;
+                               if ((length < copybreak) ||
+                                   (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) {
+                                       /* Because alignment differs,
+                                        * the new_skb is newly allocated,
+                                        * and data is copied to new_skb.
+                                        * Padding data is deleted
+                                        * at the time of a copy.*/
+                                       new_skb = netdev_alloc_skb(netdev,
+                                                        length + NET_IP_ALIGN);
+                                       if (!new_skb) {
+                                               /* dorrop error */
+                                               pr_err("New skb allocation "
+                                                       "Error\n");
+                                               goto dorrop;
                                        }
+                                       skb_reserve(new_skb, NET_IP_ALIGN);
                                        memcpy(new_skb->data, skb->data,
-                                               length);
-                                       /* save the skb
-                                        * in buffer_info as good */
+                                              ETH_HLEN);
+                                       memcpy(&new_skb->data[ETH_HLEN],
+                                              &skb->data[ETH_HLEN +
+                                              PCH_GBE_DMA_PADDING],
+                                              length - ETH_HLEN);
                                        skb = new_skb;
-                               } else if (!skb_padding_flag) {
-                                       /* dorrop error */
-                                       pr_err("New skb allocation Error\n");
-                                       goto dorrop;
+                               } else {
+                                       /* Padding data is deleted
+                                        * by moving header data.*/
+                                       memmove(&skb->data[PCH_GBE_DMA_PADDING],
+                                               &skb->data[0], ETH_HLEN);
+                                       skb_reserve(skb, NET_IP_ALIGN);
+                                       buffer_info->skb = NULL;
                                }
-                       } else {
-                               buffer_info->skb = NULL;
                        }
-                       if (skb_padding_flag) {
-                               memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN);
-                               memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0],
-                                       ETH_HLEN);
-                               skb_reserve(skb, NET_IP_ALIGN);
-
-                       }
-
+                       /* The length includes FCS length */
+                       length = length - ETH_FCS_LEN;
                        /* update status of driver */
                        adapter->stats.rx_bytes += length;
                        adapter->stats.rx_packets++;
@@ -2247,7 +2262,7 @@ static void pch_gbe_remove(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
-       flush_scheduled_work();
+       cancel_work_sync(&adapter->reset_task);
        unregister_netdev(netdev);
 
        pch_gbe_hal_phy_hw_reset(&adapter->hw);
@@ -2322,6 +2337,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO;
        pch_gbe_set_ethtool_ops(netdev);
 
+       pch_gbe_mac_load_mac_addr(&adapter->hw);
        pch_gbe_mac_reset_hw(&adapter->hw);
 
        /* setup the private structure */
index 1f42f6a..d3cb772 100644 (file)
@@ -1488,12 +1488,10 @@ static void ei_rx_overrun(struct net_device *dev)
     
        /* 
         * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
-        * Early datasheets said to poll the reset bit, but now they say that
-        * it "is not a reliable indicator and subsequently should be ignored."
-        * We wait at least 10ms.
+        * We wait at least 2ms.
         */
 
-       mdelay(10);
+       mdelay(2);
 
        /*
         * Reset RBCR[01] back to zero as per magic incantation.
index 9226cda..530ab5a 100644 (file)
@@ -691,6 +691,7 @@ static struct pcmcia_device_id fmvj18x_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
        PCMCIA_DEVICE_NULL,
 };
index bde7d61..7ffdb80 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/firmware.h>
+#include <linux/pci-aspm.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -617,8 +618,9 @@ static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
        }
 }
 
-static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
+static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
 {
+       void __iomem *ioaddr = tp->mmio_addr;
        int i;
 
        RTL_W8(ERIDR, cmd);
@@ -630,7 +632,7 @@ static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
                        break;
        }
 
-       ocp_write(ioaddr, 0x1, 0x30, 0x00000001);
+       ocp_write(tp, 0x1, 0x30, 0x00000001);
 }
 
 #define OOB_CMD_RESET          0x00
@@ -973,7 +975,8 @@ static void __rtl8169_check_link_status(struct net_device *dev,
                if (pm)
                        pm_request_resume(&tp->pci_dev->dev);
                netif_carrier_on(dev);
-               netif_info(tp, ifup, dev, "link up\n");
+               if (net_ratelimit())
+                       netif_info(tp, ifup, dev, "link up\n");
        } else {
                netif_carrier_off(dev);
                netif_info(tp, ifdown, dev, "link down\n");
@@ -2867,8 +2870,11 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+       if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+            (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
+           (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
                return;
+       }
 
        if (((tp->mac_version == RTL_GIGA_MAC_VER_23) ||
             (tp->mac_version == RTL_GIGA_MAC_VER_24)) &&
@@ -2890,6 +2896,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_25:
        case RTL_GIGA_MAC_VER_26:
+       case RTL_GIGA_MAC_VER_27:
+       case RTL_GIGA_MAC_VER_28:
                RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
                break;
        }
@@ -2899,12 +2907,17 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+       if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+            (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
+           (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
                return;
+       }
 
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_25:
        case RTL_GIGA_MAC_VER_26:
+       case RTL_GIGA_MAC_VER_27:
+       case RTL_GIGA_MAC_VER_28:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
        }
@@ -3008,6 +3021,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        mii->reg_num_mask = 0x1f;
        mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
 
+       /* disable ASPM completely as that cause random device stop working
+        * problems as well as full system hangs for some PCIe devices users */
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                                    PCIE_LINK_STATE_CLKPM);
+
        /* enable device (incl. PCI PM wakeup and hotplug setup) */
        rc = pci_enable_device(pdev);
        if (rc < 0) {
@@ -3041,7 +3059,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_mwi_2;
        }
 
-       tp->cp_cmd = PCIMulRW | RxChkSum;
+       tp->cp_cmd = RxChkSum;
 
        if ((sizeof(dma_addr_t) > 4) &&
            !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
@@ -3189,6 +3207,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_dev_run_wake(pdev))
                pm_runtime_put_noidle(&pdev->dev);
 
+       netif_carrier_off(dev);
+
 out:
        return rc;
 
@@ -3315,7 +3335,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
        /* Disable interrupts */
        rtl8169_irq_mask_and_ack(ioaddr);
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_28) {
+       if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_28) {
                while (RTL_R8(TxPoll) & NPQ)
                        udelay(20);
 
@@ -3757,7 +3778,8 @@ static void rtl_hw_start_8168(struct net_device *dev)
        RTL_W16(IntrMitigate, 0x5151);
 
        /* Work around for RxFIFO overflow. */
-       if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+       if (tp->mac_version == RTL_GIGA_MAC_VER_11 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_22) {
                tp->intr_event |= RxFIFOOver | PCSTimeout;
                tp->intr_event &= ~RxOverflow;
        }
@@ -3843,8 +3865,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
        Cxpl_dbg_sel | \
        ASF | \
        PktCntrDisable | \
-       PCIDAC | \
-       PCIMulRW)
+       Mac_dbgo_sel)
 
 static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
 {
@@ -3874,8 +3895,6 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
        if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
                RTL_W8(Config1, cfg1 & ~LEDS0);
 
-       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
-
        rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
 }
 
@@ -3887,8 +3906,6 @@ static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
 
        RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
        RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
-
-       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
 }
 
 static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev)
@@ -3914,6 +3931,8 @@ static void rtl_hw_start_8101(struct net_device *dev)
                }
        }
 
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_07:
                rtl_hw_start_8102e_1(ioaddr, pdev);
@@ -3928,14 +3947,13 @@ static void rtl_hw_start_8101(struct net_device *dev)
                break;
        }
 
-       RTL_W8(Cfg9346, Cfg9346_Unlock);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
 
        RTL_W8(MaxTxPacketSize, TxPacketMax);
 
        rtl_set_rx_max_size(ioaddr, rx_buf_sz);
 
-       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
-
+       tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
        RTL_W16(CPlusCmd, tp->cp_cmd);
 
        RTL_W16(IntrMitigate, 0x0000);
@@ -3945,14 +3963,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
        RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
        rtl_set_rx_tx_config_registers(tp);
 
-       RTL_W8(Cfg9346, Cfg9346_Lock);
-
        RTL_R8(IntrMask);
 
        rtl_set_rx_mode(dev);
 
-       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
 
        RTL_W16(IntrMask, tp->intr_event);
@@ -4639,12 +4653,33 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                        break;
                }
 
-               /* Work around for rx fifo overflow */
-               if (unlikely(status & RxFIFOOver) &&
-               (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
-                       netif_stop_queue(dev);
-                       rtl8169_tx_timeout(dev);
-                       break;
+               if (unlikely(status & RxFIFOOver)) {
+                       switch (tp->mac_version) {
+                       /* Work around for rx fifo overflow */
+                       case RTL_GIGA_MAC_VER_11:
+                       case RTL_GIGA_MAC_VER_22:
+                       case RTL_GIGA_MAC_VER_26:
+                               netif_stop_queue(dev);
+                               rtl8169_tx_timeout(dev);
+                               goto done;
+                       /* Testers needed. */
+                       case RTL_GIGA_MAC_VER_17:
+                       case RTL_GIGA_MAC_VER_19:
+                       case RTL_GIGA_MAC_VER_20:
+                       case RTL_GIGA_MAC_VER_21:
+                       case RTL_GIGA_MAC_VER_23:
+                       case RTL_GIGA_MAC_VER_24:
+                       case RTL_GIGA_MAC_VER_27:
+                       case RTL_GIGA_MAC_VER_28:
+                       /* Experimental science. Pktgen proof. */
+                       case RTL_GIGA_MAC_VER_12:
+                       case RTL_GIGA_MAC_VER_25:
+                               if (status == RxFIFOOver)
+                                       goto done;
+                               break;
+                       default:
+                               break;
+                       }
                }
 
                if (unlikely(status & SYSErr)) {
@@ -4680,7 +4715,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                        (status & RxFIFOOver) ? (status | RxOverflow) : status);
                status = RTL_R16(IntrStatus);
        }
-
+done:
        return IRQ_RETVAL(handled);
 }
 
index 0e8bb19..ca886d9 100644 (file)
@@ -569,9 +569,14 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                                  struct ethtool_test *test, u64 *data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       struct efx_self_tests efx_tests;
+       struct efx_self_tests *efx_tests;
        int already_up;
-       int rc;
+       int rc = -ENOMEM;
+
+       efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL);
+       if (!efx_tests)
+               goto fail;
+
 
        ASSERT_RTNL();
        if (efx->state != STATE_RUNNING) {
@@ -589,13 +594,11 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                if (rc) {
                        netif_err(efx, drv, efx->net_dev,
                                  "failed opening device.\n");
-                       goto fail2;
+                       goto fail1;
                }
        }
 
-       memset(&efx_tests, 0, sizeof(efx_tests));
-
-       rc = efx_selftest(efx, &efx_tests, test->flags);
+       rc = efx_selftest(efx, efx_tests, test->flags);
 
        if (!already_up)
                dev_close(efx->net_dev);
@@ -604,10 +607,11 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                   rc == 0 ? "passed" : "failed",
                   (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
- fail2:
- fail1:
+fail1:
        /* Fill ethtool results structures */
-       efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
+       efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data);
+       kfree(efx_tests);
+fail:
        if (rc)
                test->flags |= ETH_TEST_FL_FAILED;
 }
index 5976d1d..640e368 100644 (file)
@@ -1777,6 +1777,7 @@ static int sis900_rx(struct net_device *net_dev)
                                              "cur_rx:%4.4d, dirty_rx:%4.4d\n",
                                              net_dev->name, sis_priv->cur_rx,
                                              sis_priv->dirty_rx);
+                               dev_kfree_skb(skb);
                                break;
                        }
 
index 42daf98..35b28f4 100644 (file)
@@ -3856,9 +3856,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-       /* device is off until link detection */
-       netif_carrier_off(dev);
-
        return dev;
 }
 
index 34a0af3..0e5f031 100644 (file)
@@ -1560,8 +1560,10 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 
        priv->hw = device;
 
-       if (device_can_wakeup(priv->device))
+       if (device_can_wakeup(priv->device)) {
                priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
+               enable_irq_wake(dev->irq);
+       }
 
        return 0;
 }
index 7841a8f..06c0e50 100644 (file)
 #define BAR_0  0
 #define BAR_2  2
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define TG3_VLAN_TAG_USED 1
-#else
-#define TG3_VLAN_TAG_USED 0
-#endif
-
 #include "tg3.h"
 
 #define DRV_MODULE_NAME                "tg3"
                                 TG3_TX_RING_SIZE)
 #define NEXT_TX(N)             (((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
-#define TG3_RX_DMA_ALIGN               16
-#define TG3_RX_HEADROOM                        ALIGN(VLAN_HLEN, TG3_RX_DMA_ALIGN)
-
 #define TG3_DMA_BYTE_ENAB              64
 
 #define TG3_RX_STD_DMA_SZ              1536
@@ -4722,8 +4713,6 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                struct sk_buff *skb;
                dma_addr_t dma_addr;
                u32 opaque_key, desc_idx, *post_ptr;
-               bool hw_vlan __maybe_unused = false;
-               u16 vtag __maybe_unused = 0;
 
                desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
                opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
@@ -4782,12 +4771,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
 
-                       copy_skb = netdev_alloc_skb(tp->dev, len + VLAN_HLEN +
+                       copy_skb = netdev_alloc_skb(tp->dev, len +
                                                    TG3_RAW_IP_ALIGN);
                        if (copy_skb == NULL)
                                goto drop_it_no_recycle;
 
-                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN + VLAN_HLEN);
+                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
                        skb_put(copy_skb, len);
                        pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
                        skb_copy_from_linear_data(skb, copy_skb->data, len);
@@ -4814,30 +4803,11 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                }
 
                if (desc->type_flags & RXD_FLAG_VLAN &&
-                   !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG)) {
-                       vtag = desc->err_vlan & RXD_VLAN_MASK;
-#if TG3_VLAN_TAG_USED
-                       if (tp->vlgrp)
-                               hw_vlan = true;
-                       else
-#endif
-                       {
-                               struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
-                                                   __skb_push(skb, VLAN_HLEN);
-
-                               memmove(ve, skb->data + VLAN_HLEN,
-                                       ETH_ALEN * 2);
-                               ve->h_vlan_proto = htons(ETH_P_8021Q);
-                               ve->h_vlan_TCI = htons(vtag);
-                       }
-               }
+                   !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
+                       __vlan_hwaccel_put_tag(skb,
+                                              desc->err_vlan & RXD_VLAN_MASK);
 
-#if TG3_VLAN_TAG_USED
-               if (hw_vlan)
-                       vlan_gro_receive(&tnapi->napi, tp->vlgrp, vtag, skb);
-               else
-#endif
-                       napi_gro_receive(&tnapi->napi, skb);
+               napi_gro_receive(&tnapi->napi, skb);
 
                received++;
                budget--;
@@ -5740,11 +5710,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
                base_flags |= TXD_FLAG_TCPUDP_CSUM;
        }
 
-#if TG3_VLAN_TAG_USED
        if (vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
                               (vlan_tx_tag_get(skb) << 16));
-#endif
 
        len = skb_headlen(skb);
 
@@ -5986,11 +5954,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                        }
                }
        }
-#if TG3_VLAN_TAG_USED
+
        if (vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
                               (vlan_tx_tag_get(skb) << 16));
-#endif
 
        if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
            !mss && skb->len > VLAN_ETH_FRAME_LEN)
@@ -9532,17 +9499,10 @@ static void __tg3_set_rx_mode(struct net_device *dev)
        rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
                                  RX_MODE_KEEP_VLAN_TAG);
 
+#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE)
        /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
         * flag clear.
         */
-#if TG3_VLAN_TAG_USED
-       if (!tp->vlgrp &&
-           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
-               rx_mode |= RX_MODE_KEEP_VLAN_TAG;
-#else
-       /* By definition, VLAN is disabled always in this
-        * case.
-        */
        if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
                rx_mode |= RX_MODE_KEEP_VLAN_TAG;
 #endif
@@ -11198,7 +11158,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
                        break;                  /* We have no PHY */
 
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
+                   ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+                    !netif_running(dev)))
                        return -EAGAIN;
 
                spin_lock_bh(&tp->lock);
@@ -11214,7 +11176,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
                        break;                  /* We have no PHY */
 
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
+                   ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+                    !netif_running(dev)))
                        return -EAGAIN;
 
                spin_lock_bh(&tp->lock);
@@ -11230,31 +11194,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
-#if TG3_VLAN_TAG_USED
-static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-       struct tg3 *tp = netdev_priv(dev);
-
-       if (!netif_running(dev)) {
-               tp->vlgrp = grp;
-               return;
-       }
-
-       tg3_netif_stop(tp);
-
-       tg3_full_lock(tp, 0);
-
-       tp->vlgrp = grp;
-
-       /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
-       __tg3_set_rx_mode(dev);
-
-       tg3_netif_start(tp);
-
-       tg3_full_unlock(tp);
-}
-#endif
-
 static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -13066,9 +13005,7 @@ static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
 
 static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
 {
-#if TG3_VLAN_TAG_USED
        dev->vlan_features |= flags;
-#endif
 }
 
 static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
@@ -13861,11 +13798,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-       tp->rx_offset = NET_IP_ALIGN + TG3_RX_HEADROOM;
+       tp->rx_offset = NET_IP_ALIGN;
        tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
            (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
-               tp->rx_offset -= NET_IP_ALIGN;
+               tp->rx_offset = 0;
 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                tp->rx_copy_thresh = ~(u16)0;
 #endif
@@ -14629,9 +14566,6 @@ static const struct net_device_ops tg3_netdev_ops = {
        .ndo_do_ioctl           = tg3_ioctl,
        .ndo_tx_timeout         = tg3_tx_timeout,
        .ndo_change_mtu         = tg3_change_mtu,
-#if TG3_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = tg3_vlan_rx_register,
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = tg3_poll_controller,
 #endif
@@ -14648,9 +14582,6 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
        .ndo_do_ioctl           = tg3_ioctl,
        .ndo_tx_timeout         = tg3_tx_timeout,
        .ndo_change_mtu         = tg3_change_mtu,
-#if TG3_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = tg3_vlan_rx_register,
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = tg3_poll_controller,
 #endif
@@ -14700,9 +14631,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
-#if TG3_VLAN_TAG_USED
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif
 
        tp = netdev_priv(dev);
        tp->pdev = pdev;
index d62c8d9..f528243 100644 (file)
@@ -2808,9 +2808,6 @@ struct tg3 {
        u32                             rx_std_max_post;
        u32                             rx_offset;
        u32                             rx_pkt_map_sz;
-#if TG3_VLAN_TAG_USED
-       struct vlan_group               *vlgrp;
-#endif
 
 
        /* begin "everything else" cacheline(s) section */
index d776c4a..7113168 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cdc_ncm.c
  *
- * Copyright (C) ST-Ericsson 2010
+ * Copyright (C) ST-Ericsson 2010-2011
  * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
  * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
  *
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "30-Nov-2010"
+#define        DRIVER_VERSION                          "7-Feb-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -77,6 +77,9 @@
  */
 #define        CDC_NCM_DPT_DATAGRAMS_MAX               32
 
+/* Maximum amount of IN datagrams in NTB */
+#define        CDC_NCM_DPT_DATAGRAMS_IN_MAX            0 /* unlimited */
+
 /* Restart the timer, if amount of datagrams is less than given value */
 #define        CDC_NCM_RESTART_TIMER_DATAGRAM_CNT      3
 
        (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
        (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
 
-struct connection_speed_change {
-       __le32  USBitRate; /* holds 3GPP downlink value, bits per second */
-       __le32  DSBitRate; /* holds 3GPP uplink value, bits per second */
-} __attribute__ ((packed));
-
 struct cdc_ncm_data {
        struct usb_cdc_ncm_nth16 nth16;
        struct usb_cdc_ncm_ndp16 ndp16;
@@ -198,10 +196,10 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 {
        struct usb_cdc_notification req;
        u32 val;
-       __le16 max_datagram_size;
        u8 flags;
        u8 iface_no;
        int err;
+       u16 ntb_fmt_supported;
 
        iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
 
@@ -223,6 +221,9 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
        ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
        ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
        ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
+       /* devices prior to NCM Errata shall set this field to zero */
+       ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+       ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
 
        if (ctx->func_desc != NULL)
                flags = ctx->func_desc->bmNetworkCapabilities;
@@ -231,22 +232,58 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
                 "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
-                "wNdpOutAlignment=%u flags=0x%x\n",
+                "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
                 ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
-                ctx->tx_ndp_modulus, flags);
+                ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags);
 
-       /* max count of tx datagrams without terminating NULL entry */
-       ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+       /* max count of tx datagrams */
+       if ((ctx->tx_max_datagrams == 0) ||
+                       (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
+               ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
 
        /* verify maximum size of received NTB in bytes */
-       if ((ctx->rx_max <
-           (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
-           (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX)) {
+       if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) {
+               pr_debug("Using min receive length=%d\n",
+                                               USB_CDC_NCM_NTB_MIN_IN_SIZE);
+               ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE;
+       }
+
+       if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) {
                pr_debug("Using default maximum receive length=%d\n",
                                                CDC_NCM_NTB_MAX_SIZE_RX);
                ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
        }
 
+       /* inform device about NTB input size changes */
+       if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE;
+               req.wValue = 0;
+               req.wIndex = cpu_to_le16(iface_no);
+
+               if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
+                       struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
+
+                       req.wLength = 8;
+                       ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+                       ndp_in_sz.wNtbInMaxDatagrams =
+                                       cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX);
+                       ndp_in_sz.wReserved = 0;
+                       err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL,
+                                                                       1000);
+               } else {
+                       __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
+                       req.wLength = 4;
+                       err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0,
+                                                               NULL, 1000);
+               }
+
+               if (err)
+                       pr_debug("Setting NTB Input Size failed\n");
+       }
+
        /* verify maximum size of transmitted NTB in bytes */
        if ((ctx->tx_max <
            (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
@@ -297,47 +334,84 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
        /* additional configuration */
 
        /* set CRC Mode */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_SET_CRC_MODE;
-       req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = 0;
-
-       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-       if (err)
-               pr_debug("Setting CRC mode off failed\n");
+       if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_CRC_MODE;
+               req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = 0;
+
+               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+               if (err)
+                       pr_debug("Setting CRC mode off failed\n");
+       }
 
-       /* set NTB format */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
-       req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = 0;
+       /* set NTB format, if both formats are supported */
+       if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
+               req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = 0;
+
+               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+               if (err)
+                       pr_debug("Setting NTB format to 16-bit failed\n");
+       }
 
-       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-       if (err)
-               pr_debug("Setting NTB format to 16-bit failed\n");
+       ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
 
        /* set Max Datagram Size (MTU) */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
-       req.wValue = 0;
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = cpu_to_le16(2);
+       if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
+               __le16 max_datagram_size;
+               u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
+               req.wValue = 0;
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = cpu_to_le16(2);
+
+               err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL,
+                                                                       1000);
+               if (err) {
+                       pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
+                                               CDC_NCM_MIN_DATAGRAM_SIZE);
+               } else {
+                       ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+                       /* Check Eth descriptor value */
+                       if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
+                               if (ctx->max_datagram_size > eth_max_sz)
+                                       ctx->max_datagram_size = eth_max_sz;
+                       } else {
+                               if (ctx->max_datagram_size >
+                                               CDC_NCM_MAX_DATAGRAM_SIZE)
+                                       ctx->max_datagram_size =
+                                               CDC_NCM_MAX_DATAGRAM_SIZE;
+                       }
 
-       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, 1000);
-       if (err) {
-               pr_debug(" GET_MAX_DATAGRAM_SIZE failed, using size=%u\n",
-                        CDC_NCM_MIN_DATAGRAM_SIZE);
-               /* use default */
-               ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
-       } else {
-               ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+                       if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
+                               ctx->max_datagram_size =
+                                       CDC_NCM_MIN_DATAGRAM_SIZE;
+
+                       /* if value changed, update device */
+                       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+                       req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE;
+                       req.wValue = 0;
+                       req.wIndex = cpu_to_le16(iface_no);
+                       req.wLength = 2;
+                       max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
+
+                       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size,
+                                                               0, NULL, 1000);
+                       if (err)
+                               pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
+               }
 
-               if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
-                       ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
-               else if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
-                       ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
        }
 
        if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
@@ -466,19 +540,13 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 
                        ctx->ether_desc =
                                        (const struct usb_cdc_ether_desc *)buf;
-
                        dev->hard_mtu =
                                le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
 
-                       if (dev->hard_mtu <
-                           (CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN))
-                               dev->hard_mtu =
-                                       CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN;
-
-                       else if (dev->hard_mtu >
-                                (CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN))
-                               dev->hard_mtu =
-                                       CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN;
+                       if (dev->hard_mtu < CDC_NCM_MIN_DATAGRAM_SIZE)
+                               dev->hard_mtu = CDC_NCM_MIN_DATAGRAM_SIZE;
+                       else if (dev->hard_mtu > CDC_NCM_MAX_DATAGRAM_SIZE)
+                               dev->hard_mtu = CDC_NCM_MAX_DATAGRAM_SIZE;
                        break;
 
                case USB_CDC_NCM_TYPE:
@@ -628,13 +696,13 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        u32 offset;
        u32 last_offset;
        u16 n = 0;
-       u8 timeout = 0;
+       u8 ready2send = 0;
 
        /* if there is a remaining skb, it gets priority */
        if (skb != NULL)
                swap(skb, ctx->tx_rem_skb);
        else
-               timeout = 1;
+               ready2send = 1;
 
        /*
         * +----------------+
@@ -682,9 +750,10 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
 
        for (; n < ctx->tx_max_datagrams; n++) {
                /* check if end of transmit buffer is reached */
-               if (offset >= ctx->tx_max)
+               if (offset >= ctx->tx_max) {
+                       ready2send = 1;
                        break;
-
+               }
                /* compute maximum buffer size */
                rem = ctx->tx_max - offset;
 
@@ -711,9 +780,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                                }
                                ctx->tx_rem_skb = skb;
                                skb = NULL;
-
-                               /* loop one more time */
-                               timeout = 1;
+                               ready2send = 1;
                        }
                        break;
                }
@@ -756,7 +823,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                ctx->tx_curr_last_offset = last_offset;
                goto exit_no_skb;
 
-       } else if ((n < ctx->tx_max_datagrams) && (timeout == 0)) {
+       } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) {
                /* wait for more frames */
                /* push variables */
                ctx->tx_curr_skb = skb_out;
@@ -813,7 +880,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                                        cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
        ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
        ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
-       ctx->tx_ncm.nth16.wFpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+       ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
                                                        ctx->tx_ndp_modulus);
 
        memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
@@ -825,13 +892,13 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
                                        sizeof(struct usb_cdc_ncm_dpe16));
        ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
-       ctx->tx_ncm.ndp16.wNextFpIndex = 0; /* reserved */
+       ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex,
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex,
                                                &(ctx->tx_ncm.ndp16),
                                                sizeof(ctx->tx_ncm.ndp16));
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex +
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex +
                                        sizeof(ctx->tx_ncm.ndp16),
                                        &(ctx->tx_ncm.dpe16),
                                        (ctx->tx_curr_frame_num + 1) *
@@ -868,15 +935,19 @@ static void cdc_ncm_tx_timeout(unsigned long arg)
        if (ctx->tx_timer_pending != 0) {
                ctx->tx_timer_pending--;
                restart = 1;
-       } else
+       } else {
                restart = 0;
+       }
 
        spin_unlock(&ctx->mtx);
 
-       if (restart)
+       if (restart) {
+               spin_lock(&ctx->mtx);
                cdc_ncm_tx_timeout_start(ctx);
-       else if (ctx->netdev != NULL)
+               spin_unlock(&ctx->mtx);
+       } else if (ctx->netdev != NULL) {
                usbnet_start_xmit(NULL, ctx->netdev);
+       }
 }
 
 static struct sk_buff *
@@ -900,7 +971,6 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
        skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
        if (ctx->tx_curr_skb != NULL)
                need_timer = 1;
-       spin_unlock(&ctx->mtx);
 
        /* Start timer, if there is a remaining skb */
        if (need_timer)
@@ -908,6 +978,8 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
 
        if (skb_out)
                dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+
+       spin_unlock(&ctx->mtx);
        return skb_out;
 
 error:
@@ -956,7 +1028,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
                goto error;
        }
 
-       temp = le16_to_cpu(ctx->rx_ncm.nth16.wFpIndex);
+       temp = le16_to_cpu(ctx->rx_ncm.nth16.wNdpIndex);
        if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) {
                pr_debug("invalid DPT16 index\n");
                goto error;
@@ -1020,8 +1092,8 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
                if (((offset + temp) > actlen) ||
                    (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
                        pr_debug("invalid frame detected (ignored)"
-                               "offset[%u]=%u, length=%u, skb=%p\n",
-                                                       x, offset, temp, skb_in);
+                                       "offset[%u]=%u, length=%u, skb=%p\n",
+                                       x, offset, temp, skb_in);
                        if (!x)
                                goto error;
                        break;
@@ -1043,10 +1115,10 @@ error:
 
 static void
 cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
-                    struct connection_speed_change *data)
+                    struct usb_cdc_speed_change *data)
 {
-       uint32_t rx_speed = le32_to_cpu(data->USBitRate);
-       uint32_t tx_speed = le32_to_cpu(data->DSBitRate);
+       uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
+       uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
 
        /*
         * Currently the USB-NET API does not support reporting the actual
@@ -1087,7 +1159,7 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
        /* test for split data in 8-byte chunks */
        if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
                cdc_ncm_speed_change(ctx,
-                     (struct connection_speed_change *)urb->transfer_buffer);
+                     (struct usb_cdc_speed_change *)urb->transfer_buffer);
                return;
        }
 
@@ -1115,12 +1187,12 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
                break;
 
        case USB_CDC_NOTIFY_SPEED_CHANGE:
-               if (urb->actual_length <
-                   (sizeof(*event) + sizeof(struct connection_speed_change)))
+               if (urb->actual_length < (sizeof(*event) +
+                                       sizeof(struct usb_cdc_speed_change)))
                        set_bit(EVENT_STS_SPLIT, &dev->flags);
                else
                        cdc_ncm_speed_change(ctx,
-                               (struct connection_speed_change *) &event[1]);
+                               (struct usb_cdc_speed_change *) &event[1]);
                break;
 
        default:
index 02b622e..5002f5b 100644 (file)
@@ -651,6 +651,10 @@ static const struct usb_device_id products[] = {
        .driver_info = (unsigned long)&dm9601_info,
         },
        {
+        USB_DEVICE(0x0fe6, 0x9700),    /* DM9601 USB to Fast Ethernet Adapter */
+        .driver_info = (unsigned long)&dm9601_info,
+        },
+       {
         USB_DEVICE(0x0a46, 0x9000),    /* DM9000E */
         .driver_info = (unsigned long)&dm9601_info,
         },
index bed8fce..6d83812 100644 (file)
@@ -2628,15 +2628,15 @@ exit:
 
 static void hso_free_tiomget(struct hso_serial *serial)
 {
-       struct hso_tiocmget *tiocmget = serial->tiocmget;
+       struct hso_tiocmget *tiocmget;
+       if (!serial)
+               return;
+       tiocmget = serial->tiocmget;
        if (tiocmget) {
-               if (tiocmget->urb) {
-                       usb_free_urb(tiocmget->urb);
-                       tiocmget->urb = NULL;
-               }
+               usb_free_urb(tiocmget->urb);
+               tiocmget->urb = NULL;
                serial->tiocmget = NULL;
                kfree(tiocmget);
-
        }
 }
 
index 5e98643..7dc8497 100644 (file)
@@ -406,6 +406,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
 
        if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
                err("Firmware too big: %zu", fw->size);
+               release_firmware(fw);
                return -ENOSPC;
        }
        data_len = fw->size;
index ed9a416..95c41d5 100644 (file)
@@ -931,8 +931,10 @@ fail_halt:
                if (urb != NULL) {
                        clear_bit (EVENT_RX_MEMORY, &dev->flags);
                        status = usb_autopm_get_interface(dev->intf);
-                       if (status < 0)
+                       if (status < 0) {
+                               usb_free_urb(urb);
                                goto fail_lowmem;
+                       }
                        if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK)
                                resched = 0;
                        usb_autopm_put_interface(dev->intf);
index 90a23e4..82dba5a 100644 (file)
@@ -446,6 +446,20 @@ static void skb_recv_done(struct virtqueue *rvq)
        }
 }
 
+static void virtnet_napi_enable(struct virtnet_info *vi)
+{
+       napi_enable(&vi->napi);
+
+       /* If all buffers were filled by other side before we napi_enabled, we
+        * won't get another interrupt, so process any outstanding packets
+        * now.  virtnet_poll wants re-enable the queue, so we disable here.
+        * We synchronize against interrupts via NAPI_STATE_SCHED */
+       if (napi_schedule_prep(&vi->napi)) {
+               virtqueue_disable_cb(vi->rvq);
+               __napi_schedule(&vi->napi);
+       }
+}
+
 static void refill_work(struct work_struct *work)
 {
        struct virtnet_info *vi;
@@ -454,7 +468,7 @@ static void refill_work(struct work_struct *work)
        vi = container_of(work, struct virtnet_info, refill.work);
        napi_disable(&vi->napi);
        still_empty = !try_fill_recv(vi, GFP_KERNEL);
-       napi_enable(&vi->napi);
+       virtnet_napi_enable(vi);
 
        /* In theory, this can happen: if we don't get any buffers in
         * we will *never* try to fill again. */
@@ -638,16 +652,7 @@ static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
-       napi_enable(&vi->napi);
-
-       /* If all buffers were filled by other side before we napi_enabled, we
-        * won't get another interrupt, so process any outstanding packets
-        * now.  virtnet_poll wants re-enable the queue, so we disable here.
-        * We synchronize against interrupts via NAPI_STATE_SCHED */
-       if (napi_schedule_prep(&vi->napi)) {
-               virtqueue_disable_cb(vi->rvq);
-               __napi_schedule(&vi->napi);
-       }
+       virtnet_napi_enable(vi);
        return 0;
 }
 
index d143e8b..cc14b4a 100644 (file)
@@ -48,6 +48,9 @@ static atomic_t devices_found;
 static int enable_mq = 1;
 static int irq_share_mode;
 
+static void
+vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
+
 /*
  *    Enable/Disable the given intr
  */
@@ -139,9 +142,13 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
 {
        u32 ret;
        int i;
+       unsigned long flags;
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
        ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+
        adapter->link_speed = ret >> 16;
        if (ret & 1) { /* Link is up. */
                printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
@@ -183,8 +190,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
 
        /* Check if there is an error on xmit/recv queues */
        if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
+               spin_lock(&adapter->cmd_lock);
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                       VMXNET3_CMD_GET_QUEUE_STATUS);
+               spin_unlock(&adapter->cmd_lock);
 
                for (i = 0; i < adapter->num_tx_queues; i++)
                        if (adapter->tqd_start[i].status.stopped)
@@ -804,30 +813,25 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                                   skb_transport_header(skb))->doff * 4;
                ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size;
        } else {
-               unsigned int pull_size;
-
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        ctx->eth_ip_hdr_size = skb_checksum_start_offset(skb);
 
                        if (ctx->ipv4) {
                                struct iphdr *iph = (struct iphdr *)
                                                    skb_network_header(skb);
-                               if (iph->protocol == IPPROTO_TCP) {
-                                       pull_size = ctx->eth_ip_hdr_size +
-                                                   sizeof(struct tcphdr);
-
-                                       if (unlikely(!pskb_may_pull(skb,
-                                                               pull_size))) {
-                                               goto err;
-                                       }
+                               if (iph->protocol == IPPROTO_TCP)
                                        ctx->l4_hdr_size = ((struct tcphdr *)
                                           skb_transport_header(skb))->doff * 4;
-                               } else if (iph->protocol == IPPROTO_UDP) {
+                               else if (iph->protocol == IPPROTO_UDP)
+                                       /*
+                                        * Use tcp header size so that bytes to
+                                        * be copied are more than required by
+                                        * the device.
+                                        */
                                        ctx->l4_hdr_size =
-                                                       sizeof(struct udphdr);
-                               } else {
+                                                       sizeof(struct tcphdr);
+                               else
                                        ctx->l4_hdr_size = 0;
-                               }
                        } else {
                                /* for simplicity, don't copy L4 headers */
                                ctx->l4_hdr_size = 0;
@@ -1859,18 +1863,14 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        struct Vmxnet3_DriverShared *shared = adapter->shared;
        u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+       unsigned long flags;
 
        if (grp) {
                /* add vlan rx stripping. */
                if (adapter->netdev->features & NETIF_F_HW_VLAN_RX) {
                        int i;
-                       struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
                        adapter->vlan_grp = grp;
 
-                       /* update FEATURES to device */
-                       devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
-                       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
-                                              VMXNET3_CMD_UPDATE_FEATURE);
                        /*
                         *  Clear entire vfTable; then enable untagged pkts.
                         *  Note: setting one entry in vfTable to non-zero turns
@@ -1880,8 +1880,10 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
                                vfTable[i] = 0;
 
                        VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
+                       spin_lock_irqsave(&adapter->cmd_lock, flags);
                        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                               VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+                       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
                } else {
                        printk(KERN_ERR "%s: vlan_rx_register when device has "
                               "no NETIF_F_HW_VLAN_RX\n", netdev->name);
@@ -1900,13 +1902,10 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
                                 */
                                vfTable[i] = 0;
                        }
+                       spin_lock_irqsave(&adapter->cmd_lock, flags);
                        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                               VMXNET3_CMD_UPDATE_VLAN_FILTERS);
-
-                       /* update FEATURES to device */
-                       devRead->misc.uptFeatures &= ~UPT1_F_RXVLAN;
-                       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
-                                              VMXNET3_CMD_UPDATE_FEATURE);
+                       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
                }
        }
 }
@@ -1939,10 +1938,13 @@ vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+       unsigned long flags;
 
        VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 }
 
 
@@ -1951,10 +1953,13 @@ vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+       unsigned long flags;
 
        VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 }
 
 
@@ -1985,6 +1990,7 @@ static void
 vmxnet3_set_mc(struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
        struct Vmxnet3_RxFilterConf *rxConf =
                                        &adapter->shared->devRead.rxFilterConf;
        u8 *new_table = NULL;
@@ -2020,6 +2026,7 @@ vmxnet3_set_mc(struct net_device *netdev)
                rxConf->mfTablePA = 0;
        }
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        if (new_mode != rxConf->rxMode) {
                rxConf->rxMode = cpu_to_le32(new_mode);
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
@@ -2028,6 +2035,7 @@ vmxnet3_set_mc(struct net_device *netdev)
 
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_MAC_FILTERS);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        kfree(new_table);
 }
@@ -2080,10 +2088,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
                devRead->misc.uptFeatures |= UPT1_F_LRO;
                devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS);
        }
-       if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX) &&
-           adapter->vlan_grp) {
+       if (adapter->netdev->features & NETIF_F_HW_VLAN_RX)
                devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
-       }
 
        devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
        devRead->misc.queueDescPA = cpu_to_le64(adapter->queue_desc_pa);
@@ -2168,6 +2174,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
        /* rx filter settings */
        devRead->rxFilterConf.rxMode = 0;
        vmxnet3_restore_vlan(adapter);
+       vmxnet3_write_mac_addr(adapter, adapter->netdev->dev_addr);
+
        /* the rest are already zeroed */
 }
 
@@ -2177,6 +2185,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
 {
        int err, i;
        u32 ret;
+       unsigned long flags;
 
        dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
                " ring sizes %u %u %u\n", adapter->netdev->name,
@@ -2206,9 +2215,11 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
                               adapter->shared_pa));
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH, VMXNET3_GET_ADDR_HI(
                               adapter->shared_pa));
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_ACTIVATE_DEV);
        ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        if (ret != 0) {
                printk(KERN_ERR "Failed to activate dev %s: error %u\n",
@@ -2255,7 +2266,10 @@ rq_err:
 void
 vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 }
 
 
@@ -2263,12 +2277,15 @@ int
 vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
 {
        int i;
+       unsigned long flags;
        if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state))
                return 0;
 
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_QUIESCE_DEV);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
        vmxnet3_disable_all_intrs(adapter);
 
        for (i = 0; i < adapter->num_rx_queues; i++)
@@ -2426,7 +2443,7 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
        sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
        ring0_size = adapter->rx_queue[0].rx_ring[0].size;
        ring0_size = (ring0_size + sz - 1) / sz * sz;
-       ring0_size = min_t(u32, rq->rx_ring[0].size, VMXNET3_RX_RING_MAX_SIZE /
+       ring0_size = min_t(u32, ring0_size, VMXNET3_RX_RING_MAX_SIZE /
                           sz * sz);
        ring1_size = adapter->rx_queue[0].rx_ring[1].size;
        comp_size = ring0_size + ring1_size;
@@ -2695,7 +2712,7 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
                        break;
                } else {
                        /* If fails to enable required number of MSI-x vectors
-                        * try enabling 3 of them. One each for rx, tx and event
+                        * try enabling minimum number of vectors required.
                         */
                        vectors = vector_threshold;
                        printk(KERN_ERR "Failed to enable %d MSI-X for %s, try"
@@ -2718,9 +2735,11 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
        u32 cfg;
 
        /* intr settings */
+       spin_lock(&adapter->cmd_lock);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_GET_CONF_INTR);
        cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+       spin_unlock(&adapter->cmd_lock);
        adapter->intr.type = cfg & 0x3;
        adapter->intr.mask_mode = (cfg >> 2) & 0x3;
 
@@ -2755,7 +2774,7 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
                 */
                if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
                        if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
-                           || adapter->num_rx_queues != 2) {
+                           || adapter->num_rx_queues != 1) {
                                adapter->share_intr = VMXNET3_INTR_TXSHARE;
                                printk(KERN_ERR "Number of rx queues : 1\n");
                                adapter->num_rx_queues = 1;
@@ -2905,6 +2924,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        adapter->netdev = netdev;
        adapter->pdev = pdev;
 
+       spin_lock_init(&adapter->cmd_lock);
        adapter->shared = pci_alloc_consistent(adapter->pdev,
                          sizeof(struct Vmxnet3_DriverShared),
                          &adapter->shared_pa);
@@ -3108,11 +3128,15 @@ vmxnet3_suspend(struct device *device)
        u8 *arpreq;
        struct in_device *in_dev;
        struct in_ifaddr *ifa;
+       unsigned long flags;
        int i = 0;
 
        if (!netif_running(netdev))
                return 0;
 
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               napi_disable(&adapter->rx_queue[i].napi);
+
        vmxnet3_disable_all_intrs(adapter);
        vmxnet3_free_irqs(adapter);
        vmxnet3_free_intr_resources(adapter);
@@ -3188,8 +3212,10 @@ skip_arp:
        adapter->shared->devRead.pmConfDesc.confPA = cpu_to_le64(virt_to_phys(
                                                                 pmConf));
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_PMCFG);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        pci_save_state(pdev);
        pci_enable_wake(pdev, pci_choose_state(pdev, PMSG_SUSPEND),
@@ -3204,7 +3230,8 @@ skip_arp:
 static int
 vmxnet3_resume(struct device *device)
 {
-       int err;
+       int err, i = 0;
+       unsigned long flags;
        struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
@@ -3232,10 +3259,14 @@ vmxnet3_resume(struct device *device)
 
        pci_enable_wake(pdev, PCI_D0, 0);
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_PMCFG);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
        vmxnet3_alloc_intr_resources(adapter);
        vmxnet3_request_irqs(adapter);
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               napi_enable(&adapter->rx_queue[i].napi);
        vmxnet3_enable_all_intrs(adapter);
 
        return 0;
index 8e17fc8..81254be 100644 (file)
@@ -45,6 +45,7 @@ static int
 vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
 
        if (adapter->rxcsum != val) {
                adapter->rxcsum = val;
@@ -56,8 +57,10 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
                                adapter->shared->devRead.misc.uptFeatures &=
                                ~UPT1_F_RXCSUM;
 
+                       spin_lock_irqsave(&adapter->cmd_lock, flags);
                        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                               VMXNET3_CMD_UPDATE_FEATURE);
+                       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
                }
        }
        return 0;
@@ -68,76 +71,78 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
 static const struct vmxnet3_stat_desc
 vmxnet3_tq_dev_stats[] = {
        /* description,         offset */
-       { "TSO pkts tx",        offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
-       { "TSO bytes tx",       offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
-       { "ucast pkts tx",      offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
-       { "ucast bytes tx",     offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
-       { "mcast pkts tx",      offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
-       { "mcast bytes tx",     offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
-       { "bcast pkts tx",      offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
-       { "bcast bytes tx",     offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
-       { "pkts tx err",        offsetof(struct UPT1_TxStats, pktsTxError) },
-       { "pkts tx discard",    offsetof(struct UPT1_TxStats, pktsTxDiscard) },
+       { "Tx Queue#",        0 },
+       { "  TSO pkts tx",      offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
+       { "  TSO bytes tx",     offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
+       { "  ucast pkts tx",    offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
+       { "  ucast bytes tx",   offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
+       { "  mcast pkts tx",    offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
+       { "  mcast bytes tx",   offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
+       { "  bcast pkts tx",    offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
+       { "  bcast bytes tx",   offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
+       { "  pkts tx err",      offsetof(struct UPT1_TxStats, pktsTxError) },
+       { "  pkts tx discard",  offsetof(struct UPT1_TxStats, pktsTxDiscard) },
 };
 
 /* per tq stats maintained by the driver */
 static const struct vmxnet3_stat_desc
 vmxnet3_tq_driver_stats[] = {
        /* description,         offset */
-       {"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
-                                       drop_total) },
-       { "   too many frags",  offsetof(struct vmxnet3_tq_driver_stats,
-                                       drop_too_many_frags) },
-       { "   giant hdr",       offsetof(struct vmxnet3_tq_driver_stats,
-                                       drop_oversized_hdr) },
-       { "   hdr err",         offsetof(struct vmxnet3_tq_driver_stats,
-                                       drop_hdr_inspect_err) },
-       { "   tso",             offsetof(struct vmxnet3_tq_driver_stats,
-                                       drop_tso) },
-       { "ring full",          offsetof(struct vmxnet3_tq_driver_stats,
-                                       tx_ring_full) },
-       { "pkts linearized",    offsetof(struct vmxnet3_tq_driver_stats,
-                                       linearized) },
-       { "hdr cloned",         offsetof(struct vmxnet3_tq_driver_stats,
-                                       copy_skb_header) },
-       { "giant hdr",          offsetof(struct vmxnet3_tq_driver_stats,
-                                       oversized_hdr) },
+       {"  drv dropped tx total",      offsetof(struct vmxnet3_tq_driver_stats,
+                                                drop_total) },
+       { "     too many frags", offsetof(struct vmxnet3_tq_driver_stats,
+                                         drop_too_many_frags) },
+       { "     giant hdr",     offsetof(struct vmxnet3_tq_driver_stats,
+                                        drop_oversized_hdr) },
+       { "     hdr err",       offsetof(struct vmxnet3_tq_driver_stats,
+                                        drop_hdr_inspect_err) },
+       { "     tso",           offsetof(struct vmxnet3_tq_driver_stats,
+                                        drop_tso) },
+       { "  ring full",        offsetof(struct vmxnet3_tq_driver_stats,
+                                        tx_ring_full) },
+       { "  pkts linearized",  offsetof(struct vmxnet3_tq_driver_stats,
+                                        linearized) },
+       { "  hdr cloned",       offsetof(struct vmxnet3_tq_driver_stats,
+                                        copy_skb_header) },
+       { "  giant hdr",        offsetof(struct vmxnet3_tq_driver_stats,
+                                        oversized_hdr) },
 };
 
 /* per rq stats maintained by the device */
 static const struct vmxnet3_stat_desc
 vmxnet3_rq_dev_stats[] = {
-       { "LRO pkts rx",        offsetof(struct UPT1_RxStats, LROPktsRxOK) },
-       { "LRO byte rx",        offsetof(struct UPT1_RxStats, LROBytesRxOK) },
-       { "ucast pkts rx",      offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
-       { "ucast bytes rx",     offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
-       { "mcast pkts rx",      offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
-       { "mcast bytes rx",     offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
-       { "bcast pkts rx",      offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
-       { "bcast bytes rx",     offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
-       { "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
-       { "pkts rx err",        offsetof(struct UPT1_RxStats, pktsRxError) },
+       { "Rx Queue#",        0 },
+       { "  LRO pkts rx",      offsetof(struct UPT1_RxStats, LROPktsRxOK) },
+       { "  LRO byte rx",      offsetof(struct UPT1_RxStats, LROBytesRxOK) },
+       { "  ucast pkts rx",    offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
+       { "  ucast bytes rx",   offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
+       { "  mcast pkts rx",    offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
+       { "  mcast bytes rx",   offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
+       { "  bcast pkts rx",    offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
+       { "  bcast bytes rx",   offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
+       { "  pkts rx OOB",      offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
+       { "  pkts rx err",      offsetof(struct UPT1_RxStats, pktsRxError) },
 };
 
 /* per rq stats maintained by the driver */
 static const struct vmxnet3_stat_desc
 vmxnet3_rq_driver_stats[] = {
        /* description,         offset */
-       { "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
-                                          drop_total) },
-       { "   err",            offsetof(struct vmxnet3_rq_driver_stats,
-                                       drop_err) },
-       { "   fcs",            offsetof(struct vmxnet3_rq_driver_stats,
-                                       drop_fcs) },
-       { "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
-                                       rx_buf_alloc_failure) },
+       { "  drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
+                                            drop_total) },
+       { "     err",           offsetof(struct vmxnet3_rq_driver_stats,
+                                        drop_err) },
+       { "     fcs",           offsetof(struct vmxnet3_rq_driver_stats,
+                                        drop_fcs) },
+       { "  rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
+                                         rx_buf_alloc_failure) },
 };
 
 /* gloabl stats maintained by the driver */
 static const struct vmxnet3_stat_desc
 vmxnet3_global_stats[] = {
        /* description,         offset */
-       { "tx timeout count",   offsetof(struct vmxnet3_adapter,
+       { "tx timeout count",   offsetof(struct vmxnet3_adapter,
                                         tx_timeout_count) }
 };
 
@@ -151,12 +156,15 @@ vmxnet3_get_stats(struct net_device *netdev)
        struct UPT1_TxStats *devTxStats;
        struct UPT1_RxStats *devRxStats;
        struct net_device_stats *net_stats = &netdev->stats;
+       unsigned long flags;
        int i;
 
        adapter = netdev_priv(netdev);
 
        /* Collect the dev stats into the shared area */
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        memset(net_stats, 0, sizeof(*net_stats));
        for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -193,12 +201,15 @@ vmxnet3_get_stats(struct net_device *netdev)
 static int
 vmxnet3_get_sset_count(struct net_device *netdev, int sset)
 {
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        switch (sset) {
        case ETH_SS_STATS:
-               return ARRAY_SIZE(vmxnet3_tq_dev_stats) +
-                       ARRAY_SIZE(vmxnet3_tq_driver_stats) +
-                       ARRAY_SIZE(vmxnet3_rq_dev_stats) +
-                       ARRAY_SIZE(vmxnet3_rq_driver_stats) +
+               return (ARRAY_SIZE(vmxnet3_tq_dev_stats) +
+                       ARRAY_SIZE(vmxnet3_tq_driver_stats)) *
+                      adapter->num_tx_queues +
+                      (ARRAY_SIZE(vmxnet3_rq_dev_stats) +
+                       ARRAY_SIZE(vmxnet3_rq_driver_stats)) *
+                      adapter->num_rx_queues +
                        ARRAY_SIZE(vmxnet3_global_stats);
        default:
                return -EOPNOTSUPP;
@@ -206,10 +217,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
 }
 
 
+/* Should be multiple of 4 */
+#define NUM_TX_REGS    8
+#define NUM_RX_REGS    12
+
 static int
 vmxnet3_get_regs_len(struct net_device *netdev)
 {
-       return 20 * sizeof(u32);
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
+               adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
 }
 
 
@@ -240,29 +257,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 static void
 vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
 {
+        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        if (stringset == ETH_SS_STATS) {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
-                       memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
-                              ETH_GSTRING_LEN);
-                       buf += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) {
-                       memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
-                              ETH_GSTRING_LEN);
-                       buf += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
-                       memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
-                              ETH_GSTRING_LEN);
-                       buf += ETH_GSTRING_LEN;
+               int i, j;
+               for (j = 0; j < adapter->num_tx_queues; j++) {
+                       for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
+                               memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
+                                      ETH_GSTRING_LEN);
+                               buf += ETH_GSTRING_LEN;
+                       }
+                       for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats);
+                            i++) {
+                               memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
+                                      ETH_GSTRING_LEN);
+                               buf += ETH_GSTRING_LEN;
+                       }
                }
-               for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
-                       memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
-                              ETH_GSTRING_LEN);
-                       buf += ETH_GSTRING_LEN;
+
+               for (j = 0; j < adapter->num_rx_queues; j++) {
+                       for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
+                               memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
+                                      ETH_GSTRING_LEN);
+                               buf += ETH_GSTRING_LEN;
+                       }
+                       for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
+                            i++) {
+                               memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
+                                      ETH_GSTRING_LEN);
+                               buf += ETH_GSTRING_LEN;
+                       }
                }
+
                for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
                        memcpy(buf, vmxnet3_global_stats[i].desc,
                                ETH_GSTRING_LEN);
@@ -277,6 +302,7 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1;
        u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1;
+       unsigned long flags;
 
        if (data & ~ETH_FLAG_LRO)
                return -EOPNOTSUPP;
@@ -292,8 +318,10 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
                else
                        adapter->shared->devRead.misc.uptFeatures &=
                                                        ~UPT1_F_LRO;
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                       VMXNET3_CMD_UPDATE_FEATURE);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
        }
        return 0;
 }
@@ -303,30 +331,41 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
                          struct ethtool_stats *stats, u64  *buf)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
        u8 *base;
        int i;
        int j = 0;
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        /* this does assume each counter is 64-bit wide */
-/* TODO change this for multiple queues */
-
-       base = (u8 *)&adapter->tqd_start[j].stats;
-       for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
-               *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
-
-       base = (u8 *)&adapter->tx_queue[j].stats;
-       for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
-               *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
-
-       base = (u8 *)&adapter->rqd_start[j].stats;
-       for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
-               *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
+       for (j = 0; j < adapter->num_tx_queues; j++) {
+               base = (u8 *)&adapter->tqd_start[j].stats;
+               *buf++ = (u64)j;
+               for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
+                       *buf++ = *(u64 *)(base +
+                                         vmxnet3_tq_dev_stats[i].offset);
+
+               base = (u8 *)&adapter->tx_queue[j].stats;
+               for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
+                       *buf++ = *(u64 *)(base +
+                                         vmxnet3_tq_driver_stats[i].offset);
+       }
 
-       base = (u8 *)&adapter->rx_queue[j].stats;
-       for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
-               *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
+       for (j = 0; j < adapter->num_tx_queues; j++) {
+               base = (u8 *)&adapter->rqd_start[j].stats;
+               *buf++ = (u64) j;
+               for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
+                       *buf++ = *(u64 *)(base +
+                                         vmxnet3_rq_dev_stats[i].offset);
+
+               base = (u8 *)&adapter->rx_queue[j].stats;
+               for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
+                       *buf++ = *(u64 *)(base +
+                                         vmxnet3_rq_driver_stats[i].offset);
+       }
 
        base = (u8 *)adapter;
        for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
@@ -339,7 +378,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u32 *buf = p;
-       int i = 0;
+       int i = 0, j = 0;
 
        memset(p, 0, vmxnet3_get_regs_len(netdev));
 
@@ -348,31 +387,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
        /* Update vmxnet3_get_regs_len if we want to dump more registers */
 
        /* make each ring use multiple of 16 bytes */
-/* TODO change this for multiple queues */
-       buf[0] = adapter->tx_queue[i].tx_ring.next2fill;
-       buf[1] = adapter->tx_queue[i].tx_ring.next2comp;
-       buf[2] = adapter->tx_queue[i].tx_ring.gen;
-       buf[3] = 0;
-
-       buf[4] = adapter->tx_queue[i].comp_ring.next2proc;
-       buf[5] = adapter->tx_queue[i].comp_ring.gen;
-       buf[6] = adapter->tx_queue[i].stopped;
-       buf[7] = 0;
-
-       buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
-       buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp;
-       buf[10] = adapter->rx_queue[i].rx_ring[0].gen;
-       buf[11] = 0;
-
-       buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill;
-       buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
-       buf[14] = adapter->rx_queue[i].rx_ring[1].gen;
-       buf[15] = 0;
-
-       buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
-       buf[17] = adapter->rx_queue[i].comp_ring.gen;
-       buf[18] = 0;
-       buf[19] = 0;
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
+               buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
+               buf[j++] = adapter->tx_queue[i].tx_ring.gen;
+               buf[j++] = 0;
+
+               buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
+               buf[j++] = adapter->tx_queue[i].comp_ring.gen;
+               buf[j++] = adapter->tx_queue[i].stopped;
+               buf[j++] = 0;
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
+               buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
+               buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
+               buf[j++] = 0;
+
+               buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
+               buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
+               buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
+               buf[j++] = 0;
+
+               buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
+               buf[j++] = adapter->rx_queue[i].comp_ring.gen;
+               buf[j++] = 0;
+               buf[j++] = 0;
+       }
+
 }
 
 
@@ -574,6 +617,7 @@ vmxnet3_set_rss_indir(struct net_device *netdev,
                      const struct ethtool_rxfh_indir *p)
 {
        unsigned int i;
+       unsigned long flags;
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        struct UPT1_RSSConf *rssConf = adapter->rss_conf;
 
@@ -592,8 +636,10 @@ vmxnet3_set_rss_indir(struct net_device *netdev,
        for (i = 0; i < rssConf->indTableSize; i++)
                rssConf->indTable[i] = p->ring_index[i];
 
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                               VMXNET3_CMD_UPDATE_RSSIDT);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        return 0;
 
index 7fadeed..fb5d245 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.0.16.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.0.25.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01001000
+#define VMXNET3_DRIVER_VERSION_NUM      0x01001900
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
@@ -289,7 +289,7 @@ struct vmxnet3_rx_queue {
 
 #define VMXNET3_LINUX_MAX_MSIX_VECT     (VMXNET3_DEVICE_MAX_TX_QUEUES + \
                                         VMXNET3_DEVICE_MAX_RX_QUEUES + 1)
-#define VMXNET3_LINUX_MIN_MSIX_VECT     3    /* 1 for each : tx, rx and event */
+#define VMXNET3_LINUX_MIN_MSIX_VECT     2 /* 1 for tx-rx pair and 1 for event */
 
 
 struct vmxnet3_intr {
@@ -317,6 +317,7 @@ struct vmxnet3_adapter {
        struct vmxnet3_rx_queue         rx_queue[VMXNET3_DEVICE_MAX_RX_QUEUES];
        struct vlan_group               *vlan_grp;
        struct vmxnet3_intr             intr;
+       spinlock_t                      cmd_lock;
        struct Vmxnet3_DriverShared     *shared;
        struct Vmxnet3_PMConf           *pm_conf;
        struct Vmxnet3_TxQueueDesc      *tqd_start;     /* all tx queue desc */
index 01c05f5..228d4f7 100644 (file)
@@ -3690,7 +3690,7 @@ __vxge_hw_vpath_rts_table_get(struct __vxge_hw_vpath_handle *vp,
        if (status != VXGE_HW_OK)
                goto exit;
 
-       if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
+       if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) &&
            (rts_table !=
             VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
                *data1 = 0;
index 019a74d..09ae4ef 100644 (file)
@@ -2294,6 +2294,8 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
        int i;
        bool needreset = false;
 
+       mutex_lock(&sc->lock);
+
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
                if (sc->txqs[i].setup) {
                        txq = &sc->txqs[i];
@@ -2321,6 +2323,8 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
                ath5k_reset(sc, NULL, true);
        }
 
+       mutex_unlock(&sc->lock);
+
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
                msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
 }
index 0064be7..21091c2 100644 (file)
@@ -838,9 +838,9 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah)
        for (i = 0; i < qmax; i++) {
                err = ath5k_hw_stop_tx_dma(ah, i);
                /* -EINVAL -> queue inactive */
-               if (err != -EINVAL)
+               if (err && err != -EINVAL)
                        return err;
        }
 
-       return err;
+       return 0;
 }
index e5f2b96..a702817 100644 (file)
@@ -86,7 +86,7 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
        if (!ah->ah_bwmode) {
                dur = ieee80211_generic_frame_duration(sc->hw,
                                                NULL, len, rate);
-               return dur;
+               return le16_to_cpu(dur);
        }
 
        bitrate = rate->bitrate;
@@ -265,8 +265,6 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
                 * what rate we should choose to TX ACKs. */
                tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
 
-               tx_time = le16_to_cpu(tx_time);
-
                ath5k_hw_reg_write(ah, tx_time, reg);
 
                if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
index 78c26fd..62ce2f4 100644 (file)
@@ -282,6 +282,34 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah)
        return 0;
 }
 
+/*
+ * Wait for synth to settle
+ */
+static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
+                       struct ieee80211_channel *channel)
+{
+       /*
+        * On 5211+ read activation -> rx delay
+        * and use it (100ns steps).
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               u32 delay;
+               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+                       AR5K_PHY_RX_DELAY_M;
+               delay = (channel->hw_value & CHANNEL_CCK) ?
+                       ((delay << 2) / 22) : (delay / 10);
+               if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
+                       delay = delay << 1;
+               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
+                       delay = delay << 2;
+               /* XXX: /2 on turbo ? Let's be safe
+                * for now */
+               udelay(100 + delay);
+       } else {
+               mdelay(1);
+       }
+}
+
 
 /**********************\
 * RF Gain optimization *
@@ -1253,6 +1281,7 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
        case AR5K_RF5111:
                ret = ath5k_hw_rf5111_channel(ah, channel);
                break;
+       case AR5K_RF2317:
        case AR5K_RF2425:
                ret = ath5k_hw_rf2425_channel(ah, channel);
                break;
@@ -3237,6 +3266,13 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                /* Failed */
                if (i >= 100)
                        return -EIO;
+
+               /* Set channel and wait for synth */
+               ret = ath5k_hw_channel(ah, channel);
+               if (ret)
+                       return ret;
+
+               ath5k_hw_wait_for_synth(ah, channel);
        }
 
        /*
@@ -3251,13 +3287,53 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        if (ret)
                return ret;
 
+       /* Write OFDM timings on 5212*/
+       if (ah->ah_version == AR5K_AR5212 &&
+               channel->hw_value & CHANNEL_OFDM) {
+
+               ret = ath5k_hw_write_ofdm_timings(ah, channel);
+               if (ret)
+                       return ret;
+
+               /* Spur info is available only from EEPROM versions
+                * greater than 5.3, but the EEPROM routines will use
+                * static values for older versions */
+               if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
+                       ath5k_hw_set_spur_mitigation_filter(ah,
+                                                           channel);
+       }
+
+       /* If we used fast channel switching
+        * we are done, release RF bus and
+        * fire up NF calibration.
+        *
+        * Note: Only NF calibration due to
+        * channel change, not AGC calibration
+        * since AGC is still running !
+        */
+       if (fast) {
+               /*
+                * Release RF Bus grant
+                */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+                                   AR5K_PHY_RFBUS_REQ_REQUEST);
+
+               /*
+                * Start NF calibration
+                */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                                       AR5K_PHY_AGCCTL_NF);
+
+               return ret;
+       }
+
        /*
         * For 5210 we do all initialization using
         * initvals, so we don't have to modify
         * any settings (5210 also only supports
         * a/aturbo modes)
         */
-       if ((ah->ah_version != AR5K_AR5210) && !fast) {
+       if (ah->ah_version != AR5K_AR5210) {
 
                /*
                 * Write initial RF gain settings
@@ -3276,22 +3352,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                if (ret)
                        return ret;
 
-               /* Write OFDM timings on 5212*/
-               if (ah->ah_version == AR5K_AR5212 &&
-                       channel->hw_value & CHANNEL_OFDM) {
-
-                       ret = ath5k_hw_write_ofdm_timings(ah, channel);
-                       if (ret)
-                               return ret;
-
-                       /* Spur info is available only from EEPROM versions
-                        * greater than 5.3, but the EEPROM routines will use
-                        * static values for older versions */
-                       if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
-                               ath5k_hw_set_spur_mitigation_filter(ah,
-                                                                   channel);
-               }
-
                /*Enable/disable 802.11b mode on 5111
                (enable 2111 frequency converter + CCK)*/
                if (ah->ah_radio == AR5K_RF5111) {
@@ -3322,47 +3382,20 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
         */
        ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 
+       ath5k_hw_wait_for_synth(ah, channel);
+
        /*
-        * On 5211+ read activation -> rx delay
-        * and use it.
+        * Perform ADC test to see if baseband is ready
+        * Set tx hold and check adc test register
         */
-       if (ah->ah_version != AR5K_AR5210) {
-               u32 delay;
-               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
-                       AR5K_PHY_RX_DELAY_M;
-               delay = (channel->hw_value & CHANNEL_CCK) ?
-                       ((delay << 2) / 22) : (delay / 10);
-               if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
-                       delay = delay << 1;
-               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
-                       delay = delay << 2;
-               /* XXX: /2 on turbo ? Let's be safe
-                * for now */
-               udelay(100 + delay);
-       } else {
-               mdelay(1);
-       }
-
-       if (fast)
-               /*
-                * Release RF Bus grant
-                */
-               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
-                                   AR5K_PHY_RFBUS_REQ_REQUEST);
-       else {
-               /*
-                * Perform ADC test to see if baseband is ready
-                * Set tx hold and check adc test register
-                */
-               phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
-               ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
-               for (i = 0; i <= 20; i++) {
-                       if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
-                               break;
-                       udelay(200);
-               }
-               ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+       phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+       ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+       for (i = 0; i <= 20; i++) {
+               if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+                       break;
+               udelay(200);
        }
+       ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
 
        /*
         * Start automatic gain control calibration
index ea2e7d7..5e300bd 100644 (file)
@@ -679,10 +679,6 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 
        /* Do NF cal only at longer intervals */
        if (longcal || nfcal_pending) {
-               /* Do periodic PAOffset Cal */
-               ar9002_hw_pa_cal(ah, false);
-               ar9002_hw_olc_temp_compensation(ah);
-
                /*
                 * Get the value from the previous NF cal and update
                 * history buffer.
@@ -697,8 +693,12 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
                        ath9k_hw_loadnf(ah, ah->curchan);
                }
 
-               if (longcal)
+               if (longcal) {
                        ath9k_hw_start_nfcal(ah, false);
+                       /* Do periodic PAOffset Cal */
+                       ar9002_hw_pa_cal(ah, false);
+                       ar9002_hw_olc_temp_compensation(ah);
+               }
        }
 
        return iscaldone;
index f8a7771..f44c84a 100644 (file)
@@ -426,9 +426,8 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
                }
 
                /* WAR for ASPM system hang */
-               if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+               if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
                        val |= (AR_WA_BIT6 | AR_WA_BIT7);
-               }
 
                if (AR_SREV_9285E_20(ah))
                        val |= AR_WA_BIT23;
index 81f9cf2..9ecca93 100644 (file)
@@ -1842,7 +1842,7 @@ static const u32 ar9300_2p2_soc_preamble[][2] = {
 
 static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
        /* Addr      allmodes  */
-       {0x00004040, 0x08212e5e},
+       {0x00004040, 0x0821265e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
 };
index 6137634..06fb2c8 100644 (file)
@@ -146,8 +146,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                /* Sleep Setting */
 
                INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                               ar9300PciePhy_clkreq_enable_L1_2p2,
-                               ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+                               ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+                               ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
                                2);
 
                /* Fast clock modal settings */
index 3681caf..1a7fa6e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/device.h>
 #include <linux/leds.h>
 #include <linux/completion.h>
-#include <linux/pm_qos_params.h>
 
 #include "debug.h"
 #include "common.h"
@@ -57,8 +56,6 @@ struct ath_node;
 
 #define A_MAX(a, b) ((a) > (b) ? (a) : (b))
 
-#define ATH9K_PM_QOS_DEFAULT_VALUE     55
-
 #define TSF_TO_TU(_h,_l) \
        ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
@@ -218,6 +215,7 @@ struct ath_frame_info {
 struct ath_buf_state {
        u8 bf_type;
        u8 bfs_paprd;
+       unsigned long bfs_paprd_timestamp;
        enum ath9k_internal_frame_type bfs_ftype;
 };
 
@@ -593,7 +591,6 @@ struct ath_softc {
        struct work_struct paprd_work;
        struct work_struct hw_check_work;
        struct completion paprd_complete;
-       bool paprd_pending;
 
        u32 intrstatus;
        u32 sc_flags; /* SC_OP_* */
@@ -633,8 +630,6 @@ struct ath_softc {
        struct ath_descdma txsdma;
 
        struct ath_ant_comb ant_comb;
-
-       struct pm_qos_request_list pm_qos_req;
 };
 
 struct ath_wiphy {
@@ -666,7 +661,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 extern struct ieee80211_ops ath9k_ops;
 extern int ath9k_modparam_nohwcrypt;
 extern int led_blink;
-extern int ath9k_pm_qos_value;
 extern bool is_ath9k_unloaded;
 
 irqreturn_t ath_isr(int irq, void *dev);
index 5ab3084..07b1633 100644 (file)
@@ -219,8 +219,9 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
        struct tx_buf *tx_buf = NULL;
        struct sk_buff *nskb = NULL;
        int ret = 0, i;
-       u16 *hdr, tx_skb_cnt = 0;
+       u16 tx_skb_cnt = 0;
        u8 *buf;
+       __le16 *hdr;
 
        if (hif_dev->tx.tx_skb_cnt == 0)
                return 0;
@@ -245,9 +246,9 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
 
                buf = tx_buf->buf;
                buf += tx_buf->offset;
-               hdr = (u16 *)buf;
-               *hdr++ = nskb->len;
-               *hdr++ = ATH_USB_TX_STREAM_MODE_TAG;
+               hdr = (__le16 *)buf;
+               *hdr++ = cpu_to_le16(nskb->len);
+               *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
                buf += 4;
                memcpy(buf, nskb->data, nskb->len);
                tx_buf->len = nskb->len + 4;
index 1ce506f..780ac5e 100644 (file)
@@ -78,7 +78,7 @@ struct tx_frame_hdr {
        u8 node_idx;
        u8 vif_idx;
        u8 tidno;
-       u32 flags; /* ATH9K_HTC_TX_* */
+       __be32 flags; /* ATH9K_HTC_TX_* */
        u8 key_type;
        u8 keyix;
        u8 reserved[26];
index 38433f9..0352f09 100644 (file)
@@ -142,9 +142,6 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
 {
        ath9k_htc_exit_debug(priv->ah);
        ath9k_hw_deinit(priv->ah);
-       tasklet_kill(&priv->swba_tasklet);
-       tasklet_kill(&priv->rx_tasklet);
-       tasklet_kill(&priv->tx_tasklet);
        kfree(priv->ah);
        priv->ah = NULL;
 }
index f4d576b..6bb5995 100644 (file)
@@ -1025,12 +1025,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        int ret = 0;
        u8 cmd_rsp;
 
-       /* Cancel all the running timers/work .. */
-       cancel_work_sync(&priv->fatal_work);
-       cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
-       ath9k_led_stop_brightness(priv);
-
        mutex_lock(&priv->mutex);
 
        if (priv->op_flags & OP_INVALID) {
@@ -1044,8 +1038,23 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
        WMI_CMD(WMI_STOP_RECV_CMDID);
+
+       tasklet_kill(&priv->swba_tasklet);
+       tasklet_kill(&priv->rx_tasklet);
+       tasklet_kill(&priv->tx_tasklet);
+
        skb_queue_purge(&priv->tx_queue);
 
+       mutex_unlock(&priv->mutex);
+
+       /* Cancel all the running timers/work .. */
+       cancel_work_sync(&priv->fatal_work);
+       cancel_work_sync(&priv->ps_work);
+       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+       ath9k_led_stop_brightness(priv);
+
+       mutex_lock(&priv->mutex);
+
        /* Remove monitor interface here */
        if (ah->opmode == NL80211_IFTYPE_MONITOR) {
                if (ath9k_htc_remove_monitor_interface(priv))
index 33f3602..7a5ffca 100644 (file)
@@ -113,6 +113,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
 
        if (ieee80211_is_data(fc)) {
                struct tx_frame_hdr tx_hdr;
+               u32 flags = 0;
                u8 *qc;
 
                memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
@@ -136,13 +137,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
                /* Check for RTS protection */
                if (priv->hw->wiphy->rts_threshold != (u32) -1)
                        if (skb->len > priv->hw->wiphy->rts_threshold)
-                               tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS;
+                               flags |= ATH9K_HTC_TX_RTSCTS;
 
                /* CTS-to-self */
-               if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) &&
+               if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
                    (priv->op_flags & OP_PROTECT_ENABLE))
-                       tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY;
+                       flags |= ATH9K_HTC_TX_CTSONLY;
 
+               tx_hdr.flags = cpu_to_be32(flags);
                tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
                if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
                        tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
index 1afb8bb..9f01e50 100644 (file)
@@ -369,6 +369,9 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        else
                ah->config.ht_enable = 0;
 
+       /* PAPRD needs some more work to be enabled */
+       ah->config.paprd_disable = 1;
+
        ah->config.rx_intr_mitigation = true;
        ah->config.pcieSerDesWrite = true;
 
@@ -1933,7 +1936,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->rx_status_len = sizeof(struct ar9003_rxs);
                pCap->tx_desc_len = sizeof(struct ar9003_txc);
                pCap->txs_len = sizeof(struct ar9003_txs);
-               if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+               if (!ah->config.paprd_disable &&
+                   ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
        } else {
                pCap->tx_desc_len = sizeof(struct ath_desc);
index 5a3dfec..ea9fde6 100644 (file)
@@ -225,6 +225,7 @@ struct ath9k_ops_config {
        u32 pcie_waen;
        u8 analog_shiftreg;
        u8 ht_enable;
+       u8 paprd_disable;
        u32 ofdm_trig_low;
        u32 ofdm_trig_high;
        u32 cck_trig_high;
index 767d8b8..a033d01 100644 (file)
@@ -41,10 +41,6 @@ static int ath9k_btcoex_enable;
 module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
 MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
 
-int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE;
-module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH);
-MODULE_PARM_DESC(pmqos, "User specified PM-QOS value");
-
 bool is_ath9k_unloaded;
 /* We use the hw_value as an index into our private channel structure */
 
@@ -598,8 +594,6 @@ err_btcoex:
 err_queues:
        ath9k_hw_deinit(ah);
 err_hw:
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
 
        kfree(ah);
        sc->sc_ah = NULL;
@@ -764,9 +758,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
        ath_init_leds(sc);
        ath_start_rfkill_poll(sc);
 
-       pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
-
        return 0;
 
 error_world:
@@ -807,9 +798,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 
        ath9k_hw_deinit(sc->sc_ah);
 
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
-
        kfree(sc->sc_ah);
        sc->sc_ah = NULL;
 }
@@ -824,6 +812,8 @@ void ath9k_deinit_device(struct ath_softc *sc)
        wiphy_rfkill_stop_polling(sc->hw->wiphy);
        ath_deinit_leds(sc);
 
+       ath9k_ps_restore(sc);
+
        for (i = 0; i < sc->num_sec_wiphy; i++) {
                struct ath_wiphy *aphy = sc->sec_wiphy[i];
                if (aphy == NULL)
@@ -834,7 +824,6 @@ void ath9k_deinit_device(struct ath_softc *sc)
        }
 
        ieee80211_unregister_hw(hw);
-       pm_qos_remove_request(&sc->pm_qos_req);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
        ath9k_deinit_softc(sc);
index 180170d..2915b11 100644 (file)
@@ -885,7 +885,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
        struct ath_common *common = ath9k_hw_common(ah);
 
        if (!(ints & ATH9K_INT_GLOBAL))
-               ath9k_hw_enable_interrupts(ah);
+               ath9k_hw_disable_interrupts(ah);
 
        ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 
@@ -963,7 +963,8 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
                        REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
        }
 
-       ath9k_hw_enable_interrupts(ah);
+       if (ints & ATH9K_INT_GLOBAL)
+               ath9k_hw_enable_interrupts(ah);
 
        return;
 }
index f90a6ca..a09d15f 100644 (file)
@@ -325,6 +325,8 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
 {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_tx_control txctl;
        int time_left;
 
@@ -340,14 +342,16 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
        tx_info->control.rates[1].idx = -1;
 
        init_completion(&sc->paprd_complete);
-       sc->paprd_pending = true;
        txctl.paprd = BIT(chain);
-       if (ath_tx_start(hw, skb, &txctl) != 0)
+
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
+               ath_dbg(common, ATH_DBG_XMIT, "PAPRD TX failed\n");
+               dev_kfree_skb_any(skb);
                return false;
+       }
 
        time_left = wait_for_completion_timeout(&sc->paprd_complete,
                        msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
-       sc->paprd_pending = false;
 
        if (!time_left)
                ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CALIBRATE,
@@ -592,14 +596,12 @@ void ath9k_tasklet(unsigned long data)
        u32 status = sc->intrstatus;
        u32 rxmask;
 
-       ath9k_ps_wakeup(sc);
-
        if (status & ATH9K_INT_FATAL) {
                ath_reset(sc, true);
-               ath9k_ps_restore(sc);
                return;
        }
 
+       ath9k_ps_wakeup(sc);
        spin_lock(&sc->sc_pcu_lock);
 
        if (!ath9k_hw_check_alive(ah))
@@ -955,8 +957,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
-
-       ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 }
 
 int ath_reset(struct ath_softc *sc, bool retry_tx)
@@ -969,6 +969,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        /* Stop ANI */
        del_timer_sync(&common->ani.timer);
 
+       ath9k_ps_wakeup(sc);
        spin_lock_bh(&sc->sc_pcu_lock);
 
        ieee80211_stop_queues(hw);
@@ -1015,6 +1016,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 
        /* Start ANI */
        ath_start_ani(common);
+       ath9k_ps_restore(sc);
 
        return r;
 }
@@ -1171,12 +1173,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
                        ath9k_btcoex_timer_resume(sc);
        }
 
-       /* User has the option to provide pm-qos value as a module
-        * parameter rather than using the default value of
-        * 'ATH9K_PM_QOS_DEFAULT_VALUE'.
-        */
-       pm_qos_update_request(&sc->pm_qos_req, ath9k_pm_qos_value);
-
        if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
                common->bus_ops->extn_synch_en(common);
 
@@ -1309,6 +1305,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        spin_lock_bh(&sc->sc_pcu_lock);
 
+       /* prevent tasklets to enable interrupts once we disable them */
+       ah->imask &= ~ATH9K_INT_GLOBAL;
+
        /* make sure h/w will not generate any interrupt
         * before setting the invalid flag. */
        ath9k_hw_disable_interrupts(ah);
@@ -1326,6 +1325,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
 
+       /* we can now sync irq and kill any running tasklets, since we already
+        * disabled interrupts and not holding a spin lock */
+       synchronize_irq(sc->irq);
+       tasklet_kill(&sc->intr_tq);
+       tasklet_kill(&sc->bcon_tasklet);
+
        ath9k_ps_restore(sc);
 
        sc->ps_idle = true;
@@ -1334,8 +1339,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        sc->sc_flags |= SC_OP_INVALID;
 
-       pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE);
-
        mutex_unlock(&sc->mutex);
 
        ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
@@ -1701,7 +1704,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
                sc->config.txpowlimit = 2 * conf->power_level;
+               ath9k_ps_wakeup(sc);
                ath_update_txpow(sc);
+               ath9k_ps_restore(sc);
        }
 
        spin_lock_bh(&sc->wiphy_lock);
index 332d1fe..07b7804 100644 (file)
@@ -1725,6 +1725,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                        ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
                                                   bf->bf_state.bfs_paprd);
 
+               if (txctl->paprd)
+                       bf->bf_state.bfs_paprd_timestamp = jiffies;
+
                ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
        }
 
@@ -1886,7 +1889,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
        bf->bf_buf_addr = 0;
 
        if (bf->bf_state.bfs_paprd) {
-               if (!sc->paprd_pending)
+               if (time_after(jiffies,
+                               bf->bf_state.bfs_paprd_timestamp +
+                               msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
                        dev_kfree_skb_any(skb);
                else
                        complete(&sc->paprd_complete);
@@ -2113,9 +2118,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
        if (needreset) {
                ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
                        "tx hung, resetting the chip\n");
-               ath9k_ps_wakeup(sc);
                ath_reset(sc, true);
-               ath9k_ps_restore(sc);
        }
 
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
index 939a0e9..84866a4 100644 (file)
@@ -564,7 +564,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
        cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
 
        /* 2. Maybe the AP wants to send multicast/broadcast data? */
-       cam = !!(tim_ie->bitmap_ctrl & 0x01);
+       cam |= !!(tim_ie->bitmap_ctrl & 0x01);
 
        if (!cam) {
                /* back to low-power land. */
index 537732e..f82c400 100644 (file)
@@ -118,6 +118,8 @@ static struct usb_device_id carl9170_usb_ids[] = {
        { USB_DEVICE(0x057c, 0x8402) },
        /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
        { USB_DEVICE(0x1668, 0x1200) },
+       /* Airlive X.USB a/b/g/n */
+       { USB_DEVICE(0x1b75, 0x9170) },
 
        /* terminate */
        {}
index a9b852b..39b6f16 100644 (file)
@@ -402,72 +402,6 @@ static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
 }
 #endif
 
-/**
- * iwl3945_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
-                               struct iwl_rx_packet *pkt)
-{
-       bool rc = true;
-       struct iwl3945_notif_statistics current_stat;
-       int combined_plcp_delta;
-       unsigned int plcp_msec;
-       unsigned long plcp_received_jiffies;
-
-       if (priv->cfg->base_params->plcp_delta_threshold ==
-           IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
-               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
-               return rc;
-       }
-       memcpy(&current_stat, pkt->u.raw, sizeof(struct
-                       iwl3945_notif_statistics));
-       /*
-        * check for plcp_err and trigger radio reset if it exceeds
-        * the plcp error threshold plcp_delta.
-        */
-       plcp_received_jiffies = jiffies;
-       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
-                                       (long) priv->plcp_jiffies);
-       priv->plcp_jiffies = plcp_received_jiffies;
-       /*
-        * check to make sure plcp_msec is not 0 to prevent division
-        * by zero.
-        */
-       if (plcp_msec) {
-               combined_plcp_delta =
-                       (le32_to_cpu(current_stat.rx.ofdm.plcp_err) -
-                       le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err));
-
-               if ((combined_plcp_delta > 0) &&
-                       ((combined_plcp_delta * 100) / plcp_msec) >
-                       priv->cfg->base_params->plcp_delta_threshold) {
-                       /*
-                        * if plcp_err exceed the threshold, the following
-                        * data is printed in csv format:
-                        *    Text: plcp_err exceeded %d,
-                        *    Received ofdm.plcp_err,
-                        *    Current ofdm.plcp_err,
-                        *    combined_plcp_delta,
-                        *    plcp_msec
-                        */
-                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
-                               "%u, %d, %u mSecs\n",
-                               priv->cfg->base_params->plcp_delta_threshold,
-                               le32_to_cpu(current_stat.rx.ofdm.plcp_err),
-                               combined_plcp_delta, plcp_msec);
-                       /*
-                        * Reset the RF radio due to the high plcp
-                        * error rate
-                        */
-                       rc = false;
-               }
-       }
-       return rc;
-}
-
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                struct iwl_rx_mem_buffer *rxb)
 {
@@ -2734,7 +2668,6 @@ static struct iwl_lib_ops iwl3945_lib = {
        .isr_ops = {
                .isr = iwl_isr_legacy,
        },
-       .check_plcp_health = iwl3945_good_plcp_health,
 
        .debugfs_ops = {
                .rx_stats_read = iwl3945_ucode_rx_stats_read,
index 3f1e5f1..91a9f52 100644 (file)
@@ -2624,6 +2624,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .fw_name_pre = IWL4965_FW_PRE,
        .ucode_api_max = IWL4965_UCODE_API_MAX,
        .ucode_api_min = IWL4965_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
index 79ab0a6..537fb8c 100644 (file)
@@ -51,7 +51,7 @@
 #include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 2
+#define IWL5000_UCODE_API_MAX 5
 #define IWL5150_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
index af505bc..ef36aff 100644 (file)
@@ -681,6 +681,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,                          \
        .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
        .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
        .ops = &iwl6050_ops,                                    \
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,       \
index 97906dd..27b5a3e 100644 (file)
@@ -152,11 +152,14 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
 
        eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
 
-       priv->cfg->sku = ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
+       if (!priv->cfg->sku) {
+               /* not using sku overwrite */
+               priv->cfg->sku =
+                       ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
                        EEPROM_SKU_CAP_BAND_POS);
-       if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
-               priv->cfg->sku |= IWL_SKU_N;
-
+               if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
+                       priv->cfg->sku |= IWL_SKU_N;
+       }
        if (!priv->cfg->sku) {
                IWL_ERR(priv, "Invalid device sku\n");
                return -EINVAL;
@@ -168,7 +171,7 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
                /* not using .cfg overwrite */
                radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
                priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
-               priv->cfg->valid_rx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+               priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
                if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
                        IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
                                priv->cfg->valid_tx_ant,
index 36335b1..c1cfd99 100644 (file)
@@ -1157,6 +1157,9 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
        /* only Re-enable if disabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
+       /* Re-enable RF_KILL if it occurred */
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
@@ -1371,6 +1374,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
        /* only Re-enable if disabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
+       /* Re-enable RF_KILL if it occurred */
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(priv);
 }
 
 /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
index 13a69eb..5091d77 100644 (file)
@@ -126,6 +126,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
        ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
        if (!ndev) {
                dev_err(dev, "no memory for network device instance\n");
+               ret = -ENOMEM;
                goto out_priv;
        }
 
@@ -138,6 +139,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
                                    GFP_KERNEL);
        if (!iwm->umac_profile) {
                dev_err(dev, "Couldn't alloc memory for profile\n");
+               ret = -ENOMEM;
                goto out_profile;
        }
 
index 1eacba4..0494d7b 100644 (file)
@@ -199,6 +199,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
        while (i != idx) {
                u16 len;
                struct sk_buff *skb;
+               dma_addr_t dma_addr;
                desc = &ring[i];
                len = le16_to_cpu(desc->len);
                skb = rx_buf[i];
@@ -216,17 +217,20 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
 
                        len = priv->common.rx_mtu;
                }
+               dma_addr = le32_to_cpu(desc->host_addr);
+               pci_dma_sync_single_for_cpu(priv->pdev, dma_addr,
+                       priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                skb_put(skb, len);
 
                if (p54_rx(dev, skb)) {
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        priv->common.rx_mtu + 32,
-                                        PCI_DMA_FROMDEVICE);
+                       pci_unmap_single(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                        rx_buf[i] = NULL;
-                       desc->host_addr = 0;
+                       desc->host_addr = cpu_to_le32(0);
                } else {
                        skb_trim(skb, 0);
+                       pci_dma_sync_single_for_device(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                        desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
                }
 
index 21713a7..9b344a9 100644 (file)
@@ -98,6 +98,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
        {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
        {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
+       {USB_DEVICE(0x1740, 0x1000)},   /* Senao NUB-350 */
        {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
        {USB_DEVICE(0x2001, 0x3705)},   /* D-Link DWL-G120 rev C1 */
        {USB_DEVICE(0x413c, 0x5513)},   /* Dell WLA3310 USB Wireless Adapter */
index 848cc2c..518542b 100644 (file)
@@ -2597,6 +2597,9 @@ static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        __le32 mode;
        int ret;
 
+       if (priv->device_type != RNDIS_BCM4320B)
+               return -ENOTSUPP;
+
        netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__,
                                enabled ? "enabled" : "disabled",
                                timeout);
index aa97971..3b3f1e4 100644 (file)
@@ -652,6 +652,12 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
 
+               /*
+                * The hardware has already checked the Michael Mic and has
+                * stripped it from the frame. Signal this to mac80211.
+                */
+               rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
                if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
                        rxdesc->flags |= RX_FLAG_DECRYPTED;
                else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
@@ -1065,6 +1071,8 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT35XX
+       { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) },
+       { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
index b97a4a5..197a36c 100644 (file)
@@ -486,6 +486,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
 
+               /*
+                * The hardware has already checked the Michael Mic and has
+                * stripped it from the frame. Signal this to mac80211.
+                */
+               rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
                if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
                        rxdesc->flags |= RX_FLAG_DECRYPTED;
                else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
index f0e1eb7..be0ff78 100644 (file)
@@ -58,6 +58,7 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
 
        if (!fw || !fw->size || !fw->data) {
                ERROR(rt2x00dev, "Failed to read Firmware.\n");
+               release_firmware(fw);
                return -ENOENT;
        }
 
index 0b4e859..029be3c 100644 (file)
@@ -2446,6 +2446,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
index b8433f3..62876cd 100644 (file)
@@ -726,9 +726,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
 }
 
 static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
-                               u8 efuse_data, u8 offset, int *bcontinual,
-                               u8 *write_state, struct pgpkt_struct target_pkt,
-                               int *repeat_times, int *bresult, u8 word_en)
+                       u8 efuse_data, u8 offset, int *bcontinual,
+                       u8 *write_state, struct pgpkt_struct *target_pkt,
+                       int *repeat_times, int *bresult, u8 word_en)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct pgpkt_struct tmp_pkt;
@@ -744,8 +744,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
        tmp_pkt.word_en = tmp_header & 0x0F;
        tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
 
-       if (tmp_pkt.offset != target_pkt.offset) {
-               efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+       if (tmp_pkt.offset != target_pkt->offset) {
+               *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
                *write_state = PG_STATE_HEADER;
        } else {
                for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
@@ -756,23 +756,23 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                }
 
                if (bdataempty == false) {
-                       efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+                       *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
                        *write_state = PG_STATE_HEADER;
                } else {
                        match_word_en = 0x0F;
-                       if (!((target_pkt.word_en & BIT(0)) |
+                       if (!((target_pkt->word_en & BIT(0)) |
                             (tmp_pkt.word_en & BIT(0))))
                                match_word_en &= (~BIT(0));
 
-                       if (!((target_pkt.word_en & BIT(1)) |
+                       if (!((target_pkt->word_en & BIT(1)) |
                             (tmp_pkt.word_en & BIT(1))))
                                match_word_en &= (~BIT(1));
 
-                       if (!((target_pkt.word_en & BIT(2)) |
+                       if (!((target_pkt->word_en & BIT(2)) |
                             (tmp_pkt.word_en & BIT(2))))
                                match_word_en &= (~BIT(2));
 
-                       if (!((target_pkt.word_en & BIT(3)) |
+                       if (!((target_pkt->word_en & BIT(3)) |
                             (tmp_pkt.word_en & BIT(3))))
                                match_word_en &= (~BIT(3));
 
@@ -780,7 +780,7 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                badworden = efuse_word_enable_data_write(
                                                            hw, *efuse_addr + 1,
                                                            tmp_pkt.word_en,
-                                                           target_pkt.data);
+                                                           target_pkt->data);
 
                                if (0x0F != (badworden & 0x0F)) {
                                        u8 reorg_offset = offset;
@@ -791,26 +791,26 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                }
 
                                tmp_word_en = 0x0F;
-                               if ((target_pkt.word_en & BIT(0)) ^
+                               if ((target_pkt->word_en & BIT(0)) ^
                                    (match_word_en & BIT(0)))
                                        tmp_word_en &= (~BIT(0));
 
-                               if ((target_pkt.word_en & BIT(1)) ^
+                               if ((target_pkt->word_en & BIT(1)) ^
                                    (match_word_en & BIT(1)))
                                        tmp_word_en &= (~BIT(1));
 
-                               if ((target_pkt.word_en & BIT(2)) ^
+                               if ((target_pkt->word_en & BIT(2)) ^
                                        (match_word_en & BIT(2)))
                                        tmp_word_en &= (~BIT(2));
 
-                               if ((target_pkt.word_en & BIT(3)) ^
+                               if ((target_pkt->word_en & BIT(3)) ^
                                    (match_word_en & BIT(3)))
                                        tmp_word_en &= (~BIT(3));
 
                                if ((tmp_word_en & 0x0F) != 0x0F) {
                                        *efuse_addr = efuse_get_current_size(hw);
-                                       target_pkt.offset = offset;
-                                       target_pkt.word_en = tmp_word_en;
+                                       target_pkt->offset = offset;
+                                       target_pkt->word_en = tmp_word_en;
                                } else
                                        *bcontinual = false;
                                *write_state = PG_STATE_HEADER;
@@ -821,8 +821,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                }
                        } else {
                                *efuse_addr += (2 * tmp_word_cnts) + 1;
-                               target_pkt.offset = offset;
-                               target_pkt.word_en = word_en;
+                               target_pkt->offset = offset;
+                               target_pkt->word_en = word_en;
                                *write_state = PG_STATE_HEADER;
                        }
                }
@@ -938,7 +938,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
                                efuse_write_data_case1(hw, &efuse_addr,
                                                       efuse_data, offset,
                                                       &bcontinual,
-                                                      &write_state, target_pkt,
+                                                      &write_state, &target_pkt,
                                                       &repeat_times, &bresult,
                                                       word_en);
                        else
index 0fa36aa..1758d44 100644 (file)
@@ -619,6 +619,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                        struct sk_buff *uskb = NULL;
                                        u8 *pdata;
                                        uskb = dev_alloc_skb(skb->len + 128);
+                                       if (!uskb) {
+                                               RT_TRACE(rtlpriv,
+                                                       (COMP_INTR | COMP_RECV),
+                                                       DBG_EMERG,
+                                                       ("can't alloc rx skb\n"));
+                                               goto done;
+                                       }
                                        memcpy(IEEE80211_SKB_RXCB(uskb),
                                                        &rx_status,
                                                        sizeof(rx_status));
@@ -641,7 +648,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
                        if (unlikely(!new_skb)) {
                                RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-                                        DBG_DMESG,
+                                        DBG_EMERG,
                                         ("can't alloc skb for rx\n"));
                                goto done;
                        }
@@ -1066,9 +1073,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                        struct sk_buff *skb =
                            dev_alloc_skb(rtlpci->rxbuffersize);
                        u32 bufferaddress;
-                       entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
                        if (!skb)
                                return 0;
+                       entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
 
                        /*skb->dev = dev; */
 
index 012e1a4..40372ba 100644 (file)
@@ -1039,6 +1039,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
+               if (!beacon)
+                       goto out_sleep;
+
                ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
                                              beacon->len);
 
index 4671491..7145ea5 100644 (file)
@@ -110,9 +110,8 @@ static void wl1271_spi_reset(struct wl1271 *wl)
        spi_message_add_tail(&t, &m);
 
        spi_sync(wl_to_spi(wl), &m);
-       kfree(cmd);
-
        wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+       kfree(cmd);
 }
 
 static void wl1271_spi_init(struct wl1271 *wl)
index 546de57..da1f121 100644 (file)
@@ -120,6 +120,9 @@ struct netfront_info {
        unsigned long rx_pfn_array[NET_RX_RING_SIZE];
        struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
        struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+
+       /* Statistics */
+       int rx_gso_checksum_fixup;
 };
 
 struct netfront_rx_info {
@@ -770,11 +773,29 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
        return cons;
 }
 
-static int skb_checksum_setup(struct sk_buff *skb)
+static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
 {
        struct iphdr *iph;
        unsigned char *th;
        int err = -EPROTO;
+       int recalculate_partial_csum = 0;
+
+       /*
+        * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
+        * peers can fail to set NETRXF_csum_blank when sending a GSO
+        * frame. In this case force the SKB to CHECKSUM_PARTIAL and
+        * recalculate the partial checksum.
+        */
+       if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
+               struct netfront_info *np = netdev_priv(dev);
+               np->rx_gso_checksum_fixup++;
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               recalculate_partial_csum = 1;
+       }
+
+       /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
 
        if (skb->protocol != htons(ETH_P_IP))
                goto out;
@@ -788,9 +809,23 @@ static int skb_checksum_setup(struct sk_buff *skb)
        switch (iph->protocol) {
        case IPPROTO_TCP:
                skb->csum_offset = offsetof(struct tcphdr, check);
+
+               if (recalculate_partial_csum) {
+                       struct tcphdr *tcph = (struct tcphdr *)th;
+                       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        skb->len - iph->ihl*4,
+                                                        IPPROTO_TCP, 0);
+               }
                break;
        case IPPROTO_UDP:
                skb->csum_offset = offsetof(struct udphdr, check);
+
+               if (recalculate_partial_csum) {
+                       struct udphdr *udph = (struct udphdr *)th;
+                       udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        skb->len - iph->ihl*4,
+                                                        IPPROTO_UDP, 0);
+               }
                break;
        default:
                if (net_ratelimit())
@@ -829,13 +864,11 @@ static int handle_incoming_queue(struct net_device *dev,
                /* Ethernet work: Delayed to here as it peeks the header. */
                skb->protocol = eth_type_trans(skb, dev);
 
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       if (skb_checksum_setup(skb)) {
-                               kfree_skb(skb);
-                               packets_dropped++;
-                               dev->stats.rx_errors++;
-                               continue;
-                       }
+               if (checksum_setup(dev, skb)) {
+                       kfree_skb(skb);
+                       packets_dropped++;
+                       dev->stats.rx_errors++;
+                       continue;
                }
 
                dev->stats.rx_packets++;
@@ -1632,12 +1665,59 @@ static void netback_changed(struct xenbus_device *dev,
        }
 }
 
+static const struct xennet_stat {
+       char name[ETH_GSTRING_LEN];
+       u16 offset;
+} xennet_stats[] = {
+       {
+               "rx_gso_checksum_fixup",
+               offsetof(struct netfront_info, rx_gso_checksum_fixup)
+       },
+};
+
+static int xennet_get_sset_count(struct net_device *dev, int string_set)
+{
+       switch (string_set) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(xennet_stats);
+       default:
+               return -EINVAL;
+       }
+}
+
+static void xennet_get_ethtool_stats(struct net_device *dev,
+                                    struct ethtool_stats *stats, u64 * data)
+{
+       void *np = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_stats); i++)
+               data[i] = *(int *)(np + xennet_stats[i].offset);
+}
+
+static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < ARRAY_SIZE(xennet_stats); i++)
+                       memcpy(data + i * ETH_GSTRING_LEN,
+                              xennet_stats[i].name, ETH_GSTRING_LEN);
+               break;
+       }
+}
+
 static const struct ethtool_ops xennet_ethtool_ops =
 {
        .set_tx_csum = ethtool_op_set_tx_csum,
        .set_sg = xennet_set_sg,
        .set_tso = xennet_set_tso,
        .get_link = ethtool_op_get_link,
+
+       .get_sset_count = xennet_get_sset_count,
+       .get_ethtool_stats = xennet_get_ethtool_stats,
+       .get_strings = xennet_get_strings,
 };
 
 #ifdef CONFIG_SYSFS
index ffedfd4..ea15800 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig NFC_DEVICES
-       bool "NFC devices"
+       bool "Near Field Communication (NFC) devices"
        default n
        ---help---
          You'll have to say Y if your computer contains an NFC device that
index bae6472..724f65d 100644 (file)
@@ -60,7 +60,7 @@ enum pn544_irq {
 struct pn544_info {
        struct miscdevice miscdev;
        struct i2c_client *i2c_dev;
-       struct regulator_bulk_data regs[2];
+       struct regulator_bulk_data regs[3];
 
        enum pn544_state state;
        wait_queue_head_t read_wait;
@@ -74,6 +74,7 @@ struct pn544_info {
 
 static const char reg_vdd_io[] = "Vdd_IO";
 static const char reg_vbat[]   = "VBat";
+static const char reg_vsim[]   = "VSim";
 
 /* sysfs interface */
 static ssize_t pn544_test(struct device *dev,
@@ -740,6 +741,7 @@ static int __devinit pn544_probe(struct i2c_client *client,
 
        info->regs[0].supply = reg_vdd_io;
        info->regs[1].supply = reg_vbat;
+       info->regs[2].supply = reg_vsim;
        r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
                                 info->regs);
        if (r < 0)
index 28295d0..4d87b5d 100644 (file)
@@ -36,19 +36,55 @@ unsigned int of_pdt_unique_id __initdata;
        (p)->unique_id = of_pdt_unique_id++; \
 } while (0)
 
-static inline const char *of_pdt_node_name(struct device_node *dp)
+static char * __init of_pdt_build_full_name(struct device_node *dp)
 {
-       return dp->path_component_name;
+       int len, ourlen, plen;
+       char *n;
+
+       dp->path_component_name = build_path_component(dp);
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(dp->path_component_name);
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!of_node_is_root(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, dp->path_component_name);
+
+       return n;
 }
 
-#else
+#else /* CONFIG_SPARC */
 
 static inline void of_pdt_incr_unique_id(void *p) { }
 static inline void irq_trans_init(struct device_node *dp) { }
 
-static inline const char *of_pdt_node_name(struct device_node *dp)
+static char * __init of_pdt_build_full_name(struct device_node *dp)
 {
-       return dp->name;
+       static int failsafe_id = 0; /* for generating unique names on failure */
+       char *buf;
+       int len;
+
+       if (of_pdt_prom_ops->pkg2path(dp->phandle, NULL, 0, &len))
+               goto failsafe;
+
+       buf = prom_early_alloc(len + 1);
+       if (of_pdt_prom_ops->pkg2path(dp->phandle, buf, len, &len))
+               goto failsafe;
+       return buf;
+
+ failsafe:
+       buf = prom_early_alloc(strlen(dp->parent->full_name) +
+                              strlen(dp->name) + 16);
+       sprintf(buf, "%s/%s@unknown%i",
+               of_node_is_root(dp->parent) ? "" : dp->parent->full_name,
+               dp->name, failsafe_id++);
+       pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf);
+       return buf;
 }
 
 #endif /* !CONFIG_SPARC */
@@ -132,47 +168,6 @@ static char * __init of_pdt_get_one_property(phandle node, const char *name)
        return buf;
 }
 
-static char * __init of_pdt_try_pkg2path(phandle node)
-{
-       char *res, *buf = NULL;
-       int len;
-
-       if (!of_pdt_prom_ops->pkg2path)
-               return NULL;
-
-       if (of_pdt_prom_ops->pkg2path(node, buf, 0, &len))
-               return NULL;
-       buf = prom_early_alloc(len + 1);
-       if (of_pdt_prom_ops->pkg2path(node, buf, len, &len)) {
-               pr_err("%s: package-to-path failed\n", __func__);
-               return NULL;
-       }
-
-       res = strrchr(buf, '/');
-       if (!res) {
-               pr_err("%s: couldn't find / in %s\n", __func__, buf);
-               return NULL;
-       }
-       return res+1;
-}
-
-/*
- * When fetching the node's name, first try using package-to-path; if
- * that fails (either because the arch hasn't supplied a PROM callback,
- * or some other random failure), fall back to just looking at the node's
- * 'name' property.
- */
-static char * __init of_pdt_build_name(phandle node)
-{
-       char *buf;
-
-       buf = of_pdt_try_pkg2path(node);
-       if (!buf)
-               buf = of_pdt_get_one_property(node, "name");
-
-       return buf;
-}
-
 static struct device_node * __init of_pdt_create_node(phandle node,
                                                    struct device_node *parent)
 {
@@ -187,7 +182,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
 
        kref_init(&dp->kref);
 
-       dp->name = of_pdt_build_name(node);
+       dp->name = of_pdt_get_one_property(node, "name");
        dp->type = of_pdt_get_one_property(node, "device_type");
        dp->phandle = node;
 
@@ -198,26 +193,6 @@ static struct device_node * __init of_pdt_create_node(phandle node,
        return dp;
 }
 
-static char * __init of_pdt_build_full_name(struct device_node *dp)
-{
-       int len, ourlen, plen;
-       char *n;
-
-       plen = strlen(dp->parent->full_name);
-       ourlen = strlen(of_pdt_node_name(dp));
-       len = ourlen + plen + 2;
-
-       n = prom_early_alloc(len);
-       strcpy(n, dp->parent->full_name);
-       if (!of_node_is_root(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, of_pdt_node_name(dp));
-
-       return n;
-}
-
 static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
                                                   phandle node,
                                                   struct device_node ***nextp)
@@ -240,9 +215,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
                *(*nextp) = dp;
                *nextp = &dp->allnext;
 
-#if defined(CONFIG_SPARC)
-               dp->path_component_name = build_path_component(dp);
-#endif
                dp->full_name = of_pdt_build_full_name(dp);
 
                dp->child = of_pdt_build_tree(dp,
index a2d9d1e..a848e02 100644 (file)
@@ -678,7 +678,7 @@ void parport_unregister_device(struct pardevice *dev)
 
        /* Make sure we haven't left any pointers around in the wait
         * list. */
-       spin_lock (&port->waitlist_lock);
+       spin_lock_irq(&port->waitlist_lock);
        if (dev->waitprev || dev->waitnext || port->waithead == dev) {
                if (dev->waitprev)
                        dev->waitprev->waitnext = dev->waitnext;
@@ -689,7 +689,7 @@ void parport_unregister_device(struct pardevice *dev)
                else
                        port->waittail = dev->waitprev;
        }
-       spin_unlock (&port->waitlist_lock);
+       spin_unlock_irq(&port->waitlist_lock);
 
        kfree(dev->state);
        kfree(dev);
index 8ecaac9..ea25e5b 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/capability.h>
+#include <linux/security.h>
 #include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include "pci.h"
@@ -368,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj,
        u8 *data = (u8*) buf;
 
        /* Several chips lock up trying to read undefined config space */
-       if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) {
+       if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) {
                size = dev->cfg_size;
        } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                size = 128;
index dda7098..dc29348 100644 (file)
@@ -31,7 +31,7 @@ source "drivers/pci/pcie/aer/Kconfig"
 # PCI Express ASPM
 #
 config PCIEASPM
-       bool "PCI Express ASPM control" if EMBEDDED
+       bool "PCI Express ASPM control" if EXPERT
        depends on PCI && PCIEPORTBUS
        default y
        help
index de886f3..6e318ce 100644 (file)
@@ -69,7 +69,7 @@ comment "PC-card bridges"
 config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
-       select CARDBUS if !EMBEDDED
+       select CARDBUS if !EXPERT
        select PCCARD_NONSTATIC if PCMCIA != n
        ---help---
          This option enables support for CardBus host bridges.  Virtually
@@ -84,27 +84,27 @@ config YENTA
 
 config YENTA_O2
        default y
-       bool "Special initialization for O2Micro bridges" if EMBEDDED
+       bool "Special initialization for O2Micro bridges" if EXPERT
        depends on YENTA
 
 config YENTA_RICOH
        default y
-       bool "Special initialization for Ricoh bridges" if EMBEDDED
+       bool "Special initialization for Ricoh bridges" if EXPERT
        depends on YENTA
 
 config YENTA_TI
        default y
-       bool "Special initialization for TI and EnE bridges" if EMBEDDED
+       bool "Special initialization for TI and EnE bridges" if EXPERT
        depends on YENTA
 
 config YENTA_ENE_TUNE
        default y
-       bool "Auto-tune EnE bridges for CB cards" if EMBEDDED
+       bool "Auto-tune EnE bridges for CB cards" if EXPERT
        depends on YENTA_TI && CARDBUS
 
 config YENTA_TOSHIBA
        default y
-       bool "Special initialization for Toshiba ToPIC bridges" if EMBEDDED
+       bool "Special initialization for Toshiba ToPIC bridges" if EXPERT
        depends on YENTA
 
 config PD6729
index 0bdda5b..42fbf1a 100644 (file)
@@ -518,6 +518,8 @@ int pcmcia_enable_device(struct pcmcia_device *p_dev)
                flags |= CONF_ENABLE_IOCARD;
        if (flags & CONF_ENABLE_IOCARD)
                s->socket.flags |= SS_IOCARD;
+       if (flags & CONF_ENABLE_ZVCARD)
+               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
        if (flags & CONF_ENABLE_SPKR) {
                s->socket.flags |= SS_SPKR_ENA;
                status = CCSR_AUDIO_ENA;
index 3755e7c..2c54054 100644 (file)
@@ -215,7 +215,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
 }
 #endif
 
-static void pxa2xx_configure_sockets(struct device *dev)
+void pxa2xx_configure_sockets(struct device *dev)
 {
        struct pcmcia_low_level *ops = dev->platform_data;
        /*
index bb62ea8..b609b45 100644 (file)
@@ -1,3 +1,4 @@
 int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt);
 void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops);
+void pxa2xx_configure_sockets(struct device *dev);
 
index b9f8c8f..25afe63 100644 (file)
@@ -226,6 +226,7 @@ int pcmcia_lubbock_init(struct sa1111_dev *sadev)
                lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
 
                pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
+               pxa2xx_configure_sockets(&sadev->dev);
                ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
                                pxa2xx_drv_pcmcia_add_one);
        }
index d163bc2..a59af5b 100644 (file)
@@ -227,7 +227,7 @@ config SONYPI_COMPAT
 config IDEAPAD_LAPTOP
        tristate "Lenovo IdeaPad Laptop Extras"
        depends on ACPI
-       depends on RFKILL
+       depends on RFKILL && INPUT
        select INPUT_SPARSEKMAP
        help
          This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
index c5c4b8c..38b34a7 100644 (file)
@@ -84,7 +84,7 @@ MODULE_LICENSE("GPL");
  */
 #define AMW0_GUID1             "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
 #define AMW0_GUID2             "431F16ED-0C2B-444C-B267-27DEB140CF9C"
-#define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
+#define WMID_GUID1             "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
 #define WMID_GUID3             "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
 
@@ -1280,7 +1280,7 @@ static ssize_t set_bool_threeg(struct device *dev,
                        return -EINVAL;
        return count;
 }
-static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
        set_bool_threeg);
 
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
index 4633fd8..fe49593 100644 (file)
@@ -1081,14 +1081,8 @@ static int asus_hotk_add_fs(struct acpi_device *device)
        struct proc_dir_entry *proc;
        mode_t mode;
 
-       /*
-        * If parameter uid or gid is not changed, keep the default setting for
-        * our proc entries (-rw-rw-rw-) else, it means we care about security,
-        * and then set to -rw-rw----
-        */
-
        if ((asus_uid == 0) && (asus_gid == 0)) {
-               mode = S_IFREG | S_IRUGO | S_IWUGO;
+               mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
        } else {
                mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
                printk(KERN_WARNING "  asus_uid and asus_gid parameters are "
index 34657f9..ad24ef3 100644 (file)
@@ -290,9 +290,12 @@ static int dell_rfkill_set(void *data, bool blocked)
        dell_send_request(buffer, 17, 11);
 
        /* If the hardware switch controls this radio, and the hardware
-          switch is disabled, don't allow changing the software state */
+          switch is disabled, don't allow changing the software state.
+          If the hardware switch is reported as not supported, always
+          fire the SMI to toggle the killswitch. */
        if ((hwswitch_state & BIT(hwswitch_bit)) &&
-           !(buffer->output[1] & BIT(16))) {
+           !(buffer->output[1] & BIT(16)) &&
+           (buffer->output[1] & BIT(0))) {
                ret = -EINVAL;
                goto out;
        }
@@ -398,6 +401,23 @@ static const struct file_operations dell_debugfs_fops = {
 
 static void dell_update_rfkill(struct work_struct *ignored)
 {
+       int status;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+       status = buffer->output[1];
+       release_buffer();
+
+       /* if hardware rfkill is not supported, set it explicitly */
+       if (!(status & BIT(0))) {
+               if (wifi_rfkill)
+                       dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17));
+               if (bluetooth_rfkill)
+                       dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18));
+               if (wwan_rfkill)
+                       dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19));
+       }
+
        if (wifi_rfkill)
                dell_rfkill_query(wifi_rfkill, (void *)1);
        if (bluetooth_rfkill)
index 930e627..61433d4 100644 (file)
@@ -60,69 +60,20 @@ enum pmic_gpio_register {
 #define GPOSW_DOU 0x08
 #define GPOSW_RDRV 0x30
 
+#define GPIO_UPDATE_TYPE       0x80000000
 
 #define NUM_GPIO 24
 
-struct pmic_gpio_irq {
-       spinlock_t lock;
-       u32 trigger[NUM_GPIO];
-       u32 dirty;
-       struct work_struct work;
-};
-
-
 struct pmic_gpio {
+       struct mutex            buslock;
        struct gpio_chip        chip;
-       struct pmic_gpio_irq    irqtypes;
        void                    *gpiointr;
        int                     irq;
        unsigned                irq_base;
+       unsigned int            update_type;
+       u32                     trigger_type;
 };
 
-static void pmic_program_irqtype(int gpio, int type)
-{
-       if (type & IRQ_TYPE_EDGE_RISING)
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
-       else
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
-
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
-       else
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
-};
-
-static void pmic_irqtype_work(struct work_struct *work)
-{
-       struct pmic_gpio_irq *t =
-               container_of(work, struct pmic_gpio_irq, work);
-       unsigned long flags;
-       int i;
-       u16 type;
-
-       spin_lock_irqsave(&t->lock, flags);
-       /* As we drop the lock, we may need multiple scans if we race the
-          pmic_irq_type function */
-       while (t->dirty) {
-               /*
-                *      For each pin that has the dirty bit set send an IPC
-                *      message to configure the hardware via the PMIC
-                */
-               for (i = 0; i < NUM_GPIO; i++) {
-                       if (!(t->dirty & (1 << i)))
-                               continue;
-                       t->dirty &= ~(1 << i);
-                       /* We can't trust the array entry or dirty
-                          once the lock is dropped */
-                       type = t->trigger[i];
-                       spin_unlock_irqrestore(&t->lock, flags);
-                       pmic_program_irqtype(i, type);
-                       spin_lock_irqsave(&t->lock, flags);
-               }
-       }
-       spin_unlock_irqrestore(&t->lock, flags);
-}
-
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        if (offset > 8) {
@@ -190,25 +141,24 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                        1 << (offset - 16));
 }
 
-static int pmic_irq_type(unsigned irq, unsigned type)
+/*
+ * This is called from genirq with pg->buslock locked and
+ * irq_desc->lock held. We can not access the scu bus here, so we
+ * store the change and update in the bus_sync_unlock() function below
+ */
+static int pmic_irq_type(struct irq_data *data, unsigned type)
 {
-       struct pmic_gpio *pg = get_irq_chip_data(irq);
-       u32 gpio = irq - pg->irq_base;
-       unsigned long flags;
+       struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+       u32 gpio = data->irq - pg->irq_base;
 
        if (gpio >= pg->chip.ngpio)
                return -EINVAL;
 
-       spin_lock_irqsave(&pg->irqtypes.lock, flags);
-       pg->irqtypes.trigger[gpio] = type;
-       pg->irqtypes.dirty |=  (1 << gpio);
-       spin_unlock_irqrestore(&pg->irqtypes.lock, flags);
-       schedule_work(&pg->irqtypes.work);
+       pg->trigger_type = type;
+       pg->update_type = gpio | GPIO_UPDATE_TYPE;
        return 0;
 }
 
-
-
 static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
@@ -217,38 +167,32 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 }
 
 /* the gpiointr register is read-clear, so just do nothing. */
-static void pmic_irq_unmask(unsigned irq)
-{
-};
+static void pmic_irq_unmask(struct irq_data *data) { }
 
-static void pmic_irq_mask(unsigned irq)
-{
-};
+static void pmic_irq_mask(struct irq_data *data) { }
 
 static struct irq_chip pmic_irqchip = {
        .name           = "PMIC-GPIO",
-       .mask           = pmic_irq_mask,
-       .unmask         = pmic_irq_unmask,
-       .set_type       = pmic_irq_type,
+       .irq_mask       = pmic_irq_mask,
+       .irq_unmask     = pmic_irq_unmask,
+       .irq_set_type   = pmic_irq_type,
 };
 
-static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
+static irqreturn_t pmic_irq_handler(int irq, void *data)
 {
-       struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq);
+       struct pmic_gpio *pg = data;
        u8 intsts = *((u8 *)pg->gpiointr + 4);
        int gpio;
+       irqreturn_t ret = IRQ_NONE;
 
        for (gpio = 0; gpio < 8; gpio++) {
                if (intsts & (1 << gpio)) {
                        pr_debug("pmic pin %d triggered\n", gpio);
                        generic_handle_irq(pg->irq_base + gpio);
+                       ret = IRQ_HANDLED;
                }
        }
-
-       if (desc->chip->irq_eoi)
-               desc->chip->irq_eoi(irq_get_irq_data(irq));
-       else
-               dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq);
+       return ret;
 }
 
 static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
@@ -297,8 +241,7 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
        pg->chip.can_sleep = 1;
        pg->chip.dev = dev;
 
-       INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work);
-       spin_lock_init(&pg->irqtypes.lock);
+       mutex_init(&pg->buslock);
 
        pg->chip.dev = dev;
        retval = gpiochip_add(&pg->chip);
@@ -306,8 +249,13 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
                printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__);
                goto err;
        }
-       set_irq_data(pg->irq, pg);
-       set_irq_chained_handler(pg->irq, pmic_irq_handler);
+
+       retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg);
+       if (retval) {
+               printk(KERN_WARNING "pmic: Interrupt request failed\n");
+               goto err;
+       }
+
        for (i = 0; i < 8; i++) {
                set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip,
                                        handle_simple_irq, "demux");
index 1752ef0..a91d510 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/sfi.h>
 #include <asm/mrst.h>
 #include <asm/intel_scu_ipc.h>
-#include <asm/mrst.h>
 
 /* IPC defines the following message types */
 #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
@@ -161,7 +160,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
        int i, nc, bytes, d;
        u32 offset = 0;
-       u32 err = 0;
+       int err;
        u8 cbuf[IPC_WWBUF_SIZE] = { };
        u32 *wbuf = (u32 *)&cbuf;
 
@@ -404,7 +403,7 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register);
  */
 int intel_scu_ipc_simple_command(int cmd, int sub)
 {
-       u32 err = 0;
+       int err;
 
        mutex_lock(&ipclock);
        if (ipcdev.pdev == NULL) {
@@ -434,8 +433,7 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
 int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
                                                        u32 *out, int outlen)
 {
-       u32 err = 0;
-       int i = 0;
+       int i, err;
 
        mutex_lock(&ipclock);
        if (ipcdev.pdev == NULL) {
index ba3231d..b93a032 100644 (file)
@@ -128,6 +128,6 @@ static void __exit ipc_module_exit(void)
 module_init(ipc_module_init);
 module_exit(ipc_module_exit);
 
-MODULE_LICENSE("GPL V2");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Utility driver for intel scu ipc");
 MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");
index 1fe0f1f..865ef78 100644 (file)
@@ -162,7 +162,7 @@ set_bool_##value(struct device *dev, struct device_attribute *attr, \
                        return -EINVAL; \
        return count; \
 } \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, \
        show_bool_##value, set_bool_##value);
 
 show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
index dd59958..eb99223 100644 (file)
@@ -2275,16 +2275,12 @@ static void tpacpi_input_send_key(const unsigned int scancode)
        if (keycode != KEY_RESERVED) {
                mutex_lock(&tpacpi_inputdev_send_mutex);
 
+               input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode);
                input_report_key(tpacpi_inputdev, keycode, 1);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
                input_sync(tpacpi_inputdev);
 
+               input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode);
                input_report_key(tpacpi_inputdev, keycode, 0);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
                input_sync(tpacpi_inputdev);
 
                mutex_unlock(&tpacpi_inputdev_send_mutex);
index 2728469..82583b0 100644 (file)
@@ -46,8 +46,6 @@ static void pps_ktimer_event(unsigned long ptr)
        /* First of all we get the time stamp... */
        pps_get_ts(&ts);
 
-       dev_info(pps->dev, "PPS event at %lu\n", jiffies);
-
        pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
 
        mod_timer(&ktimer, jiffies + HZ);
index 32221ef..c571d6d 100644 (file)
@@ -163,7 +163,7 @@ static void parport_attach(struct parport *port)
        }
 
        device->pardev = parport_register_device(port, KBUILD_MODNAME,
-                       NULL, NULL, parport_irq, 0, device);
+                       NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device);
        if (!device->pardev) {
                pr_err("couldn't register with %s\n", port->name);
                goto err_free;
index f3a73dd..e4c4f3d 100644 (file)
@@ -6,7 +6,7 @@ comment "PPS generators support"
 
 config PPS_GENERATOR_PARPORT
        tristate "Parallel port PPS signal generator"
-       depends on PARPORT
+       depends on PARPORT && BROKEN
        help
          If you say yes here you get support for a PPS signal generator which
          utilizes STROBE pin of a parallel port to send PPS signals. It uses
index 5c32f8d..b93af3e 100644 (file)
@@ -198,7 +198,7 @@ static void parport_attach(struct parport *port)
        }
 
        device.pardev = parport_register_device(port, KBUILD_MODNAME,
-                       NULL, NULL, NULL, 0, &device);
+                       NULL, NULL, NULL, PARPORT_FLAG_EXCL, &device);
        if (!device.pardev) {
                pr_err("couldn't register with %s\n", port->name);
                return;
index cba1b43..a4e8eb9 100644 (file)
@@ -168,7 +168,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 {
        unsigned long flags;
        int captured = 0;
-       struct pps_ktime ts_real;
+       struct pps_ktime ts_real = { .sec = 0, .nsec = 0, .flags = 0 };
 
        /* check event type */
        BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
index 467e82b..a50391b 100644 (file)
@@ -943,6 +943,8 @@ static int rio_enum_complete(struct rio_mport *port)
  * @port: Master port to send transactions
  * @destid: Current destination ID in network
  * @hopcount: Number of hops into the network
+ * @prev: previous rio_dev
+ * @prev_port: previous port number
  *
  * Recursively discovers a RIO network.  Transactions are sent via the
  * master port passed in @port.
index 76b4185..1269fbd 100644 (file)
@@ -77,9 +77,9 @@ rio_read_config(struct file *filp, struct kobject *kobj,
 
        /* Several chips lock up trying to read undefined config space */
        if (capable(CAP_SYS_ADMIN))
-               size = 0x200000;
+               size = RIO_MAINT_SPACE_SZ;
 
-       if (off > size)
+       if (off >= size)
                return 0;
        if (off + count > size) {
                size -= off;
@@ -147,10 +147,10 @@ rio_write_config(struct file *filp, struct kobject *kobj,
        loff_t init_off = off;
        u8 *data = (u8 *) buf;
 
-       if (off > 0x200000)
+       if (off >= RIO_MAINT_SPACE_SZ)
                return 0;
-       if (off + count > 0x200000) {
-               size = 0x200000 - off;
+       if (off + count > RIO_MAINT_SPACE_SZ) {
+               size = RIO_MAINT_SPACE_SZ - off;
                count = size;
        }
 
@@ -200,7 +200,7 @@ static struct bin_attribute rio_config_attr = {
                 .name = "config",
                 .mode = S_IRUGO | S_IWUSR,
                 },
-       .size = 0x200000,
+       .size = RIO_MAINT_SPACE_SZ,
        .read = rio_read_config,
        .write = rio_write_config,
 };
index f53d31b..2bb5de1 100644 (file)
@@ -174,7 +174,7 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
 
-       BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages);
+       BUG_ON(val > mc13xxx_regulators[id].desc.n_voltages);
 
        return mc13xxx_regulators[id].voltages[val];
 }
index 8b0d2c4..06df898 100644 (file)
@@ -120,6 +120,7 @@ static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev)
                return REGULATOR_MODE_IDLE;
        default:
                BUG();
+               return -EINVAL;
        }
 }
 
index 9583cbc..c404b61 100644 (file)
@@ -143,6 +143,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->id = id;
        rtc->ops = ops;
        rtc->owner = owner;
+       rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
        rtc->dev.parent = dev;
        rtc->dev.class = rtc_class;
index 90384b9..cb2f072 100644 (file)
@@ -16,6 +16,9 @@
 #include <linux/log2.h>
 #include <linux/workqueue.h>
 
+static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
+static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
+
 static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 {
        int err;
@@ -120,12 +123,18 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;
-       alarm->enabled = rtc->aie_timer.enabled;
-       if (alarm->enabled)
+       if (rtc->ops == NULL)
+               err = -ENODEV;
+       else if (!rtc->ops->read_alarm)
+               err = -EINVAL;
+       else {
+               memset(alarm, 0, sizeof(struct rtc_wkalrm));
+               alarm->enabled = rtc->aie_timer.enabled;
                alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
+       }
        mutex_unlock(&rtc->ops_lock);
 
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
 
@@ -175,16 +184,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                return err;
        if (rtc->aie_timer.enabled) {
                rtc_timer_remove(rtc, &rtc->aie_timer);
-               rtc->aie_timer.enabled = 0;
        }
        rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
        rtc->aie_timer.period = ktime_set(0, 0);
        if (alarm->enabled) {
-               rtc->aie_timer.enabled = 1;
-               rtc_timer_enqueue(rtc, &rtc->aie_timer);
+               err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
        }
        mutex_unlock(&rtc->ops_lock);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(rtc_set_alarm);
 
@@ -195,16 +202,15 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
                return err;
 
        if (rtc->aie_timer.enabled != enabled) {
-               if (enabled) {
-                       rtc->aie_timer.enabled = 1;
-                       rtc_timer_enqueue(rtc, &rtc->aie_timer);
-               } else {
+               if (enabled)
+                       err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
+               else
                        rtc_timer_remove(rtc, &rtc->aie_timer);
-                       rtc->aie_timer.enabled = 0;
-               }
        }
 
-       if (!rtc->ops)
+       if (err)
+               /* nothing */;
+       else if (!rtc->ops)
                err = -ENODEV;
        else if (!rtc->ops->alarm_irq_enable)
                err = -EINVAL;
@@ -222,6 +228,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
        if (err)
                return err;
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       if (enabled == 0 && rtc->uie_irq_active) {
+               mutex_unlock(&rtc->ops_lock);
+               return rtc_dev_update_irq_enable_emul(rtc, 0);
+       }
+#endif
        /* make sure we're changing state */
        if (rtc->uie_rtctimer.enabled == enabled)
                goto out;
@@ -235,15 +247,22 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
                now = rtc_tm_to_ktime(tm);
                rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
                rtc->uie_rtctimer.period = ktime_set(1, 0);
-               rtc->uie_rtctimer.enabled = 1;
-               rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
-       } else {
+               err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
+       } else
                rtc_timer_remove(rtc, &rtc->uie_rtctimer);
-               rtc->uie_rtctimer.enabled = 0;
-       }
 
 out:
        mutex_unlock(&rtc->ops_lock);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       /*
+        * Enable emulation if the driver did not provide
+        * the update_irq_enable function pointer or if returned
+        * -EINVAL to signal that it has been configured without
+        * interrupts or that are not available at the moment.
+        */
+       if (err == -EINVAL)
+               err = rtc_dev_update_irq_enable_emul(rtc, enabled);
+#endif
        return err;
 
 }
@@ -259,7 +278,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
  *
  * Triggers the registered irq_task function callback.
  */
-static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
+void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
 {
        unsigned long flags;
 
@@ -460,6 +479,9 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
        int err = 0;
        unsigned long flags;
 
+       if (freq <= 0)
+               return -EINVAL;
+
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != NULL && task == NULL)
                err = -EBUSY;
@@ -488,10 +510,13 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
  * Enqueues a timer onto the rtc devices timerqueue and sets
  * the next alarm event appropriately.
  *
+ * Sets the enabled bit on the added timer.
+ *
  * Must hold ops_lock for proper serialization of timerqueue
  */
-void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
+static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 {
+       timer->enabled = 1;
        timerqueue_add(&rtc->timerqueue, &timer->node);
        if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
                struct rtc_wkalrm alarm;
@@ -501,7 +526,13 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
                err = __rtc_set_alarm(rtc, &alarm);
                if (err == -ETIME)
                        schedule_work(&rtc->irqwork);
+               else if (err) {
+                       timerqueue_del(&rtc->timerqueue, &timer->node);
+                       timer->enabled = 0;
+                       return err;
+               }
        }
+       return 0;
 }
 
 /**
@@ -512,13 +543,15 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
  * Removes a timer onto the rtc devices timerqueue and sets
  * the next alarm event appropriately.
  *
+ * Clears the enabled bit on the removed timer.
+ *
  * Must hold ops_lock for proper serialization of timerqueue
  */
-void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
+static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
 {
        struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
        timerqueue_del(&rtc->timerqueue, &timer->node);
-
+       timer->enabled = 0;
        if (next == &timer->node) {
                struct rtc_wkalrm alarm;
                int err;
@@ -626,8 +659,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
        timer->node.expires = expires;
        timer->period = period;
 
-       timer->enabled = 1;
-       rtc_timer_enqueue(rtc, timer);
+       ret = rtc_timer_enqueue(rtc, timer);
 
        mutex_unlock(&rtc->ops_lock);
        return ret;
@@ -645,7 +677,6 @@ int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
        mutex_lock(&rtc->ops_lock);
        if (timer->enabled)
                rtc_timer_remove(rtc, timer);
-       timer->enabled = 0;
        mutex_unlock(&rtc->ops_lock);
        return ret;
 }
index b2752b6..e725d51 100644 (file)
@@ -134,36 +134,29 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-static int at32_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
        int ret = 0;
 
        spin_lock_irq(&rtc->lock);
 
-       switch (cmd) {
-       case RTC_AIE_ON:
+       if(enabled) {
                if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
                        ret = -EINVAL;
-                       break;
+                       goto out;
                }
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
                                | RTC_BIT(CTRL_TOPEN));
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
                rtc_writel(rtc, IER, RTC_BIT(IER_TOPI));
-               break;
-       case RTC_AIE_OFF:
+       } else {
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
                                & ~RTC_BIT(CTRL_TOPEN));
                rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
        }
-
+out:
        spin_unlock_irq(&rtc->lock);
 
        return ret;
@@ -195,11 +188,11 @@ static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id)
 }
 
 static struct rtc_class_ops at32_rtc_ops = {
-       .ioctl          = at32_rtc_ioctl,
        .read_time      = at32_rtc_readtime,
        .set_time       = at32_rtc_settime,
        .read_alarm     = at32_rtc_readalarm,
        .set_alarm      = at32_rtc_setalarm,
+       .alarm_irq_enable = at32_rtc_alarm_irq_enable,
 };
 
 static int __init at32_rtc_probe(struct platform_device *pdev)
index bc8bbca..26d1cf5 100644 (file)
@@ -195,13 +195,6 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
 
        /* important:  scrub old status before enabling IRQs */
        switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
-               at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
-               break;
-       case RTC_AIE_ON:        /* alarm on */
-               at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
-               at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
-               break;
        case RTC_UIE_OFF:       /* update off */
                at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
                break;
@@ -217,6 +210,18 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
        return ret;
 }
 
+static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       pr_debug("%s(): cmd=%08x\n", __func__, enabled);
+
+       if (enabled) {
+               at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
+               at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+       } else
+               at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+
+       return 0;
+}
 /*
  * Provide additional RTC information in /proc/driver/rtc
  */
@@ -270,6 +275,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
        .read_alarm     = at91_rtc_readalarm,
        .set_alarm      = at91_rtc_setalarm,
        .proc           = at91_rtc_proc,
+       .alarm_irq_enable = at91_rtc_alarm_irq_enable,
 };
 
 /*
index f677e07..5469c52 100644 (file)
@@ -229,12 +229,6 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
        dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
 
        switch (cmd) {
-       case RTC_AIE_OFF:               /* alarm off */
-               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
-               break;
-       case RTC_AIE_ON:                /* alarm on */
-               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
-               break;
        case RTC_UIE_OFF:               /* update off */
                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
                break;
@@ -249,6 +243,19 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
        return ret;
 }
 
+static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       u32 mr = rtt_readl(rtc, MR);
+
+       dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n", enabled, mr);
+       if (enabled)
+               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+       else
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+       return 0;
+}
+
 /*
  * Provide additional RTC information in /proc/driver/rtc
  */
@@ -302,6 +309,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
        .read_alarm     = at91_rtc_readalarm,
        .set_alarm      = at91_rtc_setalarm,
        .proc           = at91_rtc_proc,
+       .alarm_irq_enable = at91_rtc_alarm_irq_enable,
 };
 
 /*
index b4b6087..17971d9 100644 (file)
@@ -259,15 +259,6 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar
                bfin_rtc_int_clear(~RTC_ISTAT_SEC);
                break;
 
-       case RTC_AIE_ON:
-               dev_dbg_stamp(dev);
-               bfin_rtc_int_set_alarm(rtc);
-               break;
-       case RTC_AIE_OFF:
-               dev_dbg_stamp(dev);
-               bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
-               break;
-
        default:
                dev_dbg_stamp(dev);
                ret = -ENOIOCTLCMD;
@@ -276,6 +267,17 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar
        return ret;
 }
 
+static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct bfin_rtc *rtc = dev_get_drvdata(dev);
+
+       dev_dbg_stamp(dev);
+       if (enabled)
+               bfin_rtc_int_set_alarm(rtc);
+       else
+               bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+}
+
 static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
@@ -362,6 +364,7 @@ static struct rtc_class_ops bfin_rtc_ops = {
        .read_alarm    = bfin_rtc_read_alarm,
        .set_alarm     = bfin_rtc_set_alarm,
        .proc          = bfin_rtc_proc,
+       .alarm_irq_enable = bfin_rtc_alarm_irq_enable,
 };
 
 static int __devinit bfin_rtc_probe(struct platform_device *pdev)
index 212b16e..d0e06ed 100644 (file)
@@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
        return err;
 }
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(struct work_struct *work)
+{
+       struct rtc_device *rtc =
+               container_of(work, struct rtc_device, uie_task);
+       struct rtc_time tm;
+       int num = 0;
+       int err;
+
+       err = rtc_read_time(rtc, &tm);
+
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->stop_uie_polling || err) {
+               rtc->uie_task_active = 0;
+       } else if (rtc->oldsecs != tm.tm_sec) {
+               num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+               rtc->uie_timer_active = 1;
+               rtc->uie_task_active = 0;
+               add_timer(&rtc->uie_timer);
+       } else if (schedule_work(&rtc->uie_task) == 0) {
+               rtc->uie_task_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+       if (num)
+               rtc_handle_legacy_irq(rtc, num, RTC_UF);
+}
+static void rtc_uie_timer(unsigned long data)
+{
+       struct rtc_device *rtc = (struct rtc_device *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc->irq_lock, flags);
+       rtc->uie_timer_active = 0;
+       rtc->uie_task_active = 1;
+       if ((schedule_work(&rtc->uie_task) == 0))
+               rtc->uie_task_active = 0;
+       spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static int clear_uie(struct rtc_device *rtc)
+{
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->uie_irq_active) {
+               rtc->stop_uie_polling = 1;
+               if (rtc->uie_timer_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       del_timer_sync(&rtc->uie_timer);
+                       spin_lock_irq(&rtc->irq_lock);
+                       rtc->uie_timer_active = 0;
+               }
+               if (rtc->uie_task_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       flush_scheduled_work();
+                       spin_lock_irq(&rtc->irq_lock);
+               }
+               rtc->uie_irq_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+       return 0;
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+       struct rtc_time tm;
+       int err;
+
+       err = rtc_read_time(rtc, &tm);
+       if (err)
+               return err;
+       spin_lock_irq(&rtc->irq_lock);
+       if (!rtc->uie_irq_active) {
+               rtc->uie_irq_active = 1;
+               rtc->stop_uie_polling = 0;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_task_active = 1;
+               if (schedule_work(&rtc->uie_task) == 0)
+                       rtc->uie_task_active = 0;
+       }
+       rtc->irq_data = 0;
+       spin_unlock_irq(&rtc->irq_lock);
+       return 0;
+}
+
+int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
+{
+       if (enabled)
+               return set_uie(rtc);
+       else
+               return clear_uie(rtc);
+}
+EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
+
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
 
 static ssize_t
 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -154,19 +253,7 @@ static long rtc_dev_ioctl(struct file *file,
        if (err)
                goto done;
 
-       /* try the driver's ioctl interface */
-       if (ops->ioctl) {
-               err = ops->ioctl(rtc->dev.parent, cmd, arg);
-               if (err != -ENOIOCTLCMD) {
-                       mutex_unlock(&rtc->ops_lock);
-                       return err;
-               }
-       }
-
-       /* if the driver does not provide the ioctl interface
-        * or if that particular ioctl was not implemented
-        * (-ENOIOCTLCMD), we will try to emulate here.
-        *
+       /*
         * Drivers *SHOULD NOT* provide ioctl implementations
         * for these requests.  Instead, provide methods to
         * support the following code, so that the RTC's main
@@ -329,7 +416,12 @@ static long rtc_dev_ioctl(struct file *file,
                return err;
 
        default:
-               err = -ENOTTY;
+               /* Finally try the driver's ioctl interface */
+               if (ops->ioctl) {
+                       err = ops->ioctl(rtc->dev.parent, cmd, arg);
+                       if (err == -ENOIOCTLCMD)
+                               err = -ENOTTY;
+               }
                break;
        }
 
@@ -394,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc)
 
        rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       INIT_WORK(&rtc->uie_task, rtc_uie_task);
+       setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
+
        cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc->char_dev.owner = rtc->owner;
 }
index bf430f9..60ce696 100644 (file)
@@ -40,6 +40,26 @@ static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
        __raw_writel(data, &priv->rtcregs[reg]);
 }
 
+
+static int ds1286_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       unsigned char val;
+
+       /* Allow or mask alarm interrupts */
+       spin_lock_irqsave(&priv->lock, flags);
+       val = ds1286_rtc_read(priv, RTC_CMD);
+       if (enabled)
+               val &=  ~RTC_TDM;
+       else
+               val |=  RTC_TDM;
+       ds1286_rtc_write(priv, val, RTC_CMD);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
 #ifdef CONFIG_RTC_INTF_DEV
 
 static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
@@ -49,22 +69,6 @@ static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        unsigned char val;
 
        switch (cmd) {
-       case RTC_AIE_OFF:
-               /* Mask alarm int. enab. bit    */
-               spin_lock_irqsave(&priv->lock, flags);
-               val = ds1286_rtc_read(priv, RTC_CMD);
-               val |=  RTC_TDM;
-               ds1286_rtc_write(priv, val, RTC_CMD);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               break;
-       case RTC_AIE_ON:
-               /* Allow alarm interrupts.      */
-               spin_lock_irqsave(&priv->lock, flags);
-               val = ds1286_rtc_read(priv, RTC_CMD);
-               val &=  ~RTC_TDM;
-               ds1286_rtc_write(priv, val, RTC_CMD);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               break;
        case RTC_WIE_OFF:
                /* Mask watchdog int. enab. bit */
                spin_lock_irqsave(&priv->lock, flags);
@@ -316,12 +320,13 @@ static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 }
 
 static const struct rtc_class_ops ds1286_ops = {
-       .ioctl          = ds1286_ioctl,
-       .proc           = ds1286_proc,
+       .ioctl          = ds1286_ioctl,
+       .proc           = ds1286_proc,
        .read_time      = ds1286_read_time,
        .set_time       = ds1286_set_time,
        .read_alarm     = ds1286_read_alarm,
        .set_alarm      = ds1286_set_alarm,
+       .alarm_irq_enable = ds1286_alarm_irq_enable,
 };
 
 static int __devinit ds1286_probe(struct platform_device *pdev)
index 077af1d..57fbcc1 100644 (file)
@@ -139,49 +139,32 @@ static u8 hour2bcd(bool hr12, int hour)
  * Interface to RTC framework
  */
 
-#ifdef CONFIG_RTC_INTF_DEV
-
-/*
- * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
- */
-static int ds1305_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
+static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct ds1305   *ds1305 = dev_get_drvdata(dev);
        u8              buf[2];
-       int             status = -ENOIOCTLCMD;
+       long            err = -EINVAL;
 
        buf[0] = DS1305_WRITE | DS1305_CONTROL;
        buf[1] = ds1305->ctrl[0];
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               status = 0;
-               if (!(buf[1] & DS1305_AEI0))
-                       goto done;
-               buf[1] &= ~DS1305_AEI0;
-               break;
-
-       case RTC_AIE_ON:
-               status = 0;
+       if (enabled) {
                if (ds1305->ctrl[0] & DS1305_AEI0)
                        goto done;
                buf[1] |= DS1305_AEI0;
-               break;
-       }
-       if (status == 0) {
-               status = spi_write_then_read(ds1305->spi, buf, sizeof buf,
-                               NULL, 0);
-               if (status >= 0)
-                       ds1305->ctrl[0] = buf[1];
+       } else {
+               if (!(buf[1] & DS1305_AEI0))
+                       goto done;
+               buf[1] &= ~DS1305_AEI0;
        }
-
+       err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0);
+       if (err >= 0)
+               ds1305->ctrl[0] = buf[1];
 done:
-       return status;
+       return err;
+
 }
 
-#else
-#define ds1305_ioctl   NULL
-#endif
 
 /*
  * Get/set of date and time is pretty normal.
@@ -460,12 +443,12 @@ done:
 #endif
 
 static const struct rtc_class_ops ds1305_ops = {
-       .ioctl          = ds1305_ioctl,
        .read_time      = ds1305_get_time,
        .set_time       = ds1305_set_time,
        .read_alarm     = ds1305_get_alarm,
        .set_alarm      = ds1305_set_alarm,
        .proc           = ds1305_proc,
+       .alarm_irq_enable = ds1305_alarm_irq_enable,
 };
 
 static void ds1305_work(struct work_struct *work)
index 0d559b6..4724ba3 100644 (file)
@@ -495,50 +495,27 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
-static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client       *client = to_i2c_client(dev);
        struct ds1307           *ds1307 = i2c_get_clientdata(client);
        int                     ret;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               if (!test_bit(HAS_ALARM, &ds1307->flags))
-                       return -ENOTTY;
-
-               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (ret < 0)
-                       return ret;
-
-               ret &= ~DS1337_BIT_A1IE;
-
-               ret = i2c_smbus_write_byte_data(client,
-                                               DS1337_REG_CONTROL, ret);
-               if (ret < 0)
-                       return ret;
-
-               break;
-
-       case RTC_AIE_ON:
-               if (!test_bit(HAS_ALARM, &ds1307->flags))
-                       return -ENOTTY;
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -ENOTTY;
 
-               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (ret < 0)
-                       return ret;
+       ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+       if (ret < 0)
+               return ret;
 
+       if (enabled)
                ret |= DS1337_BIT_A1IE;
+       else
+               ret &= ~DS1337_BIT_A1IE;
 
-               ret = i2c_smbus_write_byte_data(client,
-                                               DS1337_REG_CONTROL, ret);
-               if (ret < 0)
-                       return ret;
-
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -548,7 +525,7 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
        .set_time       = ds1307_set_time,
        .read_alarm     = ds1337_read_alarm,
        .set_alarm      = ds1337_set_alarm,
-       .ioctl          = ds1307_ioctl,
+       .alarm_irq_enable = ds1307_alarm_irq_enable,
 };
 
 /*----------------------------------------------------------------------*/
index 47fb635..d834a63 100644 (file)
@@ -307,42 +307,25 @@ unlock:
        mutex_unlock(&ds1374->mutex);
 }
 
-static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct ds1374 *ds1374 = i2c_get_clientdata(client);
-       int ret = -ENOIOCTLCMD;
+       int ret;
 
        mutex_lock(&ds1374->mutex);
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
-               if (ret < 0)
-                       goto out;
-
-               ret &= ~DS1374_REG_CR_WACE;
-
-               ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
-               if (ret < 0)
-                       goto out;
-
-               break;
-
-       case RTC_AIE_ON:
-               ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
-               if (ret < 0)
-                       goto out;
+       ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+       if (ret < 0)
+               goto out;
 
+       if (enabled) {
                ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
                ret &= ~DS1374_REG_CR_WDALM;
-
-               ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
-               if (ret < 0)
-                       goto out;
-
-               break;
+       } else {
+               ret &= ~DS1374_REG_CR_WACE;
        }
+       ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
 
 out:
        mutex_unlock(&ds1374->mutex);
@@ -354,7 +337,7 @@ static const struct rtc_class_ops ds1374_rtc_ops = {
        .set_time = ds1374_set_time,
        .read_alarm = ds1374_read_alarm,
        .set_alarm = ds1374_set_alarm,
-       .ioctl = ds1374_ioctl,
+       .alarm_irq_enable = ds1374_alarm_irq_enable,
 };
 
 static int ds1374_probe(struct i2c_client *client,
index 23a9ee1..9507354 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
  *
- * Copyright (C) 2009-2010 Freescale Semiconductor.
+ * Copyright (C) 2009-2011 Freescale Semiconductor.
  * Author: Jack Lan <jack.lan@freescale.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -141,9 +141,11 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
                time->tm_hour = bcd2bin(hour);
        }
 
-       time->tm_wday = bcd2bin(week);
+       /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
+       time->tm_wday = bcd2bin(week) - 1;
        time->tm_mday = bcd2bin(day);
-       time->tm_mon = bcd2bin(month & 0x7F);
+       /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
+       time->tm_mon = bcd2bin(month & 0x7F) - 1;
        if (century)
                add_century = 100;
 
@@ -162,9 +164,11 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
        buf[0] = bin2bcd(time->tm_sec);
        buf[1] = bin2bcd(time->tm_min);
        buf[2] = bin2bcd(time->tm_hour);
-       buf[3] = bin2bcd(time->tm_wday); /* Day of the week */
+       /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
+       buf[3] = bin2bcd(time->tm_wday + 1);
        buf[4] = bin2bcd(time->tm_mday); /* Date */
-       buf[5] = bin2bcd(time->tm_mon);
+       /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
+       buf[5] = bin2bcd(time->tm_mon + 1);
        if (time->tm_year >= 100) {
                buf[5] |= 0x80;
                buf[6] = bin2bcd(time->tm_year - 100);
index 5a8daa3..69fe664 100644 (file)
@@ -213,41 +213,27 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return m41t80_set_datetime(to_i2c_client(dev), tm);
 }
 
-#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
-static int
-m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client *client = to_i2c_client(dev);
        int rc;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-
        rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
        if (rc < 0)
                goto err;
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               rc &= ~M41T80_ALMON_AFE;
-               break;
-       case RTC_AIE_ON:
+
+       if (enabled)
                rc |= M41T80_ALMON_AFE;
-               break;
-       }
+       else
+               rc &= ~M41T80_ALMON_AFE;
+
        if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0)
                goto err;
+
        return 0;
 err:
        return -EIO;
 }
-#else
-#define        m41t80_rtc_ioctl NULL
-#endif
 
 static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
@@ -374,7 +360,7 @@ static struct rtc_class_ops m41t80_rtc_ops = {
        .read_alarm = m41t80_rtc_read_alarm,
        .set_alarm = m41t80_rtc_set_alarm,
        .proc = m41t80_rtc_proc,
-       .ioctl = m41t80_rtc_ioctl,
+       .alarm_irq_enable = m41t80_rtc_alarm_irq_enable,
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
index a99a0b5..3978f4c 100644 (file)
@@ -263,30 +263,21 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 /*
  * Handle commands from user-space
  */
-static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct m48t59_plat_data *pdata = pdev->dev.platform_data;
        struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
        unsigned long flags;
-       int ret = 0;
 
        spin_lock_irqsave(&m48t59->lock, flags);
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm interrupt off */
-               M48T59_WRITE(0x00, M48T59_INTR);
-               break;
-       case RTC_AIE_ON:        /* alarm interrupt on */
+       if (enabled)
                M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
+       else
+               M48T59_WRITE(0x00, M48T59_INTR);
        spin_unlock_irqrestore(&m48t59->lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
@@ -330,12 +321,12 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)
 }
 
 static const struct rtc_class_ops m48t59_rtc_ops = {
-       .ioctl          = m48t59_rtc_ioctl,
        .read_time      = m48t59_rtc_read_time,
        .set_time       = m48t59_rtc_set_time,
        .read_alarm     = m48t59_rtc_readalarm,
        .set_alarm      = m48t59_rtc_setalarm,
        .proc           = m48t59_rtc_proc,
+       .alarm_irq_enable = m48t59_rtc_alarm_irq_enable,
 };
 
 static const struct rtc_class_ops m48t02_rtc_ops = {
index bcd0cf6..1db62db 100644 (file)
@@ -255,42 +255,21 @@ static int mrst_irq_set_state(struct device *dev, int enabled)
        return 0;
 }
 
-#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
-
 /* Currently, the vRTC doesn't support UIE ON/OFF */
-static int
-mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned long   flags;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               if (!mrst->irq)
-                       return -EINVAL;
-               break;
-       default:
-               /* PIE ON/OFF is handled by mrst_irq_set_state() */
-               return -ENOIOCTLCMD;
-       }
-
        spin_lock_irqsave(&rtc_lock, flags);
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
-               mrst_irq_disable(mrst, RTC_AIE);
-               break;
-       case RTC_AIE_ON:        /* alarm on */
+       if (enabled)
                mrst_irq_enable(mrst, RTC_AIE);
-               break;
-       }
+       else
+               mrst_irq_disable(mrst, RTC_AIE);
        spin_unlock_irqrestore(&rtc_lock, flags);
        return 0;
 }
 
-#else
-#define        mrst_rtc_ioctl  NULL
-#endif
 
 #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
 
@@ -317,13 +296,13 @@ static int mrst_procfs(struct device *dev, struct seq_file *seq)
 #endif
 
 static const struct rtc_class_ops mrst_rtc_ops = {
-       .ioctl          = mrst_rtc_ioctl,
        .read_time      = mrst_read_time,
        .set_time       = mrst_set_time,
        .read_alarm     = mrst_read_alarm,
        .set_alarm      = mrst_set_alarm,
        .proc           = mrst_procfs,
        .irq_set_state  = mrst_irq_set_state,
+       .alarm_irq_enable = mrst_rtc_alarm_irq_enable,
 };
 
 static struct mrst_rtc mrst_rtc;
index b2fff0c..6782062 100644 (file)
@@ -82,7 +82,7 @@ static inline unsigned int msm6242_read(struct msm6242_priv *priv,
 static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
                                unsigned int reg)
 {
-       return __raw_writel(val, &priv->regs[reg]);
+       __raw_writel(val, &priv->regs[reg]);
 }
 
 static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
index bcca472..60627a7 100644 (file)
@@ -169,25 +169,19 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        return 0;
 }
 
-static int mv_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int mv_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
        void __iomem *ioaddr = pdata->ioaddr;
 
        if (pdata->irq < 0)
-               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
-               break;
-       case RTC_AIE_ON:
+               return -EINVAL; /* fall back into rtc-dev's emulation */
+
+       if (enabled)
                writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
+       else
+               writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
        return 0;
 }
 
@@ -216,7 +210,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = {
        .set_time       = mv_rtc_set_time,
        .read_alarm     = mv_rtc_read_alarm,
        .set_alarm      = mv_rtc_set_alarm,
-       .ioctl          = mv_rtc_ioctl,
+       .alarm_irq_enable = mv_rtc_alarm_irq_enable,
 };
 
 static int __devinit mv_rtc_probe(struct platform_device *pdev)
index e72b523..b4dbf3a 100644 (file)
@@ -143,8 +143,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        u8 reg;
 
        switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
        case RTC_UIE_OFF:
        case RTC_UIE_ON:
                break;
@@ -156,13 +154,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        rtc_wait_not_busy();
        reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
        switch (cmd) {
-       /* AIE = Alarm Interrupt Enable */
-       case RTC_AIE_OFF:
-               reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
-               break;
-       case RTC_AIE_ON:
-               reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
-               break;
        /* UIE = Update Interrupt Enable (1/second) */
        case RTC_UIE_OFF:
                reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER;
@@ -182,6 +173,24 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 #define        omap_rtc_ioctl  NULL
 #endif
 
+static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       u8 reg;
+
+       local_irq_disable();
+       rtc_wait_not_busy();
+       reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+       if (enabled)
+               reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
+       else
+               reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+       rtc_wait_not_busy();
+       rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
+       local_irq_enable();
+
+       return 0;
+}
+
 /* this hardware doesn't support "don't care" alarm fields */
 static int tm2bcd(struct rtc_time *tm)
 {
@@ -309,6 +318,7 @@ static struct rtc_class_ops omap_rtc_ops = {
        .set_time       = omap_rtc_set_time,
        .read_alarm     = omap_rtc_read_alarm,
        .set_alarm      = omap_rtc_set_alarm,
+       .alarm_irq_enable = omap_rtc_alarm_irq_enable,
 };
 
 static int omap_rtc_alarm;
index c086fc3..242bbf8 100644 (file)
@@ -81,12 +81,16 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
 
 static int rtc_proc_open(struct inode *inode, struct file *file)
 {
+       int ret;
        struct rtc_device *rtc = PDE(inode)->data;
 
        if (!try_module_get(THIS_MODULE))
                return -ENODEV;
 
-       return single_open(file, rtc_proc_show, rtc);
+       ret = single_open(file, rtc_proc_show, rtc);
+       if (ret)
+               module_put(THIS_MODULE);
+       return ret;
 }
 
 static int rtc_proc_release(struct inode *inode, struct file *file)
index 36eb661..694da39 100644 (file)
@@ -76,7 +76,7 @@ static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
 static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
                                unsigned int reg)
 {
-       return __raw_writel(val, &priv->regs[reg]);
+       __raw_writel(val, &priv->regs[reg]);
 }
 
 static void rp5c01_lock(struct rp5c01_priv *priv)
index dd14e20..6aaa155 100644 (file)
@@ -299,14 +299,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
                if (rs5c->type == rtc_rs5c372a
                                && (buf & RS5C372A_CTRL1_SL1))
                        return -ENOIOCTLCMD;
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               /* these irq management calls only make sense for chips
-                * which are wired up to an IRQ.
-                */
-               if (!rs5c->has_irq)
-                       return -ENOIOCTLCMD;
-               break;
        default:
                return -ENOIOCTLCMD;
        }
@@ -317,12 +309,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 
        addr = RS5C_ADDR(RS5C_REG_CTRL1);
        switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
-               buf &= ~RS5C_CTRL1_AALE;
-               break;
-       case RTC_AIE_ON:        /* alarm on */
-               buf |= RS5C_CTRL1_AALE;
-               break;
        case RTC_UIE_OFF:       /* update off */
                buf &= ~RS5C_CTRL1_CT_MASK;
                break;
@@ -347,6 +333,39 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 #endif
 
 
+static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct rs5c372          *rs5c = i2c_get_clientdata(client);
+       unsigned char           buf;
+       int                     status, addr;
+
+       buf = rs5c->regs[RS5C_REG_CTRL1];
+
+       if (!rs5c->has_irq)
+               return -EINVAL;
+
+       status = rs5c_get_regs(rs5c);
+       if (status < 0)
+               return status;
+
+       addr = RS5C_ADDR(RS5C_REG_CTRL1);
+       if (enabled)
+               buf |= RS5C_CTRL1_AALE;
+       else
+               buf &= ~RS5C_CTRL1_AALE;
+
+       if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
+               printk(KERN_WARNING "%s: can't update alarm\n",
+                       rs5c->rtc->name);
+               status = -EIO;
+       } else
+               rs5c->regs[RS5C_REG_CTRL1] = buf;
+
+       return status;
+}
+
+
 /* NOTE:  Since RTC_WKALM_{RD,SET} were originally defined for EFI,
  * which only exposes a polled programming interface; and since
  * these calls map directly to those EFI requests; we don't demand
@@ -466,6 +485,7 @@ static const struct rtc_class_ops rs5c372_rtc_ops = {
        .set_time       = rs5c372_rtc_set_time,
        .read_alarm     = rs5c_read_alarm,
        .set_alarm      = rs5c_set_alarm,
+       .alarm_irq_enable = rs5c_rtc_alarm_irq_enable,
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
index cf953ec..b80fa28 100644 (file)
@@ -77,18 +77,20 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
 }
 
 /* Update control registers */
-static void s3c_rtc_setaie(int to)
+static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
        unsigned int tmp;
 
-       pr_debug("%s: aie=%d\n", __func__, to);
+       pr_debug("%s: aie=%d\n", __func__, enabled);
 
        tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 
-       if (to)
+       if (enabled)
                tmp |= S3C2410_RTCALM_ALMEN;
 
        writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
+
+       return 0;
 }
 
 static int s3c_rtc_setpie(struct device *dev, int enabled)
@@ -308,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        writeb(alrm_en, base + S3C2410_RTCALM);
 
-       s3c_rtc_setaie(alrm->enabled);
+       s3c_rtc_setaie(dev, alrm->enabled);
 
        return 0;
 }
@@ -440,7 +442,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
        rtc_device_unregister(rtc);
 
        s3c_rtc_setpie(&dev->dev, 0);
-       s3c_rtc_setaie(0);
+       s3c_rtc_setaie(&dev->dev, 0);
 
        clk_disable(rtc_clk);
        clk_put(rtc_clk);
index 88ea52b..5dfe5ff 100644 (file)
@@ -314,16 +314,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
                unsigned long arg)
 {
        switch (cmd) {
-       case RTC_AIE_OFF:
-               spin_lock_irq(&sa1100_rtc_lock);
-               RTSR &= ~RTSR_ALE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
-       case RTC_AIE_ON:
-               spin_lock_irq(&sa1100_rtc_lock);
-               RTSR |= RTSR_ALE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
        case RTC_UIE_OFF:
                spin_lock_irq(&sa1100_rtc_lock);
                RTSR &= ~RTSR_HZE;
@@ -338,6 +328,17 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
        return -ENOIOCTLCMD;
 }
 
+static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       spin_lock_irq(&sa1100_rtc_lock);
+       if (enabled)
+               RTSR |= RTSR_ALE;
+       else
+               RTSR &= ~RTSR_ALE;
+       spin_unlock_irq(&sa1100_rtc_lock);
+       return 0;
+}
+
 static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        rtc_time_to_tm(RCNR, tm);
@@ -410,6 +411,7 @@ static const struct rtc_class_ops sa1100_rtc_ops = {
        .proc = sa1100_rtc_proc,
        .irq_set_freq = sa1100_irq_set_freq,
        .irq_set_state = sa1100_irq_set_state,
+       .alarm_irq_enable = sa1100_rtc_alarm_irq_enable,
 };
 
 static int sa1100_rtc_probe(struct platform_device *pdev)
index 06e41ed..93314a9 100644 (file)
@@ -350,10 +350,6 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        unsigned int ret = 0;
 
        switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
-               break;
        case RTC_UIE_OFF:
                rtc->periodic_freq &= ~PF_OXS;
                sh_rtc_setcie(dev, 0);
@@ -369,6 +365,12 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        return ret;
 }
 
+static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       sh_rtc_setaie(dev, enabled);
+       return 0;
+}
+
 static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -604,6 +606,7 @@ static struct rtc_class_ops sh_rtc_ops = {
        .irq_set_state  = sh_rtc_irq_set_state,
        .irq_set_freq   = sh_rtc_irq_set_freq,
        .proc           = sh_rtc_proc,
+       .alarm_irq_enable = sh_rtc_alarm_irq_enable,
 };
 
 static int __init sh_rtc_probe(struct platform_device *pdev)
index 51725f7..a82d6fe 100644 (file)
@@ -50,24 +50,9 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
-static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
-       unsigned long arg)
+static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
 {
-       /* We do support interrupts, they're generated
-        * using the sysfs interface.
-        */
-       switch (cmd) {
-       case RTC_PIE_ON:
-       case RTC_PIE_OFF:
-       case RTC_UIE_ON:
-       case RTC_UIE_OFF:
-       case RTC_AIE_ON:
-       case RTC_AIE_OFF:
-               return 0;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       return 0;
 }
 
 static const struct rtc_class_ops test_rtc_ops = {
@@ -76,7 +61,7 @@ static const struct rtc_class_ops test_rtc_ops = {
        .read_alarm = test_rtc_read_alarm,
        .set_alarm = test_rtc_set_alarm,
        .set_mmss = test_rtc_set_mmss,
-       .ioctl = test_rtc_ioctl,
+       .alarm_irq_enable = test_rtc_alarm_irq_enable,
 };
 
 static ssize_t test_irq_show(struct device *dev,
index c324424..769190a 100644 (file)
@@ -240,26 +240,6 @@ static int vr41xx_rtc_irq_set_state(struct device *dev, int enabled)
 static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        switch (cmd) {
-       case RTC_AIE_ON:
-               spin_lock_irq(&rtc_lock);
-
-               if (!alarm_enabled) {
-                       enable_irq(aie_irq);
-                       alarm_enabled = 1;
-               }
-
-               spin_unlock_irq(&rtc_lock);
-               break;
-       case RTC_AIE_OFF:
-               spin_lock_irq(&rtc_lock);
-
-               if (alarm_enabled) {
-                       disable_irq(aie_irq);
-                       alarm_enabled = 0;
-               }
-
-               spin_unlock_irq(&rtc_lock);
-               break;
        case RTC_EPOCH_READ:
                return put_user(epoch, (unsigned long __user *)arg);
        case RTC_EPOCH_SET:
@@ -275,6 +255,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
        return 0;
 }
 
+static int vr41xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       spin_lock_irq(&rtc_lock);
+       if (enabled) {
+               if (!alarm_enabled) {
+                       enable_irq(aie_irq);
+                       alarm_enabled = 1;
+               }
+       } else {
+               if (alarm_enabled) {
+                       disable_irq(aie_irq);
+                       alarm_enabled = 0;
+               }
+       }
+       spin_unlock_irq(&rtc_lock);
+       return 0;
+}
+
 static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = (struct platform_device *)dev_id;
index 4155805..2b771f1 100644 (file)
@@ -319,6 +319,9 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        lcu = private->lcu;
+       /* nothing to do if already disconnected */
+       if (!lcu)
+               return;
        device->discipline->get_uid(device, &uid);
        spin_lock_irqsave(&lcu->lock, flags);
        list_del_init(&device->alias_list);
@@ -680,6 +683,9 @@ int dasd_alias_remove_device(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        lcu = private->lcu;
+       /* nothing to do if already removed */
+       if (!lcu)
+               return 0;
        spin_lock_irqsave(&lcu->lock, flags);
        _remove_device_from_lcu(lcu, device);
        spin_unlock_irqrestore(&lcu->lock, flags);
index 318672d..a9fe23d 100644 (file)
@@ -72,7 +72,7 @@ static struct dasd_discipline dasd_eckd_discipline;
 static struct ccw_device_id dasd_eckd_ids[] = {
        { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
        { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
-       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
+       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3380, 0), .driver_info = 0x3},
        { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
        { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
        { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
index e9fff2b..5640c89 100644 (file)
@@ -476,7 +476,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)
 static int get_inbound_buffer_frontier(struct qdio_q *q)
 {
        int count, stop;
-       unsigned char state;
+       unsigned char state = 0;
 
        /*
         * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -643,7 +643,7 @@ void qdio_inbound_processing(unsigned long data)
 static int get_outbound_buffer_frontier(struct qdio_q *q)
 {
        int count, stop;
-       unsigned char state;
+       unsigned char state = 0;
 
        if (need_siga_sync(q))
                if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
index 65ebee0..b6a6356 100644 (file)
@@ -565,7 +565,7 @@ static int netiucv_callback_connreq(struct iucv_path *path,
        struct iucv_event ev;
        int rc;
 
-       if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+       if (memcmp(iucvMagic, ipuser, 16))
                /* ipuser must match iucvMagic. */
                return -EINVAL;
        rc = -EINVAL;
index 29f848b..019ae58 100644 (file)
@@ -988,16 +988,30 @@ static void qeth_get_channel_path_desc(struct qeth_card *card)
        chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
        if (chp_dsc != NULL) {
                /* CHPP field bit 6 == 1 -> single queue */
-               if ((chp_dsc->chpp & 0x02) == 0x02)
+               if ((chp_dsc->chpp & 0x02) == 0x02) {
+                       if ((atomic_read(&card->qdio.state) !=
+                               QETH_QDIO_UNINITIALIZED) &&
+                           (card->qdio.no_out_queues == 4))
+                               /* change from 4 to 1 outbound queues */
+                               qeth_free_qdio_buffers(card);
                        card->qdio.no_out_queues = 1;
+                       if (card->qdio.default_out_queue != 0)
+                               dev_info(&card->gdev->dev,
+                                       "Priority Queueing not supported\n");
+                       card->qdio.default_out_queue = 0;
+               } else {
+                       if ((atomic_read(&card->qdio.state) !=
+                               QETH_QDIO_UNINITIALIZED) &&
+                           (card->qdio.no_out_queues == 1)) {
+                               /* change from 1 to 4 outbound queues */
+                               qeth_free_qdio_buffers(card);
+                               card->qdio.default_out_queue = 2;
+                       }
+                       card->qdio.no_out_queues = 4;
+               }
                card->info.func_level = 0x4100 + chp_dsc->desc;
                kfree(chp_dsc);
        }
-       if (card->qdio.no_out_queues == 1) {
-               card->qdio.default_out_queue = 0;
-               dev_info(&card->gdev->dev,
-                       "Priority Queueing not supported\n");
-       }
        QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues);
        QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level);
        return;
@@ -1832,33 +1846,6 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
        }
 }
 
-static inline int qeth_get_max_mtu_for_card(int cardtype)
-{
-       switch (cardtype) {
-
-       case QETH_CARD_TYPE_UNKNOWN:
-       case QETH_CARD_TYPE_OSD:
-       case QETH_CARD_TYPE_OSN:
-       case QETH_CARD_TYPE_OSM:
-       case QETH_CARD_TYPE_OSX:
-               return 61440;
-       case QETH_CARD_TYPE_IQD:
-               return 57344;
-       default:
-               return 1500;
-       }
-}
-
-static inline int qeth_get_mtu_out_of_mpc(int cardtype)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_IQD:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
 static inline int qeth_get_mtu_outof_framesize(int framesize)
 {
        switch (framesize) {
@@ -1881,10 +1868,9 @@ static inline int qeth_mtu_is_valid(struct qeth_card *card, int mtu)
        case QETH_CARD_TYPE_OSD:
        case QETH_CARD_TYPE_OSM:
        case QETH_CARD_TYPE_OSX:
-               return ((mtu >= 576) && (mtu <= 61440));
        case QETH_CARD_TYPE_IQD:
                return ((mtu >= 576) &&
-                       (mtu <= card->info.max_mtu + 4096 - 32));
+                       (mtu <= card->info.max_mtu));
        case QETH_CARD_TYPE_OSN:
        case QETH_CARD_TYPE_UNKNOWN:
        default:
@@ -1907,7 +1893,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
        memcpy(&card->token.ulp_filter_r,
               QETH_ULP_ENABLE_RESP_FILTER_TOKEN(iob->data),
               QETH_MPC_TOKEN_LENGTH);
-       if (qeth_get_mtu_out_of_mpc(card->info.type)) {
+       if (card->info.type == QETH_CARD_TYPE_IQD) {
                memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(iob->data), 2);
                mtu = qeth_get_mtu_outof_framesize(framesize);
                if (!mtu) {
@@ -1915,12 +1901,21 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
                        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
                        return 0;
                }
-               card->info.max_mtu = mtu;
+               if (card->info.initial_mtu && (card->info.initial_mtu != mtu)) {
+                       /* frame size has changed */
+                       if (card->dev &&
+                           ((card->dev->mtu == card->info.initial_mtu) ||
+                            (card->dev->mtu > mtu)))
+                               card->dev->mtu = mtu;
+                       qeth_free_qdio_buffers(card);
+               }
                card->info.initial_mtu = mtu;
+               card->info.max_mtu = mtu;
                card->qdio.in_buf_size = mtu + 2 * PAGE_SIZE;
        } else {
                card->info.initial_mtu = qeth_get_initial_mtu_for_card(card);
-               card->info.max_mtu = qeth_get_max_mtu_for_card(card->info.type);
+               card->info.max_mtu = *(__u16 *)QETH_ULP_ENABLE_RESP_MAX_MTU(
+                       iob->data);
                card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT;
        }
 
@@ -3775,6 +3770,47 @@ static inline int qeth_get_qdio_q_format(struct qeth_card *card)
        }
 }
 
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+       int rc;
+       int length;
+       char *prcd;
+       struct ccw_device *ddev;
+       int ddev_offline = 0;
+
+       QETH_DBF_TEXT(SETUP, 2, "detcapab");
+       ddev = CARD_DDEV(card);
+       if (!ddev->online) {
+               ddev_offline = 1;
+               rc = ccw_device_set_online(ddev);
+               if (rc) {
+                       QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+                       goto out;
+               }
+       }
+
+       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+       if (rc) {
+               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+               goto out_offline;
+       }
+       qeth_configure_unitaddr(card, prcd);
+       qeth_configure_blkt_default(card, prcd);
+       kfree(prcd);
+
+       rc = qdio_get_ssqd_desc(ddev, &card->ssqd);
+       if (rc)
+               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+       if (ddev_offline == 1)
+               ccw_device_set_offline(ddev);
+out:
+       return;
+}
+
 static int qeth_qdio_establish(struct qeth_card *card)
 {
        struct qdio_initialize init_data;
@@ -3905,6 +3941,7 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
        atomic_set(&card->force_alloc_skb, 0);
+       qeth_get_channel_path_desc(card);
 retry:
        if (retries)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
@@ -3933,6 +3970,7 @@ retriable:
                else
                        goto retry;
        }
+       qeth_determine_capabilities(card);
        qeth_init_tokens(card);
        qeth_init_func_level(card);
        rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -4202,41 +4240,6 @@ void qeth_core_free_discipline(struct qeth_card *card)
        card->discipline.ccwgdriver = NULL;
 }
 
-static void qeth_determine_capabilities(struct qeth_card *card)
-{
-       int rc;
-       int length;
-       char *prcd;
-
-       QETH_DBF_TEXT(SETUP, 2, "detcapab");
-       rc = ccw_device_set_online(CARD_DDEV(card));
-       if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-               goto out;
-       }
-
-
-       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
-       if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
-               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
-               goto out_offline;
-       }
-       qeth_configure_unitaddr(card, prcd);
-       qeth_configure_blkt_default(card, prcd);
-       kfree(prcd);
-
-       rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
-       if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
-
-out_offline:
-       ccw_device_set_offline(CARD_DDEV(card));
-out:
-       return;
-}
-
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
index 7a7a1b6..ada0fe7 100644 (file)
@@ -573,13 +573,13 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
                case IPA_RC_L2_DUP_LAYER3_MAC:
                        dev_warn(&card->gdev->dev,
                                "MAC address %pM already exists\n",
-                               card->dev->dev_addr);
+                               cmd->data.setdelmac.mac);
                        break;
                case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
                case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
                        dev_warn(&card->gdev->dev,
                                "MAC address %pM is not authorized\n",
-                               card->dev->dev_addr);
+                               cmd->data.setdelmac.mac);
                        break;
                default:
                        break;
@@ -831,12 +831,14 @@ tx_drop:
        return NETDEV_TX_OK;
 }
 
-static int qeth_l2_open(struct net_device *dev)
+static int __qeth_l2_open(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
        int rc = 0;
 
        QETH_CARD_TEXT(card, 4, "qethopen");
+       if (card->state == CARD_STATE_UP)
+               return rc;
        if (card->state != CARD_STATE_SOFTSETUP)
                return -ENODEV;
 
@@ -857,6 +859,18 @@ static int qeth_l2_open(struct net_device *dev)
        return rc;
 }
 
+static int qeth_l2_open(struct net_device *dev)
+{
+       struct qeth_card *card = dev->ml_priv;
+
+       QETH_CARD_TEXT(card, 5, "qethope_");
+       if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
+               QETH_CARD_TEXT(card, 3, "openREC");
+               return -ERESTARTSYS;
+       }
+       return __qeth_l2_open(dev);
+}
+
 static int qeth_l2_stop(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
@@ -1046,7 +1060,7 @@ contin:
        if (recover_flag == CARD_STATE_RECOVER) {
                if (recovery_mode &&
                    card->info.type != QETH_CARD_TYPE_OSN) {
-                       qeth_l2_open(card->dev);
+                       __qeth_l2_open(card->dev);
                } else {
                        rtnl_lock();
                        dev_open(card->dev);
index e227e46..d09b0c4 100644 (file)
@@ -2998,7 +2998,9 @@ static inline void qeth_l3_hdr_csum(struct qeth_card *card,
         */
        if (iph->protocol == IPPROTO_UDP)
                hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_UDP;
-       hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
+       hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ |
+               QETH_HDR_EXT_CSUM_HDR_REQ;
+       iph->check = 0;
        if (card->options.performance_stats)
                card->perf_stats.tx_csum++;
 }
@@ -3240,12 +3242,14 @@ tx_drop:
        return NETDEV_TX_OK;
 }
 
-static int qeth_l3_open(struct net_device *dev)
+static int __qeth_l3_open(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
        int rc = 0;
 
        QETH_CARD_TEXT(card, 4, "qethopen");
+       if (card->state == CARD_STATE_UP)
+               return rc;
        if (card->state != CARD_STATE_SOFTSETUP)
                return -ENODEV;
        card->data.state = CH_STATE_UP;
@@ -3260,6 +3264,18 @@ static int qeth_l3_open(struct net_device *dev)
        return rc;
 }
 
+static int qeth_l3_open(struct net_device *dev)
+{
+       struct qeth_card *card = dev->ml_priv;
+
+       QETH_CARD_TEXT(card, 5, "qethope_");
+       if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
+               QETH_CARD_TEXT(card, 3, "openREC");
+               return -ERESTARTSYS;
+       }
+       return __qeth_l3_open(dev);
+}
+
 static int qeth_l3_stop(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
@@ -3564,7 +3580,7 @@ contin:
                netif_carrier_off(card->dev);
        if (recover_flag == CARD_STATE_RECOVER) {
                if (recovery_mode)
-                       qeth_l3_open(card->dev);
+                       __qeth_l3_open(card->dev);
                else {
                        rtnl_lock();
                        dev_open(card->dev);
index 65e1cf1..207b7d7 100644 (file)
@@ -60,7 +60,7 @@ static struct iucv_handler smsg_handler = {
 static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
                             u8 ipuser[16])
 {
-       if (strncmp(ipvmid, "*MSG    ", sizeof(ipvmid)) != 0)
+       if (strncmp(ipvmid, "*MSG    ", 8) != 0)
                return -EINVAL;
        /* Path pending from *MSG. */
        return iucv_path_accept(path, &smsg_handler, "SMSGIUCV        ", NULL);
index 475c31a..77b26f5 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr.h
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: SCSI RAID Device Driver for
 **                ARECA RAID Host adapter
 *******************************************************************************
 struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD                                             256
-#define ARCMSR_MAX_FREECCB_NUM                                                 320
-#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2010/02/02"
+#ifdef CONFIG_XEN
+       #define ARCMSR_MAX_FREECCB_NUM  160
+#else
+       #define ARCMSR_MAX_FREECCB_NUM  320
+#endif
+#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2010/08/05"
 #define ARCMSR_SCSI_INITIATOR_ID                                               255
 #define ARCMSR_MAX_XFER_SECTORS                                                        512
 #define ARCMSR_MAX_XFER_SECTORS_B                                              4096
@@ -60,7 +64,6 @@ struct device_attribute;
 #define ARCMSR_MAX_HBB_POSTQUEUE                                               264
 #define ARCMSR_MAX_XFER_LEN                                                    0x26000 /* 152K */
 #define ARCMSR_CDB_SG_PAGE_LENGTH                                              256 
-#define SCSI_CMD_ARECA_SPECIFIC                                                0xE1
 #ifndef PCI_DEVICE_ID_ARECA_1880
 #define PCI_DEVICE_ID_ARECA_1880 0x1880
  #endif
index a4e04c5..acdae33 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr_attr.c
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: attributes exported to sysfs and device host
 *******************************************************************************
 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
index 1cadcd6..984bd52 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr_hba.c
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: SCSI RAID Device Driver for
 **                ARECA RAID Host adapter
 *******************************************************************************
@@ -76,7 +76,7 @@ MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapte
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 static int sleeptime = 10;
-static int retrycount = 30;
+static int retrycount = 12;
 wait_queue_head_t wait_q;
 static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                                        struct scsi_cmnd *cmd);
@@ -187,7 +187,6 @@ int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
                if (isleep > 0) {
                        msleep(isleep*1000);
                }
-               printk(KERN_NOTICE "wake-up\n");
                return 0;
 }
 
@@ -921,7 +920,6 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
 }
 
 static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
-
 {
        int id, lun;
        if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
@@ -948,7 +946,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma
                                , pCCB->startdone
                                , atomic_read(&acb->ccboutstandingcount));
                  return;
-               }
+       }
        arcmsr_report_ccb_state(acb, pCCB, error);
 }
 
@@ -981,7 +979,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
        case ACB_ADAPTER_TYPE_B: {
                struct MessageUnit_B *reg = acb->pmuB;
                /*clear all outbound posted Q*/
-               writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, &reg->iop2drv_doorbell); /* clear doorbell interrupt */
+               writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */
                for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
                        if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
                                writel(0, &reg->done_qbuffer[i]);
@@ -1511,7 +1509,6 @@ static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
                arcmsr_drain_donequeue(acb, pCCB, error);
        }
 }
-
 static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
 {
        uint32_t index;
@@ -2106,10 +2103,6 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
        if (atomic_read(&acb->ccboutstandingcount) >=
                        ARCMSR_MAX_OUTSTANDING_CMD)
                return SCSI_MLQUEUE_HOST_BUSY;
-       if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
-               printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
-               return 0;
-       }
        ccb = arcmsr_get_freeccb(acb);
        if (!ccb)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -2393,6 +2386,7 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
        int index, rtn;
        bool error;
        polling_hbb_ccb_retry:
+
        poll_count++;
        /* clear doorbell interrupt */
        writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
@@ -2663,6 +2657,7 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
@@ -2670,8 +2665,10 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
                        atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if (atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
        }
@@ -2682,15 +2679,18 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_B __iomem *reg = acb->pmuB;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
                if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
-                       atomic_set(&acb->rq_map_token,16);
+                       atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if(atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
        }
@@ -2701,6 +2701,7 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_C __iomem *reg = acb->pmuC;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
@@ -2708,8 +2709,10 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
                        atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if (atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
                writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
@@ -2897,6 +2900,8 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
        uint32_t intmask_org;
        uint8_t rtnval = 0x00;
        int i = 0;
+       unsigned long flags;
+
        if (atomic_read(&acb->ccboutstandingcount) != 0) {
                /* disable all outbound interrupt */
                intmask_org = arcmsr_disable_outbound_ints(acb);
@@ -2907,7 +2912,12 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
                for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
                        ccb = acb->pccb_pool[i];
                        if (ccb->startdone == ARCMSR_CCB_START) {
-                               arcmsr_ccb_complete(ccb);
+                               scsi_dma_unmap(ccb->pcmd);
+                               ccb->startdone = ARCMSR_CCB_DONE;
+                               ccb->ccb_flags = 0;
+                               spin_lock_irqsave(&acb->ccblist_lock, flags);
+                               list_add_tail(&ccb->list, &acb->ccb_free_list);
+                               spin_unlock_irqrestore(&acb->ccblist_lock, flags);
                        }
                }
                atomic_set(&acb->ccboutstandingcount, 0);
@@ -2920,8 +2930,7 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
 
 static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
 {
-       struct AdapterControlBlock *acb =
-               (struct AdapterControlBlock *)cmd->device->host->hostdata;
+       struct AdapterControlBlock *acb;
        uint32_t intmask_org, outbound_doorbell;
        int retry_count = 0;
        int rtn = FAILED;
@@ -2971,31 +2980,16 @@ sleep_again:
                                atomic_set(&acb->rq_map_token, 16);
                                atomic_set(&acb->ante_token_value, 16);
                                acb->fw_flag = FW_NORMAL;
-                               init_timer(&acb->eternal_timer);
-                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                               acb->eternal_timer.data = (unsigned long) acb;
-                               acb->eternal_timer.function = &arcmsr_request_device_map;
-                               add_timer(&acb->eternal_timer);
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
                                rtn = SUCCESS;
                                printk(KERN_ERR "arcmsr: scsi  bus reset eh returns with success\n");
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
                                rtn = SUCCESS;
                        }
                        break;
@@ -3007,21 +3001,10 @@ sleep_again:
                                rtn = FAILED;
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                rtn = SUCCESS;
                        }
                        break;
@@ -3067,31 +3050,16 @@ sleep:
                                atomic_set(&acb->rq_map_token, 16);
                                atomic_set(&acb->ante_token_value, 16);
                                acb->fw_flag = FW_NORMAL;
-                               init_timer(&acb->eternal_timer);
-                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
-                               acb->eternal_timer.data = (unsigned long) acb;
-                               acb->eternal_timer.function = &arcmsr_request_device_map;
-                               add_timer(&acb->eternal_timer);
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
                                rtn = SUCCESS;
                                printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
                                rtn = SUCCESS;
                        }
                        break;
index 5815cbe..9a7aaf5 100644 (file)
@@ -646,6 +646,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 
        spin_lock_irqsave(shost->host_lock, flags);
        list_splice_init(&shost->eh_cmd_q, &eh_work_q);
+       shost->host_eh_scheduled = 0;
        spin_unlock_irqrestore(shost->host_lock, flags);
 
        SAS_DPRINTK("Enter %s\n", __func__);
index b2a8170..9ead039 100644 (file)
@@ -2176,9 +2176,9 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
                /* adjust hba_queue_depth, reply_free_queue_depth,
                 * and queue_size
                 */
-               ioc->hba_queue_depth -= queue_diff;
-               ioc->reply_free_queue_depth -= queue_diff;
-               queue_size -= queue_diff;
+               ioc->hba_queue_depth -= (queue_diff / 2);
+               ioc->reply_free_queue_depth -= (queue_diff / 2);
+               queue_size = facts->MaxReplyDescriptorPostQueueDepth;
        }
        ioc->reply_post_queue_depth = queue_size;
 
@@ -3941,6 +3941,8 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
 {
+       mpt2sas_scsih_reset_handler(ioc, reset_phase);
+       mpt2sas_ctl_reset_handler(ioc, reset_phase);
        switch (reset_phase) {
        case MPT2_IOC_PRE_RESET:
                dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
@@ -3971,8 +3973,6 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
                    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
                break;
        }
-       mpt2sas_scsih_reset_handler(ioc, reset_phase);
-       mpt2sas_ctl_reset_handler(ioc, reset_phase);
 }
 
 /**
@@ -4026,6 +4026,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 {
        int r;
        unsigned long flags;
+       u8 pe_complete = ioc->wait_for_port_enable_to_complete;
 
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
            __func__));
@@ -4068,6 +4069,14 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
        if (r)
                goto out;
        _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
+
+       /* If this hard reset is called while port enable is active, then
+        * there is no reason to call make_ioc_operational
+        */
+       if (pe_complete) {
+               r = -EFAULT;
+               goto out;
+       }
        r = _base_make_ioc_operational(ioc, sleep_flag);
        if (!r)
                _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
index eda347c..5ded3db 100644 (file)
@@ -819,7 +819,7 @@ _scsih_is_end_device(u32 device_info)
 }
 
 /**
- * mptscsih_get_scsi_lookup - returns scmd entry
+ * _scsih_scsi_lookup_get - returns scmd entry
  * @ioc: per adapter object
  * @smid: system request message index
  *
@@ -832,6 +832,28 @@ _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
 }
 
 /**
+ * _scsih_scsi_lookup_get_clear - returns scmd entry
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ * Then will derefrence the stored scmd pointer.
+ */
+static inline struct scsi_cmnd *
+_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long flags;
+       struct scsi_cmnd *scmd;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->scsi_lookup[smid - 1].scmd;
+       ioc->scsi_lookup[smid - 1].scmd = NULL;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       return scmd;
+}
+
+/**
  * _scsih_scsi_lookup_find_by_scmd - scmd lookup
  * @ioc: per adapter object
  * @smid: system request message index
@@ -2981,9 +3003,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
        u16 handle;
 
        for (i = 0 ; i < event_data->NumEntries; i++) {
-               if (event_data->PHY[i].PhyStatus &
-                   MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
-                       continue;
                handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
                if (!handle)
                        continue;
@@ -3210,7 +3229,7 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
        u16 count = 0;
 
        for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
-               scmd = _scsih_scsi_lookup_get(ioc, smid);
+               scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
                if (!scmd)
                        continue;
                count++;
@@ -3804,7 +3823,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        u32 response_code = 0;
 
        mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
-       scmd = _scsih_scsi_lookup_get(ioc, smid);
+       scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
        if (scmd == NULL)
                return 1;
 
@@ -5005,6 +5024,12 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
                     event_data);
 #endif
 
+       /* In MPI Revision K (0xC), the internal device reset complete was
+        * implemented, so avoid setting tm_busy flag for older firmware.
+        */
+       if ((ioc->facts.HeaderVersion >> 8) < 0xC)
+               return;
+
        if (event_data->ReasonCode !=
            MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
           event_data->ReasonCode !=
@@ -5099,6 +5124,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
     struct fw_event_work *fw_event)
 {
        struct scsi_cmnd *scmd;
+       struct scsi_device *sdev;
        u16 smid, handle;
        u32 lun;
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -5109,12 +5135,17 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
        Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
 #endif
        u16 ioc_status;
+       unsigned long flags;
+       int r;
+
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: "
            "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
            event_data->PortWidth));
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
            __func__));
 
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->broadcast_aen_busy = 0;
        termination_count = 0;
        query_count = 0;
        mpi_reply = ioc->tm_cmds.reply;
@@ -5122,7 +5153,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                scmd = _scsih_scsi_lookup_get(ioc, smid);
                if (!scmd)
                        continue;
-               sas_device_priv_data = scmd->device->hostdata;
+               sdev = scmd->device;
+               sas_device_priv_data = sdev->hostdata;
                if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
                        continue;
                 /* skip hidden raid components */
@@ -5138,6 +5170,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                lun = sas_device_priv_data->lun;
                query_count++;
 
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
                    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
                ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
@@ -5147,14 +5180,20 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                    (mpi_reply->ResponseCode ==
                     MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
                     mpi_reply->ResponseCode ==
-                    MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+                    MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) {
+                       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                        continue;
-
-               mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
-                   MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);
+               }
+               r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
+                   sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
+                   scmd);
+               if (r == FAILED)
+                       sdev_printk(KERN_WARNING, sdev, "task abort: FAILED "
+                           "scmd(%p)\n", scmd);
                termination_count += le32_to_cpu(mpi_reply->TerminationCount);
+               spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
        }
-       ioc->broadcast_aen_busy = 0;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
            "%s - exit, query_count = %d termination_count = %d\n",
@@ -6626,6 +6665,7 @@ _scsih_remove(struct pci_dev *pdev)
                destroy_workqueue(wq);
 
        /* release all the volumes */
+       _scsih_ir_shutdown(ioc);
        list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
            list) {
                if (raid_device->starget) {
index 44578b5..d3e58d7 100644 (file)
@@ -1561,6 +1561,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
        struct Scsi_Host *host = rport_to_shost(rport);
        fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+       unsigned long flags;
 
        if (!fcport)
                return;
@@ -1573,10 +1574,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
         * Transport has effectively 'deleted' the rport, clear
         * all local references.
         */
-       spin_lock_irq(host->host_lock);
+       spin_lock_irqsave(host->host_lock, flags);
        fcport->rport = fcport->drport = NULL;
        *((fc_port_t **)rport->dd_data) = NULL;
-       spin_unlock_irq(host->host_lock);
+       spin_unlock_irqrestore(host->host_lock, flags);
 
        if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
                return;
index f948e1a..d9479c3 100644 (file)
@@ -2505,11 +2505,12 @@ qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
        struct fc_rport *rport;
+       unsigned long flags;
 
-       spin_lock_irq(fcport->vha->host->host_lock);
+       spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        rport = fcport->drport ? fcport->drport: fcport->rport;
        fcport->drport = NULL;
-       spin_unlock_irq(fcport->vha->host->host_lock);
+       spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
        if (rport)
                fc_remote_port_delete(rport);
 }
@@ -2879,6 +2880,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
        struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
 
        qla2x00_rport_del(fcport);
 
@@ -2893,9 +2895,9 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
                    "Unable to allocate fc remote port!\n");
                return;
        }
-       spin_lock_irq(fcport->vha->host->host_lock);
+       spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        *((fc_port_t **)rport->dd_data) = fcport;
-       spin_unlock_irq(fcport->vha->host->host_lock);
+       spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
 
        rport->supported_classes = fcport->supported_classes;
 
index c194c23..f27724d 100644 (file)
@@ -562,7 +562,6 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)
        }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-                       atomic_read(&fcport->state) == FCS_DEVICE_LOST ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
@@ -2513,6 +2512,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
 {
        struct fc_rport *rport;
        scsi_qla_host_t *base_vha;
+       unsigned long flags;
 
        if (!fcport->rport)
                return;
@@ -2520,9 +2520,9 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
        rport = fcport->rport;
        if (defer) {
                base_vha = pci_get_drvdata(vha->hw->pdev);
-               spin_lock_irq(vha->host->host_lock);
+               spin_lock_irqsave(vha->host->host_lock, flags);
                fcport->drport = rport;
-               spin_unlock_irq(vha->host->host_lock);
+               spin_unlock_irqrestore(vha->host->host_lock, flags);
                set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
                qla2xxx_wake_dpc(base_vha);
        } else
@@ -3282,10 +3282,10 @@ qla2x00_do_dpc(void *data)
 
        set_user_nice(current, -20);
 
+       set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
                DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
 
-               set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                __set_current_state(TASK_RUNNING);
 
@@ -3454,7 +3454,9 @@ qla2x00_do_dpc(void *data)
                qla2x00_do_dpc_all_vps(base_vha);
 
                ha->dpc_active = 0;
+               set_current_state(TASK_INTERRUPTIBLE);
        } /* End of while(1) */
+       __set_current_state(TASK_RUNNING);
 
        DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no));
 
index 7b31093..a6b2d72 100644 (file)
@@ -1671,7 +1671,7 @@ static int do_device_access(struct scsi_cmnd *scmd,
                            unsigned long long lba, unsigned int num, int write)
 {
        int ret;
-       unsigned int block, rest = 0;
+       unsigned long long block, rest = 0;
        int (*func)(struct scsi_cmnd *, unsigned char *, int);
 
        func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
index 9045c52..fb2bb35 100644 (file)
@@ -443,7 +443,7 @@ static void scsi_run_queue(struct request_queue *q)
                                        &sdev->request_queue->queue_flags);
                if (flagset)
                        queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue);
-               __blk_run_queue(sdev->request_queue);
+               __blk_run_queue(sdev->request_queue, false);
                if (flagset)
                        queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);
                spin_unlock(sdev->request_queue->queue_lock);
index 998c01b..5c3ccfc 100644 (file)
@@ -3829,7 +3829,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
                  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
        if (flagset)
                queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q);
-       __blk_run_queue(rport->rqst_q);
+       __blk_run_queue(rport->rqst_q, false);
        if (flagset)
                queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
        spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
deleted file mode 100644 (file)
index d89aa38..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * linux/drivers/serial/21285.c
- *
- * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
- *
- * Based on drivers/char/serial.c
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/hardware/dec21285.h>
-#include <mach/hardware.h>
-
-#define BAUD_BASE              (mem_fclk_21285/64)
-
-#define SERIAL_21285_NAME      "ttyFB"
-#define SERIAL_21285_MAJOR     204
-#define SERIAL_21285_MINOR     4
-
-#define RXSTAT_DUMMY_READ      0x80000000
-#define RXSTAT_FRAME           (1 << 0)
-#define RXSTAT_PARITY          (1 << 1)
-#define RXSTAT_OVERRUN         (1 << 2)
-#define RXSTAT_ANYERR          (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
-
-#define H_UBRLCR_BREAK         (1 << 0)
-#define H_UBRLCR_PARENB                (1 << 1)
-#define H_UBRLCR_PAREVN                (1 << 2)
-#define H_UBRLCR_STOPB         (1 << 3)
-#define H_UBRLCR_FIFO          (1 << 4)
-
-static const char serial21285_name[] = "Footbridge UART";
-
-#define tx_enabled(port)       ((port)->unused[0])
-#define rx_enabled(port)       ((port)->unused[1])
-
-/*
- * The documented expression for selecting the divisor is:
- *  BAUD_BASE / baud - 1
- * However, typically BAUD_BASE is not divisible by baud, so
- * we want to select the divisor that gives us the minimum
- * error.  Therefore, we want:
- *  int(BAUD_BASE / baud - 0.5) ->
- *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
- *  int((BAUD_BASE - (baud >> 1)) / baud)
- */
-
-static void serial21285_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               disable_irq_nosync(IRQ_CONTX);
-               tx_enabled(port) = 0;
-       }
-}
-
-static void serial21285_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(IRQ_CONTX);
-               tx_enabled(port) = 1;
-       }
-}
-
-static void serial21285_stop_rx(struct uart_port *port)
-{
-       if (rx_enabled(port)) {
-               disable_irq_nosync(IRQ_CONRX);
-               rx_enabled(port) = 0;
-       }
-}
-
-static void serial21285_enable_ms(struct uart_port *port)
-{
-}
-
-static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, flag, rxs, max_count = 256;
-
-       status = *CSR_UARTFLG;
-       while (!(status & 0x10) && max_count--) {
-               ch = *CSR_UARTDR;
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
-               if (unlikely(rxs & RXSTAT_ANYERR)) {
-                       if (rxs & RXSTAT_PARITY)
-                               port->icount.parity++;
-                       else if (rxs & RXSTAT_FRAME)
-                               port->icount.frame++;
-                       if (rxs & RXSTAT_OVERRUN)
-                               port->icount.overrun++;
-
-                       rxs &= port->read_status_mask;
-
-                       if (rxs & RXSTAT_PARITY)
-                               flag = TTY_PARITY;
-                       else if (rxs & RXSTAT_FRAME)
-                               flag = TTY_FRAME;
-               }
-
-               uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
-
-               status = *CSR_UARTFLG;
-       }
-       tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count = 256;
-
-       if (port->x_char) {
-               *CSR_UARTDR = port->x_char;
-               port->icount.tx++;
-               port->x_char = 0;
-               goto out;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               serial21285_stop_tx(port);
-               goto out;
-       }
-
-       do {
-               *CSR_UARTDR = xmit->buf[xmit->tail];
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               serial21285_stop_tx(port);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial21285_tx_empty(struct uart_port *port)
-{
-       return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
-}
-
-/* no modem control lines */
-static unsigned int serial21285_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial21285_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int h_lcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-       h_lcr = *CSR_H_UBRLCR;
-       if (break_state)
-               h_lcr |= H_UBRLCR_BREAK;
-       else
-               h_lcr &= ~H_UBRLCR_BREAK;
-       *CSR_H_UBRLCR = h_lcr;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int serial21285_startup(struct uart_port *port)
-{
-       int ret;
-
-       tx_enabled(port) = 1;
-       rx_enabled(port) = 1;
-
-       ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
-                         serial21285_name, port);
-       if (ret == 0) {
-               ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
-                                 serial21285_name, port);
-               if (ret)
-                       free_irq(IRQ_CONRX, port);
-       }
-
-       return ret;
-}
-
-static void serial21285_shutdown(struct uart_port *port)
-{
-       free_irq(IRQ_CONTX, port);
-       free_irq(IRQ_CONRX, port);
-}
-
-static void
-serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
-                       struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, quot, h_lcr, b;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       /*
-        * We don't support BREAK character recognition.
-        */
-       termios->c_iflag &= ~(IGNBRK | BRKINT);
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-       b = port->uartclk / (16 * quot);
-       tty_termios_encode_baud_rate(termios, b, b);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               h_lcr = 0x00;
-               break;
-       case CS6:
-               h_lcr = 0x20;
-               break;
-       case CS7:
-               h_lcr = 0x40;
-               break;
-       default: /* CS8 */
-               h_lcr = 0x60;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               h_lcr |= H_UBRLCR_STOPB;
-       if (termios->c_cflag & PARENB) {
-               h_lcr |= H_UBRLCR_PARENB;
-               if (!(termios->c_cflag & PARODD))
-                       h_lcr |= H_UBRLCR_PAREVN;
-       }
-
-       if (port->fifosize)
-               h_lcr |= H_UBRLCR_FIFO;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Which character status flags are we interested in?
-        */
-       port->read_status_mask = RXSTAT_OVERRUN;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
-
-       /*
-        * Which character status flags should we ignore?
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
-       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RXSTAT_OVERRUN;
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
-       quot -= 1;
-
-       *CSR_UARTCON = 0;
-       *CSR_L_UBRLCR = quot & 0xff;
-       *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
-       *CSR_H_UBRLCR = h_lcr;
-       *CSR_UARTCON = 1;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *serial21285_type(struct uart_port *port)
-{
-       return port->type == PORT_21285 ? "DC21285" : NULL;
-}
-
-static void serial21285_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, 32);
-}
-
-static int serial21285_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, 32, serial21285_name)
-                        != NULL ? 0 : -EBUSY;
-}
-
-static void serial21285_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
-               port->type = PORT_21285;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
-               ret = -EINVAL;
-       if (ser->irq != NO_IRQ)
-               ret = -EINVAL;
-       if (ser->baud_base != port->uartclk / 16)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops serial21285_ops = {
-       .tx_empty       = serial21285_tx_empty,
-       .get_mctrl      = serial21285_get_mctrl,
-       .set_mctrl      = serial21285_set_mctrl,
-       .stop_tx        = serial21285_stop_tx,
-       .start_tx       = serial21285_start_tx,
-       .stop_rx        = serial21285_stop_rx,
-       .enable_ms      = serial21285_enable_ms,
-       .break_ctl      = serial21285_break_ctl,
-       .startup        = serial21285_startup,
-       .shutdown       = serial21285_shutdown,
-       .set_termios    = serial21285_set_termios,
-       .type           = serial21285_type,
-       .release_port   = serial21285_release_port,
-       .request_port   = serial21285_request_port,
-       .config_port    = serial21285_config_port,
-       .verify_port    = serial21285_verify_port,
-};
-
-static struct uart_port serial21285_port = {
-       .mapbase        = 0x42000160,
-       .iotype         = UPIO_MEM,
-       .irq            = NO_IRQ,
-       .fifosize       = 16,
-       .ops            = &serial21285_ops,
-       .flags          = UPF_BOOT_AUTOCONF,
-};
-
-static void serial21285_setup_ports(void)
-{
-       serial21285_port.uartclk = mem_fclk_21285 / 4;
-}
-
-#ifdef CONFIG_SERIAL_21285_CONSOLE
-static void serial21285_console_putchar(struct uart_port *port, int ch)
-{
-       while (*CSR_UARTFLG & 0x20)
-               barrier();
-       *CSR_UARTDR = ch;
-}
-
-static void
-serial21285_console_write(struct console *co, const char *s,
-                         unsigned int count)
-{
-       uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
-}
-
-static void __init
-serial21285_get_options(struct uart_port *port, int *baud,
-                       int *parity, int *bits)
-{
-       if (*CSR_UARTCON == 1) {
-               unsigned int tmp;
-
-               tmp = *CSR_H_UBRLCR;
-               switch (tmp & 0x60) {
-               case 0x00:
-                       *bits = 5;
-                       break;
-               case 0x20:
-                       *bits = 6;
-                       break;
-               case 0x40:
-                       *bits = 7;
-                       break;
-               default:
-               case 0x60:
-                       *bits = 8;
-                       break;
-               }
-
-               if (tmp & H_UBRLCR_PARENB) {
-                       *parity = 'o';
-                       if (tmp & H_UBRLCR_PAREVN)
-                               *parity = 'e';
-               }
-
-               tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
-
-               *baud = port->uartclk / (16 * (tmp + 1));
-       }
-}
-
-static int __init serial21285_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &serial21285_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (machine_is_personal_server())
-               baud = 57600;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               serial21285_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver serial21285_reg;
-
-static struct console serial21285_console =
-{
-       .name           = SERIAL_21285_NAME,
-       .write          = serial21285_console_write,
-       .device         = uart_console_device,
-       .setup          = serial21285_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial21285_reg,
-};
-
-static int __init rs285_console_init(void)
-{
-       serial21285_setup_ports();
-       register_console(&serial21285_console);
-       return 0;
-}
-console_initcall(rs285_console_init);
-
-#define SERIAL_21285_CONSOLE   &serial21285_console
-#else
-#define SERIAL_21285_CONSOLE   NULL
-#endif
-
-static struct uart_driver serial21285_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyFB",
-       .dev_name               = "ttyFB",
-       .major                  = SERIAL_21285_MAJOR,
-       .minor                  = SERIAL_21285_MINOR,
-       .nr                     = 1,
-       .cons                   = SERIAL_21285_CONSOLE,
-};
-
-static int __init serial21285_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: 21285 driver\n");
-
-       serial21285_setup_ports();
-
-       ret = uart_register_driver(&serial21285_reg);
-       if (ret == 0)
-               uart_add_one_port(&serial21285_reg, &serial21285_port);
-
-       return ret;
-}
-
-static void __exit serial21285_exit(void)
-{
-       uart_remove_one_port(&serial21285_reg, &serial21285_port);
-       uart_unregister_driver(&serial21285_reg);
-}
-
-module_init(serial21285_init);
-module_exit(serial21285_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
-MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
deleted file mode 100644 (file)
index be0ebce..0000000
+++ /dev/null
@@ -1,1472 +0,0 @@
-/* 68328serial.c: Serial port driver for 68328 microcontroller
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- * Copyright (C) 2002-2003  David McCullough   <davidm@snapgear.com>
- * Copyright (C) 2002       Greg Ungerer       <gerg@snapgear.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- * Multiple UART support        Daniel Potts <danielp@cse.unsw.edu.au>
- * Power management support     Daniel Potts <danielp@cse.unsw.edu.au>
- * VZ Second Serial Port enable Phil Wilshire
- * 2.4/2.5 port                 David McCullough
- */
-
-#include <asm/dbg.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/reboot.h>
-#include <linux/keyboard.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-
-/* (es) */
-/* note: perhaps we can murge these files, so that you can just
- *      define 1 of them, and they can sort that out for themselves
- */
-#if defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#else
-#if defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#else
-#include <asm/MC68328.h>
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_M68EZ328 */
-
-#include "68328serial.h"
-
-/* Turn off usage of real serial interrupt code, to "support" Copilot */
-#ifdef CONFIG_XCOPILOT_BUGS
-#undef USE_INTS
-#else
-#define USE_INTS
-#endif
-
-static struct m68k_serial m68k_soft[NR_PORTS];
-
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
-
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
-
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
-
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
-
-struct tty_driver *serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#define RS_ISR_PASS_LIMIT 256
-
-static void change_speed(struct m68k_serial *info);
-
-/*
- *     Setup for console. Argument comes from the boot command line.
- */
-
-/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
-#ifdef CONFIG_M68VZ328
-#define CONSOLE_BAUD_RATE      19200
-#define DEFAULT_CBAUD          B19200
-#endif
-
-
-#ifndef CONSOLE_BAUD_RATE
-#define        CONSOLE_BAUD_RATE       9600
-#define        DEFAULT_CBAUD           B9600
-#endif
-
-
-static int m68328_console_initted = 0;
-static int m68328_console_baud    = CONSOLE_BAUD_RATE;
-static int m68328_console_cbaud   = DEFAULT_CBAUD;
-
-
-static inline int serial_paranoia_check(struct m68k_serial *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct %s in %s\n";
-       static const char *badinfo =
-               "Warning: null m68k_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 0 };
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
-       if (set) {
-               /* set the RTS/CTS line */
-       } else {
-               /* clear it */
-       }
-       return;
-}
-
-/* Utility routines */
-static inline int get_baud(struct m68k_serial *ss)
-{
-       unsigned long result = 115200;
-       unsigned short int baud = uart_addr[ss->line].ubaud;
-       if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
-       result >>= GET_FIELD(baud, UBAUD_DIVIDE);
-
-       return result;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       uart->ustcnt &= ~USTCNT_TXEN;
-       local_irq_restore(flags);
-}
-
-static int rs_put_char(char ch)
-{
-        int flags, loops = 0;
-
-        local_irq_save(flags);
-
-       while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
-               loops++;
-               udelay(5);
-        }
-
-       UTX_TXDATA = ch;
-        udelay(5);
-        local_irq_restore(flags);
-        return 1;
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_start"))
-               return;
-       
-       local_irq_save(flags);
-       if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
-#ifdef USE_INTS
-               uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
-               uart->ustcnt |= USTCNT_TXEN;
-#endif
-       }
-       local_irq_restore(flags);
-}
-
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
-{
-       /* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
-{
-#if 0
-       if(status & DCD) {
-               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
-                  ((info->curregs[3] & AUTO_ENAB)==0)) {
-                       info->curregs[3] |= AUTO_ENAB;
-                       info->pendregs[3] |= AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       } else {
-               if((info->curregs[3] & AUTO_ENAB)) {
-                       info->curregs[3] &= ~AUTO_ENAB;
-                       info->pendregs[3] &= ~AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       }
-#endif
-       /* If this is console input and this is a
-        * 'break asserted' status change interrupt
-        * see if we can drop into the debugger
-        */
-       if((status & URX_BREAK) && info->break_abort)
-               batten_down_hatches();
-       return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
-       struct tty_struct *tty = info->port.tty;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned char ch, flag;
-
-       /*
-        * This do { } while() loop will get ALL chars out of Rx FIFO 
-         */
-#ifndef CONFIG_XCOPILOT_BUGS
-       do {
-#endif 
-               ch = GET_FIELD(rx, URX_RXDATA);
-       
-               if(info->is_cons) {
-                       if(URX_BREAK & rx) { /* whee, break received */
-                               status_handle(info, rx);
-                               return;
-#ifdef CONFIG_MAGIC_SYSRQ
-                       } else if (ch == 0x10) { /* ^P */
-                               show_state();
-                               show_free_areas();
-                               show_buffers();
-/*                             show_net_buffers(); */
-                               return;
-                       } else if (ch == 0x12) { /* ^R */
-                               emergency_restart();
-                               return;
-#endif /* CONFIG_MAGIC_SYSRQ */
-                       }
-               }
-
-               if(!tty)
-                       goto clear_and_exit;
-               
-               flag = TTY_NORMAL;
-
-               if(rx & URX_PARITY_ERROR) {
-                       flag = TTY_PARITY;
-                       status_handle(info, rx);
-               } else if(rx & URX_OVRUN) {
-                       flag = TTY_OVERRUN;
-                       status_handle(info, rx);
-               } else if(rx & URX_FRAME_ERROR) {
-                       flag = TTY_FRAME;
-                       status_handle(info, rx);
-               }
-               tty_insert_flip_char(tty, ch, flag);
-#ifndef CONFIG_XCOPILOT_BUGS
-       } while((rx = uart->urx.w) & URX_DATA_READY);
-#endif
-
-       tty_schedule_flip(tty);
-
-clear_and_exit:
-       return;
-}
-
-static void transmit_chars(struct m68k_serial *info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-
-       if (info->x_char) {
-               /* Send next char */
-               uart->utx.b.txdata = info->x_char;
-               info->x_char = 0;
-               goto clear_and_return;
-       }
-
-       if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-               /* That's peculiar... TX ints off */
-               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
-               goto clear_and_return;
-       }
-
-       /* Send char */
-       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-       info->xmit_cnt--;
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               schedule_work(&info->tqueue);
-
-       if(info->xmit_cnt <= 0) {
-               /* All done for now... TX ints off */
-               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
-               goto clear_and_return;
-       }
-
-clear_and_return:
-       /* Clear interrupt (should be auto)*/
-       return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
-       struct m68k_serial *info = dev_id;
-       m68328_uart *uart;
-       unsigned short rx;
-       unsigned short tx;
-
-       uart = &uart_addr[info->line];
-       rx = uart->urx.w;
-
-#ifdef USE_INTS
-       tx = uart->utx.w;
-
-       if (rx & URX_DATA_READY) receive_chars(info, rx);
-       if (tx & UTX_TX_AVAIL)   transmit_chars(info);
-#else
-       receive_chars(info, rx);                
-#endif
-       return IRQ_HANDLED;
-}
-
-static void do_softint(struct work_struct *work)
-{
-       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-#if 0
-       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               tty_wakeup(tty);
-       }
-#endif   
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       tty_hangup(tty);
-}
-
-
-static int startup(struct m68k_serial * info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-       
-       if (info->flags & S_INITIALIZED)
-               return 0;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in change_speed())
-        */
-
-       uart->ustcnt = USTCNT_UEN;
-       info->xmit_fifo_size = 1;
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
-       (void)uart->urx.w;
-
-       /*
-        * Finally, enable sequencing and interrupts
-        */
-#ifdef USE_INTS
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | 
-                 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
-#else
-       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
-#endif
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-
-       change_speed(info);
-
-       info->flags |= S_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct m68k_serial * info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long   flags;
-
-       uart->ustcnt = 0; /* All off! */
-       if (!(info->flags & S_INITIALIZED))
-               return;
-
-       local_irq_save(flags);
-       
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       
-       info->flags &= ~S_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-struct {
-       int divisor, prescale;
-}
-#ifndef CONFIG_M68VZ328
- hw_baud_table[18] = {
-       {0,0}, /* 0 */
-       {0,0}, /* 50 */
-       {0,0}, /* 75 */
-       {0,0}, /* 110 */
-       {0,0}, /* 134 */
-       {0,0}, /* 150 */
-       {0,0}, /* 200 */
-       {7,0x26}, /* 300 */
-       {6,0x26}, /* 600 */
-       {5,0x26}, /* 1200 */
-       {0,0}, /* 1800 */
-       {4,0x26}, /* 2400 */
-       {3,0x26}, /* 4800 */
-       {2,0x26}, /* 9600 */
-       {1,0x26}, /* 19200 */
-       {0,0x26}, /* 38400 */
-       {1,0x38}, /* 57600 */
-       {0,0x38}, /* 115200 */
-};
-#else
- hw_baud_table[18] = {
-                 {0,0}, /* 0 */
-                 {0,0}, /* 50 */
-                 {0,0}, /* 75 */
-                 {0,0}, /* 110 */
-                 {0,0}, /* 134 */
-                 {0,0}, /* 150 */
-                 {0,0}, /* 200 */
-                 {0,0}, /* 300 */
-                 {7,0x26}, /* 600 */
-                 {6,0x26}, /* 1200 */
-                 {0,0}, /* 1800 */
-                 {5,0x26}, /* 2400 */
-                 {4,0x26}, /* 4800 */
-                 {3,0x26}, /* 9600 */
-                 {2,0x26}, /* 19200 */
-                 {1,0x26}, /* 38400 */
-                 {0,0x26}, /* 57600 */
-                 {1,0x38}, /* 115200 */
-}; 
-#endif
-/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct m68k_serial *info)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned short port;
-       unsigned short ustcnt;
-       unsigned cflag;
-       int     i;
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-       if (!(port = info->port))
-               return;
-
-       ustcnt = uart->ustcnt;
-       uart->ustcnt = ustcnt & ~USTCNT_TXEN;
-
-       i = cflag & CBAUD;
-        if (i & CBAUDEX) {
-                i = (i & ~CBAUDEX) + B38400;
-        }
-
-       info->baud = baud_table[i];
-       uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
-               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-
-       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-       
-       if ((cflag & CSIZE) == CS8)
-               ustcnt |= USTCNT_8_7;
-               
-       if (cflag & CSTOPB)
-               ustcnt |= USTCNT_STOP;
-
-       if (cflag & PARENB)
-               ustcnt |= USTCNT_PARITYEN;
-       if (cflag & PARODD)
-               ustcnt |= USTCNT_ODD_EVEN;
-       
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       if (cflag & CRTSCTS) {
-               uart->utx.w &= ~ UTX_NOCTS;
-       } else {
-               uart->utx.w |= UTX_NOCTS;
-       }
-#endif
-
-       ustcnt |= USTCNT_TXEN;
-       
-       uart->ustcnt = ustcnt;
-       return;
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
-       int left;               /* Output no more than that */
-       unsigned long flags;
-       struct m68k_serial *info = &m68k_soft[0];
-       char c;
-
-       if (info == 0) return;
-       if (info->xmit_buf == 0) return;
-
-       local_irq_save(flags);
-       left = info->xmit_cnt;
-       while (left != 0) {
-               c = info->xmit_buf[info->xmit_tail];
-               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt--;
-               local_irq_restore(flags);
-
-               rs_put_char(c);
-
-               local_irq_save(flags);
-               left = min(info->xmit_cnt, left-1);
-       }
-
-       /* Last character is being transmitted now (hopefully). */
-       udelay(5);
-
-       local_irq_restore(flags);
-       return;
-}
-
-/*
- * m68k_console_print is registered for printk.
- */
-void console_print_68328(const char *p)
-{
-       char c;
-       
-       while((c=*(p++)) != 0) {
-               if(c == '\n')
-                       rs_put_char('\r');
-               rs_put_char(c);
-       }
-
-       /* Comment this if you want to have a strict interrupt-driven output */
-       rs_fair_output();
-
-       return;
-}
-
-static void rs_set_ldisc(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
-               return;
-
-       info->is_cons = (tty->termios->c_line == N_TTY);
-       
-       printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-               return;
-#ifndef USE_INTS
-       for(;;) {
-#endif
-
-       /* Enable transmitter */
-       local_irq_save(flags);
-
-       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-                       !info->xmit_buf) {
-               local_irq_restore(flags);
-               return;
-       }
-
-#ifdef USE_INTS
-       uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
-       uart->ustcnt |= USTCNT_TXEN;
-#endif
-
-#ifdef USE_INTS
-       if (uart->utx.w & UTX_TX_AVAIL) {
-#else
-       if (1) {
-#endif
-               /* Send char */
-               uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt--;
-       }
-
-#ifndef USE_INTS
-       while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-       }
-#endif
-       local_irq_restore(flags);
-}
-
-extern void console_printn(const char * b, int count);
-
-static int rs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, total = 0;
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf)
-               return 0;
-
-       local_save_flags(flags);
-       while (1) {
-               local_irq_disable();            
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                  SERIAL_XMIT_SIZE - info->xmit_head));
-               local_irq_restore(flags);
-
-               if (c <= 0)
-                       break;
-
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
-               local_irq_disable();
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               local_irq_restore(flags);
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
-               /* Enable transmitter */
-               local_irq_disable();            
-#ifndef USE_INTS
-               while(info->xmit_cnt) {
-#endif
-
-               uart->ustcnt |= USTCNT_TXEN;
-#ifdef USE_INTS
-               uart->ustcnt |= USTCNT_TX_INTR_MASK;
-#else
-               while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-#endif
-               if (uart->utx.w & UTX_TX_AVAIL) {
-                       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
-                       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-                       info->xmit_cnt--;
-               }
-
-#ifndef USE_INTS
-               }
-#endif
-               local_irq_restore(flags);
-       }
-
-       return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       int     ret;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-       unsigned long flags;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-       local_irq_save(flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       local_irq_restore(flags);
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               info->x_char = STOP_CHAR(tty);
-
-       /* Turn off RTS line (do this atomic) */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       info->x_char = START_CHAR(tty);
-       }
-
-       /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct m68k_serial * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-  
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = info->port;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int set_serial_info(struct m68k_serial * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct m68k_serial old_info;
-       int                     retval = 0;
-
-       if (!new_info)
-               return -EFAULT;
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~S_USR_MASK) !=
-                    (info->flags & ~S_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~S_USR_MASK) |
-                              (new_serial.flags & S_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~S_FLAGS) |
-                       (new_serial.flags & S_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
-{
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       m68328_uart *uart = &uart_addr[info->line];
-#endif
-       unsigned char status;
-       unsigned long flags;
-
-       local_irq_save(flags);
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
-       status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
-#else
-       status = 0;
-#endif
-       local_irq_restore(flags);
-       return put_user(status, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(struct m68k_serial * info, unsigned int duration)
-{
-       m68328_uart *uart = &uart_addr[info->line];
-        unsigned long flags;
-        if (!info->port)
-                return;
-        local_irq_save(flags);
-#ifdef USE_INTS        
-       uart->utx.w |= UTX_SEND_BREAK;
-       msleep_interruptible(duration);
-       uart->utx.w &= ~UTX_SEND_BREAK;
-#endif         
-        local_irq_restore(flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       int error;
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       int retval;
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (!arg)
-                               send_break(info, 250);  /* 1/4 second */
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       send_break(info, arg ? arg*(100) : 250);
-                       return 0;
-               case TIOCGSERIAL:
-                       return get_serial_info(info,
-                                      (struct serial_struct *) arg);
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       return get_lsr_info(info, (unsigned int *) arg);
-               case TIOCSERGSTRUCT:
-                       if (copy_to_user((struct m68k_serial *) arg,
-                                   info, sizeof(struct m68k_serial)))
-                               return -EFAULT;
-                       return 0;
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
-       change_speed(info);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_start(tty);
-       }
-       
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       m68328_uart *uart = &uart_addr[info->line];
-       unsigned long flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-       
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("rs_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk("rs_close: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= S_CLOSING;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != S_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-
-       uart->ustcnt &= ~USTCNT_RXEN;
-       uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
-
-       shutdown(info);
-       rs_flush_buffer(tty);
-               
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-#warning "This is not and has never been valid so fix it"      
-#if 0
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
-               if (tty->ldisc.close)
-                       (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
-               tty->termios->c_line = N_TTY;
-               if (tty->ldisc.open)
-                       (tty->ldisc.open)(tty);
-       }
-#endif 
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void rs_hangup(struct tty_struct *tty)
-{
-       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-       
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~S_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct m68k_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & S_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & S_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-       
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= S_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-
-       info->count--;
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               m68k_rtsdtr(info, 1);
-               local_irq_enable();
-               current->state = TASK_INTERRUPTIBLE;
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & S_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & S_CLOSING) && do_clocal)
-                       break;
-                if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-
-       if (retval)
-               return retval;
-       info->flags |= S_NORMAL_ACTIVE;
-       return 0;
-}      
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its S structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-int rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct m68k_serial      *info;
-       int                     retval, line;
-
-       line = tty->index;
-       
-       if (line >= NR_PORTS || line < 0) /* we have exactly one */
-               return -ENODEV;
-
-       info = &m68k_soft[line];
-
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       return block_til_ready(tty, filp, info);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk("MC68328 serial driver version 1.00\n");
-}
-
-static const struct tty_operations rs_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .set_ldisc = rs_set_ldisc,
-};
-
-/* rs_init inits the driver */
-static int __init
-rs68328_init(void)
-{
-       int flags, i;
-       struct m68k_serial *info;
-
-       serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!serial_driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       /* SPARC: Not all of this is exactly right for us. */
-       
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag = 
-                       m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(serial_driver, &rs_ops);
-
-       if (tty_register_driver(serial_driver)) {
-               put_tty_driver(serial_driver);
-               printk(KERN_ERR "Couldn't register serial driver\n");
-               return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-       for(i=0;i<NR_PORTS;i++) {
-
-           info = &m68k_soft[i];
-           info->magic = SERIAL_MAGIC;
-           info->port = (int) &uart_addr[i];
-           info->port.tty = NULL;
-           info->irq = uart_irqs[i];
-           info->custom_divisor = 16;
-           info->close_delay = 50;
-           info->closing_wait = 3000;
-           info->x_char = 0;
-           info->event = 0;
-           info->count = 0;
-           info->blocked_open = 0;
-           INIT_WORK(&info->tqueue, do_softint);
-           INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
-           init_waitqueue_head(&info->open_wait);
-           init_waitqueue_head(&info->close_wait);
-           info->line = i;
-           info->is_cons = 1; /* Means shortcuts work */
-           
-           printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, 
-                  info->port, info->irq);
-           printk(" is a builtin MC68328 UART\n");
-           
-#ifdef CONFIG_M68VZ328
-               if (i > 0 )
-                       PJSEL &= 0xCF;  /* PSW enable second port output */
-#endif
-
-           if (request_irq(uart_irqs[i],
-                           rs_interrupt,
-                           IRQF_DISABLED,
-                           "M68328_UART", info))
-                panic("Unable to attach 68328 serial interrupt\n");
-       }
-       local_irq_restore(flags);
-       return 0;
-}
-
-module_init(rs68328_init);
-
-
-
-static void m68328_set_baud(void)
-{
-       unsigned short ustcnt;
-       int     i;
-
-       ustcnt = USTCNT;
-       USTCNT = ustcnt & ~USTCNT_TXEN;
-
-again:
-       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
-               if (baud_table[i] == m68328_console_baud)
-                       break;
-       if (i >= ARRAY_SIZE(baud_table)) {
-               m68328_console_baud = 9600;
-               goto again;
-       }
-
-       UBAUD = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
-               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-       ustcnt |= USTCNT_8_7;
-       ustcnt |= USTCNT_TXEN;
-       USTCNT = ustcnt;
-       m68328_console_initted = 1;
-       return;
-}
-
-
-int m68328_console_setup(struct console *cp, char *arg)
-{
-       int             i, n = CONSOLE_BAUD_RATE;
-
-       if (!cp)
-               return(-1);
-
-       if (arg)
-               n = simple_strtoul(arg,NULL,0);
-
-       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
-               if (baud_table[i] == n)
-                       break;
-       if (i < ARRAY_SIZE(baud_table)) {
-               m68328_console_baud = n;
-               m68328_console_cbaud = 0;
-               if (i > 15) {
-                       m68328_console_cbaud |= CBAUDEX;
-                       i -= 15;
-               }
-               m68328_console_cbaud |= i;
-       }
-
-       m68328_set_baud(); /* make sure baud rate changes */
-       return(0);
-}
-
-
-static struct tty_driver *m68328_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-
-void m68328_console_write (struct console *co, const char *str,
-                          unsigned int count)
-{
-       if (!m68328_console_initted)
-               m68328_set_baud();
-    while (count--) {
-        if (*str == '\n')
-           rs_put_char('\r');
-        rs_put_char( *str++ );
-    }
-}
-
-
-static struct console m68328_driver = {
-       .name           = "ttyS",
-       .write          = m68328_console_write,
-       .device         = m68328_console_device,
-       .setup          = m68328_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-
-static int __init m68328_console_init(void)
-{
-       register_console(&m68328_driver);
-       return 0;
-}
-
-console_initcall(m68328_console_init);
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
deleted file mode 100644 (file)
index 664ceb0..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF     0
-#define S_CLOSING_WAIT_NONE    65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-                                  on the callout port */
-#define S_FOURPORT  0x0002     /* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK  0x0004  /* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK     0x0030
-#define S_SPD_HI       0x0010  /* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI      0x0020  /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST     0x0030  /* Use user-specified divisor */
-
-#define S_SKIP_TEST    0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS        0x0FFF  /* Possible legal S flags */
-#define S_USR_MASK 0x0430      /* Legal flags that non-privileged
-                                * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED  0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE       0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE        0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF        0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING              0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW             0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD             0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to 
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- *                                  -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real  328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- *                                  -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
-       char soft_carrier;  /* Use soft carrier on this channel */
-       char break_abort;   /* Is serial console in, so process brk/abrt */
-       char is_cons;       /* Is this our console. */
-
-       /* We need to know the current clock divisor
-        * to read the bps rate the chip has currently
-        * loaded.
-        */
-       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-       int baud;
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-/* 
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
deleted file mode 100644 (file)
index 88b1335..0000000
+++ /dev/null
@@ -1,2978 +0,0 @@
-/*
- *  UART driver for 68360 CPM SCC or SMC
- *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
- *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
- *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *
- * I used the serial.c driver as the framework for this driver.
- * Give credit to those guys.
- * The original code was written for the MBX860 board.  I tried to make
- * it generic, but there may be some assumptions in the structures that
- * have to be fixed later.
- * To save porting time, I did not bother to change any object names
- * that are not accessed outside of this file.
- * It still needs lots of work........When it was easy, I included code
- * to support the SCCs, but this has never been tested, nor is it complete.
- * Only the SCCs support modem control, so that is not complete either.
- *
- * This module exports the following rs232 io functions:
- *
- *     int rs_360_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h> 
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int  kgdb_output_string (const char* s, unsigned int count);
-#endif
-
-
-/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
-#include <linux/console.h>
-#include <linux/jiffies.h>
-
-/* this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT     1 /* ie SMC2 - note USE_SMC2 must be defined */
-#endif
-/* #endif */
-
-#if 0
-/* SCC2 for console
- */
-#undef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT     2
-#endif
-
-
-#define TX_WAKEUP      ASYNC_SHARE_IRQ
-
-static char *serial_name = "CPM UART driver";
-static char *serial_version = "0.03";
-
-static struct tty_driver *serial_driver;
-int serial_console_setup(struct console *co, char *options);
-
-/*
- * Serial driver configuration section.  Here are the various options:
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
-#define _INLINE_ inline
-  
-#define DBG_CNT(s)
-
-/* We overload some of the items in the data structure to meet our
- * needs.  For example, the port address is the CPM parameter ram
- * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
- * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
- * a flag indicating SCC or SMC, and the number is used as an index into
- * the CPM parameter area for this device.
- * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
- * not currently used.  I should probably use it to indicate the port
- * type of SMC or SCC.
- * The SMCs do not support any modem control signals.
- */
-#define smc_scc_num    hub6
-#define NUM_IS_SCC     ((int)0x00010000)
-#define PORT_NUM(P)    ((P) & 0x0000ffff)
-
-
-#if defined (CONFIG_UCQUICC)
-
-volatile extern void *_periph_base;
-/* sipex transceiver
- *   mode bits for       are on pins
- *
- *    SCC2                d16..19
- *    SCC3                d20..23
- *    SCC4                d24..27
- */
-#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
-
-static uint sipex_mode_bits = 0x00000000;
-
-#endif
-
-/* There is no `serial_state' defined back here in 2.0.
- * Try to get by with serial_struct
- */
-/* #define serial_state serial_struct */
-
-/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
- * extras: */
-
-#if 0
-struct async_icount_24 {
-       __u32   cts, dsr, rng, dcd, tx, rx;
-       __u32   frame, parity, overrun, brk;
-       __u32   buf_overrun;
-} icount;
-#endif
-
-#if 0
-
-struct serial_state {
-        int     magic;
-        int     baud_base;
-        unsigned long   port;
-        int     irq;
-        int     flags;
-        int     hub6;
-        int     type;
-        int     line;
-        int     revision;       /* Chip revision (950) */
-        int     xmit_fifo_size;
-        int     custom_divisor;
-        int     count;
-        u8      *iomem_base;
-        u16     iomem_reg_shift;
-        unsigned short  close_delay;
-        unsigned short  closing_wait; /* time to wait before closing */
-        struct async_icount_24     icount; 
-        int     io_type;
-        struct async_struct *info;
-};
-#endif
-
-#define SSTATE_MAGIC 0x5302
-
-
-
-/* SMC2 is sometimes used for low performance TDM interfaces.  Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-
-#if 0
-/* Define SCC to ttySx mapping. */
-#define SCC_NUM_BASE   (USE_SMC2 + 1)  /* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port.  These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE   1       /* table index */
-#endif
-
-
-/* Processors other than the 860 only get SMCs configured by default.
- * Either they don't have SCCs or they are allocated somewhere else.
- * Of course, there are now 860s without some SCCs, so we will need to
- * address that someday.
- * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
- * stereo codec parts, and we use SMC2 to help support that.
- */
-static struct serial_state rs_table[] = {
-/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
-       {  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
-#if USE_SMC2
-       ,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
-#endif
-
-#if defined(CONFIG_SERIAL_68360_SCC)
-       ,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
-       ,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
-       ,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
-#endif
-};
-
-#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
-
-/* The number of buffer descriptors and their sizes.
- */
-#define RX_NUM_FIFO    4
-#define RX_BUF_SIZE    32
-#define TX_NUM_FIFO    4
-#define TX_BUF_SIZE    32
-
-#define CONSOLE_NUM_FIFO 2
-#define CONSOLE_BUF_SIZE 4
-
-char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
-
-/* The async_struct in serial.h does not really give us what we
- * need, so define our own here.
- */
-typedef struct serial_info {
-       int                     magic;
-       int                     flags;
-
-       struct serial_state     *state;
-       /* struct serial_struct *state; */
-       /* struct async_struct  *state; */
-       
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     line;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     blocked_open; /* # of blocked opens */
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait; 
-       wait_queue_head_t       close_wait; 
-
-       
-/* CPM Buffer Descriptor pointers.
-       */
-       QUICC_BD                        *rx_bd_base;
-       QUICC_BD                        *rx_cur;
-       QUICC_BD                        *tx_bd_base;
-       QUICC_BD                        *tx_cur;
-} ser_info_t;
-
-
-/* since kmalloc_init() does not get called until much after this initialization: */
-static ser_info_t  quicc_ser_info[NR_PORTS];
-static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
-static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
-
-static void change_speed(ser_info_t *info);
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(ser_info_t *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char *badmagic =
-               "Warning: bad magic number for serial struct (%s) in %s\n";
-       static const char *badinfo =
-               "Warning: null async_struct for (%s) in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts,
- * indexed by the termio value.  The generic CPM functions are responsible
- * for setting and assigning baud rate generators for us.
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-/* This sucks. There is a better way: */
-#if defined(CONFIG_CONSOLE_9600)
-  #define CONSOLE_BAUDRATE 9600
-#elif defined(CONFIG_CONSOLE_19200)
-  #define CONSOLE_BAUDRATE 19200
-#elif defined(CONFIG_CONSOLE_115200)
-  #define CONSOLE_BAUDRATE 115200
-#else
-  #warning "console baud rate undefined"
-  #define CONSOLE_BAUDRATE 9600
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_360_stop(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     idx;
-       unsigned long flags;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_regs *smcp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_sccm &= ~UART_SCCM_TX;
-       } else {
-               /* smcp = &cpmp->cp_smc[idx]; */
-               smcp = &pquicc->smc_regs[idx];
-               smcp->smc_smcm &= ~SMCM_TX;
-       }
-       local_irq_restore(flags);
-}
-
-
-static void rs_360_start(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     idx;
-       unsigned long flags;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_regs *smcp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_sccm |= UART_SCCM_TX;
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-               smcp->smc_smcm |= SMCM_TX;
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static _INLINE_ void receive_chars(ser_info_t *info)
-{
-       struct tty_struct *tty = info->port.tty;
-       unsigned char ch, flag, *cp;
-       /*int   ignored = 0;*/
-       int     i;
-       ushort  status;
-        struct async_icount *icount; 
-       /* struct       async_icount_24 *icount; */
-       volatile QUICC_BD       *bdp;
-
-       icount = &info->state->icount;
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = info->rx_cur;
-       for (;;) {
-               if (bdp->status & BD_SC_EMPTY)  /* If this one is empty */
-                       break;                  /*   we are all done */
-
-               /* The read status mask tell us what we should do with
-                * incoming characters, especially if errors occur.
-                * One special case is the use of BD_SC_EMPTY.  If
-                * this is not set, we are supposed to be ignoring
-                * inputs.  In this case, just mark the buffer empty and
-                * continue.
-                */
-               if (!(info->read_status_mask & BD_SC_EMPTY)) {
-                       bdp->status |= BD_SC_EMPTY;
-                       bdp->status &=
-                               ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-                       if (bdp->status & BD_SC_WRAP)
-                               bdp = info->rx_bd_base;
-                       else
-                               bdp++;
-                       continue;
-               }
-
-               /* Get the number of characters and the buffer pointer.
-               */
-               i = bdp->length;
-               /* cp = (unsigned char *)__va(bdp->buf); */
-               cp = (char *)bdp->buf;
-               status = bdp->status;
-
-               while (i-- > 0) {
-                       ch = *cp++;
-                       icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
-                       printk("DR%02x:%02x...", ch, status);
-#endif
-                       flag = TTY_NORMAL;
-
-                       if (status & (BD_SC_BR | BD_SC_FR |
-                                      BD_SC_PR | BD_SC_OV)) {
-                               /*
-                                * For statistics only
-                                */
-                               if (status & BD_SC_BR)
-                                       icount->brk++;
-                               else if (status & BD_SC_PR)
-                                       icount->parity++;
-                               else if (status & BD_SC_FR)
-                                       icount->frame++;
-                               if (status & BD_SC_OV)
-                                       icount->overrun++;
-
-                               /*
-                                * Now check to see if character should be
-                                * ignored, and mask off conditions which
-                                * should be ignored.
-                               if (status & info->ignore_status_mask) {
-                                       if (++ignored > 100)
-                                               break;
-                                       continue;
-                               }
-                                */
-                               status &= info->read_status_mask;
-               
-                               if (status & (BD_SC_BR)) {
-#ifdef SERIAL_DEBUG_INTR
-                                       printk("handling break....");
-#endif
-                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
-                                       if (info->flags & ASYNC_SAK)
-                                               do_SAK(tty);
-                               } else if (status & BD_SC_PR)
-                                       flag = TTY_PARITY;
-                               else if (status & BD_SC_FR)
-                                       flag = TTY_FRAME;
-                       }
-                       tty_insert_flip_char(tty, ch, flag);
-                       if (status & BD_SC_OV)
-                               /*
-                                * Overrun is special, since it's
-                                * reported immediately, and doesn't
-                                * affect the current character
-                                */
-                               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-
-               /* This BD is ready to be used again.  Clear status.
-                * Get next BD.
-                */
-               bdp->status |= BD_SC_EMPTY;
-               bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = info->rx_bd_base;
-               else
-                       bdp++;
-       }
-
-       info->rx_cur = (QUICC_BD *)bdp;
-
-       tty_schedule_flip(tty);
-}
-
-static _INLINE_ void receive_break(ser_info_t *info)
-{
-       struct tty_struct *tty = info->port.tty;
-
-       info->state->icount.brk++;
-       /* Check to see if there is room in the tty buffer for
-        * the break.  If not, we exit now, losing the break.  FIXME
-        */
-       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       tty_schedule_flip(tty);
-}
-
-static _INLINE_ void transmit_chars(ser_info_t *info)
-{
-
-       if ((info->flags & TX_WAKEUP) ||
-           (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
-               schedule_work(&info->tqueue);
-       }
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("THRE...");
-#endif
-}
-
-#ifdef notdef
-       /* I need to do this for the SCCs, so it is left as a reminder.
-       */
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
-       int     status;
-       /* struct       async_icount *icount; */
-       struct  async_icount_24 *icount;
-       
-       status = serial_in(info, UART_MSR);
-
-       if (status & UART_MSR_ANY_DELTA) {
-               icount = &info->state->icount;
-               /* update input line counters */
-               if (status & UART_MSR_TERI)
-                       icount->rng++;
-               if (status & UART_MSR_DDSR)
-                       icount->dsr++;
-               if (status & UART_MSR_DDCD) {
-                       icount->dcd++;
-#ifdef CONFIG_HARD_PPS
-                       if ((info->flags & ASYNC_HARDPPS_CD) &&
-                           (status & UART_MSR_DCD))
-                               hardpps();
-#endif
-               }
-               if (status & UART_MSR_DCTS)
-                       icount->cts++;
-               wake_up_interruptible(&info->delta_msr_wait);
-       }
-
-       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-               printk("ttys%d CD now %s...", info->line,
-                      (status & UART_MSR_DCD) ? "on" : "off");
-#endif         
-               if (status & UART_MSR_DCD)
-                       wake_up_interruptible(&info->open_wait);
-               else {
-#ifdef SERIAL_DEBUG_OPEN
-                       printk("scheduling hangup...");
-#endif
-                       queue_task(&info->tqueue_hangup,
-                                          &tq_scheduler);
-               }
-       }
-       if (info->flags & ASYNC_CTS_FLOW) {
-               if (info->port.tty->hw_stopped) {
-                       if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-                               printk("CTS tx start...");
-#endif
-                               info->port.tty->hw_stopped = 0;
-                               info->IER |= UART_IER_THRI;
-                               serial_out(info, UART_IER, info->IER);
-                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-                               return;
-                       }
-               } else {
-                       if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-                               printk("CTS tx stop...");
-#endif
-                               info->port.tty->hw_stopped = 1;
-                               info->IER &= ~UART_IER_THRI;
-                               serial_out(info, UART_IER, info->IER);
-                       }
-               }
-       }
-}
-#endif
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id)
-{
-       u_char  events;
-       int     idx;
-       ser_info_t *info;
-       volatile struct smc_regs *smcp;
-       volatile struct scc_regs *sccp;
-       
-       info = dev_id;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               events = sccp->scc_scce;
-               if (events & SCCM_RX)
-                       receive_chars(info);
-               if (events & SCCM_TX)
-                       transmit_chars(info);
-               sccp->scc_scce = events;
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-               events = smcp->smc_smce;
-               if (events & SMCM_BRKE)
-                       receive_break(info);
-               if (events & SMCM_RX)
-                       receive_chars(info);
-               if (events & SMCM_TX)
-                       transmit_chars(info);
-               smcp->smc_smce = events;
-       }
-       
-#ifdef SERIAL_DEBUG_INTR
-       printk("rs_interrupt_single(%d, %x)...",
-                                       info->state->smc_scc_num, events);
-#endif
-#ifdef modem_control
-       check_modem_status(info);
-#endif
-       info->last_active = jiffies;
-#ifdef SERIAL_DEBUG_INTR
-       printk("end.\n");
-#endif
-}
-
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-
-static void do_softint(void *private_)
-{
-       ser_info_t      *info = (ser_info_t *) private_;
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void do_serial_hangup(void *private_)
-{
-       struct async_struct     *info = (struct async_struct *) private_;
-       struct tty_struct       *tty;
-       
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       tty_hangup(tty);
-}
-
-
-static int startup(ser_info_t *info)
-{
-       unsigned long flags;
-       int     retval=0;
-       int     idx;
-       /*struct serial_state *state = info->state;*/
-       volatile struct smc_regs *smcp;
-       volatile struct scc_regs *sccp;
-       volatile struct smc_uart_pram   *up;
-       volatile struct uart_pram           *scup;
-
-
-       local_irq_save(flags);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               goto errout;
-       }
-
-#ifdef maybe
-       if (!state->port || !state->type) {
-               if (info->port.tty)
-                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-               goto errout;
-       }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-
-#ifdef modem_control
-       info->MCR = 0;
-       if (info->port.tty->termios->c_cflag & CBAUD)
-               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#endif
-       
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       /*
-        * and set the speed of the serial port
-        */
-       change_speed(info);
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               scup = &pquicc->pram[info->state->port].scc.pscc.u;
-
-               scup->mrblr = RX_BUF_SIZE;
-               scup->max_idl = RX_BUF_SIZE;
-
-               sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
-               sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-
-               /* Enable interrupts and I/O.
-               */
-               smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
-               smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
-
-               /* We can tune the buffer length and idle characters
-                * to take advantage of the entire incoming buffer size.
-                * If mrblr is something other than 1, maxidl has to be
-                * non-zero or we never get an interrupt.  The maxidl
-                * is the number of character times we wait after reception
-                * of the last character before we decide no more characters
-                * are coming.
-                */
-               /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
-               /* holy unionized structures, Batman: */
-               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-               up->mrblr = RX_BUF_SIZE;
-               up->max_idl = RX_BUF_SIZE;
-
-               up->brkcr = 1;  /* number of break chars */
-       }
-
-       info->flags |= ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-       
-errout:
-       local_irq_restore(flags);
-       return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(ser_info_t *info)
-{
-       unsigned long   flags;
-       struct serial_state *state;
-       int             idx;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-       state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....", info->line,
-              state->irq);
-#endif
-       
-       local_irq_save(flags);
-
-       idx = PORT_NUM(state->smc_scc_num);
-       if (state->smc_scc_num & NUM_IS_SCC) {
-               sccp = &pquicc->scc_regs[idx];
-               sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* We can't disable the transmitter if this is the
-                * system console.
-                */
-               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-               sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
-       } else {
-               smcp = &pquicc->smc_regs[idx];
-
-               /* Disable interrupts and I/O.
-                */
-               smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* We can't disable the transmitter if this is the
-                * system console.
-                */
-               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
-                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-       }
-       
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(ser_info_t *info)
-{
-       int     baud_rate;
-       unsigned cflag, cval, scval, prev_mode;
-       int     i, bits, sbits, idx;
-       unsigned long   flags;
-       struct serial_state *state;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-
-       state = info->state;
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-       cval = 0;
-       scval = 0;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-             case CS5: bits = 5; break;
-             case CS6: bits = 6; break;
-             case CS7: bits = 7; break;
-             case CS8: bits = 8; break;
-             /* Never happens, but GCC is too dumb to figure it out */
-             default:  bits = 8; break;
-       }
-       sbits = bits - 5;
-
-       if (cflag & CSTOPB) {
-               cval |= SMCMR_SL;       /* Two stops */
-               scval |= SCU_PMSR_SL;
-               bits++;
-       }
-       if (cflag & PARENB) {
-               cval |= SMCMR_PEN;
-               scval |= SCU_PMSR_PEN;
-               bits++;
-       }
-       if (!(cflag & PARODD)) {
-               cval |= SMCMR_PM_EVEN;
-               scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
-       }
-
-       /* Determine divisor based on baud rate */
-       i = cflag & CBAUD;
-       if (i >= (sizeof(baud_table)/sizeof(int)))
-               baud_rate = 9600;
-       else
-               baud_rate = baud_table[i];
-
-       info->timeout = (TX_BUF_SIZE*HZ*bits);
-       info->timeout += HZ/50;         /* Add .02 seconds of slop */
-
-#ifdef modem_control
-       /* CTS flow control flag and modem status interrupts */
-       info->IER &= ~UART_IER_MSI;
-       if (info->flags & ASYNC_HARDPPS_CD)
-               info->IER |= UART_IER_MSI;
-       if (cflag & CRTSCTS) {
-               info->flags |= ASYNC_CTS_FLOW;
-               info->IER |= UART_IER_MSI;
-       } else
-               info->flags &= ~ASYNC_CTS_FLOW;
-       if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
-       else {
-               info->flags |= ASYNC_CHECK_CD;
-               info->IER |= UART_IER_MSI;
-       }
-       serial_out(info, UART_IER, info->IER);
-#endif
-
-       /*
-        * Set up parity check flag
-        */
-       info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-       if (I_INPCK(info->port.tty))
-               info->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
-               info->read_status_mask |= BD_SC_BR;
-       
-       /*
-        * Characters to ignore
-        */
-       info->ignore_status_mask = 0;
-       if (I_IGNPAR(info->port.tty))
-               info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (I_IGNBRK(info->port.tty)) {
-               info->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore 
-                * overruns too.  (For real raw support).
-                */
-               if (I_IGNPAR(info->port.tty))
-                       info->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-        info->read_status_mask &= ~BD_SC_EMPTY;
-        local_irq_save(flags);
-
-        /* Start bit has not been added (so don't, because we would just
-         * subtract it later), and we need to add one for the number of
-         * stops bits (there is always at least one).
-         */
-        bits++;
-        idx = PORT_NUM(state->smc_scc_num);
-        if (state->smc_scc_num & NUM_IS_SCC) {
-         sccp = &pquicc->scc_regs[idx];
-         sccp->scc_psmr = (sbits << 12) | scval;
-     } else {
-         smcp = &pquicc->smc_regs[idx];
-
-               /* Set the mode register.  We want to keep a copy of the
-                * enables, because we want to put them back if they were
-                * present.
-                */
-               prev_mode = smcp->smc_smcmr;
-               smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
-               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
-       }
-
-       m360_cpm_setbrg((state - rs_table), baud_rate);
-
-       local_irq_restore(flags);
-}
-
-static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       volatile QUICC_BD       *bdp;
-
-       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
-               return 0;
-
-       if (!tty)
-               return 0;
-
-       bdp = info->tx_cur;
-       while (bdp->status & BD_SC_READY);
-
-       /* *((char *)__va(bdp->buf)) = ch; */
-       *((char *)bdp->buf) = ch;
-       bdp->length = 1;
-       bdp->status |= BD_SC_READY;
-
-       /* Get next BD.
-       */
-       if (bdp->status & BD_SC_WRAP)
-               bdp = info->tx_bd_base;
-       else
-               bdp++;
-
-       info->tx_cur = (QUICC_BD *)bdp;
-       return 1;
-
-}
-
-static int rs_360_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       int     c, ret = 0;
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       volatile QUICC_BD *bdp;
-
-#ifdef CONFIG_KGDB
-       /* Try to let stub handle output. Returns true if it did. */ 
-       if (kgdb_output_string(buf, count))
-               return ret;
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_write"))
-               return 0;
-
-       if (!tty) 
-               return 0;
-
-       bdp = info->tx_cur;
-
-       while (1) {
-               c = min(count, TX_BUF_SIZE);
-
-               if (c <= 0)
-                       break;
-
-               if (bdp->status & BD_SC_READY) {
-                       info->flags |= TX_WAKEUP;
-                       break;
-               }
-
-               /* memcpy(__va(bdp->buf), buf, c); */
-               memcpy((void *)bdp->buf, buf, c);
-
-               bdp->length = c;
-               bdp->status |= BD_SC_READY;
-
-               buf += c;
-               count -= c;
-               ret += c;
-
-               /* Get next BD.
-               */
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = info->tx_bd_base;
-               else
-                       bdp++;
-               info->tx_cur = (QUICC_BD *)bdp;
-       }
-       return ret;
-}
-
-static int rs_360_write_room(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
-               return 0;
-
-       if ((info->tx_cur->status & BD_SC_READY) == 0) {
-               info->flags &= ~TX_WAKEUP;
-               ret = TX_BUF_SIZE;
-       }
-       else {
-               info->flags |= TX_WAKEUP;
-               ret = 0;
-       }
-       return ret;
-}
-
-/* I could track this with transmit counters....maybe later.
-*/
-static int rs_360_chars_in_buffer(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
-               return 0;
-       return 0;
-}
-
-static void rs_360_flush_buffer(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-                               
-       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-               return;
-
-       /* There is nothing to "flush", whatever we gave the CPM
-        * is on its way out.
-        */
-       tty_wakeup(tty);
-       info->flags &= ~TX_WAKEUP;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_360_send_xchar(struct tty_struct *tty, char ch)
-{
-       volatile QUICC_BD       *bdp;
-
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "rs_send_char"))
-               return;
-
-       bdp = info->tx_cur;
-       while (bdp->status & BD_SC_READY);
-
-       /* *((char *)__va(bdp->buf)) = ch; */
-       *((char *)bdp->buf) = ch;
-       bdp->length = 1;
-       bdp->status |= BD_SC_READY;
-
-       /* Get next BD.
-       */
-       if (bdp->status & BD_SC_WRAP)
-               bdp = info->tx_bd_base;
-       else
-               bdp++;
-
-       info->tx_cur = (QUICC_BD *)bdp;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_360_throttle(struct tty_struct * tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("throttle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               rs_360_send_xchar(tty, STOP_CHAR(tty));
-
-#ifdef modem_control
-       if (tty->termios->c_cflag & CRTSCTS)
-               info->MCR &= ~UART_MCR_RTS;
-
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-}
-
-static void rs_360_unthrottle(struct tty_struct * tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       rs_360_send_xchar(tty, START_CHAR(tty));
-       }
-#ifdef modem_control
-       if (tty->termios->c_cflag & CRTSCTS)
-               info->MCR |= UART_MCR_RTS;
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#ifdef maybe
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
-       unsigned char status;
-       unsigned int result;
-
-       local_irq_disable();
-       status = serial_in(info, UART_LSR);
-       local_irq_enable();
-       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       return put_user(result,value);
-}
-#endif
-
-static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned int result = 0;
-#ifdef modem_control
-       unsigned char control, status;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       control = info->MCR;
-       local_irq_disable();
-       status = serial_in(info, UART_MSR);
-       local_irq_enable();
-       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
-               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
-               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
-               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
-               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
-               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
-               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
-               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-#endif
-       return result;
-}
-
-static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
-                          unsigned int set, unsigned int clear)
-{
-#ifdef modem_control
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned int arg;
-
-       if (serial_paranoia_check(info, tty->name, __func__))
-               return -ENODEV;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-       /* FIXME: locking on info->mcr */
-       if (set & TIOCM_RTS)
-               info->mcr |= UART_MCR_RTS;
-       if (set & TIOCM_DTR)
-               info->mcr |= UART_MCR_DTR;
-       if (clear & TIOCM_RTS)
-               info->MCR &= ~UART_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               info->MCR &= ~UART_MCR_DTR;
-
-#ifdef TIOCM_OUT1
-       if (set & TIOCM_OUT1)
-               info->MCR |= UART_MCR_OUT1;
-       if (set & TIOCM_OUT2)
-               info->MCR |= UART_MCR_OUT2;
-       if (clear & TIOCM_OUT1)
-               info->MCR &= ~UART_MCR_OUT1;
-       if (clear & TIOCM_OUT2)
-               info->MCR &= ~UART_MCR_OUT2;
-#endif
-
-       local_irq_disable();
-       serial_out(info, UART_MCR, info->MCR);
-       local_irq_enable();
-#endif
-       return 0;
-}
-
-/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
- * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
- * command.  We take advantage of the begin/end functions to make this
- * happen.
- */
-static ushort  smc_chan_map[] = {
-       CPM_CR_CH_SMC1,
-       CPM_CR_CH_SMC2
-};
-
-static ushort  scc_chan_map[] = {
-       CPM_CR_CH_SCC1,
-       CPM_CR_CH_SCC2,
-       CPM_CR_CH_SCC3,
-       CPM_CR_CH_SCC4
-};
-
-static void begin_break(ser_info_t *info)
-{
-       volatile QUICC *cp;
-       ushort  chan;
-       int     idx;
-
-       cp = pquicc;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC)
-               chan = scc_chan_map[idx];
-       else
-               chan = smc_chan_map[idx];
-
-       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
-       while (cp->cp_cr & CPM_CR_FLG);
-}
-
-static void end_break(ser_info_t *info)
-{
-       volatile QUICC *cp;
-       ushort  chan;
-       int idx;
-
-       cp = pquicc;
-
-       idx = PORT_NUM(info->state->smc_scc_num);
-       if (info->state->smc_scc_num & NUM_IS_SCC)
-               chan = scc_chan_map[idx];
-       else
-               chan = smc_chan_map[idx];
-
-       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
-       while (cp->cp_cr & CPM_CR_FLG);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(ser_info_t *info, unsigned int duration)
-{
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
-       begin_break(info);
-       msleep_interruptible(duration);
-       end_break(info);
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- *     RI where only 0->1 is counted.
- */
-static int rs_360_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       struct async_icount cnow;
-
-       local_irq_disable();
-       cnow = info->state->icount;
-       local_irq_enable();
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-
-       return 0;
-}
-
-static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       int error;
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       int retval;
-       struct async_icount cnow; 
-       /* struct async_icount_24 cnow;*/       /* kernel counter temps */
-       struct serial_icounter_struct *p_cuser; /* user space */
-
-       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-               return -ENODEV;
-
-       if (cmd != TIOCMIWAIT) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       if (!arg) {
-                               send_break(info, 250);  /* 1/4 second */
-                               if (signal_pending(current))
-                                       return -EINTR;
-                       }
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       send_break(info, arg ? arg*100 : 250);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       return 0;
-               case TIOCSBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       begin_break(info);
-                       return 0;
-               case TIOCCBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       end_break(info);
-                       return 0;
-#ifdef maybe
-               case TIOCSERGETLSR: /* Get line status register */
-                       return get_lsr_info(info, (unsigned int *) arg);
-#endif
-               /*
-                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-                * - mask passed in arg for lines of interest
-                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-                * Caller should use TIOCGICOUNT to see which one it was
-                */
-                case TIOCMIWAIT:
-#ifdef modem_control
-                       local_irq_disable();
-                       /* note the counters on entry */
-                       cprev = info->state->icount;
-                       local_irq_enable();
-                       while (1) {
-                               interruptible_sleep_on(&info->delta_msr_wait);
-                               /* see if a signal did it */
-                               if (signal_pending(current))
-                                       return -ERESTARTSYS;
-                               local_irq_disable();
-                               cnow = info->state->icount; /* atomic copy */
-                               local_irq_enable();
-                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                                       return -EIO; /* no change => error */
-                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-                                       return 0;
-                               }
-                               cprev = cnow;
-                       }
-                       /* NOTREACHED */
-#else
-                       return 0;
-#endif
-
-
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-/* FIX UP modem control here someday......
-*/
-static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-
-       change_speed(info);
-
-#ifdef modem_control
-       /* Handle transition to B0 status */
-       if ((old_termios->c_cflag & CBAUD) &&
-           !(tty->termios->c_cflag & CBAUD)) {
-               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-               local_irq_disable();
-               serial_out(info, UART_MCR, info->MCR);
-               local_irq_enable();
-       }
-       
-       /* Handle transition away from B0 status */
-       if (!(old_termios->c_cflag & CBAUD) &&
-           (tty->termios->c_cflag & CBAUD)) {
-               info->MCR |= UART_MCR_DTR;
-               if (!tty->hw_stopped ||
-                   !(tty->termios->c_cflag & CRTSCTS)) {
-                       info->MCR |= UART_MCR_RTS;
-               }
-               local_irq_disable();
-               serial_out(info, UART_MCR, info->MCR);
-               local_irq_enable();
-       }
-       
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_360_start(tty);
-       }
-#endif
-
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_360_close(struct tty_struct *tty, struct file * filp)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       /* struct async_state *state; */
-       struct serial_state *state;
-       unsigned long   flags;
-       int             idx;
-       volatile struct smc_regs        *smcp;
-       volatile struct scc_regs        *sccp;
-
-       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-               return;
-
-       state = info->state;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               DBG_CNT("before DEC-hung");
-               local_irq_restore(flags);
-               return;
-       }
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-       if ((tty->count == 1) && (state->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  state->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("rs_close: bad serial port count; tty->count is 1, "
-                      "state->count is %d\n", state->count);
-               state->count = 1;
-       }
-       if (--state->count < 0) {
-               printk("rs_close: bad serial port count for ttys%d: %d\n",
-                      info->line, state->count);
-               state->count = 0;
-       }
-       if (state->count) {
-               DBG_CNT("before DEC-2");
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-       info->read_status_mask &= ~BD_SC_EMPTY;
-       if (info->flags & ASYNC_INITIALIZED) {
-
-               idx = PORT_NUM(info->state->smc_scc_num);
-               if (info->state->smc_scc_num & NUM_IS_SCC) {
-                       sccp = &pquicc->scc_regs[idx];
-                       sccp->scc_sccm &= ~UART_SCCM_RX;
-                       sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
-               } else {
-                       smcp = &pquicc->smc_regs[idx];
-                       smcp->smc_smcm &= ~SMCM_RX;
-                       smcp->smc_smcmr &= ~SMCMR_REN;
-               }
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               rs_360_wait_until_sent(tty, info->timeout);
-       }
-       shutdown(info);
-       rs_360_flush_buffer(tty);
-       tty_ldisc_flush(tty);           
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       unsigned long orig_jiffies, char_time;
-       /*int lsr;*/
-       volatile QUICC_BD *bdp;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-               return;
-
-#ifdef maybe
-       if (info->state->type == PORT_UNKNOWN)
-               return;
-#endif
-
-       orig_jiffies = jiffies;
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        * 
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       char_time = 1;
-       if (timeout)
-               char_time = min(char_time, (unsigned long)timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
-       printk("jiff=%lu...", jiffies);
-#endif
-
-       /* We go through the loop at least once because we can't tell
-        * exactly when the last character exits the shifter.  There can
-        * be at least two characters waiting to be sent after the buffers
-        * are empty.
-        */
-       do {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-/*             current->counter = 0;    make us low-priority */
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
-                       break;
-               /* The 'tx_cur' is really the next buffer to send.  We
-                * have to back up to the previous BD and wait for it
-                * to go.  This isn't perfect, because all this indicates
-                * is the buffer is available.  There are still characters
-                * in the CPM FIFO.
-                */
-               bdp = info->tx_cur;
-               if (bdp == info->tx_bd_base)
-                       bdp += (TX_NUM_FIFO-1);
-               else
-                       bdp--;
-       } while (bdp->status & BD_SC_READY);
-       current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_360_hangup(struct tty_struct *tty)
-{
-       ser_info_t *info = (ser_info_t *)tty->driver_data;
-       struct serial_state *state = info->state;
-       
-       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
-               return;
-
-       state = info->state;
-       
-       rs_360_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       state->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          ser_info_t *info)
-{
-#ifdef DO_THIS_LATER
-       DECLARE_WAITQUEUE(wait, current);
-#endif
-       struct serial_state *state = info->state;
-       int             retval;
-       int             do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               if (info->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        * If this is an SMC port, we don't have modem control to wait
-        * for, so just get out here.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR)) ||
-           !(info->state->smc_scc_num & NUM_IS_SCC)) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-       
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, state->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-#ifdef DO_THIS_LATER
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttys%d, count = %d\n",
-              state->line, state->count);
-#endif
-       local_irq_disable();
-       if (!tty_hung_up_p(filp)) 
-               state->count--;
-       local_irq_enable();
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               if (tty->termios->c_cflag & CBAUD)
-                       serial_out(info, UART_MCR,
-                                  serial_inp(info, UART_MCR) |
-                                  (UART_MCR_DTR | UART_MCR_RTS));
-               local_irq_enable();
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) &&
-                   (do_clocal || (serial_in(info, UART_MSR) &
-                                  UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttys%d, count = %d\n",
-                      info->line, state->count);
-#endif
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               state->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttys%d, count = %d\n",
-              info->line, state->count);
-#endif
-#endif /* DO_THIS_LATER */
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static int get_async_struct(int line, ser_info_t **ret_info)
-{
-       struct serial_state *sstate;
-
-       sstate = rs_table + line;
-       if (sstate->info) {
-               sstate->count++;
-               *ret_info = (ser_info_t *)sstate->info;
-               return 0;
-       }
-       else {
-               return -ENOMEM;
-       }
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_360_open(struct tty_struct *tty, struct file * filp)
-{
-       ser_info_t      *info;
-       int             retval, line;
-
-       line = tty->index;
-       if ((line < 0) || (line >= NR_PORTS))
-               return -ENODEV;
-       retval = get_async_struct(line, &info);
-       if (retval)
-               return retval;
-       if (serial_paranoia_check(info, tty->name, "rs_open"))
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s successful...", tty->name);
-#endif
-       return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
-#ifdef notdef
-       struct async_struct *info = state->info, scr_info;
-       char    stat_buf[30], control, status;
-#endif
-       int     ret;
-
-       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
-                     state->line,
-                     (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
-                     (unsigned int)(state->port), state->irq);
-
-       if (!state->port || (state->type == PORT_UNKNOWN)) {
-               ret += sprintf(buf+ret, "\n");
-               return ret;
-       }
-
-#ifdef notdef
-       /*
-        * Figure out the current RS-232 lines
-        */
-       if (!info) {
-               info = &scr_info;       /* This is just for serial_{in,out} */
-
-               info->magic = SERIAL_MAGIC;
-               info->port = state->port;
-               info->flags = state->flags;
-               info->quot = 0;
-               info->port.tty = NULL;
-       }
-       local_irq_disable();
-       status = serial_in(info, UART_MSR);
-       control = info ? info->MCR : serial_in(info, UART_MCR);
-       local_irq_enable();
-       
-       stat_buf[0] = 0;
-       stat_buf[1] = 0;
-       if (control & UART_MCR_RTS)
-               strcat(stat_buf, "|RTS");
-       if (status & UART_MSR_CTS)
-               strcat(stat_buf, "|CTS");
-       if (control & UART_MCR_DTR)
-               strcat(stat_buf, "|DTR");
-       if (status & UART_MSR_DSR)
-               strcat(stat_buf, "|DSR");
-       if (status & UART_MSR_DCD)
-               strcat(stat_buf, "|CD");
-       if (status & UART_MSR_RI)
-               strcat(stat_buf, "|RI");
-
-       if (info->quot) {
-               ret += sprintf(buf+ret, " baud:%d",
-                              state->baud_base / info->quot);
-       }
-
-       ret += sprintf(buf+ret, " tx:%d rx:%d",
-                     state->icount.tx, state->icount.rx);
-
-       if (state->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-       
-       if (state->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-       
-       if (state->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
-
-       if (state->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
-       /*
-        * Last thing is the RS-232 status lines
-        */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-#endif
-       return ret;
-}
-
-int rs_360_read_proc(char *page, char **start, off_t off, int count,
-                int *eof, void *data)
-{
-       int i, len = 0;
-       off_t   begin = 0;
-
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-       for (i = 0; i < NR_PORTS && len < 4000; i++) {
-               len += line_info(page + len, &rs_table[i]);
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
-       }
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (begin-off);
-       return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_serial_version(void)
-{
-       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
-/*
- * The serial console driver used during boot.  Note that these names
- * clash with those found in "serial.c", so we currently can't support
- * the 16xxx uarts and these at the same time.  I will fix this to become
- * an indirect function call from tty_io.c (or something).
- */
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
- */
-static void my_console_write(int idx, const char *s,
-                               unsigned count)
-{
-       struct          serial_state    *ser;
-       ser_info_t              *info;
-       unsigned                i;
-       QUICC_BD                *bdp, *bdbase;
-       volatile struct smc_uart_pram   *up;
-       volatile        u_char          *cp;
-
-       ser = rs_table + idx;
-
-
-       /* If the port has been initialized for general use, we have
-        * to use the buffer descriptors allocated there.  Otherwise,
-        * we simply use the single buffer allocated.
-        */
-       if ((info = (ser_info_t *)ser->info) != NULL) {
-               bdp = info->tx_cur;
-               bdbase = info->tx_bd_base;
-       }
-       else {
-               /* Pointer to UART in parameter ram.
-               */
-               /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-               /* Get the address of the host memory buffer.
-                */
-               bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-       }
-
-       /*
-        * We need to gracefully shut down the transmitter, disable
-        * interrupts, then send our bytes out.
-        */
-
-       /*
-        * Now, do each character.  This is not as bad as it looks
-        * since this is a holding FIFO and not a transmitting FIFO.
-        * We could add the complexity of filling the entire transmit
-        * buffer, but we would just wait longer between accesses......
-        */
-       for (i = 0; i < count; i++, s++) {
-               /* Wait for transmitter fifo to empty.
-                * Ready indicates output is ready, and xmt is doing
-                * that, not that it is ready for us to send.
-                */
-               while (bdp->status & BD_SC_READY);
-
-               /* Send the character out.
-                */
-               cp = bdp->buf;
-               *cp = *s;
-               
-               bdp->length = 1;
-               bdp->status |= BD_SC_READY;
-
-               if (bdp->status & BD_SC_WRAP)
-                       bdp = bdbase;
-               else
-                       bdp++;
-
-               /* if a LF, also do CR... */
-               if (*s == 10) {
-                       while (bdp->status & BD_SC_READY);
-                       /* cp = __va(bdp->buf); */
-                       cp = bdp->buf;
-                       *cp = 13;
-                       bdp->length = 1;
-                       bdp->status |= BD_SC_READY;
-
-                       if (bdp->status & BD_SC_WRAP) {
-                               bdp = bdbase;
-                       }
-                       else {
-                               bdp++;
-                       }
-               }
-       }
-
-       /*
-        * Finally, Wait for transmitter & holding register to empty
-        *  and restore the IER
-        */
-       while (bdp->status & BD_SC_READY);
-
-       if (info)
-               info->tx_cur = (QUICC_BD *)bdp;
-}
-
-static void serial_console_write(struct console *c, const char *s,
-                               unsigned count)
-{
-#ifdef CONFIG_KGDB
-       /* Try to let stub handle output. Returns true if it did. */ 
-       if (kgdb_output_string(s, count))
-               return;
-#endif
-       my_console_write(c->index, s, count);
-}
-
-
-
-/*void console_print_68360(const char *p)
-{
-       const char *cp = p;
-       int i;
-
-       for (i=0;cp[i]!=0;i++);
-
-       serial_console_write (p, i);
-
-       //Comment this if you want to have a strict interrupt-driven output
-       //rs_fair_output();
-
-       return;
-}*/
-
-
-
-
-
-
-#ifdef CONFIG_XMON
-int
-xmon_360_write(const char *s, unsigned count)
-{
-       my_console_write(0, s, count);
-       return(count);
-}
-#endif
-
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
-       my_console_write(0, &ch, 1);
-}
-#endif
-
-/*
- * Receive character from the serial port.  This only works well
- * before the port is initialized for real use.
- */
-static int my_console_wait_key(int idx, int xmon, char *obuf)
-{
-       struct serial_state             *ser;
-       u_char                  c, *cp;
-       ser_info_t              *info;
-       QUICC_BD                *bdp;
-       volatile struct smc_uart_pram   *up;
-       int                             i;
-
-       ser = rs_table + idx;
-
-       /* Get the address of the host memory buffer.
-        * If the port has been initialized for general use, we must
-        * use information from the port structure.
-        */
-       if ((info = (ser_info_t *)ser->info))
-               bdp = info->rx_cur;
-       else
-               /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
-               bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-
-       /* Pointer to UART in parameter ram.
-        */
-       /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
-       up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
-       /*
-        * We need to gracefully shut down the receiver, disable
-        * interrupts, then read the input.
-        * XMON just wants a poll.  If no character, return -1, else
-        * return the character.
-        */
-       if (!xmon) {
-               while (bdp->status & BD_SC_EMPTY);
-       }
-       else {
-               if (bdp->status & BD_SC_EMPTY)
-                       return -1;
-       }
-
-       cp = (char *)bdp->buf;
-
-       if (obuf) {
-               i = c = bdp->length;
-               while (i-- > 0)
-                       *obuf++ = *cp++;
-       }
-       else {
-               c = *cp;
-       }
-       bdp->status |= BD_SC_EMPTY;
-
-       if (info) {
-               if (bdp->status & BD_SC_WRAP) {
-                       bdp = info->rx_bd_base;
-               }
-               else {
-                       bdp++;
-               }
-               info->rx_cur = (QUICC_BD *)bdp;
-       }
-
-       return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
-       return(my_console_wait_key(co->index, 0, NULL));
-}
-
-#ifdef CONFIG_XMON
-int
-xmon_360_read_poll(void)
-{
-       return(my_console_wait_key(0, 1, NULL));
-}
-
-int
-xmon_360_read_char(void)
-{
-       return(my_console_wait_key(0, 0, NULL));
-}
-#endif
-
-#ifdef CONFIG_KGDB
-static char kgdb_buf[RX_BUF_SIZE], *kgdp;
-static int kgdb_chars;
-
-unsigned char
-getDebugChar(void)
-{
-       if (kgdb_chars <= 0) {
-               kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
-               kgdp = kgdb_buf;
-       }
-       kgdb_chars--;
-
-       return(*kgdp++);
-}
-
-void kgdb_interruptible(int state)
-{
-}
-void kgdb_map_scc(void)
-{
-       struct          serial_state *ser;
-       uint            mem_addr;
-       volatile        QUICC_BD                *bdp;
-       volatile        smc_uart_t      *up;
-
-       cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-
-       /* To avoid data cache CPM DMA coherency problems, allocate a
-        * buffer in the CPM DPRAM.  This will work until the CPM and
-        * serial ports are initialized.  At that time a memory buffer
-        * will be allocated.
-        * The port is already initialized from the boot procedure, all
-        * we do here is give it a different buffer and make it a FIFO.
-        */
-
-       ser = rs_table;
-
-       /* Right now, assume we are using SMCs.
-       */
-       up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
-
-       /* Allocate space for an input FIFO, plus a few bytes for output.
-        * Allocate bytes to maintain word alignment.
-        */
-       mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
-
-       /* Set the physical address of the host memory buffers in
-        * the buffer descriptors.
-        */
-       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
-       bdp->buf = mem_addr;
-
-       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
-       bdp->buf = mem_addr+RX_BUF_SIZE;
-
-       up->smc_mrblr = RX_BUF_SIZE;            /* receive buffer length */
-       up->smc_maxidl = RX_BUF_SIZE;
-}
-#endif
-
-static struct tty_struct *serial_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return serial_driver;
-}
-
-
-struct console sercons = {
-       .name           = "ttyS",
-       .write          = serial_console_write,
-       .device         = serial_console_device,
-       .wait_key       = serial_console_wait_key,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = CONFIG_SERIAL_CONSOLE_PORT, 
-};
-
-
-
-/*
- *     Register console.
- */
-long console_360_init(long kmem_start, long kmem_end)
-{
-       register_console(&sercons);
-       /*register_console (console_print_68360); - 2.0.38 only required a write
-      function pointer. */
-       return kmem_start;
-}
-
-#endif
-
-/* Index in baud rate table of the default console baud rate.
-*/
-static int     baud_idx;
-
-static const struct tty_operations rs_360_ops = {
-       .owner = THIS_MODULE,
-       .open = rs_360_open,
-       .close = rs_360_close,
-       .write = rs_360_write,
-       .put_char = rs_360_put_char,
-       .write_room = rs_360_write_room,
-       .chars_in_buffer = rs_360_chars_in_buffer,
-       .flush_buffer = rs_360_flush_buffer,
-       .ioctl = rs_360_ioctl,
-       .throttle = rs_360_throttle,
-       .unthrottle = rs_360_unthrottle,
-       /* .send_xchar = rs_360_send_xchar, */
-       .set_termios = rs_360_set_termios,
-       .stop = rs_360_stop,
-       .start = rs_360_start,
-       .hangup = rs_360_hangup,
-       /* .wait_until_sent = rs_360_wait_until_sent, */
-       /* .read_proc = rs_360_read_proc, */
-       .tiocmget = rs_360_tiocmget,
-       .tiocmset = rs_360_tiocmset,
-};
-
-static int __init rs_360_init(void)
-{
-       struct serial_state * state;
-       ser_info_t      *info;
-       void       *mem_addr;
-       uint            dp_addr, iobits;
-       int                 i, j, idx;
-       ushort          chan;
-       QUICC_BD        *bdp;
-       volatile        QUICC           *cp;
-       volatile        struct smc_regs *sp;
-       volatile        struct smc_uart_pram    *up;
-       volatile        struct scc_regs *scp;
-       volatile        struct uart_pram        *sup;
-       /* volatile     immap_t         *immap; */
-       
-       serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!serial_driver)
-               return -1;
-
-       show_serial_version();
-
-       serial_driver->name = "ttyS";
-       serial_driver->major = TTY_MAJOR;
-       serial_driver->minor_start = 64;
-       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       serial_driver->init_termios = tty_std_termios;
-       serial_driver->init_termios.c_cflag =
-               baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(serial_driver, &rs_360_ops);
-       
-       if (tty_register_driver(serial_driver))
-               panic("Couldn't register serial driver\n");
-
-       cp = pquicc;    /* Get pointer to Communication Processor */
-       /* immap = (immap_t *)IMAP_ADDR; */     /* and to internal registers */
-
-
-       /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
-        */
-       /* The "standard" configuration through the 860.
-       */
-/*     immap->im_ioport.iop_papar |= 0x00fc; */
-/*     immap->im_ioport.iop_padir &= ~0x00fc; */
-/*     immap->im_ioport.iop_paodr &= ~0x00fc; */
-       cp->pio_papar |= 0x00fc;
-       cp->pio_padir &= ~0x00fc;
-       /* cp->pio_paodr &= ~0x00fc; */
-
-
-       /* Since we don't yet do modem control, connect the port C pins
-        * as general purpose I/O.  This will assert CTS and CD for the
-        * SCC ports.
-        */
-       /* FIXME: see 360um p.7-365 and 860um p.34-12 
-        * I can't make sense of these bits - mleslie*/
-/*     immap->im_ioport.iop_pcdir |= 0x03c6; */
-/*     immap->im_ioport.iop_pcpar &= ~0x03c6; */
-
-/*     cp->pio_pcdir |= 0x03c6; */
-/*     cp->pio_pcpar &= ~0x03c6; */
-
-
-
-       /* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
-        * BRG4 to SCC3.
-        */
-       cp->si_sicr &= ~0x00ffff00;
-       cp->si_sicr |=  0x001b1200;
-
-#ifdef CONFIG_PP04
-       /* Frequentis PP04 forced to RS-232 until we know better.
-        * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
-        */
-       immap->im_ioport.iop_pcdir |= 0x000c;
-       immap->im_ioport.iop_pcpar &= ~0x000c;
-       immap->im_ioport.iop_pcdat &= ~0x000c;
-
-       /* This enables the TX driver.
-       */
-       cp->cp_pbpar &= ~0x6000;
-       cp->cp_pbdat &= ~0x6000;
-#endif
-
-       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
-               state->magic = SSTATE_MAGIC;
-               state->line = i;
-               state->type = PORT_UNKNOWN;
-               state->custom_divisor = 0;
-               state->close_delay = 5*HZ/10;
-               state->closing_wait = 30*HZ;
-               state->icount.cts = state->icount.dsr = 
-                       state->icount.rng = state->icount.dcd = 0;
-               state->icount.rx = state->icount.tx = 0;
-               state->icount.frame = state->icount.parity = 0;
-               state->icount.overrun = state->icount.brk = 0;
-               printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
-                      i, (unsigned int)(state->irq),
-                      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
-
-#ifdef CONFIG_SERIAL_CONSOLE
-               /* If we just printed the message on the console port, and
-                * we are about to initialize it for general use, we have
-                * to wait a couple of character times for the CR/NL to
-                * make it out of the transmit buffer.
-                */
-               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                       mdelay(8);
-
-
-/*             idx = PORT_NUM(info->state->smc_scc_num); */
-/*             if (info->state->smc_scc_num & NUM_IS_SCC) */
-/*                     chan = scc_chan_map[idx]; */
-/*             else */
-/*                     chan = smc_chan_map[idx]; */
-
-/*             cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
-/*             while (cp->cp_cr & CPM_CR_FLG); */
-
-#endif
-               /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
-               info = &quicc_ser_info[i];
-               if (info) {
-                       memset (info, 0, sizeof(ser_info_t));
-                       info->magic = SERIAL_MAGIC;
-                       info->line = i;
-                       info->flags = state->flags;
-                       INIT_WORK(&info->tqueue, do_softint, info);
-                       INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
-                       init_waitqueue_head(&info->open_wait);
-                       init_waitqueue_head(&info->close_wait);
-                       info->state = state;
-                       state->info = (struct async_struct *)info;
-
-                       /* We need to allocate a transmit and receive buffer
-                        * descriptors from dual port ram, and a character
-                        * buffer area from host mem.
-                        */
-                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
-
-                       /* Allocate space for FIFOs in the host memory.
-                        *  (for now this is from a static array of buffers :(
-                        */
-                       /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
-                       /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
-                       mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
-
-                       /* Set the physical address of the host memory
-                        * buffers in the buffer descriptors, and the
-                        * virtual address for us to work with.
-                        */
-                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-                       info->rx_cur = info->rx_bd_base = bdp;
-
-                       /* initialize rx buffer descriptors */
-                       for (j=0; j<(RX_NUM_FIFO-1); j++) {
-                               bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-                               bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
-                               mem_addr += RX_BUF_SIZE;
-                               bdp++;
-                       }
-                       bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
-                       bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-
-                       idx = PORT_NUM(info->state->smc_scc_num);
-                       if (info->state->smc_scc_num & NUM_IS_SCC) {
-
-#if defined (CONFIG_UCQUICC) && 1
-                               /* set the transceiver mode to RS232 */
-                               sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
-                               sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
-                               *(uint *)_periph_base = sipex_mode_bits;
-                               /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
-#endif
-                       }
-
-                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
-
-                       /* Allocate space for FIFOs in the host memory.
-                       */
-                       /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
-                       /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
-                       mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
-
-                       /* Set the physical address of the host memory
-                        * buffers in the buffer descriptors, and the
-                        * virtual address for us to work with.
-                        */
-                       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-                       info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
-
-                       /* initialize tx buffer descriptors */
-                       for (j=0; j<(TX_NUM_FIFO-1); j++) {
-                               bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-                               bdp->status = BD_SC_INTRPT;
-                               mem_addr += TX_BUF_SIZE;
-                               bdp++;
-                       }
-                       bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
-                       bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
-
-                       if (info->state->smc_scc_num & NUM_IS_SCC) {
-                               scp = &pquicc->scc_regs[idx];
-                               sup = &pquicc->pram[info->state->port].scc.pscc.u;
-                               sup->rbase = dp_addr;
-                               sup->tbase = dp_addr;
-
-                               /* Set up the uart parameters in the
-                                * parameter ram.
-                                */
-                               sup->rfcr = SMC_EB;
-                               sup->tfcr = SMC_EB;
-
-                               /* Set this to 1 for now, so we get single
-                                * character interrupts.  Using idle character
-                                * time requires some additional tuning.
-                                */
-                               sup->mrblr = 1;
-                               sup->max_idl = 0;
-                               sup->brkcr = 1;
-                               sup->parec = 0;
-                               sup->frmer = 0;
-                               sup->nosec = 0;
-                               sup->brkec = 0;
-                               sup->uaddr1 = 0;
-                               sup->uaddr2 = 0;
-                               sup->toseq = 0;
-                               {
-                                       int i;
-                                       for (i=0;i<8;i++)
-                                               sup->cc[i] = 0x8000;
-                               }
-                               sup->rccm = 0xc0ff;
-
-                               /* Send the CPM an initialize command.
-                               */
-                               chan = scc_chan_map[idx];
-
-                               /* execute the INIT RX & TX PARAMS command for this channel. */
-                               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-                               while (cp->cp_cr & CPM_CR_FLG);
-
-                               /* Set UART mode, 8 bit, no parity, one stop.
-                                * Enable receive and transmit.
-                                */
-                               scp->scc_gsmr.w.high = 0;
-                               scp->scc_gsmr.w.low = 
-                                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-                               /* Disable all interrupts and clear all pending
-                                * events.
-                                */
-                               scp->scc_sccm = 0;
-                               scp->scc_scce = 0xffff;
-                               scp->scc_dsr = 0x7e7e;
-                               scp->scc_psmr = 0x3000;
-
-                               /* If the port is the console, enable Rx and Tx.
-                               */
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-                       }
-                       else {
-                               /* Configure SMCs Tx/Rx instead of port B
-                                * parallel I/O.
-                                */
-                               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-                               up->rbase = dp_addr;
-
-                               iobits = 0xc0 << (idx * 4);
-                               cp->pip_pbpar |= iobits;
-                               cp->pip_pbdir &= ~iobits;
-                               cp->pip_pbodr &= ~iobits;
-
-
-                               /* Connect the baud rate generator to the
-                                * SMC based upon index in rs_table.  Also
-                                * make sure it is connected to NMSI.
-                                */
-                               cp->si_simode &= ~(0xffff << (idx * 16));
-                               cp->si_simode |= (i << ((idx * 16) + 12));
-
-                               up->tbase = dp_addr;
-
-                               /* Set up the uart parameters in the
-                                * parameter ram.
-                                */
-                               up->rfcr = SMC_EB;
-                               up->tfcr = SMC_EB;
-
-                               /* Set this to 1 for now, so we get single
-                                * character interrupts.  Using idle character
-                                * time requires some additional tuning.
-                                */
-                               up->mrblr = 1;
-                               up->max_idl = 0;
-                               up->brkcr = 1;
-
-                               /* Send the CPM an initialize command.
-                               */
-                               chan = smc_chan_map[idx];
-
-                               cp->cp_cr = mk_cr_cmd(chan,
-                                                                         CPM_CR_INIT_TRX) | CPM_CR_FLG;
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       printk("");
-#endif
-                               while (cp->cp_cr & CPM_CR_FLG);
-
-                               /* Set UART mode, 8 bit, no parity, one stop.
-                                * Enable receive and transmit.
-                                */
-                               sp = &cp->smc_regs[idx];
-                               sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
-                               /* Disable all interrupts and clear all pending
-                                * events.
-                                */
-                               sp->smc_smcm = 0;
-                               sp->smc_smce = 0xff;
-
-                               /* If the port is the console, enable Rx and Tx.
-                               */
-#ifdef CONFIG_SERIAL_CONSOLE
-                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
-                                       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-#endif
-                       }
-
-                       /* Install interrupt handler.
-                       */
-                       /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
-                       /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
-                       request_irq(state->irq, rs_360_interrupt,
-                                               IRQ_FLG_LOCK, "ttyS", (void *)info);
-
-                       /* Set up the baud rate generator.
-                       */
-                       m360_cpm_setbrg(i, baud_table[baud_idx]);
-
-               }
-       }
-
-       return 0;
-}
-module_init(rs_360_init);
-
-/* This must always be called before the rs_360_init() function, otherwise
- * it blows away the port control information.
- */
-//static int __init serial_console_setup( struct console *co, char *options)
-int serial_console_setup( struct console *co, char *options)
-{
-       struct          serial_state    *ser;
-       uint            mem_addr, dp_addr, bidx, idx, iobits;
-       ushort          chan;
-       QUICC_BD        *bdp;
-       volatile        QUICC                   *cp;
-       volatile        struct smc_regs *sp;
-       volatile        struct scc_regs *scp;
-       volatile        struct smc_uart_pram    *up;
-       volatile        struct uart_pram                *sup;
-
-/* mleslie TODO:
- * add something to the 68k bootloader to store a desired initial console baud rate */
-
-/*     bd_t                                            *bd; */ /* a board info struct used by EPPC-bug */
-/*     bd = (bd_t *)__res; */
-
-       for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
-        /* if (bd->bi_baudrate == baud_table[bidx]) */
-               if (CONSOLE_BAUDRATE == baud_table[bidx])
-                       break;
-
-       /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
-       baud_idx = bidx;
-
-       ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
-
-       cp = pquicc;    /* Get pointer to Communication Processor */
-
-       idx = PORT_NUM(ser->smc_scc_num);
-       if (ser->smc_scc_num & NUM_IS_SCC) {
-
-               /* TODO: need to set up SCC pin assignment etc. here */
-               
-       }
-       else {
-               iobits = 0xc0 << (idx * 4);
-               cp->pip_pbpar |= iobits;
-               cp->pip_pbdir &= ~iobits;
-               cp->pip_pbodr &= ~iobits;
-
-               /* Connect the baud rate generator to the
-                * SMC based upon index in rs_table.  Also
-                * make sure it is connected to NMSI.
-                */
-               cp->si_simode &= ~(0xffff << (idx * 16));
-               cp->si_simode |= (idx << ((idx * 16) + 12));
-       }
-
-       /* When we get here, the CPM has been reset, so we need
-        * to configure the port.
-        * We need to allocate a transmit and receive buffer descriptor
-        * from dual port ram, and a character buffer area from host mem.
-        */
-
-       /* Allocate space for two buffer descriptors in the DP ram.
-       */
-       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
-
-       /* Allocate space for two 2 byte FIFOs in the host memory.
-        */
-       /* mem_addr = m360_cpm_hostalloc(8); */
-       mem_addr = (uint)console_fifos;
-
-
-       /* Set the physical address of the host memory buffers in
-        * the buffer descriptors.
-        */
-       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
-       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
-       bdp->buf = (char *)mem_addr;
-       (bdp+1)->buf = (char *)(mem_addr+4);
-
-       /* For the receive, set empty and wrap.
-        * For transmit, set wrap.
-        */
-       bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
-       (bdp+1)->status = BD_SC_WRAP;
-
-       /* Set up the uart parameters in the parameter ram.
-        */
-       if (ser->smc_scc_num & NUM_IS_SCC) {
-               scp = &cp->scc_regs[idx];
-               /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
-               sup = &pquicc->pram[ser->port].scc.pscc.u;
-
-               sup->rbase = dp_addr;
-               sup->tbase = dp_addr + sizeof(QUICC_BD);
-
-               /* Set up the uart parameters in the
-                * parameter ram.
-                */
-               sup->rfcr = SMC_EB;
-               sup->tfcr = SMC_EB;
-
-               /* Set this to 1 for now, so we get single
-                * character interrupts.  Using idle character
-                * time requires some additional tuning.
-                */
-               sup->mrblr = 1;
-               sup->max_idl = 0;
-               sup->brkcr = 1;
-               sup->parec = 0;
-               sup->frmer = 0;
-               sup->nosec = 0;
-               sup->brkec = 0;
-               sup->uaddr1 = 0;
-               sup->uaddr2 = 0;
-               sup->toseq = 0;
-               {
-                       int i;
-                       for (i=0;i<8;i++)
-                               sup->cc[i] = 0x8000;
-               }
-               sup->rccm = 0xc0ff;
-
-               /* Send the CPM an initialize command.
-               */
-               chan = scc_chan_map[idx];
-
-               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-               while (cp->cp_cr & CPM_CR_FLG);
-
-               /* Set UART mode, 8 bit, no parity, one stop.
-                * Enable receive and transmit.
-                */
-               scp->scc_gsmr.w.high = 0;
-               scp->scc_gsmr.w.low = 
-                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-               /* Disable all interrupts and clear all pending
-                * events.
-                */
-               scp->scc_sccm = 0;
-               scp->scc_scce = 0xffff;
-               scp->scc_dsr = 0x7e7e;
-               scp->scc_psmr = 0x3000;
-
-               scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
-       }
-       else {
-               /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
-               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
-               up->rbase = dp_addr;    /* Base of receive buffer desc. */
-               up->tbase = dp_addr+sizeof(QUICC_BD);   /* Base of xmt buffer desc. */
-               up->rfcr = SMC_EB;
-               up->tfcr = SMC_EB;
-
-               /* Set this to 1 for now, so we get single character interrupts.
-               */
-               up->mrblr = 1;          /* receive buffer length */
-               up->max_idl = 0;                /* wait forever for next char */
-
-               /* Send the CPM an initialize command.
-               */
-               chan = smc_chan_map[idx];
-               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-               while (cp->cp_cr & CPM_CR_FLG);
-
-               /* Set UART mode, 8 bit, no parity, one stop.
-                * Enable receive and transmit.
-                */
-               sp = &cp->smc_regs[idx];
-               sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
-
-               /* And finally, enable Rx and Tx.
-               */
-               sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-       }
-
-       /* Set up the baud rate generator.
-       */
-       /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
-       m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
-
-       return 0;
-}
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
deleted file mode 100644 (file)
index b25e6e4..0000000
+++ /dev/null
@@ -1,3377 +0,0 @@
-/*
- *  linux/drivers/char/8250.c
- *
- *  Driver for 8250/16550-type serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * A note about mapbase / membase
- *
- *  mapbase is the physical address of the IO port.
- *  membase is an 'ioremapped' cookie.
- */
-
-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/ratelimit.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-#include <linux/nmi.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8250.h"
-
-#ifdef CONFIG_SPARC
-#include "suncore.h"
-#endif
-
-/*
- * Configuration:
- *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
- *                is unsafe when used on edge-triggered interrupts.
- */
-static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
-
-static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
-
-static struct uart_driver serial8250_reg;
-
-static int serial_index(struct uart_port *port)
-{
-       return (serial8250_reg.minor - 64) + port->line;
-}
-
-static unsigned int skip_txen_test; /* force skip of txen test at init time */
-
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...)     printk(fmt)
-#else
-#define DEBUG_INTR(fmt...)     do { } while (0)
-#endif
-
-#define PASS_LIMIT     256
-
-#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq) ((irq) != 0)
-
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_8250_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
-
-/*
- * HUB6 is always on.  This will be removed once the header
- * files have been cleaned.
- */
-#define CONFIG_HUB6 1
-
-#include <asm/serial.h>
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism.   Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
-#ifndef SERIAL_PORT_DFNS
-#define SERIAL_PORT_DFNS
-#endif
-
-static const struct old_serial_port old_serial_port[] = {
-       SERIAL_PORT_DFNS /* defined in asm/serial.h */
-};
-
-#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
-
-#ifdef CONFIG_SERIAL_8250_RSA
-
-#define PORT_RSA_MAX 4
-static unsigned long probe_rsa[PORT_RSA_MAX];
-static unsigned int probe_rsa_count;
-#endif /* CONFIG_SERIAL_8250_RSA  */
-
-struct uart_8250_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          capabilities;   /* port capabilities */
-       unsigned short          bugs;           /* port bugs */
-       unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           cur_iotype;     /* Running I/O type */
-
-       /*
-        * Some bits in registers are cleared on a read, so they must
-        * be saved whenever the register is read but the bits will not
-        * be immediately processed.
-        */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
-       unsigned char           lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
-       unsigned char           msr_saved_flags;
-};
-
-struct irq_info {
-       struct                  hlist_node node;
-       int                     irq;
-       spinlock_t              lock;   /* Protects list not the hash */
-       struct list_head        *head;
-};
-
-#define NR_IRQ_HASH            32      /* Can be adjusted later */
-static struct hlist_head irq_lists[NR_IRQ_HASH];
-static DEFINE_MUTEX(hash_mutex);       /* Used to walk the hash */
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial8250_config uart_config[] = {
-       [PORT_UNKNOWN] = {
-               .name           = "unknown",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_8250] = {
-               .name           = "8250",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16450] = {
-               .name           = "16450",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16550] = {
-               .name           = "16550",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16550A] = {
-               .name           = "16550A",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_CIRRUS] = {
-               .name           = "Cirrus",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16650] = {
-               .name           = "ST16650",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16650V2] = {
-               .name           = "ST16650V2",
-               .fifo_size      = 32,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
-                                 UART_FCR_T_TRIG_00,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16750] = {
-               .name           = "TI16750",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
-                                 UART_FCR7_64BYTE,
-               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
-       },
-       [PORT_STARTECH] = {
-               .name           = "Startech",
-               .fifo_size      = 1,
-               .tx_loadsz      = 1,
-       },
-       [PORT_16C950] = {
-               .name           = "16C950/954",
-               .fifo_size      = 128,
-               .tx_loadsz      = 128,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16654] = {
-               .name           = "ST16654",
-               .fifo_size      = 64,
-               .tx_loadsz      = 32,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
-                                 UART_FCR_T_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_16850] = {
-               .name           = "XR16850",
-               .fifo_size      = 128,
-               .tx_loadsz      = 128,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
-       },
-       [PORT_RSA] = {
-               .name           = "RSA",
-               .fifo_size      = 2048,
-               .tx_loadsz      = 2048,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_NS16550A] = {
-               .name           = "NS16550A",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_NATSEMI,
-       },
-       [PORT_XSCALE] = {
-               .name           = "XScale",
-               .fifo_size      = 32,
-               .tx_loadsz      = 32,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_UUE,
-       },
-       [PORT_RM9000] = {
-               .name           = "RM9000",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_OCTEON] = {
-               .name           = "OCTEON",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO,
-       },
-       [PORT_AR7] = {
-               .name           = "AR7",
-               .fifo_size      = 16,
-               .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
-               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
-       },
-       [PORT_U6_16550A] = {
-               .name           = "U6_16550A",
-               .fifo_size      = 64,
-               .tx_loadsz      = 64,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
-       },
-};
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-
-/* Au1x00 UART hardware has a weird register layout */
-static const u8 au_io_in_map[] = {
-       [UART_RX]  = 0,
-       [UART_IER] = 2,
-       [UART_IIR] = 3,
-       [UART_LCR] = 5,
-       [UART_MCR] = 6,
-       [UART_LSR] = 7,
-       [UART_MSR] = 8,
-};
-
-static const u8 au_io_out_map[] = {
-       [UART_TX]  = 1,
-       [UART_IER] = 2,
-       [UART_FCR] = 4,
-       [UART_LCR] = 5,
-       [UART_MCR] = 6,
-};
-
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_AU)
-               return offset;
-       return au_io_in_map[offset];
-}
-
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_AU)
-               return offset;
-       return au_io_out_map[offset];
-}
-
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-
-static const u8
-       regmap_in[8] = {
-               [UART_RX]       = 0x00,
-               [UART_IER]      = 0x0c,
-               [UART_IIR]      = 0x14,
-               [UART_LCR]      = 0x1c,
-               [UART_MCR]      = 0x20,
-               [UART_LSR]      = 0x24,
-               [UART_MSR]      = 0x28,
-               [UART_SCR]      = 0x2c
-       },
-       regmap_out[8] = {
-               [UART_TX]       = 0x04,
-               [UART_IER]      = 0x0c,
-               [UART_FCR]      = 0x18,
-               [UART_LCR]      = 0x1c,
-               [UART_MCR]      = 0x20,
-               [UART_LSR]      = 0x24,
-               [UART_MSR]      = 0x28,
-               [UART_SCR]      = 0x2c
-       };
-
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_RM9000)
-               return offset;
-       return regmap_in[offset];
-}
-
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
-{
-       if (p->iotype != UPIO_RM9000)
-               return offset;
-       return regmap_out[offset];
-}
-
-#else
-
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
-
-#endif
-
-static unsigned int hub6_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       outb(p->hub6 - 1 + offset, p->iobase);
-       return inb(p->iobase + 1);
-}
-
-static void hub6_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       outb(p->hub6 - 1 + offset, p->iobase);
-       outb(value, p->iobase + 1);
-}
-
-static unsigned int mem_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return readb(p->membase + offset);
-}
-
-static void mem_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       writeb(value, p->membase + offset);
-}
-
-static void mem32_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       writel(value, p->membase + offset);
-}
-
-static unsigned int mem32_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return readl(p->membase + offset);
-}
-
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       __raw_writel(value, p->membase + offset);
-}
-
-static unsigned int tsi_serial_in(struct uart_port *p, int offset)
-{
-       unsigned int tmp;
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       if (offset == UART_IIR) {
-               tmp = readl(p->membase + (UART_IIR & ~3));
-               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
-       } else
-               return readb(p->membase + offset);
-}
-
-static void tsi_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
-               writeb(value, p->membase + offset);
-}
-
-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
-static inline void dwapb_save_out_value(struct uart_port *p, int offset,
-                                       int value)
-{
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-
-       if (offset == UART_LCR)
-               up->lcr = value;
-}
-
-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
-static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
-{
-       if (offset == UART_TX || offset == UART_IER)
-               p->serial_in(p, UART_IER);
-}
-
-static void dwapb_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writeb(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
-static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writel(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
-static unsigned int io_serial_in(struct uart_port *p, int offset)
-{
-       offset = map_8250_in_reg(p, offset) << p->regshift;
-       return inb(p->iobase + offset);
-}
-
-static void io_serial_out(struct uart_port *p, int offset, int value)
-{
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       outb(value, p->iobase + offset);
-}
-
-static void set_io_from_upio(struct uart_port *p)
-{
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-       switch (p->iotype) {
-       case UPIO_HUB6:
-               p->serial_in = hub6_serial_in;
-               p->serial_out = hub6_serial_out;
-               break;
-
-       case UPIO_MEM:
-               p->serial_in = mem_serial_in;
-               p->serial_out = mem_serial_out;
-               break;
-
-       case UPIO_RM9000:
-       case UPIO_MEM32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = mem32_serial_out;
-               break;
-
-       case UPIO_AU:
-               p->serial_in = au_serial_in;
-               p->serial_out = au_serial_out;
-               break;
-
-       case UPIO_TSI:
-               p->serial_in = tsi_serial_in;
-               p->serial_out = tsi_serial_out;
-               break;
-
-       case UPIO_DWAPB:
-               p->serial_in = mem_serial_in;
-               p->serial_out = dwapb_serial_out;
-               break;
-
-       case UPIO_DWAPB32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = dwapb32_serial_out;
-               break;
-
-       default:
-               p->serial_in = io_serial_in;
-               p->serial_out = io_serial_out;
-               break;
-       }
-       /* Remember loaded iotype */
-       up->cur_iotype = p->iotype;
-}
-
-static void
-serial_out_sync(struct uart_8250_port *up, int offset, int value)
-{
-       struct uart_port *p = &up->port;
-       switch (p->iotype) {
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               p->serial_out(p, offset, value);
-               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
-               break;
-       default:
-               p->serial_out(p, offset, value);
-       }
-}
-
-#define serial_in(up, offset)          \
-       (up->port.serial_in(&(up)->port, (offset)))
-#define serial_out(up, offset, value)  \
-       (up->port.serial_out(&(up)->port, (offset), (value)))
-/*
- * We used to support using pause I/O for certain machines.  We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset)         serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
-       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
-       serial_outp(up, UART_DLL, value & 0xff);
-       serial_outp(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
-       if (up->port.iotype == UPIO_AU)
-               return __raw_readl(up->port.membase + 0x28);
-       else
-               return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-       if (up->port.iotype == UPIO_AU)
-               __raw_writel(value, up->port.membase + 0x28);
-       else
-               _serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
-       return  (up->port.iotype == UPIO_RM9000) ?
-               (((__raw_readl(up->port.membase + 0x10) << 8) |
-               (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
-               _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-       if (up->port.iotype == UPIO_RM9000) {
-               __raw_writel(value, up->port.membase + 0x08);
-               __raw_writel(value >> 8, up->port.membase + 0x10);
-       } else {
-               _serial_dl_write(up, value);
-       }
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
-/*
- * For the 16C950
- */
-static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
-{
-       serial_out(up, UART_SCR, offset);
-       serial_out(up, UART_ICR, value);
-}
-
-static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
-{
-       unsigned int value;
-
-       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
-       serial_out(up, UART_SCR, offset);
-       value = serial_in(up, UART_ICR);
-       serial_icr_write(up, UART_ACR, up->acr);
-
-       return value;
-}
-
-/*
- * FIFO support.
- */
-static void serial8250_clear_fifos(struct uart_8250_port *p)
-{
-       if (p->capabilities & UART_CAP_FIFO) {
-               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
-               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
-                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-               serial_outp(p, UART_FCR, 0);
-       }
-}
-
-/*
- * IER sleep support.  UARTs which have EFRs need the "extended
- * capability" bit enabled.  Note that on XR16C850s, we need to
- * reset LCR to write to IER.
- */
-static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
-{
-       if (p->capabilities & UART_CAP_SLEEP) {
-               if (p->capabilities & UART_CAP_EFR) {
-                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-                       serial_outp(p, UART_EFR, UART_EFR_ECB);
-                       serial_outp(p, UART_LCR, 0);
-               }
-               serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
-               if (p->capabilities & UART_CAP_EFR) {
-                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
-                       serial_outp(p, UART_EFR, 0);
-                       serial_outp(p, UART_LCR, 0);
-               }
-       }
-}
-
-#ifdef CONFIG_SERIAL_8250_RSA
-/*
- * Attempts to turn on the RSA FIFO.  Returns zero on failure.
- * We set the port uart clock rate if we succeed.
- */
-static int __enable_rsa(struct uart_8250_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       mode = serial_inp(up, UART_RSA_MSR);
-       result = mode & UART_RSA_MSR_FIFO;
-
-       if (!result) {
-               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = mode & UART_RSA_MSR_FIFO;
-       }
-
-       if (result)
-               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
-
-       return result;
-}
-
-static void enable_rsa(struct uart_8250_port *up)
-{
-       if (up->port.type == PORT_RSA) {
-               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
-                       spin_lock_irq(&up->port.lock);
-                       __enable_rsa(up);
-                       spin_unlock_irq(&up->port.lock);
-               }
-               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
-                       serial_outp(up, UART_RSA_FRR, 0);
-       }
-}
-
-/*
- * Attempts to turn off the RSA FIFO.  Returns zero on failure.
- * It is unknown why interrupts were disabled in here.  However,
- * the caller is expected to preserve this behaviour by grabbing
- * the spinlock before calling this function.
- */
-static void disable_rsa(struct uart_8250_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       if (up->port.type == PORT_RSA &&
-           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
-               spin_lock_irq(&up->port.lock);
-
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = !(mode & UART_RSA_MSR_FIFO);
-
-               if (!result) {
-                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-                       mode = serial_inp(up, UART_RSA_MSR);
-                       result = !(mode & UART_RSA_MSR_FIFO);
-               }
-
-               if (result)
-                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
-               spin_unlock_irq(&up->port.lock);
-       }
-}
-#endif /* CONFIG_SERIAL_8250_RSA */
-
-/*
- * This is a quickie test to see how big the FIFO is.
- * It doesn't work at all the time, more's the pity.
- */
-static int size_fifo(struct uart_8250_port *up)
-{
-       unsigned char old_fcr, old_mcr, old_lcr;
-       unsigned short old_dl;
-       int count;
-
-       old_lcr = serial_inp(up, UART_LCR);
-       serial_outp(up, UART_LCR, 0);
-       old_fcr = serial_inp(up, UART_FCR);
-       old_mcr = serial_inp(up, UART_MCR);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                   UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_outp(up, UART_MCR, UART_MCR_LOOP);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       old_dl = serial_dl_read(up);
-       serial_dl_write(up, 0x0001);
-       serial_outp(up, UART_LCR, 0x03);
-       for (count = 0; count < 256; count++)
-               serial_outp(up, UART_TX, count);
-       mdelay(20);/* FIXME - schedule_timeout */
-       for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
-            (count < 256); count++)
-               serial_inp(up, UART_RX);
-       serial_outp(up, UART_FCR, old_fcr);
-       serial_outp(up, UART_MCR, old_mcr);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_dl_write(up, old_dl);
-       serial_outp(up, UART_LCR, old_lcr);
-
-       return count;
-}
-
-/*
- * Read UART ID using the divisor method - set DLL and DLM to zero
- * and the revision will be in DLL and device type in DLM.  We
- * preserve the device state across this.
- */
-static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
-{
-       unsigned char old_dll, old_dlm, old_lcr;
-       unsigned int id;
-
-       old_lcr = serial_inp(p, UART_LCR);
-       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       old_dll = serial_inp(p, UART_DLL);
-       old_dlm = serial_inp(p, UART_DLM);
-
-       serial_outp(p, UART_DLL, 0);
-       serial_outp(p, UART_DLM, 0);
-
-       id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8;
-
-       serial_outp(p, UART_DLL, old_dll);
-       serial_outp(p, UART_DLM, old_dlm);
-       serial_outp(p, UART_LCR, old_lcr);
-
-       return id;
-}
-
-/*
- * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
- * When this function is called we know it is at least a StarTech
- * 16650 V2, but it might be one of several StarTech UARTs, or one of
- * its clones.  (We treat the broken original StarTech 16650 V1 as a
- * 16550, and why not?  Startech doesn't seem to even acknowledge its
- * existence.)
- *
- * What evil have men's minds wrought...
- */
-static void autoconfig_has_efr(struct uart_8250_port *up)
-{
-       unsigned int id1, id2, id3, rev;
-
-       /*
-        * Everything with an EFR has SLEEP
-        */
-       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
-
-       /*
-        * First we check to see if it's an Oxford Semiconductor UART.
-        *
-        * If we have to do this here because some non-National
-        * Semiconductor clone chips lock up if you try writing to the
-        * LSR register (which serial_icr_read does)
-        */
-
-       /*
-        * Check for Oxford Semiconductor 16C950.
-        *
-        * EFR [4] must be set else this test fails.
-        *
-        * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)
-        * claims that it's needed for 952 dual UART's (which are not
-        * recommended for new designs).
-        */
-       up->acr = 0;
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, UART_EFR_ECB);
-       serial_out(up, UART_LCR, 0x00);
-       id1 = serial_icr_read(up, UART_ID1);
-       id2 = serial_icr_read(up, UART_ID2);
-       id3 = serial_icr_read(up, UART_ID3);
-       rev = serial_icr_read(up, UART_REV);
-
-       DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
-
-       if (id1 == 0x16 && id2 == 0xC9 &&
-           (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
-               up->port.type = PORT_16C950;
-
-               /*
-                * Enable work around for the Oxford Semiconductor 952 rev B
-                * chip which causes it to seriously miscalculate baud rates
-                * when DLL is 0.
-                */
-               if (id3 == 0x52 && rev == 0x01)
-                       up->bugs |= UART_BUG_QUOT;
-               return;
-       }
-
-       /*
-        * We check for a XR16C850 by setting DLL and DLM to 0, and then
-        * reading back DLL and DLM.  The chip type depends on the DLM
-        * value read back:
-        *  0x10 - XR16C850 and the DLL contains the chip revision.
-        *  0x12 - XR16C2850.
-        *  0x14 - XR16C854.
-        */
-       id1 = autoconfig_read_divisor_id(up);
-       DEBUG_AUTOCONF("850id=%04x ", id1);
-
-       id2 = id1 >> 8;
-       if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
-               up->port.type = PORT_16850;
-               return;
-       }
-
-       /*
-        * It wasn't an XR16C850.
-        *
-        * We distinguish between the '654 and the '650 by counting
-        * how many bytes are in the FIFO.  I'm using this for now,
-        * since that's the technique that was sent to me in the
-        * serial driver update, but I'm not convinced this works.
-        * I've had problems doing this in the past.  -TYT
-        */
-       if (size_fifo(up) == 64)
-               up->port.type = PORT_16654;
-       else
-               up->port.type = PORT_16650V2;
-}
-
-/*
- * We detected a chip without a FIFO.  Only two fall into
- * this category - the original 8250 and the 16450.  The
- * 16450 has a scratch register (accessible with LCR=0)
- */
-static void autoconfig_8250(struct uart_8250_port *up)
-{
-       unsigned char scratch, status1, status2;
-
-       up->port.type = PORT_8250;
-
-       scratch = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, 0xa5);
-       status1 = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, 0x5a);
-       status2 = serial_in(up, UART_SCR);
-       serial_outp(up, UART_SCR, scratch);
-
-       if (status1 == 0xa5 && status2 == 0x5a)
-               up->port.type = PORT_16450;
-}
-
-static int broken_efr(struct uart_8250_port *up)
-{
-       /*
-        * Exar ST16C2550 "A2" devices incorrectly detect as
-        * having an EFR, and report an ID of 0x0201.  See
-        * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 
-        */
-       if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
-               return 1;
-
-       return 0;
-}
-
-/*
- * We know that the chip has FIFOs.  Does it have an EFR?  The
- * EFR is located in the same register position as the IIR and
- * we know the top two bits of the IIR are currently set.  The
- * EFR should contain zero.  Try to read the EFR.
- */
-static void autoconfig_16550a(struct uart_8250_port *up)
-{
-       unsigned char status1, status2;
-       unsigned int iersave;
-
-       up->port.type = PORT_16550A;
-       up->capabilities |= UART_CAP_FIFO;
-
-       /*
-        * Check for presence of the EFR when DLAB is set.
-        * Only ST16C650V1 UARTs pass this test.
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       if (serial_in(up, UART_EFR) == 0) {
-               serial_outp(up, UART_EFR, 0xA8);
-               if (serial_in(up, UART_EFR) != 0) {
-                       DEBUG_AUTOCONF("EFRv1 ");
-                       up->port.type = PORT_16650;
-                       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
-               } else {
-                       DEBUG_AUTOCONF("Motorola 8xxx DUART ");
-               }
-               serial_outp(up, UART_EFR, 0);
-               return;
-       }
-
-       /*
-        * Maybe it requires 0xbf to be written to the LCR.
-        * (other ST16C650V2 UARTs, TI16C752A, etc)
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
-               DEBUG_AUTOCONF("EFRv2 ");
-               autoconfig_has_efr(up);
-               return;
-       }
-
-       /*
-        * Check for a National Semiconductor SuperIO chip.
-        * Attempt to switch to bank 2, read the value of the LOOP bit
-        * from EXCR1. Switch back to bank 0, change it in MCR. Then
-        * switch back to bank 2, read it from EXCR1 again and check
-        * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
-        */
-       serial_outp(up, UART_LCR, 0);
-       status1 = serial_in(up, UART_MCR);
-       serial_outp(up, UART_LCR, 0xE0);
-       status2 = serial_in(up, 0x02); /* EXCR1 */
-
-       if (!((status2 ^ status1) & UART_MCR_LOOP)) {
-               serial_outp(up, UART_LCR, 0);
-               serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
-               serial_outp(up, UART_LCR, 0xE0);
-               status2 = serial_in(up, 0x02); /* EXCR1 */
-               serial_outp(up, UART_LCR, 0);
-               serial_outp(up, UART_MCR, status1);
-
-               if ((status2 ^ status1) & UART_MCR_LOOP) {
-                       unsigned short quot;
-
-                       serial_outp(up, UART_LCR, 0xE0);
-
-                       quot = serial_dl_read(up);
-                       quot <<= 3;
-
-                       status1 = serial_in(up, 0x04); /* EXCR2 */
-                       status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
-                       status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
-                       serial_outp(up, 0x04, status1);
-
-                       serial_dl_write(up, quot);
-
-                       serial_outp(up, UART_LCR, 0);
-
-                       up->port.uartclk = 921600*16;
-                       up->port.type = PORT_NS16550A;
-                       up->capabilities |= UART_NATSEMI;
-                       return;
-               }
-       }
-
-       /*
-        * No EFR.  Try to detect a TI16750, which only sets bit 5 of
-        * the IIR when 64 byte FIFO mode is enabled when DLAB is set.
-        * Try setting it with and without DLAB set.  Cheap clones
-        * set bit 5 without DLAB set.
-        */
-       serial_outp(up, UART_LCR, 0);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-       status1 = serial_in(up, UART_IIR) >> 5;
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-       status2 = serial_in(up, UART_IIR) >> 5;
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_outp(up, UART_LCR, 0);
-
-       DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
-
-       if (status1 == 6 && status2 == 7) {
-               up->port.type = PORT_16750;
-               up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
-               return;
-       }
-
-       /*
-        * Try writing and reading the UART_IER_UUE bit (b6).
-        * If it works, this is probably one of the Xscale platform's
-        * internal UARTs.
-        * We're going to explicitly set the UUE bit to 0 before
-        * trying to write and read a 1 just to make sure it's not
-        * already a 1 and maybe locked there before we even start start.
-        */
-       iersave = serial_in(up, UART_IER);
-       serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
-       if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
-               /*
-                * OK it's in a known zero state, try writing and reading
-                * without disturbing the current state of the other bits.
-                */
-               serial_outp(up, UART_IER, iersave | UART_IER_UUE);
-               if (serial_in(up, UART_IER) & UART_IER_UUE) {
-                       /*
-                        * It's an Xscale.
-                        * We'll leave the UART_IER_UUE bit set to 1 (enabled).
-                        */
-                       DEBUG_AUTOCONF("Xscale ");
-                       up->port.type = PORT_XSCALE;
-                       up->capabilities |= UART_CAP_UUE;
-                       return;
-               }
-       } else {
-               /*
-                * If we got here we couldn't force the IER_UUE bit to 0.
-                * Log it and continue.
-                */
-               DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
-       }
-       serial_outp(up, UART_IER, iersave);
-
-       /*
-        * We distinguish between 16550A and U6 16550A by counting
-        * how many bytes are in the FIFO.
-        */
-       if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
-               up->port.type = PORT_U6_16550A;
-               up->capabilities |= UART_CAP_AFE;
-       }
-}
-
-/*
- * This routine is called by rs_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A.  The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
- */
-static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
-{
-       unsigned char status1, scratch, scratch2, scratch3;
-       unsigned char save_lcr, save_mcr;
-       unsigned long flags;
-
-       if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
-               return;
-
-       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
-                      serial_index(&up->port), up->port.iobase, up->port.membase);
-
-       /*
-        * We really do need global IRQs disabled here - we're going to
-        * be frobbing the chips IRQ enable register to see if it exists.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->capabilities = 0;
-       up->bugs = 0;
-
-       if (!(up->port.flags & UPF_BUGGY_UART)) {
-               /*
-                * Do a simple existence test first; if we fail this,
-                * there's no point trying anything else.
-                *
-                * 0x80 is used as a nonsense port to prevent against
-                * false positives due to ISA bus float.  The
-                * assumption is that 0x80 is a non-existent port;
-                * which should be safe since include/asm/io.h also
-                * makes this assumption.
-                *
-                * Note: this is safe as long as MCR bit 4 is clear
-                * and the device is in "PC" mode.
-                */
-               scratch = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0);
-#ifdef __i386__
-               outb(0xff, 0x080);
-#endif
-               /*
-                * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
-                * 16C754B) allow only to modify them if an EFR bit is set.
-                */
-               scratch2 = serial_inp(up, UART_IER) & 0x0f;
-               serial_outp(up, UART_IER, 0x0F);
-#ifdef __i386__
-               outb(0, 0x080);
-#endif
-               scratch3 = serial_inp(up, UART_IER) & 0x0f;
-               serial_outp(up, UART_IER, scratch);
-               if (scratch2 != 0 || scratch3 != 0x0F) {
-                       /*
-                        * We failed; there's nothing here
-                        */
-                       DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
-                                      scratch2, scratch3);
-                       goto out;
-               }
-       }
-
-       save_mcr = serial_in(up, UART_MCR);
-       save_lcr = serial_in(up, UART_LCR);
-
-       /*
-        * Check to see if a UART is really there.  Certain broken
-        * internal modems based on the Rockwell chipset fail this
-        * test, because they apparently don't implement the loopback
-        * test mode.  So this test is skipped on the COM 1 through
-        * COM 4 ports.  This *should* be safe, since no board
-        * manufacturer would be stupid enough to design a board
-        * that conflicts with COM 1-4 --- we hope!
-        */
-       if (!(up->port.flags & UPF_SKIP_TEST)) {
-               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
-               status1 = serial_inp(up, UART_MSR) & 0xF0;
-               serial_outp(up, UART_MCR, save_mcr);
-               if (status1 != 0x90) {
-                       DEBUG_AUTOCONF("LOOP test failed (%02x) ",
-                                      status1);
-                       goto out;
-               }
-       }
-
-       /*
-        * We're pretty sure there's a port here.  Lets find out what
-        * type of port it is.  The IIR top two bits allows us to find
-        * out if it's 8250 or 16450, 16550, 16550A or later.  This
-        * determines what we test for next.
-        *
-        * We also initialise the EFR (if any) to zero for later.  The
-        * EFR occupies the same register location as the FCR and IIR.
-        */
-       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_outp(up, UART_EFR, 0);
-       serial_outp(up, UART_LCR, 0);
-
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       scratch = serial_in(up, UART_IIR) >> 6;
-
-       DEBUG_AUTOCONF("iir=%d ", scratch);
-
-       switch (scratch) {
-       case 0:
-               autoconfig_8250(up);
-               break;
-       case 1:
-               up->port.type = PORT_UNKNOWN;
-               break;
-       case 2:
-               up->port.type = PORT_16550;
-               break;
-       case 3:
-               autoconfig_16550a(up);
-               break;
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Only probe for RSA ports if we got the region.
-        */
-       if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
-               int i;
-
-               for (i = 0 ; i < probe_rsa_count; ++i) {
-                       if (probe_rsa[i] == up->port.iobase &&
-                           __enable_rsa(up)) {
-                               up->port.type = PORT_RSA;
-                               break;
-                       }
-               }
-       }
-#endif
-
-       serial_outp(up, UART_LCR, save_lcr);
-
-       if (up->capabilities != uart_config[up->port.type].flags) {
-               printk(KERN_WARNING
-                      "ttyS%d: detected caps %08x should be %08x\n",
-                      serial_index(&up->port), up->capabilities,
-                      uart_config[up->port.type].flags);
-       }
-
-       up->port.fifosize = uart_config[up->port.type].fifo_size;
-       up->capabilities = uart_config[up->port.type].flags;
-       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
-
-       if (up->port.type == PORT_UNKNOWN)
-               goto out;
-
-       /*
-        * Reset the UART.
-        */
-#ifdef CONFIG_SERIAL_8250_RSA
-       if (up->port.type == PORT_RSA)
-               serial_outp(up, UART_RSA_FRR, 0);
-#endif
-       serial_outp(up, UART_MCR, save_mcr);
-       serial8250_clear_fifos(up);
-       serial_in(up, UART_RX);
-       if (up->capabilities & UART_CAP_UUE)
-               serial_outp(up, UART_IER, UART_IER_UUE);
-       else
-               serial_outp(up, UART_IER, 0);
-
- out:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
-}
-
-static void autoconfig_irq(struct uart_8250_port *up)
-{
-       unsigned char save_mcr, save_ier;
-       unsigned char save_ICP = 0;
-       unsigned int ICP = 0;
-       unsigned long irqs;
-       int irq;
-
-       if (up->port.flags & UPF_FOURPORT) {
-               ICP = (up->port.iobase & 0xfe0) | 0x1f;
-               save_ICP = inb_p(ICP);
-               outb_p(0x80, ICP);
-               (void) inb_p(ICP);
-       }
-
-       /* forget possible initially masked and pending IRQ */
-       probe_irq_off(probe_irq_on());
-       save_mcr = serial_inp(up, UART_MCR);
-       save_ier = serial_inp(up, UART_IER);
-       serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-
-       irqs = probe_irq_on();
-       serial_outp(up, UART_MCR, 0);
-       udelay(10);
-       if (up->port.flags & UPF_FOURPORT) {
-               serial_outp(up, UART_MCR,
-                           UART_MCR_DTR | UART_MCR_RTS);
-       } else {
-               serial_outp(up, UART_MCR,
-                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
-       }
-       serial_outp(up, UART_IER, 0x0f);        /* enable all intrs */
-       (void)serial_inp(up, UART_LSR);
-       (void)serial_inp(up, UART_RX);
-       (void)serial_inp(up, UART_IIR);
-       (void)serial_inp(up, UART_MSR);
-       serial_outp(up, UART_TX, 0xFF);
-       udelay(20);
-       irq = probe_irq_off(irqs);
-
-       serial_outp(up, UART_MCR, save_mcr);
-       serial_outp(up, UART_IER, save_ier);
-
-       if (up->port.flags & UPF_FOURPORT)
-               outb_p(save_ICP, ICP);
-
-       up->port.irq = (irq > 0) ? irq : 0;
-}
-
-static inline void __stop_tx(struct uart_8250_port *p)
-{
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
-       }
-}
-
-static void serial8250_stop_tx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       __stop_tx(up);
-
-       /*
-        * We really want to stop the transmitter from sending.
-        */
-       if (up->port.type == PORT_16C950) {
-               up->acr |= UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void transmit_chars(struct uart_8250_port *up);
-
-static void serial8250_start_tx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-
-               if (up->bugs & UART_BUG_TXEN) {
-                       unsigned char lsr;
-                       lsr = serial_in(up, UART_LSR);
-                       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-                       if ((up->port.type == PORT_RM9000) ?
-                               (lsr & UART_LSR_THRE) :
-                               (lsr & UART_LSR_TEMT))
-                               transmit_chars(up);
-               }
-       }
-
-       /*
-        * Re-enable the transmitter if we disabled it.
-        */
-       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
-               up->acr &= ~UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void serial8250_stop_rx(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial8250_enable_ms(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       /* no MSR capabilities */
-       if (up->bugs & UART_BUG_NOMSR)
-               return;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void
-receive_chars(struct uart_8250_port *up, unsigned int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch, lsr = *status;
-       int max_count = 256;
-       char flag;
-
-       do {
-               if (likely(lsr & UART_LSR_DR))
-                       ch = serial_inp(up, UART_RX);
-               else
-                       /*
-                        * Intel 82571 has a Serial Over Lan device that will
-                        * set UART_LSR_BI without setting UART_LSR_DR when
-                        * it receives a break. To avoid reading from the
-                        * receive buffer without UART_LSR_DR bit set, we
-                        * just force the read character to be 0
-                        */
-                       ch = 0;
-
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               lsr |= up->lsr_saved_flags;
-               up->lsr_saved_flags = 0;
-
-               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (lsr & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (lsr & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (lsr & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       lsr &= up->port.read_status_mask;
-
-                       if (lsr & UART_LSR_BI) {
-                               DEBUG_INTR("handling break....");
-                               flag = TTY_BREAK;
-                       } else if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
-               lsr = serial_inp(up, UART_LSR);
-       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-       *status = lsr;
-}
-
-static void transmit_chars(struct uart_8250_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_outp(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_tx_stopped(&up->port)) {
-               serial8250_stop_tx(&up->port);
-               return;
-       }
-       if (uart_circ_empty(xmit)) {
-               __stop_tx(up);
-               return;
-       }
-
-       count = up->tx_loadsz;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       DEBUG_INTR("THRE...");
-
-       if (uart_circ_empty(xmit))
-               __stop_tx(up);
-}
-
-static unsigned int check_modem_status(struct uart_8250_port *up)
-{
-       unsigned int status = serial_in(up, UART_MSR);
-
-       status |= up->msr_saved_flags;
-       up->msr_saved_flags = 0;
-       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-           up->port.state != NULL) {
-               if (status & UART_MSR_TERI)
-                       up->port.icount.rng++;
-               if (status & UART_MSR_DDSR)
-                       up->port.icount.dsr++;
-               if (status & UART_MSR_DDCD)
-                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-               if (status & UART_MSR_DCTS)
-                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       return status;
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static void serial8250_handle_port(struct uart_8250_port *up)
-{
-       unsigned int status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       status = serial_inp(up, UART_LSR);
-
-       DEBUG_INTR("status = %x...", status);
-
-       if (status & (UART_LSR_DR | UART_LSR_BI))
-               receive_chars(up, &status);
-       check_modem_status(up);
-       if (status & UART_LSR_THRE)
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- * This is the serial driver's interrupt routine.
- *
- * Arjan thinks the old way was overly complex, so it got simplified.
- * Alan disagrees, saying that need the complexity to handle the weird
- * nature of ISA shared interrupts.  (This is a special exception.)
- *
- * In order to handle ISA shared interrupts properly, we need to check
- * that all ports have been serviced, and therefore the ISA interrupt
- * line has been de-asserted.
- *
- * This means we need to loop through all ports. checking that they
- * don't have an interrupt pending.
- */
-static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
-{
-       struct irq_info *i = dev_id;
-       struct list_head *l, *end = NULL;
-       int pass_counter = 0, handled = 0;
-
-       DEBUG_INTR("serial8250_interrupt(%d)...", irq);
-
-       spin_lock(&i->lock);
-
-       l = i->head;
-       do {
-               struct uart_8250_port *up;
-               unsigned int iir;
-
-               up = list_entry(l, struct uart_8250_port, list);
-
-               iir = serial_in(up, UART_IIR);
-               if (!(iir & UART_IIR_NO_INT)) {
-                       serial8250_handle_port(up);
-
-                       handled = 1;
-
-                       end = NULL;
-               } else if ((up->port.iotype == UPIO_DWAPB ||
-                           up->port.iotype == UPIO_DWAPB32) &&
-                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
-                       /* The DesignWare APB UART has an Busy Detect (0x07)
-                        * interrupt meaning an LCR write attempt occured while the
-                        * UART was busy. The interrupt must be cleared by reading
-                        * the UART status register (USR) and the LCR re-written. */
-                       unsigned int status;
-                       status = *(volatile u32 *)up->port.private_data;
-                       serial_out(up, UART_LCR, up->lcr);
-
-                       handled = 1;
-
-                       end = NULL;
-               } else if (end == NULL)
-                       end = l;
-
-               l = l->next;
-
-               if (l == i->head && pass_counter++ > PASS_LIMIT) {
-                       /* If we hit this, we're dead. */
-                       printk_ratelimited(KERN_ERR
-                               "serial8250: too much work for irq%d\n", irq);
-                       break;
-               }
-       } while (l != end);
-
-       spin_unlock(&i->lock);
-
-       DEBUG_INTR("end.\n");
-
-       return IRQ_RETVAL(handled);
-}
-
-/*
- * To support ISA shared interrupts, we need to have one interrupt
- * handler that ensures that the IRQ line has been deasserted
- * before returning.  Failing to do this will result in the IRQ
- * line being stuck active, and, since ISA irqs are edge triggered,
- * no more IRQs will be seen.
- */
-static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
-{
-       spin_lock_irq(&i->lock);
-
-       if (!list_empty(i->head)) {
-               if (i->head == &up->list)
-                       i->head = i->head->next;
-               list_del(&up->list);
-       } else {
-               BUG_ON(i->head != &up->list);
-               i->head = NULL;
-       }
-       spin_unlock_irq(&i->lock);
-       /* List empty so throw away the hash node */
-       if (i->head == NULL) {
-               hlist_del(&i->node);
-               kfree(i);
-       }
-}
-
-static int serial_link_irq_chain(struct uart_8250_port *up)
-{
-       struct hlist_head *h;
-       struct hlist_node *n;
-       struct irq_info *i;
-       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
-
-       mutex_lock(&hash_mutex);
-
-       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
-       hlist_for_each(n, h) {
-               i = hlist_entry(n, struct irq_info, node);
-               if (i->irq == up->port.irq)
-                       break;
-       }
-
-       if (n == NULL) {
-               i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
-               if (i == NULL) {
-                       mutex_unlock(&hash_mutex);
-                       return -ENOMEM;
-               }
-               spin_lock_init(&i->lock);
-               i->irq = up->port.irq;
-               hlist_add_head(&i->node, h);
-       }
-       mutex_unlock(&hash_mutex);
-
-       spin_lock_irq(&i->lock);
-
-       if (i->head) {
-               list_add(&up->list, i->head);
-               spin_unlock_irq(&i->lock);
-
-               ret = 0;
-       } else {
-               INIT_LIST_HEAD(&up->list);
-               i->head = &up->list;
-               spin_unlock_irq(&i->lock);
-               irq_flags |= up->port.irqflags;
-               ret = request_irq(up->port.irq, serial8250_interrupt,
-                                 irq_flags, "serial", i);
-               if (ret < 0)
-                       serial_do_unlink(i, up);
-       }
-
-       return ret;
-}
-
-static void serial_unlink_irq_chain(struct uart_8250_port *up)
-{
-       struct irq_info *i;
-       struct hlist_node *n;
-       struct hlist_head *h;
-
-       mutex_lock(&hash_mutex);
-
-       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
-       hlist_for_each(n, h) {
-               i = hlist_entry(n, struct irq_info, node);
-               if (i->irq == up->port.irq)
-                       break;
-       }
-
-       BUG_ON(n == NULL);
-       BUG_ON(i->head == NULL);
-
-       if (list_empty(i->head))
-               free_irq(up->port.irq, i);
-
-       serial_do_unlink(i, up);
-       mutex_unlock(&hash_mutex);
-}
-
-/*
- * This function is used to handle ports that do not have an
- * interrupt.  This doesn't work very well for 16450's, but gives
- * barely passable results for a 16550A.  (Although at the expense
- * of much CPU overhead).
- */
-static void serial8250_timeout(unsigned long data)
-{
-       struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir;
-
-       iir = serial_in(up, UART_IIR);
-       if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up);
-       mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
-}
-
-static void serial8250_backup_timeout(unsigned long data)
-{
-       struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir, ier = 0, lsr;
-       unsigned long flags;
-
-       /*
-        * Must disable interrupts or else we risk racing with the interrupt
-        * based handler.
-        */
-       if (is_real_interrupt(up->port.irq)) {
-               ier = serial_in(up, UART_IER);
-               serial_out(up, UART_IER, 0);
-       }
-
-       iir = serial_in(up, UART_IIR);
-
-       /*
-        * This should be a safe test for anyone who doesn't trust the
-        * IIR bits on their UART, but it's specifically designed for
-        * the "Diva" UART used on the management processor on many HP
-        * ia64 and parisc boxes.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
-           (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
-           (lsr & UART_LSR_THRE)) {
-               iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
-               iir |= UART_IIR_THRI;
-       }
-
-       if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up);
-
-       if (is_real_interrupt(up->port.irq))
-               serial_out(up, UART_IER, ier);
-
-       /* Standard timer interval plus 0.2s to keep the port running */
-       mod_timer(&up->timer,
-               jiffies + uart_poll_timeout(&up->port) + HZ / 5);
-}
-
-static unsigned int serial8250_tx_empty(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-       unsigned int lsr;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int serial8250_get_mctrl(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned int status;
-       unsigned int ret;
-
-       status = check_modem_status(up);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial8250_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_8250_port *up, int bits)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       for (;;) {
-               status = serial_in(up, UART_LSR);
-
-               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
-
-               if ((status & bits) == bits)
-                       break;
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       }
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               unsigned int tmout;
-               for (tmout = 1000000; tmout; tmout--) {
-                       unsigned int msr = serial_in(up, UART_MSR);
-                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
-                       if (msr & UART_MSR_CTS)
-                               break;
-                       udelay(1);
-                       touch_nmi_watchdog();
-               }
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial8250_get_poll_char(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char lsr = serial_inp(up, UART_LSR);
-
-       if (!(lsr & UART_LSR_DR))
-               return NO_POLL_CHAR;
-
-       return serial_inp(up, UART_RX);
-}
-
-
-static void serial8250_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       unsigned int ier;
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       if (up->capabilities & UART_CAP_UUE)
-               serial_out(up, UART_IER, UART_IER_UUE);
-       else
-               serial_out(up, UART_IER, 0);
-
-       wait_for_xmitr(up, BOTH_EMPTY);
-       /*
-        *      Send the character out.
-        *      If a LF, also do CR...
-        */
-       serial_out(up, UART_TX, c);
-       if (c == 10) {
-               wait_for_xmitr(up, BOTH_EMPTY);
-               serial_out(up, UART_TX, 13);
-       }
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up, BOTH_EMPTY);
-       serial_out(up, UART_IER, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int serial8250_startup(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-       unsigned char lsr, iir;
-       int retval;
-
-       up->port.fifosize = uart_config[up->port.type].fifo_size;
-       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
-       up->capabilities = uart_config[up->port.type].flags;
-       up->mcr = 0;
-
-       if (up->port.iotype != up->cur_iotype)
-               set_io_from_upio(port);
-
-       if (up->port.type == PORT_16C950) {
-               /* Wake up and initialize UART */
-               up->acr = 0;
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_IER, 0);
-               serial_outp(up, UART_LCR, 0);
-               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_LCR, 0);
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * If this is an RSA port, see if we can kick it up to the
-        * higher speed clock.
-        */
-       enable_rsa(up);
-#endif
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial8250_clear_fifos(up);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       /*
-        * At this point, there's no way the LSR could still be 0xff;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (!(up->port.flags & UPF_BUGGY_UART) &&
-           (serial_inp(up, UART_LSR) == 0xff)) {
-               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
-                      serial_index(&up->port));
-               return -ENODEV;
-       }
-
-       /*
-        * For a XR16C850, we need to set the trigger levels
-        */
-       if (up->port.type == PORT_16850) {
-               unsigned char fctr;
-
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-               fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
-               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
-               serial_outp(up, UART_TRG, UART_TRG_96);
-               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
-               serial_outp(up, UART_TRG, UART_TRG_96);
-
-               serial_outp(up, UART_LCR, 0);
-       }
-
-       if (is_real_interrupt(up->port.irq)) {
-               unsigned char iir1;
-               /*
-                * Test for UARTs that do not reassert THRE when the
-                * transmitter is idle and the interrupt has already
-                * been cleared.  Real 16550s should always reassert
-                * this interrupt whenever the transmitter is idle and
-                * the interrupt is enabled.  Delays are necessary to
-                * allow register changes to become visible.
-                */
-               spin_lock_irqsave(&up->port.lock, flags);
-               if (up->port.irqflags & IRQF_SHARED)
-                       disable_irq_nosync(up->port.irq);
-
-               wait_for_xmitr(up, UART_LSR_THRE);
-               serial_out_sync(up, UART_IER, UART_IER_THRI);
-               udelay(1); /* allow THRE to set */
-               iir1 = serial_in(up, UART_IIR);
-               serial_out(up, UART_IER, 0);
-               serial_out_sync(up, UART_IER, UART_IER_THRI);
-               udelay(1); /* allow a working UART time to re-assert THRE */
-               iir = serial_in(up, UART_IIR);
-               serial_out(up, UART_IER, 0);
-
-               if (up->port.irqflags & IRQF_SHARED)
-                       enable_irq(up->port.irq);
-               spin_unlock_irqrestore(&up->port.lock, flags);
-
-               /*
-                * If the interrupt is not reasserted, setup a timer to
-                * kick the UART on a regular basis.
-                */
-               if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
-                       up->bugs |= UART_BUG_THRE;
-                       pr_debug("ttyS%d - using backup timer\n",
-                                serial_index(port));
-               }
-       }
-
-       /*
-        * The above check will only give an accurate result the first time
-        * the port is opened so this value needs to be preserved.
-        */
-       if (up->bugs & UART_BUG_THRE) {
-               up->timer.function = serial8250_backup_timeout;
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies +
-                       uart_poll_timeout(port) + HZ / 5);
-       }
-
-       /*
-        * If the "interrupt" for this port doesn't correspond with any
-        * hardware interrupt, we use a timer-based system.  The original
-        * driver used to do this with IRQ0.
-        */
-       if (!is_real_interrupt(up->port.irq)) {
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
-       } else {
-               retval = serial_link_irq_chain(up);
-               if (retval)
-                       return retval;
-       }
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               if (!is_real_interrupt(up->port.irq))
-                       up->port.mctrl |= TIOCM_OUT1;
-       } else
-               /*
-                * Most PC uarts need OUT2 raised to enable interrupts.
-                */
-               if (is_real_interrupt(up->port.irq))
-                       up->port.mctrl |= TIOCM_OUT2;
-
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-
-       /* Serial over Lan (SoL) hack:
-          Intel 8257x Gigabit ethernet chips have a
-          16550 emulation, to be used for Serial Over Lan.
-          Those chips take a longer time than a normal
-          serial device to signalize that a transmission
-          data was queued. Due to that, the above test generally
-          fails. One solution would be to delay the reading of
-          iir. However, this is not reliable, since the timeout
-          is variable. So, let's just don't test if we receive
-          TX irq. This way, we'll never enable UART_BUG_TXEN.
-        */
-       if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST)
-               goto dont_test_tx_en;
-
-       /*
-        * Do a quick test to see if we receive an
-        * interrupt when we enable the TX irq.
-        */
-       serial_outp(up, UART_IER, UART_IER_THRI);
-       lsr = serial_in(up, UART_LSR);
-       iir = serial_in(up, UART_IIR);
-       serial_outp(up, UART_IER, 0);
-
-       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
-               if (!(up->bugs & UART_BUG_TXEN)) {
-                       up->bugs |= UART_BUG_TXEN;
-                       pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-                                serial_index(port));
-               }
-       } else {
-               up->bugs &= ~UART_BUG_TXEN;
-       }
-
-dont_test_tx_en:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Clear the interrupt registers again for luck, and clear the
-        * saved flags to avoid getting false values from polling
-        * routines or the previous session.
-        */
-       serial_inp(up, UART_LSR);
-       serial_inp(up, UART_RX);
-       serial_inp(up, UART_IIR);
-       serial_inp(up, UART_MSR);
-       up->lsr_saved_flags = 0;
-       up->msr_saved_flags = 0;
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_outp(up, UART_IER, up->ier);
-
-       if (up->port.flags & UPF_FOURPORT) {
-               unsigned int icp;
-               /*
-                * Enable interrupts on the AST Fourport board
-                */
-               icp = (up->port.iobase & 0xfe0) | 0x01f;
-               outb_p(0x80, icp);
-               (void) inb_p(icp);
-       }
-
-       return 0;
-}
-
-static void serial8250_shutdown(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_outp(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               /* reset interrupts on the AST Fourport board */
-               inb((up->port.iobase & 0xfe0) | 0x1f);
-               up->port.mctrl |= TIOCM_OUT1;
-       } else
-               up->port.mctrl &= ~TIOCM_OUT2;
-
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-       serial8250_clear_fifos(up);
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Reset the RSA board back to 115kbps compat mode.
-        */
-       disable_rsa(up);
-#endif
-
-       /*
-        * Read data port to reset things, and then unlink from
-        * the IRQ chain.
-        */
-       (void) serial_in(up, UART_RX);
-
-       del_timer_sync(&up->timer);
-       up->timer.function = serial8250_timeout;
-       if (is_real_interrupt(up->port.irq))
-               serial_unlink_irq_chain(up);
-}
-
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int quot;
-
-       /*
-        * Handle magic divisors for baud rates above baud_base on
-        * SMSC SuperIO chips.
-        */
-       if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-           baud == (port->uartclk/4))
-               quot = 0x8001;
-       else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-                baud == (port->uartclk/8))
-               quot = 0x8002;
-       else
-               quot = uart_get_divisor(port, baud);
-
-       return quot;
-}
-
-void
-serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
-                         struct ktermios *old)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (termios->c_cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old,
-                                 port->uartclk / 16 / 0xffff,
-                                 port->uartclk / 16);
-       quot = serial8250_get_divisor(port, baud);
-
-       /*
-        * Oxford Semi 952 rev B workaround
-        */
-       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
-               quot++;
-
-       if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
-               if (baud < 2400)
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-               else
-                       fcr = uart_config[up->port.type].fcr;
-       }
-
-       /*
-        * MCR-based auto flow control.  When AFE is enabled, RTS will be
-        * deasserted when the receive FIFO contains more characters than
-        * the trigger, or the MCR RTS bit is cleared.  In the case where
-        * the remote UART is not using CTS auto flow control, we must
-        * have sufficient FIFO entries for the latency of the remote
-        * UART to respond.  IOW, at least 32 bytes of FIFO.
-        */
-       if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
-               up->mcr &= ~UART_MCR_AFE;
-               if (termios->c_cflag & CRTSCTS)
-                       up->mcr |= UART_MCR_AFE;
-       }
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (!(up->bugs & UART_BUG_NOMSR) &&
-                       UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-       if (up->capabilities & UART_CAP_UUE)
-               up->ier |= UART_IER_UUE | UART_IER_RTOIE;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (up->capabilities & UART_CAP_EFR) {
-               unsigned char efr = 0;
-               /*
-                * TI16C752/Startech hardware flow control.  FIXME:
-                * - TI16C752 requires control thresholds to be set.
-                * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
-                */
-               if (termios->c_cflag & CRTSCTS)
-                       efr |= UART_EFR_CTS;
-
-               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, efr);
-       }
-
-#ifdef CONFIG_ARCH_OMAP
-       /* Workaround to enable 115200 baud on OMAP1510 internal ports */
-       if (cpu_is_omap1510() && is_omap_port(up)) {
-               if (baud == 115200) {
-                       quot = 1;
-                       serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
-               } else
-                       serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
-       }
-#endif
-
-       if (up->capabilities & UART_NATSEMI) {
-               /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
-               serial_outp(up, UART_LCR, 0xe0);
-       } else {
-               serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-       }
-
-       serial_dl_write(up, quot);
-
-       /*
-        * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
-        * is written without DLAB set, this mode will be disabled.
-        */
-       if (up->port.type == PORT_16750)
-               serial_outp(up, UART_FCR, fcr);
-
-       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       if (up->port.type != PORT_16750) {
-               if (fcr & UART_FCR_ENABLE_FIFO) {
-                       /* emulated UARTs (Lucent Venus 167x) need two steps */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               }
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       }
-       serial8250_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       /* Don't rewrite B0 */
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-}
-EXPORT_SYMBOL(serial8250_do_set_termios);
-
-static void
-serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       if (port->set_termios)
-               port->set_termios(port, termios, old);
-       else
-               serial8250_do_set_termios(port, termios, old);
-}
-
-static void
-serial8250_set_ldisc(struct uart_port *port, int new)
-{
-       if (new == N_PPS) {
-               port->flags |= UPF_HARDPPS_CD;
-               serial8250_enable_ms(port);
-       } else
-               port->flags &= ~UPF_HARDPPS_CD;
-}
-
-
-void serial8250_do_pm(struct uart_port *port, unsigned int state,
-                     unsigned int oldstate)
-{
-       struct uart_8250_port *p =
-               container_of(port, struct uart_8250_port, port);
-
-       serial8250_set_sleep(p, state != 0);
-}
-EXPORT_SYMBOL(serial8250_do_pm);
-
-static void
-serial8250_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       if (port->pm)
-               port->pm(port, state, oldstate);
-       else
-               serial8250_do_pm(port, state, oldstate);
-}
-
-static unsigned int serial8250_port_size(struct uart_8250_port *pt)
-{
-       if (pt->port.iotype == UPIO_AU)
-               return 0x1000;
-#ifdef CONFIG_ARCH_OMAP
-       if (is_omap_port(pt))
-               return 0x16 << pt->port.regshift;
-#endif
-       return 8 << pt->port.regshift;
-}
-
-/*
- * Resource handling.
- */
-static int serial8250_request_std_resource(struct uart_8250_port *up)
-{
-       unsigned int size = serial8250_port_size(up);
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_MEM32:
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               if (!up->port.mapbase)
-                       break;
-
-               if (!request_mem_region(up->port.mapbase, size, "serial")) {
-                       ret = -EBUSY;
-                       break;
-               }
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap_nocache(up->port.mapbase,
-                                                                       size);
-                       if (!up->port.membase) {
-                               release_mem_region(up->port.mapbase, size);
-                               ret = -ENOMEM;
-                       }
-               }
-               break;
-
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               if (!request_region(up->port.iobase, size, "serial"))
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void serial8250_release_std_resource(struct uart_8250_port *up)
-{
-       unsigned int size = serial8250_port_size(up);
-
-       switch (up->port.iotype) {
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_MEM32:
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               if (!up->port.mapbase)
-                       break;
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-               }
-
-               release_mem_region(up->port.mapbase, size);
-               break;
-
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               release_region(up->port.iobase, size);
-               break;
-       }
-}
-
-static int serial8250_request_rsa_resource(struct uart_8250_port *up)
-{
-       unsigned long start = UART_RSA_BASE << up->port.regshift;
-       unsigned int size = 8 << up->port.regshift;
-       int ret = -EINVAL;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               start += up->port.iobase;
-               if (request_region(start, size, "serial-rsa"))
-                       ret = 0;
-               else
-                       ret = -EBUSY;
-               break;
-       }
-
-       return ret;
-}
-
-static void serial8250_release_rsa_resource(struct uart_8250_port *up)
-{
-       unsigned long offset = UART_RSA_BASE << up->port.regshift;
-       unsigned int size = 8 << up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-       case UPIO_PORT:
-               release_region(up->port.iobase + offset, size);
-               break;
-       }
-}
-
-static void serial8250_release_port(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       serial8250_release_std_resource(up);
-       if (up->port.type == PORT_RSA)
-               serial8250_release_rsa_resource(up);
-}
-
-static int serial8250_request_port(struct uart_port *port)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       int ret = 0;
-
-       ret = serial8250_request_std_resource(up);
-       if (ret == 0 && up->port.type == PORT_RSA) {
-               ret = serial8250_request_rsa_resource(up);
-               if (ret < 0)
-                       serial8250_release_std_resource(up);
-       }
-
-       return ret;
-}
-
-static void serial8250_config_port(struct uart_port *port, int flags)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       int probeflags = PROBE_ANY;
-       int ret;
-
-       /*
-        * Find the region that we can probe for.  This in turn
-        * tells us whether we can probe for the type of port.
-        */
-       ret = serial8250_request_std_resource(up);
-       if (ret < 0)
-               return;
-
-       ret = serial8250_request_rsa_resource(up);
-       if (ret < 0)
-               probeflags &= ~PROBE_RSA;
-
-       if (up->port.iotype != up->cur_iotype)
-               set_io_from_upio(port);
-
-       if (flags & UART_CONFIG_TYPE)
-               autoconfig(up, probeflags);
-
-       /* if access method is AU, it is a 16550 with a quirk */
-       if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
-               up->bugs |= UART_BUG_NOMSR;
-
-       if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
-               autoconfig_irq(up);
-
-       if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
-               serial8250_release_rsa_resource(up);
-       if (up->port.type == PORT_UNKNOWN)
-               serial8250_release_std_resource(up);
-}
-
-static int
-serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->irq >= nr_irqs || ser->irq < 0 ||
-           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-           ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
-           ser->type == PORT_STARTECH)
-               return -EINVAL;
-       return 0;
-}
-
-static const char *
-serial8250_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops serial8250_pops = {
-       .tx_empty       = serial8250_tx_empty,
-       .set_mctrl      = serial8250_set_mctrl,
-       .get_mctrl      = serial8250_get_mctrl,
-       .stop_tx        = serial8250_stop_tx,
-       .start_tx       = serial8250_start_tx,
-       .stop_rx        = serial8250_stop_rx,
-       .enable_ms      = serial8250_enable_ms,
-       .break_ctl      = serial8250_break_ctl,
-       .startup        = serial8250_startup,
-       .shutdown       = serial8250_shutdown,
-       .set_termios    = serial8250_set_termios,
-       .set_ldisc      = serial8250_set_ldisc,
-       .pm             = serial8250_pm,
-       .type           = serial8250_type,
-       .release_port   = serial8250_release_port,
-       .request_port   = serial8250_request_port,
-       .config_port    = serial8250_config_port,
-       .verify_port    = serial8250_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = serial8250_get_poll_char,
-       .poll_put_char = serial8250_put_poll_char,
-#endif
-};
-
-static struct uart_8250_port serial8250_ports[UART_NR];
-
-static void (*serial8250_isa_config)(int port, struct uart_port *up,
-       unsigned short *capabilities);
-
-void serial8250_set_isa_configurator(
-       void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
-{
-       serial8250_isa_config = v;
-}
-EXPORT_SYMBOL(serial8250_set_isa_configurator);
-
-static void __init serial8250_isa_init_ports(void)
-{
-       struct uart_8250_port *up;
-       static int first = 1;
-       int i, irqflag = 0;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               up->port.line = i;
-               spin_lock_init(&up->port.lock);
-
-               init_timer(&up->timer);
-               up->timer.function = serial8250_timeout;
-
-               /*
-                * ALPHA_KLUDGE_MCR needs to be killed.
-                */
-               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-               up->mcr_force = ALPHA_KLUDGE_MCR;
-
-               up->port.ops = &serial8250_pops;
-       }
-
-       if (share_irqs)
-               irqflag = IRQF_SHARED;
-
-       for (i = 0, up = serial8250_ports;
-            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
-            i++, up++) {
-               up->port.iobase   = old_serial_port[i].port;
-               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
-               up->port.irqflags = old_serial_port[i].irqflags;
-               up->port.uartclk  = old_serial_port[i].baud_base * 16;
-               up->port.flags    = old_serial_port[i].flags;
-               up->port.hub6     = old_serial_port[i].hub6;
-               up->port.membase  = old_serial_port[i].iomem_base;
-               up->port.iotype   = old_serial_port[i].io_type;
-               up->port.regshift = old_serial_port[i].iomem_reg_shift;
-               set_io_from_upio(&up->port);
-               up->port.irqflags |= irqflag;
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(i, &up->port, &up->capabilities);
-
-       }
-}
-
-static void
-serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
-{
-       up->port.type = type;
-       up->port.fifosize = uart_config[type].fifo_size;
-       up->capabilities = uart_config[type].flags;
-       up->tx_loadsz = uart_config[type].tx_loadsz;
-}
-
-static void __init
-serial8250_register_ports(struct uart_driver *drv, struct device *dev)
-{
-       int i;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-               up->cur_iotype = 0xFF;
-       }
-
-       serial8250_isa_init_ports();
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               up->port.dev = dev;
-
-               if (up->port.flags & UPF_FIXED_TYPE)
-                       serial8250_init_fixed_type_port(up, up->port.type);
-
-               uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-
-static void serial8250_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       wait_for_xmitr(up, UART_LSR_THRE);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void
-serial8250_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_8250_port *up = &serial8250_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       touch_nmi_watchdog();
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               /* serial8250_handle_port() already took the lock */
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-
-       if (up->capabilities & UART_CAP_UUE)
-               serial_out(up, UART_IER, UART_IER_UUE);
-       else
-               serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial8250_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up, BOTH_EMPTY);
-       serial_out(up, UART_IER, ier);
-
-       /*
-        *      The receive handling will happen properly because the
-        *      receive ready bit will still be set; it is not cleared
-        *      on read.  However, modem control will not, we must
-        *      call it if we have saved something in the saved flags
-        *      while processing with interrupts off.
-        */
-       if (up->msr_saved_flags)
-               check_modem_status(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init serial8250_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= nr_uarts)
-               co->index = 0;
-       port = &serial8250_ports[co->index].port;
-       if (!port->iobase && !port->membase)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static int serial8250_console_early_setup(void)
-{
-       return serial8250_find_port_for_earlycon();
-}
-
-static struct console serial8250_console = {
-       .name           = "ttyS",
-       .write          = serial8250_console_write,
-       .device         = uart_console_device,
-       .setup          = serial8250_console_setup,
-       .early_setup    = serial8250_console_early_setup,
-       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
-       .index          = -1,
-       .data           = &serial8250_reg,
-};
-
-static int __init serial8250_console_init(void)
-{
-       if (nr_uarts > UART_NR)
-               nr_uarts = UART_NR;
-
-       serial8250_isa_init_ports();
-       register_console(&serial8250_console);
-       return 0;
-}
-console_initcall(serial8250_console_init);
-
-int serial8250_find_port(struct uart_port *p)
-{
-       int line;
-       struct uart_port *port;
-
-       for (line = 0; line < nr_uarts; line++) {
-               port = &serial8250_ports[line].port;
-               if (uart_match_port(p, port))
-                       return line;
-       }
-       return -ENODEV;
-}
-
-#define SERIAL8250_CONSOLE     &serial8250_console
-#else
-#define SERIAL8250_CONSOLE     NULL
-#endif
-
-static struct uart_driver serial8250_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .cons                   = SERIAL8250_CONSOLE,
-};
-
-/*
- * early_serial_setup - early registration for 8250 ports
- *
- * Setup an 8250 port structure prior to console initialisation.  Use
- * after console initialisation will cause undefined behaviour.
- */
-int __init early_serial_setup(struct uart_port *port)
-{
-       struct uart_port *p;
-
-       if (port->line >= ARRAY_SIZE(serial8250_ports))
-               return -ENODEV;
-
-       serial8250_isa_init_ports();
-       p = &serial8250_ports[port->line].port;
-       p->iobase       = port->iobase;
-       p->membase      = port->membase;
-       p->irq          = port->irq;
-       p->irqflags     = port->irqflags;
-       p->uartclk      = port->uartclk;
-       p->fifosize     = port->fifosize;
-       p->regshift     = port->regshift;
-       p->iotype       = port->iotype;
-       p->flags        = port->flags;
-       p->mapbase      = port->mapbase;
-       p->private_data = port->private_data;
-       p->type         = port->type;
-       p->line         = port->line;
-
-       set_io_from_upio(p);
-       if (port->serial_in)
-               p->serial_in = port->serial_in;
-       if (port->serial_out)
-               p->serial_out = port->serial_out;
-
-       return 0;
-}
-
-/**
- *     serial8250_suspend_port - suspend one serial port
- *     @line:  serial line number
- *
- *     Suspend one serial port.
- */
-void serial8250_suspend_port(int line)
-{
-       uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
-}
-
-/**
- *     serial8250_resume_port - resume one serial port
- *     @line:  serial line number
- *
- *     Resume one serial port.
- */
-void serial8250_resume_port(int line)
-{
-       struct uart_8250_port *up = &serial8250_ports[line];
-
-       if (up->capabilities & UART_NATSEMI) {
-               unsigned char tmp;
-
-               /* Ensure it's still in high speed mode */
-               serial_outp(up, UART_LCR, 0xE0);
-
-               tmp = serial_in(up, 0x04); /* EXCR2 */
-               tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
-               tmp |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
-               serial_outp(up, 0x04, tmp);
-
-               serial_outp(up, UART_LCR, 0);
-       }
-       uart_resume_port(&serial8250_reg, &up->port);
-}
-
-/*
- * Register a set of serial devices attached to a platform device.  The
- * list is terminated with a zero flags entry, which means we expect
- * all entries to have at least UPF_BOOT_AUTOCONF set.
- */
-static int __devinit serial8250_probe(struct platform_device *dev)
-{
-       struct plat_serial8250_port *p = dev->dev.platform_data;
-       struct uart_port port;
-       int ret, i, irqflag = 0;
-
-       memset(&port, 0, sizeof(struct uart_port));
-
-       if (share_irqs)
-               irqflag = IRQF_SHARED;
-
-       for (i = 0; p && p->flags != 0; p++, i++) {
-               port.iobase             = p->iobase;
-               port.membase            = p->membase;
-               port.irq                = p->irq;
-               port.irqflags           = p->irqflags;
-               port.uartclk            = p->uartclk;
-               port.regshift           = p->regshift;
-               port.iotype             = p->iotype;
-               port.flags              = p->flags;
-               port.mapbase            = p->mapbase;
-               port.hub6               = p->hub6;
-               port.private_data       = p->private_data;
-               port.type               = p->type;
-               port.serial_in          = p->serial_in;
-               port.serial_out         = p->serial_out;
-               port.set_termios        = p->set_termios;
-               port.pm                 = p->pm;
-               port.dev                = &dev->dev;
-               port.irqflags           |= irqflag;
-               ret = serial8250_register_port(&port);
-               if (ret < 0) {
-                       dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
-                               p->iobase, (unsigned long long)p->mapbase,
-                               p->irq, ret);
-               }
-       }
-       return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static int __devexit serial8250_remove(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < nr_uarts; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.dev == &dev->dev)
-                       serial8250_unregister_port(i);
-       }
-       return 0;
-}
-
-static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_suspend_port(&serial8250_reg, &up->port);
-       }
-
-       return 0;
-}
-
-static int serial8250_resume(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       serial8250_resume_port(i);
-       }
-
-       return 0;
-}
-
-static struct platform_driver serial8250_isa_driver = {
-       .probe          = serial8250_probe,
-       .remove         = __devexit_p(serial8250_remove),
-       .suspend        = serial8250_suspend,
-       .resume         = serial8250_resume,
-       .driver         = {
-               .name   = "serial8250",
-               .owner  = THIS_MODULE,
-       },
-};
-
-/*
- * This "device" covers _all_ ISA 8250-compatible serial devices listed
- * in the table in include/asm/serial.h
- */
-static struct platform_device *serial8250_isa_devs;
-
-/*
- * serial8250_register_port and serial8250_unregister_port allows for
- * 16x50 serial ports to be configured at run-time, to support PCMCIA
- * modems and PCI multiport cards.
- */
-static DEFINE_MUTEX(serial_mutex);
-
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
-{
-       int i;
-
-       /*
-        * First, find a port entry which matches.
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (uart_match_port(&serial8250_ports[i].port, port))
-                       return &serial8250_ports[i];
-
-       /*
-        * We didn't find a matching entry, so look for the first
-        * free entry.  We look for one which hasn't been previously
-        * used (indicated by zero iobase).
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
-                   serial8250_ports[i].port.iobase == 0)
-                       return &serial8250_ports[i];
-
-       /*
-        * That also failed.  Last resort is to find any entry which
-        * doesn't have a real port associated with it.
-        */
-       for (i = 0; i < nr_uarts; i++)
-               if (serial8250_ports[i].port.type == PORT_UNKNOWN)
-                       return &serial8250_ports[i];
-
-       return NULL;
-}
-
-/**
- *     serial8250_register_port - register a serial port
- *     @port: serial port template
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use, it is hung up and unregistered
- *     first.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_port(struct uart_port *port)
-{
-       struct uart_8250_port *uart;
-       int ret = -ENOSPC;
-
-       if (port->uartclk == 0)
-               return -EINVAL;
-
-       mutex_lock(&serial_mutex);
-
-       uart = serial8250_find_match_or_unused(port);
-       if (uart) {
-               uart_remove_one_port(&serial8250_reg, &uart->port);
-
-               uart->port.iobase       = port->iobase;
-               uart->port.membase      = port->membase;
-               uart->port.irq          = port->irq;
-               uart->port.irqflags     = port->irqflags;
-               uart->port.uartclk      = port->uartclk;
-               uart->port.fifosize     = port->fifosize;
-               uart->port.regshift     = port->regshift;
-               uart->port.iotype       = port->iotype;
-               uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
-               uart->port.mapbase      = port->mapbase;
-               uart->port.private_data = port->private_data;
-               if (port->dev)
-                       uart->port.dev = port->dev;
-
-               if (port->flags & UPF_FIXED_TYPE)
-                       serial8250_init_fixed_type_port(uart, port->type);
-
-               set_io_from_upio(&uart->port);
-               /* Possibly override default I/O functions.  */
-               if (port->serial_in)
-                       uart->port.serial_in = port->serial_in;
-               if (port->serial_out)
-                       uart->port.serial_out = port->serial_out;
-               /*  Possibly override set_termios call */
-               if (port->set_termios)
-                       uart->port.set_termios = port->set_termios;
-               if (port->pm)
-                       uart->port.pm = port->pm;
-
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(0, &uart->port,
-                                       &uart->capabilities);
-
-               ret = uart_add_one_port(&serial8250_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
-       }
-       mutex_unlock(&serial_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(serial8250_register_port);
-
-/**
- *     serial8250_unregister_port - remove a 16x50 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to the our control.
- */
-void serial8250_unregister_port(int line)
-{
-       struct uart_8250_port *uart = &serial8250_ports[line];
-
-       mutex_lock(&serial_mutex);
-       uart_remove_one_port(&serial8250_reg, &uart->port);
-       if (serial8250_isa_devs) {
-               uart->port.flags &= ~UPF_BOOT_AUTOCONF;
-               uart->port.type = PORT_UNKNOWN;
-               uart->port.dev = &serial8250_isa_devs->dev;
-               uart_add_one_port(&serial8250_reg, &uart->port);
-       } else {
-               uart->port.dev = NULL;
-       }
-       mutex_unlock(&serial_mutex);
-}
-EXPORT_SYMBOL(serial8250_unregister_port);
-
-static int __init serial8250_init(void)
-{
-       int ret;
-
-       if (nr_uarts > UART_NR)
-               nr_uarts = UART_NR;
-
-       printk(KERN_INFO "Serial: 8250/16550 driver, "
-               "%d ports, IRQ sharing %sabled\n", nr_uarts,
-               share_irqs ? "en" : "dis");
-
-#ifdef CONFIG_SPARC
-       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
-#else
-       serial8250_reg.nr = UART_NR;
-       ret = uart_register_driver(&serial8250_reg);
-#endif
-       if (ret)
-               goto out;
-
-       serial8250_isa_devs = platform_device_alloc("serial8250",
-                                                   PLAT8250_DEV_LEGACY);
-       if (!serial8250_isa_devs) {
-               ret = -ENOMEM;
-               goto unreg_uart_drv;
-       }
-
-       ret = platform_device_add(serial8250_isa_devs);
-       if (ret)
-               goto put_dev;
-
-       serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
-
-       ret = platform_driver_register(&serial8250_isa_driver);
-       if (ret == 0)
-               goto out;
-
-       platform_device_del(serial8250_isa_devs);
-put_dev:
-       platform_device_put(serial8250_isa_devs);
-unreg_uart_drv:
-#ifdef CONFIG_SPARC
-       sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
-       uart_unregister_driver(&serial8250_reg);
-#endif
-out:
-       return ret;
-}
-
-static void __exit serial8250_exit(void)
-{
-       struct platform_device *isa_dev = serial8250_isa_devs;
-
-       /*
-        * This tells serial8250_unregister_port() not to re-register
-        * the ports (thereby making serial8250_isa_driver permanently
-        * in use.)
-        */
-       serial8250_isa_devs = NULL;
-
-       platform_driver_unregister(&serial8250_isa_driver);
-       platform_device_unregister(isa_dev);
-
-#ifdef CONFIG_SPARC
-       sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
-       uart_unregister_driver(&serial8250_reg);
-#endif
-}
-
-module_init(serial8250_init);
-module_exit(serial8250_exit);
-
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
-
-module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
-       " (unsafe)");
-
-module_param(nr_uarts, uint, 0644);
-MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
-
-module_param(skip_txen_test, uint, 0644);
-MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
-
-#ifdef CONFIG_SERIAL_8250_RSA
-module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
-MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
-#endif
-MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
deleted file mode 100644 (file)
index 6e19ea3..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/drivers/char/8250.h
- *
- *  Driver for 8250/16550-type serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/serial_8250.h>
-
-struct old_serial_port {
-       unsigned int uart;
-       unsigned int baud_base;
-       unsigned int port;
-       unsigned int irq;
-       unsigned int flags;
-       unsigned char hub6;
-       unsigned char io_type;
-       unsigned char *iomem_base;
-       unsigned short iomem_reg_shift;
-       unsigned long irqflags;
-};
-
-/*
- * This replaces serial_uart_config in include/linux/serial.h
- */
-struct serial8250_config {
-       const char      *name;
-       unsigned short  fifo_size;
-       unsigned short  tx_loadsz;
-       unsigned char   fcr;
-       unsigned int    flags;
-};
-
-#define UART_CAP_FIFO  (1 << 8)        /* UART has FIFO */
-#define UART_CAP_EFR   (1 << 9)        /* UART has EFR */
-#define UART_CAP_SLEEP (1 << 10)       /* UART has IER sleep */
-#define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
-#define UART_CAP_UUE   (1 << 12)       /* UART needs IER bit 6 set (Xscale) */
-
-#define UART_BUG_QUOT  (1 << 0)        /* UART has buggy quot LSB */
-#define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
-#define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
-#define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
-
-#define PROBE_RSA      (1 << 0)
-#define PROBE_ANY      (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-
-#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
-#define SERIAL8250_SHARE_IRQS 1
-#else
-#define SERIAL8250_SHARE_IRQS 0
-#endif
-
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-/*
- * Digital did something really horribly wrong with the OUT1 and OUT2
- * lines on at least some ALPHA's.  The failure mode is that if either
- * is cleared, the machine locks up with endless interrupts.
- */
-#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
-#elif defined(CONFIG_SBC8560)
-/*
- * WindRiver did something similarly broken on their SBC8560 board. The
- * UART tristates its IRQ output while OUT2 is clear, but they pulled
- * the interrupt line _up_ instead of down, so if we register the IRQ
- * while the UART is in that state, we die in an IRQ storm. */
-#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
-#else
-#define ALPHA_KLUDGE_MCR 0
-#endif
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
deleted file mode 100644 (file)
index 9c10262..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  linux/drivers/serial/8250_accent.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port accent_data[] = {
-       PORT(0x330, 4),
-       PORT(0x338, 4),
-       { },
-};
-
-static struct platform_device accent_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_ACCENT,
-       .dev                    = {
-               .platform_data  = accent_data,
-       },
-};
-
-static int __init accent_init(void)
-{
-       return platform_device_register(&accent_device);
-}
-
-module_init(accent_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
deleted file mode 100644 (file)
index b0ce8c5..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *  linux/drivers/serial/acorn.c
- *
- *  Copyright (C) 1996-2003 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/ecard.h>
-#include <asm/string.h>
-
-#include "8250.h"
-
-#define MAX_PORTS      3
-
-struct serial_card_type {
-       unsigned int    num_ports;
-       unsigned int    uartclk;
-       unsigned int    type;
-       unsigned int    offset[MAX_PORTS];
-};
-
-struct serial_card_info {
-       unsigned int    num_ports;
-       int             ports[MAX_PORTS];
-       void __iomem *vaddr;
-};
-
-static int __devinit
-serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-       struct serial_card_info *info;
-       struct serial_card_type *type = id->data;
-       struct uart_port port;
-       unsigned long bus_addr;
-       unsigned int i;
-
-       info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->num_ports = type->num_ports;
-
-       bus_addr = ecard_resource_start(ec, type->type);
-       info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
-       if (!info->vaddr) {
-               kfree(info);
-               return -ENOMEM;
-       }
-
-       ecard_set_drvdata(ec, info);
-
-       memset(&port, 0, sizeof(struct uart_port));
-       port.irq        = ec->irq;
-       port.flags      = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       port.uartclk    = type->uartclk;
-       port.iotype     = UPIO_MEM;
-       port.regshift   = 2;
-       port.dev        = &ec->dev;
-
-       for (i = 0; i < info->num_ports; i ++) {
-               port.membase = info->vaddr + type->offset[i];
-               port.mapbase = bus_addr + type->offset[i];
-
-               info->ports[i] = serial8250_register_port(&port);
-       }
-
-       return 0;
-}
-
-static void __devexit serial_card_remove(struct expansion_card *ec)
-{
-       struct serial_card_info *info = ecard_get_drvdata(ec);
-       int i;
-
-       ecard_set_drvdata(ec, NULL);
-
-       for (i = 0; i < info->num_ports; i++)
-               if (info->ports[i] > 0)
-                       serial8250_unregister_port(info->ports[i]);
-
-       kfree(info);
-}
-
-static struct serial_card_type atomwide_type = {
-       .num_ports      = 3,
-       .uartclk        = 7372800,
-       .type           = ECARD_RES_IOCSLOW,
-       .offset         = { 0x2800, 0x2400, 0x2000 },
-};
-
-static struct serial_card_type serport_type = {
-       .num_ports      = 2,
-       .uartclk        = 3686400,
-       .type           = ECARD_RES_IOCSLOW,
-       .offset         = { 0x2000, 0x2020 },
-};
-
-static const struct ecard_id serial_cids[] = {
-       { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
-       { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
-       { 0xffff, 0xffff }
-};
-
-static struct ecard_driver serial_card_driver = {
-       .probe          = serial_card_probe,
-       .remove         = __devexit_p(serial_card_remove),
-       .id_table       = serial_cids,
-       .drv = {
-               .name   = "8250_acorn",
-       },
-};
-
-static int __init serial_card_init(void)
-{
-       return ecard_register_driver(&serial_card_driver);
-}
-
-static void __exit serial_card_exit(void)
-{
-       ecard_remove_driver(&serial_card_driver);
-}
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
-MODULE_LICENSE("GPL");
-
-module_init(serial_card_init);
-module_exit(serial_card_exit);
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
deleted file mode 100644 (file)
index 3bfe0f7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  linux/drivers/serial/8250_boca.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port boca_data[] = {
-       PORT(0x100, 12),
-       PORT(0x108, 12),
-       PORT(0x110, 12),
-       PORT(0x118, 12),
-       PORT(0x120, 12),
-       PORT(0x128, 12),
-       PORT(0x130, 12),
-       PORT(0x138, 12),
-       PORT(0x140, 12),
-       PORT(0x148, 12),
-       PORT(0x150, 12),
-       PORT(0x158, 12),
-       PORT(0x160, 12),
-       PORT(0x168, 12),
-       PORT(0x170, 12),
-       PORT(0x178, 12),
-       { },
-};
-
-static struct platform_device boca_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_BOCA,
-       .dev                    = {
-               .platform_data  = boca_data,
-       },
-};
-
-static int __init boca_init(void)
-{
-       return platform_device_register(&boca_device);
-}
-
-module_init(boca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
deleted file mode 100644 (file)
index eaafb98..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Early serial console for 8250/16550 devices
- *
- * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
- *     Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
- * and on early_printk.c by Andi Kleen.
- *
- * This is for use before the serial driver has initialized, in
- * particular, before the UARTs have been discovered and named.
- * Instead of specifying the console device as, e.g., "ttyS0",
- * we locate the device directly by its MMIO or I/O port address.
- *
- * The user can specify the device directly, e.g.,
- *     earlycon=uart8250,io,0x3f8,9600n8
- *     earlycon=uart8250,mmio,0xff5e0000,115200n8
- *     earlycon=uart8250,mmio32,0xff5e0000,115200n8
- * or
- *     console=uart8250,io,0x3f8,9600n8
- *     console=uart8250,mmio,0xff5e0000,115200n8
- *     console=uart8250,mmio32,0xff5e0000,115200n8
- */
-
-#include <linux/tty.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-#include <asm/io.h>
-#include <asm/serial.h>
-#ifdef CONFIG_FIX_EARLYCON_MEM
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#endif
-
-struct early_serial8250_device {
-       struct uart_port port;
-       char options[16];               /* e.g., 115200n8 */
-       unsigned int baud;
-};
-
-static struct early_serial8250_device early_device;
-
-static unsigned int __init serial_in(struct uart_port *port, int offset)
-{
-       switch (port->iotype) {
-       case UPIO_MEM:
-               return readb(port->membase + offset);
-       case UPIO_MEM32:
-               return readl(port->membase + (offset << 2));
-       case UPIO_PORT:
-               return inb(port->iobase + offset);
-       default:
-               return 0;
-       }
-}
-
-static void __init serial_out(struct uart_port *port, int offset, int value)
-{
-       switch (port->iotype) {
-       case UPIO_MEM:
-               writeb(value, port->membase + offset);
-               break;
-       case UPIO_MEM32:
-               writel(value, port->membase + (offset << 2));
-               break;
-       case UPIO_PORT:
-               outb(value, port->iobase + offset);
-               break;
-       }
-}
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-static void __init wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int status;
-
-       for (;;) {
-               status = serial_in(port, UART_LSR);
-               if ((status & BOTH_EMPTY) == BOTH_EMPTY)
-                       return;
-               cpu_relax();
-       }
-}
-
-static void __init serial_putc(struct uart_port *port, int c)
-{
-       wait_for_xmitr(port);
-       serial_out(port, UART_TX, c);
-}
-
-static void __init early_serial8250_write(struct console *console,
-                                       const char *s, unsigned int count)
-{
-       struct uart_port *port = &early_device.port;
-       unsigned int ier;
-
-       /* Save the IER and disable interrupts */
-       ier = serial_in(port, UART_IER);
-       serial_out(port, UART_IER, 0);
-
-       uart_console_write(port, s, count, serial_putc);
-
-       /* Wait for transmitter to become empty and restore the IER */
-       wait_for_xmitr(port);
-       serial_out(port, UART_IER, ier);
-}
-
-static unsigned int __init probe_baud(struct uart_port *port)
-{
-       unsigned char lcr, dll, dlm;
-       unsigned int quot;
-
-       lcr = serial_in(port, UART_LCR);
-       serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
-       dll = serial_in(port, UART_DLL);
-       dlm = serial_in(port, UART_DLM);
-       serial_out(port, UART_LCR, lcr);
-
-       quot = (dlm << 8) | dll;
-       return (port->uartclk / 16) / quot;
-}
-
-static void __init init_port(struct early_serial8250_device *device)
-{
-       struct uart_port *port = &device->port;
-       unsigned int divisor;
-       unsigned char c;
-
-       serial_out(port, UART_LCR, 0x3);        /* 8n1 */
-       serial_out(port, UART_IER, 0);          /* no interrupt */
-       serial_out(port, UART_FCR, 0);          /* no fifo */
-       serial_out(port, UART_MCR, 0x3);        /* DTR + RTS */
-
-       divisor = port->uartclk / (16 * device->baud);
-       c = serial_in(port, UART_LCR);
-       serial_out(port, UART_LCR, c | UART_LCR_DLAB);
-       serial_out(port, UART_DLL, divisor & 0xff);
-       serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
-       serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
-}
-
-static int __init parse_options(struct early_serial8250_device *device,
-                                                               char *options)
-{
-       struct uart_port *port = &device->port;
-       int mmio, mmio32, length;
-
-       if (!options)
-               return -ENODEV;
-
-       port->uartclk = BASE_BAUD * 16;
-
-       mmio = !strncmp(options, "mmio,", 5);
-       mmio32 = !strncmp(options, "mmio32,", 7);
-       if (mmio || mmio32) {
-               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
-               port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
-                                              &options, 0);
-               if (mmio32)
-                       port->regshift = 2;
-#ifdef CONFIG_FIX_EARLYCON_MEM
-               set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
-                                       port->mapbase & PAGE_MASK);
-               port->membase =
-                       (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
-               port->membase += port->mapbase & ~PAGE_MASK;
-#else
-               port->membase = ioremap_nocache(port->mapbase, 64);
-               if (!port->membase) {
-                       printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
-                               __func__,
-                              (unsigned long long) port->mapbase);
-                       return -ENOMEM;
-               }
-#endif
-       } else if (!strncmp(options, "io,", 3)) {
-               port->iotype = UPIO_PORT;
-               port->iobase = simple_strtoul(options + 3, &options, 0);
-               mmio = 0;
-       } else
-               return -EINVAL;
-
-       options = strchr(options, ',');
-       if (options) {
-               options++;
-               device->baud = simple_strtoul(options, NULL, 0);
-               length = min(strcspn(options, " "), sizeof(device->options));
-               strncpy(device->options, options, length);
-       } else {
-               device->baud = probe_baud(port);
-               snprintf(device->options, sizeof(device->options), "%u",
-                       device->baud);
-       }
-
-       if (mmio || mmio32)
-               printk(KERN_INFO
-                      "Early serial console at MMIO%s 0x%llx (options '%s')\n",
-                       mmio32 ? "32" : "",
-                       (unsigned long long)port->mapbase,
-                       device->options);
-       else
-               printk(KERN_INFO
-                     "Early serial console at I/O port 0x%lx (options '%s')\n",
-                       port->iobase,
-                       device->options);
-
-       return 0;
-}
-
-static struct console early_serial8250_console __initdata = {
-       .name   = "uart",
-       .write  = early_serial8250_write,
-       .flags  = CON_PRINTBUFFER | CON_BOOT,
-       .index  = -1,
-};
-
-static int __init early_serial8250_setup(char *options)
-{
-       struct early_serial8250_device *device = &early_device;
-       int err;
-
-       if (device->port.membase || device->port.iobase)
-               return 0;
-
-       err = parse_options(device, options);
-       if (err < 0)
-               return err;
-
-       init_port(device);
-       return 0;
-}
-
-int __init setup_early_serial8250_console(char *cmdline)
-{
-       char *options;
-       int err;
-
-       options = strstr(cmdline, "uart8250,");
-       if (!options) {
-               options = strstr(cmdline, "uart,");
-               if (!options)
-                       return 0;
-       }
-
-       options = strchr(cmdline, ',') + 1;
-       err = early_serial8250_setup(options);
-       if (err < 0)
-               return err;
-
-       register_console(&early_serial8250_console);
-
-       return 0;
-}
-
-int serial8250_find_port_for_earlycon(void)
-{
-       struct early_serial8250_device *device = &early_device;
-       struct uart_port *port = &device->port;
-       int line;
-       int ret;
-
-       if (!device->port.membase && !device->port.iobase)
-               return -ENODEV;
-
-       line = serial8250_find_port(port);
-       if (line < 0)
-               return -ENODEV;
-
-       ret = update_console_cmdline("uart", 8250,
-                            "ttyS", line, device->options);
-       if (ret < 0)
-               ret = update_console_cmdline("uart", 0,
-                                    "ttyS", line, device->options);
-
-       return ret;
-}
-
-early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/serial/8250_exar_st16c554.c b/drivers/serial/8250_exar_st16c554.c
deleted file mode 100644 (file)
index 567143a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  linux/drivers/serial/8250_exar.c
- *
- *  Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com >
- *  Based on 8250_boca.
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                               \
-       {                                               \
-               .iobase         = _base,                \
-               .irq            = _irq,                 \
-               .uartclk        = 1843200,              \
-               .iotype         = UPIO_PORT,            \
-               .flags          = UPF_BOOT_AUTOCONF,    \
-       }
-
-static struct plat_serial8250_port exar_data[] = {
-       PORT(0x100, 5),
-       PORT(0x108, 5),
-       PORT(0x110, 5),
-       PORT(0x118, 5),
-       { },
-};
-
-static struct platform_device exar_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_EXAR_ST16C554,
-       .dev                    = {
-               .platform_data  = exar_data,
-       },
-};
-
-static int __init exar_init(void)
-{
-       return platform_device_register(&exar_device);
-}
-
-module_init(exar_init);
-
-MODULE_AUTHOR("Paul B Schroeder");
-MODULE_DESCRIPTION("8250 serial probe module for Exar cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
deleted file mode 100644 (file)
index 6375d68..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  linux/drivers/serial/8250_fourport.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define PORT(_base,_irq)                                               \
-       {                                                               \
-               .iobase         = _base,                                \
-               .irq            = _irq,                                 \
-               .uartclk        = 1843200,                              \
-               .iotype         = UPIO_PORT,                            \
-               .flags          = UPF_BOOT_AUTOCONF | UPF_FOURPORT,     \
-       }
-
-static struct plat_serial8250_port fourport_data[] = {
-       PORT(0x1a0, 9),
-       PORT(0x1a8, 9),
-       PORT(0x1b0, 9),
-       PORT(0x1b8, 9),
-       PORT(0x2a0, 5),
-       PORT(0x2a8, 5),
-       PORT(0x2b0, 5),
-       PORT(0x2b8, 5),
-       { },
-};
-
-static struct platform_device fourport_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_FOURPORT,
-       .dev                    = {
-               .platform_data  = fourport_data,
-       },
-};
-
-static int __init fourport_init(void)
-{
-       return platform_device_register(&fourport_device);
-}
-
-module_init(fourport_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
deleted file mode 100644 (file)
index d8c0ffb..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *     Serial Device Initialisation for Lasi/Asp/Wax/Dino
- *
- *     (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/serial_core.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-
-#include <asm/hardware.h>
-#include <asm/parisc-device.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-static int __init serial_init_chip(struct parisc_device *dev)
-{
-       struct uart_port port;
-       unsigned long address;
-       int err;
-
-       if (!dev->irq) {
-               /* We find some unattached serial ports by walking native
-                * busses.  These should be silently ignored.  Otherwise,
-                * what we have here is a missing parent device, so tell
-                * the user what they're missing.
-                */
-               if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
-                       printk(KERN_INFO
-                               "Serial: device 0x%llx not configured.\n"
-                               "Enable support for Wax, Lasi, Asp or Dino.\n",
-                               (unsigned long long)dev->hpa.start);
-               return -ENODEV;
-       }
-
-       address = dev->hpa.start;
-       if (dev->id.sversion != 0x8d)
-               address += 0x800;
-
-       memset(&port, 0, sizeof(port));
-       port.iotype     = UPIO_MEM;
-       /* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
-       port.uartclk    = 7272727;
-       port.mapbase    = address;
-       port.membase    = ioremap_nocache(address, 16);
-       port.irq        = dev->irq;
-       port.flags      = UPF_BOOT_AUTOCONF;
-       port.dev        = &dev->dev;
-
-       err = serial8250_register_port(&port);
-       if (err < 0) {
-               printk(KERN_WARNING
-                       "serial8250_register_port returned error %d\n", err);
-               iounmap(port.membase);
-               return err;
-       }
-
-       return 0;
-}
-
-static struct parisc_device_id serial_tbl[] = {
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
-       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
-       { 0 }
-};
-
-/* Hack.  Some machines have SERIAL_0 attached to Lasi and SERIAL_1
- * attached to Dino.  Unfortunately, Dino appears before Lasi in the device
- * tree.  To ensure that ttyS0 == SERIAL_0, we register two drivers; one
- * which only knows about Lasi and then a second which will find all the
- * other serial ports.  HPUX ignores this problem.
- */
-static struct parisc_device_id lasi_tbl[] = {
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
-       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
-       { 0 }
-};
-
-
-MODULE_DEVICE_TABLE(parisc, serial_tbl);
-
-static struct parisc_driver lasi_driver = {
-       .name           = "serial_1",
-       .id_table       = lasi_tbl,
-       .probe          = serial_init_chip,
-};
-
-static struct parisc_driver serial_driver = {
-       .name           = "serial",
-       .id_table       = serial_tbl,
-       .probe          = serial_init_chip,
-};
-
-static int __init probe_serial_gsc(void)
-{
-       register_parisc_driver(&lasi_driver);
-       register_parisc_driver(&serial_driver);
-       return 0;
-}
-
-module_init(probe_serial_gsc);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
deleted file mode 100644 (file)
index c13438c..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Driver for the 98626/98644/internal serial interface on hp300/hp400
- * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
- *
- * Ported from 2.2 and modified to use the normal 8250 driver
- * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
-#include <linux/delay.h>
-#include <linux/dio.h>
-#include <linux/console.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
-#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
-#endif
-
-#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
-       struct hp300_port *next;        /* next port */
-       int line;                       /* line (tty) number */
-};
-
-static struct hp300_port *hp300_ports;
-#endif
-
-#ifdef CONFIG_HPDCA
-
-static int __devinit hpdca_init_one(struct dio_dev *d,
-                                       const struct dio_device_id *ent);
-static void __devexit hpdca_remove_one(struct dio_dev *d);
-
-static struct dio_device_id hpdca_dio_tbl[] = {
-       { DIO_ID_DCA0 },
-       { DIO_ID_DCA0REM },
-       { DIO_ID_DCA1 },
-       { DIO_ID_DCA1REM },
-       { 0 }
-};
-
-static struct dio_driver hpdca_driver = {
-       .name      = "hpdca",
-       .id_table  = hpdca_dio_tbl,
-       .probe     = hpdca_init_one,
-       .remove    = __devexit_p(hpdca_remove_one),
-};
-
-#endif
-
-static unsigned int num_ports;
-
-extern int hp300_uart_scode;
-
-/* Offset to UART registers from base of DCA */
-#define UART_OFFSET    17
-
-#define DCA_ID         0x01    /* ID (read), reset (write) */
-#define DCA_IC         0x03    /* Interrupt control        */
-
-/* Interrupt control */
-#define DCA_IC_IE      0x80    /* Master interrupt enable  */
-
-#define HPDCA_BAUD_BASE 153600
-
-/* Base address of the Frodo part */
-#define FRODO_BASE     (0x41c000)
-
-/*
- * Where we find the 8250-like APCI ports, and how far apart they are.
- */
-#define FRODO_APCIBASE         0x0
-#define FRODO_APCISPACE                0x20
-#define FRODO_APCI_OFFSET(x)   (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
-
-#define HPAPCI_BAUD_BASE 500400
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-/*
- * Parse the bootinfo to find descriptions for headless console and
- * debug serial ports and register them with the 8250 driver.
- * This function should be called before serial_console_init() is called
- * to make sure the serial console will be available for use. IA-64 kernel
- * calls this function from setup_arch() after the EFI and ACPI tables have
- * been parsed.
- */
-int __init hp300_setup_serial_console(void)
-{
-       int scode;
-       struct uart_port port;
-
-       memset(&port, 0, sizeof(port));
-
-       if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
-               return 0;
-
-       if (DIO_SCINHOLE(hp300_uart_scode))
-               return 0;
-
-       scode = hp300_uart_scode;
-
-       /* Memory mapped I/O */
-       port.iotype = UPIO_MEM;
-       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-       port.type = PORT_UNKNOWN;
-
-       /* Check for APCI console */
-       if (scode == 256) {
-#ifdef CONFIG_HPAPCI
-               printk(KERN_INFO "Serial console is HP APCI 1\n");
-
-               port.uartclk = HPAPCI_BAUD_BASE * 16;
-               port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
-               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-               port.regshift = 2;
-               add_preferred_console("ttyS", port.line, "9600n8");
-#else
-               printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
-               return 0;
-#endif
-       } else {
-#ifdef CONFIG_HPDCA
-               unsigned long pa = dio_scodetophysaddr(scode);
-               if (!pa)
-                       return 0;
-
-               printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
-
-               port.uartclk = HPDCA_BAUD_BASE * 16;
-               port.mapbase = (pa + UART_OFFSET);
-               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-               port.regshift = 1;
-               port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
-
-               /* Enable board-interrupts */
-               out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
-
-               if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
-                       add_preferred_console("ttyS", port.line, "9600n8");
-#else
-               printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
-               return 0;
-#endif
-       }
-
-       if (early_serial_setup(&port) < 0)
-               printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
-       return 0;
-}
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-
-#ifdef CONFIG_HPDCA
-static int __devinit hpdca_init_one(struct dio_dev *d,
-                               const struct dio_device_id *ent)
-{
-       struct uart_port port;
-       int line;
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-       if (hp300_uart_scode == d->scode) {
-               /* Already got it. */
-               return 0;
-       }
-#endif
-       memset(&port, 0, sizeof(struct uart_port));
-
-       /* Memory mapped I/O */
-       port.iotype = UPIO_MEM;
-       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-       port.irq = d->ipl;
-       port.uartclk = HPDCA_BAUD_BASE * 16;
-       port.mapbase = (d->resource.start + UART_OFFSET);
-       port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
-       port.regshift = 1;
-       port.dev = &d->dev;
-       line = serial8250_register_port(&port);
-
-       if (line < 0) {
-               printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
-                      " irq %d failed\n", d->scode, port.irq);
-               return -ENOMEM;
-       }
-
-       /* Enable board-interrupts */
-       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
-       dio_set_drvdata(d, (void *)line);
-
-       /* Reset the DCA */
-       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
-       udelay(100);
-
-       num_ports++;
-
-       return 0;
-}
-#endif
-
-static int __init hp300_8250_init(void)
-{
-       static int called;
-#ifdef CONFIG_HPAPCI
-       int line;
-       unsigned long base;
-       struct uart_port uport;
-       struct hp300_port *port;
-       int i;
-#endif
-       if (called)
-               return -ENODEV;
-       called = 1;
-
-       if (!MACH_IS_HP300)
-               return -ENODEV;
-
-#ifdef CONFIG_HPDCA
-       dio_register_driver(&hpdca_driver);
-#endif
-#ifdef CONFIG_HPAPCI
-       if (hp300_model < HP_400) {
-               if (!num_ports)
-                       return -ENODEV;
-               return 0;
-       }
-       /* These models have the Frodo chip.
-        * Port 0 is reserved for the Apollo Domain keyboard.
-        * Port 1 is either the console or the DCA.
-        */
-       for (i = 1; i < 4; i++) {
-               /* Port 1 is the console on a 425e, on other machines it's
-                * mapped to DCA.
-                */
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-               if (i == 1)
-                       continue;
-#endif
-
-               /* Create new serial device */
-               port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
-               if (!port)
-                       return -ENOMEM;
-
-               memset(&uport, 0, sizeof(struct uart_port));
-
-               base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
-
-               /* Memory mapped I/O */
-               uport.iotype = UPIO_MEM;
-               uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
-                             | UPF_BOOT_AUTOCONF;
-               /* XXX - no interrupt support yet */
-               uport.irq = 0;
-               uport.uartclk = HPAPCI_BAUD_BASE * 16;
-               uport.mapbase = base;
-               uport.membase = (char *)(base + DIO_VIRADDRBASE);
-               uport.regshift = 2;
-
-               line = serial8250_register_port(&uport);
-
-               if (line < 0) {
-                       printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
-                              " %d irq %d failed\n", i, uport.irq);
-                       kfree(port);
-                       continue;
-               }
-
-               port->line = line;
-               port->next = hp300_ports;
-               hp300_ports = port;
-
-               num_ports++;
-       }
-#endif
-
-       /* Any boards found? */
-       if (!num_ports)
-               return -ENODEV;
-
-       return 0;
-}
-
-#ifdef CONFIG_HPDCA
-static void __devexit hpdca_remove_one(struct dio_dev *d)
-{
-       int line;
-
-       line = (int) dio_get_drvdata(d);
-       if (d->resource.start) {
-               /* Disable board-interrupts */
-               out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
-       }
-       serial8250_unregister_port(line);
-}
-#endif
-
-static void __exit hp300_8250_exit(void)
-{
-#ifdef CONFIG_HPAPCI
-       struct hp300_port *port, *to_free;
-
-       for (port = hp300_ports; port; ) {
-               serial8250_unregister_port(port->line);
-               to_free = port;
-               port = port->next;
-               kfree(to_free);
-       }
-
-       hp300_ports = NULL;
-#endif
-#ifdef CONFIG_HPDCA
-       dio_unregister_driver(&hpdca_driver);
-#endif
-}
-
-module_init(hp300_8250_init);
-module_exit(hp300_8250_exit);
-MODULE_DESCRIPTION("HP DCA/APCI serial driver");
-MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
deleted file mode 100644 (file)
index 7609150..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  linux/drivers/serial/8250_hub6.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/serial_8250.h>
-
-#define HUB6(card,port)                                                        \
-       {                                                               \
-               .iobase         = 0x302,                                \
-               .irq            = 3,                                    \
-               .uartclk        = 1843200,                              \
-               .iotype         = UPIO_HUB6,                            \
-               .flags          = UPF_BOOT_AUTOCONF,                    \
-               .hub6           = (card) << 6 | (port) << 3 | 1,        \
-       }
-
-static struct plat_serial8250_port hub6_data[] = {
-       HUB6(0, 0),
-       HUB6(0, 1),
-       HUB6(0, 2),
-       HUB6(0, 3),
-       HUB6(0, 4),
-       HUB6(0, 5),
-       HUB6(1, 0),
-       HUB6(1, 1),
-       HUB6(1, 2),
-       HUB6(1, 3),
-       HUB6(1, 4),
-       HUB6(1, 5),
-       { },
-};
-
-static struct platform_device hub6_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_HUB6,
-       .dev                    = {
-               .platform_data  = hub6_data,
-       },
-};
-
-static int __init hub6_init(void)
-{
-       return platform_device_register(&hub6_device);
-}
-
-module_init(hub6_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
deleted file mode 100644 (file)
index d10be94..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  linux/drivers/serial/8250_mca.c
- *
- *  Copyright (C) 2005 Russell King.
- *  Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/mca.h>
-#include <linux/serial_8250.h>
-
-/*
- * FIXME: Should we be doing AUTO_IRQ here?
- */
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
-#else
-#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
-#endif
-
-#define PORT(_base,_irq)                       \
-       {                                       \
-               .iobase         = _base,        \
-               .irq            = _irq,         \
-               .uartclk        = 1843200,      \
-               .iotype         = UPIO_PORT,    \
-               .flags          = MCA_FLAGS,    \
-       }
-
-static struct plat_serial8250_port mca_data[] = {
-       PORT(0x3220, 3),
-       PORT(0x3228, 3),
-       PORT(0x4220, 3),
-       PORT(0x4228, 3),
-       PORT(0x5220, 3),
-       PORT(0x5228, 3),
-       { },
-};
-
-static struct platform_device mca_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_MCA,
-       .dev                    = {
-               .platform_data  = mca_data,
-       },
-};
-
-static int __init mca_init(void)
-{
-       if (!MCA_bus)
-               return -ENODEV;
-       return platform_device_register(&mca_device);
-}
-
-module_init(mca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
deleted file mode 100644 (file)
index 8b8930f..0000000
+++ /dev/null
@@ -1,3850 +0,0 @@
-/*
- *  linux/drivers/char/8250_pci.c
- *
- *  Probe module for 8250/16550-type PCI serial ports.
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/8250_pci.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#include "8250.h"
-
-#undef SERIAL_DEBUG_PCI
-
-/*
- * init function returns:
- *  > 0 - number of ports
- *  = 0 - use board->num_ports
- *  < 0 - error
- */
-struct pci_serial_quirk {
-       u32     vendor;
-       u32     device;
-       u32     subvendor;
-       u32     subdevice;
-       int     (*init)(struct pci_dev *dev);
-       int     (*setup)(struct serial_private *,
-                        const struct pciserial_board *,
-                        struct uart_port *, int);
-       void    (*exit)(struct pci_dev *dev);
-};
-
-#define PCI_NUM_BAR_RESOURCES  6
-
-struct serial_private {
-       struct pci_dev          *dev;
-       unsigned int            nr;
-       void __iomem            *remapped_bar[PCI_NUM_BAR_RESOURCES];
-       struct pci_serial_quirk *quirk;
-       int                     line[0];
-};
-
-static void moan_device(const char *str, struct pci_dev *dev)
-{
-       printk(KERN_WARNING
-              "%s: %s\n"
-              "Please send the output of lspci -vv, this\n"
-              "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
-              "manufacturer and name of serial board or\n"
-              "modem board to rmk+serial@arm.linux.org.uk.\n",
-              pci_name(dev), str, dev->vendor, dev->device,
-              dev->subsystem_vendor, dev->subsystem_device);
-}
-
-static int
-setup_port(struct serial_private *priv, struct uart_port *port,
-          int bar, int offset, int regshift)
-{
-       struct pci_dev *dev = priv->dev;
-       unsigned long base, len;
-
-       if (bar >= PCI_NUM_BAR_RESOURCES)
-               return -EINVAL;
-
-       base = pci_resource_start(dev, bar);
-
-       if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
-               len =  pci_resource_len(dev, bar);
-
-               if (!priv->remapped_bar[bar])
-                       priv->remapped_bar[bar] = ioremap_nocache(base, len);
-               if (!priv->remapped_bar[bar])
-                       return -ENOMEM;
-
-               port->iotype = UPIO_MEM;
-               port->iobase = 0;
-               port->mapbase = base + offset;
-               port->membase = priv->remapped_bar[bar] + offset;
-               port->regshift = regshift;
-       } else {
-               port->iotype = UPIO_PORT;
-               port->iobase = base + offset;
-               port->mapbase = 0;
-               port->membase = NULL;
-               port->regshift = 0;
-       }
-       return 0;
-}
-
-/*
- * ADDI-DATA GmbH communication cards <info@addi-data.com>
- */
-static int addidata_apci7800_setup(struct serial_private *priv,
-                               const struct pciserial_board *board,
-                               struct uart_port *port, int idx)
-{
-       unsigned int bar = 0, offset = board->first_offset;
-       bar = FL_GET_BASE(board->flags);
-
-       if (idx < 2) {
-               offset += idx * board->uart_offset;
-       } else if ((idx >= 2) && (idx < 4)) {
-               bar += 1;
-               offset += ((idx - 2) * board->uart_offset);
-       } else if ((idx >= 4) && (idx < 6)) {
-               bar += 2;
-               offset += ((idx - 4) * board->uart_offset);
-       } else if (idx >= 6) {
-               bar += 3;
-               offset += ((idx - 6) * board->uart_offset);
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * AFAVLAB uses a different mixture of BARs and offsets
- * Not that ugly ;) -- HW
- */
-static int
-afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
-             struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       bar = FL_GET_BASE(board->flags);
-       if (idx < 4)
-               bar += idx;
-       else {
-               bar = 4;
-               offset += (idx - 4) * board->uart_offset;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * HP's Remote Management Console.  The Diva chip came in several
- * different versions.  N-class, L2000 and A500 have two Diva chips, each
- * with 3 UARTs (the third UART on the second chip is unused).  Superdome
- * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
- * one Diva chip, but it has been expanded to 5 UARTs.
- */
-static int pci_hp_diva_init(struct pci_dev *dev)
-{
-       int rc = 0;
-
-       switch (dev->subsystem_device) {
-       case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
-       case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
-       case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
-       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
-               rc = 3;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
-               rc = 2;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
-               rc = 4;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
-       case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
-               rc = 1;
-               break;
-       }
-
-       return rc;
-}
-
-/*
- * HP's Diva chip puts the 4th/5th serial port further out, and
- * some serial ports are supposed to be hidden on certain models.
- */
-static int
-pci_hp_diva_setup(struct serial_private *priv,
-               const struct pciserial_board *board,
-               struct uart_port *port, int idx)
-{
-       unsigned int offset = board->first_offset;
-       unsigned int bar = FL_GET_BASE(board->flags);
-
-       switch (priv->dev->subsystem_device) {
-       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
-               if (idx == 3)
-                       idx++;
-               break;
-       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
-               if (idx > 0)
-                       idx++;
-               if (idx > 2)
-                       idx++;
-               break;
-       }
-       if (idx > 2)
-               offset = 0x18;
-
-       offset += idx * board->uart_offset;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * Added for EKF Intel i960 serial boards
- */
-static int pci_inteli960ni_init(struct pci_dev *dev)
-{
-       unsigned long oldval;
-
-       if (!(dev->subsystem_device & 0x1000))
-               return -ENODEV;
-
-       /* is firmware started? */
-       pci_read_config_dword(dev, 0x44, (void *)&oldval);
-       if (oldval == 0x00001000L) { /* RESET value */
-               printk(KERN_DEBUG "Local i960 firmware missing");
-               return -ENODEV;
-       }
-       return 0;
-}
-
-/*
- * Some PCI serial cards using the PLX 9050 PCI interface chip require
- * that the card interrupt be explicitly enabled or disabled.  This
- * seems to be mainly needed on card using the PLX which also use I/O
- * mapped memory.
- */
-static int pci_plx9050_init(struct pci_dev *dev)
-{
-       u8 irq_config;
-       void __iomem *p;
-
-       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar 0", dev);
-               return 0;
-       }
-
-       irq_config = 0x41;
-       if (dev->vendor == PCI_VENDOR_ID_PANACOM ||
-           dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS)
-               irq_config = 0x43;
-
-       if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
-           (dev->device == PCI_DEVICE_ID_PLX_ROMULUS))
-               /*
-                * As the megawolf cards have the int pins active
-                * high, and have 2 UART chips, both ints must be
-                * enabled on the 9050. Also, the UARTS are set in
-                * 16450 mode by default, so we have to enable the
-                * 16C950 'enhanced' mode so that we can use the
-                * deep FIFOs
-                */
-               irq_config = 0x5b;
-       /*
-        * enable/disable interrupts
-        */
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p == NULL)
-               return -ENOMEM;
-       writel(irq_config, p + 0x4c);
-
-       /*
-        * Read the register back to ensure that it took effect.
-        */
-       readl(p + 0x4c);
-       iounmap(p);
-
-       return 0;
-}
-
-static void __devexit pci_plx9050_exit(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0)
-               return;
-
-       /*
-        * disable interrupts
-        */
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p != NULL) {
-               writel(0, p + 0x4c);
-
-               /*
-                * Read the register back to ensure that it took effect.
-                */
-               readl(p + 0x4c);
-               iounmap(p);
-       }
-}
-
-#define NI8420_INT_ENABLE_REG  0x38
-#define NI8420_INT_ENABLE_BIT  0x2000
-
-static void __devexit pci_ni8420_exit(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return;
-
-       /* Disable the CPU Interrupt */
-       writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
-              p + NI8420_INT_ENABLE_REG);
-       iounmap(p);
-}
-
-
-/* MITE registers */
-#define MITE_IOWBSR1   0xc4
-#define MITE_IOWCR1    0xf4
-#define MITE_LCIMR1    0x08
-#define MITE_LCIMR2    0x10
-
-#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
-
-static void __devexit pci_ni8430_exit(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return;
-
-       /* Disable the CPU Interrupt */
-       writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2);
-       iounmap(p);
-}
-
-/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
-static int
-sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
-               struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       bar = 0;
-
-       if (idx < 4) {
-               /* first four channels map to 0, 0x100, 0x200, 0x300 */
-               offset += idx * board->uart_offset;
-       } else if (idx < 8) {
-               /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
-               offset += idx * board->uart_offset + 0xC00;
-       } else /* we have only 8 ports on PMC-OCTALPRO */
-               return 1;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
-* This does initialization for PMC OCTALPRO cards:
-* maps the device memory, resets the UARTs (needed, bc
-* if the module is removed and inserted again, the card
-* is in the sleep mode) and enables global interrupt.
-*/
-
-/* global control register offset for SBS PMC-OctalPro */
-#define OCT_REG_CR_OFF         0x500
-
-static int sbs_init(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       p = pci_ioremap_bar(dev, 0);
-
-       if (p == NULL)
-               return -ENOMEM;
-       /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
-       writeb(0x10, p + OCT_REG_CR_OFF);
-       udelay(50);
-       writeb(0x0, p + OCT_REG_CR_OFF);
-
-       /* Set bit-2 (INTENABLE) of Control Register */
-       writeb(0x4, p + OCT_REG_CR_OFF);
-       iounmap(p);
-
-       return 0;
-}
-
-/*
- * Disables the global interrupt of PMC-OctalPro
- */
-
-static void __devexit sbs_exit(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-
-       p = pci_ioremap_bar(dev, 0);
-       /* FIXME: What if resource_len < OCT_REG_CR_OFF */
-       if (p != NULL)
-               writeb(0, p + OCT_REG_CR_OFF);
-       iounmap(p);
-}
-
-/*
- * SIIG serial cards have an PCI interface chip which also controls
- * the UART clocking frequency. Each UART can be clocked independently
- * (except cards equiped with 4 UARTs) and initial clocking settings
- * are stored in the EEPROM chip. It can cause problems because this
- * version of serial driver doesn't support differently clocked UART's
- * on single PCI card. To prevent this, initialization functions set
- * high frequency clocking for all UART's on given card. It is safe (I
- * hope) because it doesn't touch EEPROM settings to prevent conflicts
- * with other OSes (like M$ DOS).
- *
- *  SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
- *
- * There is two family of SIIG serial cards with different PCI
- * interface chip and different configuration methods:
- *     - 10x cards have control registers in IO and/or memory space;
- *     - 20x cards have control registers in standard PCI configuration space.
- *
- * Note: all 10x cards have PCI device ids 0x10..
- *       all 20x cards have PCI device ids 0x20..
- *
- * There are also Quartet Serial cards which use Oxford Semiconductor
- * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
- *
- * Note: some SIIG cards are probed by the parport_serial object.
- */
-
-#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
-
-static int pci_siig10x_init(struct pci_dev *dev)
-{
-       u16 data;
-       void __iomem *p;
-
-       switch (dev->device & 0xfff8) {
-       case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
-               data = 0xffdf;
-               break;
-       case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
-               data = 0xf7ff;
-               break;
-       default:                        /* 1S1P, 4S */
-               data = 0xfffb;
-               break;
-       }
-
-       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
-       if (p == NULL)
-               return -ENOMEM;
-
-       writew(readw(p + 0x28) & data, p + 0x28);
-       readw(p + 0x28);
-       iounmap(p);
-       return 0;
-}
-
-#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
-
-static int pci_siig20x_init(struct pci_dev *dev)
-{
-       u8 data;
-
-       /* Change clock frequency for the first UART. */
-       pci_read_config_byte(dev, 0x6f, &data);
-       pci_write_config_byte(dev, 0x6f, data & 0xef);
-
-       /* If this card has 2 UART, we have to do the same with second UART. */
-       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
-           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
-               pci_read_config_byte(dev, 0x73, &data);
-               pci_write_config_byte(dev, 0x73, data & 0xef);
-       }
-       return 0;
-}
-
-static int pci_siig_init(struct pci_dev *dev)
-{
-       unsigned int type = dev->device & 0xff00;
-
-       if (type == 0x1000)
-               return pci_siig10x_init(dev);
-       else if (type == 0x2000)
-               return pci_siig20x_init(dev);
-
-       moan_device("Unknown SIIG card", dev);
-       return -ENODEV;
-}
-
-static int pci_siig_setup(struct serial_private *priv,
-                         const struct pciserial_board *board,
-                         struct uart_port *port, int idx)
-{
-       unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
-
-       if (idx > 3) {
-               bar = 4;
-               offset = (idx - 4) * 8;
-       }
-
-       return setup_port(priv, port, bar, offset, 0);
-}
-
-/*
- * Timedia has an explosion of boards, and to avoid the PCI table from
- * growing *huge*, we use this function to collapse some 70 entries
- * in the PCI table into one, for sanity's and compactness's sake.
- */
-static const unsigned short timedia_single_port[] = {
-       0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
-};
-
-static const unsigned short timedia_dual_port[] = {
-       0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
-       0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
-       0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
-       0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
-       0xD079, 0
-};
-
-static const unsigned short timedia_quad_port[] = {
-       0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
-       0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
-       0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
-       0xB157, 0
-};
-
-static const unsigned short timedia_eight_port[] = {
-       0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
-       0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
-};
-
-static const struct timedia_struct {
-       int num;
-       const unsigned short *ids;
-} timedia_data[] = {
-       { 1, timedia_single_port },
-       { 2, timedia_dual_port },
-       { 4, timedia_quad_port },
-       { 8, timedia_eight_port }
-};
-
-static int pci_timedia_init(struct pci_dev *dev)
-{
-       const unsigned short *ids;
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
-               ids = timedia_data[i].ids;
-               for (j = 0; ids[j]; j++)
-                       if (dev->subsystem_device == ids[j])
-                               return timedia_data[i].num;
-       }
-       return 0;
-}
-
-/*
- * Timedia/SUNIX uses a mixture of BARs and offsets
- * Ugh, this is ugly as all hell --- TYT
- */
-static int
-pci_timedia_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       unsigned int bar = 0, offset = board->first_offset;
-
-       switch (idx) {
-       case 0:
-               bar = 0;
-               break;
-       case 1:
-               offset = board->uart_offset;
-               bar = 0;
-               break;
-       case 2:
-               bar = 1;
-               break;
-       case 3:
-               offset = board->uart_offset;
-               /* FALLTHROUGH */
-       case 4: /* BAR 2 */
-       case 5: /* BAR 3 */
-       case 6: /* BAR 4 */
-       case 7: /* BAR 5 */
-               bar = idx - 2;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-/*
- * Some Titan cards are also a little weird
- */
-static int
-titan_400l_800l_setup(struct serial_private *priv,
-                     const struct pciserial_board *board,
-                     struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset;
-
-       switch (idx) {
-       case 0:
-               bar = 1;
-               break;
-       case 1:
-               bar = 2;
-               break;
-       default:
-               bar = 4;
-               offset = (idx - 2) * board->uart_offset;
-       }
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-static int pci_xircom_init(struct pci_dev *dev)
-{
-       msleep(100);
-       return 0;
-}
-
-static int pci_ni8420_init(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return 0;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return -ENOMEM;
-
-       /* Enable CPU Interrupt */
-       writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT,
-              p + NI8420_INT_ENABLE_REG);
-
-       iounmap(p);
-       return 0;
-}
-
-#define MITE_IOWBSR1_WSIZE     0xa
-#define MITE_IOWBSR1_WIN_OFFSET        0x800
-#define MITE_IOWBSR1_WENAB     (1 << 7)
-#define MITE_LCIMR1_IO_IE_0    (1 << 24)
-#define MITE_LCIMR2_SET_CPU_IE (1 << 31)
-#define MITE_IOWCR1_RAMSEL_MASK        0xfffffffe
-
-static int pci_ni8430_init(struct pci_dev *dev)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       u32 device_window;
-       unsigned int bar = 0;
-
-       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
-               moan_device("no memory in bar", dev);
-               return 0;
-       }
-
-       base = pci_resource_start(dev, bar);
-       len =  pci_resource_len(dev, bar);
-       p = ioremap_nocache(base, len);
-       if (p == NULL)
-               return -ENOMEM;
-
-       /* Set device window address and size in BAR0 */
-       device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
-                       | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
-       writel(device_window, p + MITE_IOWBSR1);
-
-       /* Set window access to go to RAMSEL IO address space */
-       writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK),
-              p + MITE_IOWCR1);
-
-       /* Enable IO Bus Interrupt 0 */
-       writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1);
-
-       /* Enable CPU Interrupt */
-       writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2);
-
-       iounmap(p);
-       return 0;
-}
-
-/* UART Port Control Register */
-#define NI8430_PORTCON 0x0f
-#define NI8430_PORTCON_TXVR_ENABLE     (1 << 3)
-
-static int
-pci_ni8430_setup(struct serial_private *priv,
-                const struct pciserial_board *board,
-                struct uart_port *port, int idx)
-{
-       void __iomem *p;
-       unsigned long base, len;
-       unsigned int bar, offset = board->first_offset;
-
-       if (idx >= board->num_ports)
-               return 1;
-
-       bar = FL_GET_BASE(board->flags);
-       offset += idx * board->uart_offset;
-
-       base = pci_resource_start(priv->dev, bar);
-       len =  pci_resource_len(priv->dev, bar);
-       p = ioremap_nocache(base, len);
-
-       /* enable the transciever */
-       writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
-              p + offset + NI8430_PORTCON);
-
-       iounmap(p);
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-
-static int pci_netmos_init(struct pci_dev *dev)
-{
-       /* subdevice 0x00PS means <P> parallel, <S> serial */
-       unsigned int num_serial = dev->subsystem_device & 0xf;
-
-       if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
-               (dev->device == PCI_DEVICE_ID_NETMOS_9865))
-               return 0;
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
-                       dev->subsystem_device == 0x0299)
-               return 0;
-
-       if (num_serial == 0)
-               return -ENODEV;
-       return num_serial;
-}
-
-/*
- * These chips are available with optionally one parallel port and up to
- * two serial ports. Unfortunately they all have the same product id.
- *
- * Basic configuration is done over a region of 32 I/O ports. The base
- * ioport is called INTA or INTC, depending on docs/other drivers.
- *
- * The region of the 32 I/O ports is configured in POSIO0R...
- */
-
-/* registers */
-#define ITE_887x_MISCR         0x9c
-#define ITE_887x_INTCBAR       0x78
-#define ITE_887x_UARTBAR       0x7c
-#define ITE_887x_PS0BAR                0x10
-#define ITE_887x_POSIO0                0x60
-
-/* I/O space size */
-#define ITE_887x_IOSIZE                32
-/* I/O space size (bits 26-24; 8 bytes = 011b) */
-#define ITE_887x_POSIO_IOSIZE_8                (3 << 24)
-/* I/O space size (bits 26-24; 32 bytes = 101b) */
-#define ITE_887x_POSIO_IOSIZE_32       (5 << 24)
-/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
-#define ITE_887x_POSIO_SPEED           (3 << 29)
-/* enable IO_Space bit */
-#define ITE_887x_POSIO_ENABLE          (1 << 31)
-
-static int pci_ite887x_init(struct pci_dev *dev)
-{
-       /* inta_addr are the configuration addresses of the ITE */
-       static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
-                                                       0x200, 0x280, 0 };
-       int ret, i, type;
-       struct resource *iobase = NULL;
-       u32 miscr, uartbar, ioport;
-
-       /* search for the base-ioport */
-       i = 0;
-       while (inta_addr[i] && iobase == NULL) {
-               iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
-                                                               "ite887x");
-               if (iobase != NULL) {
-                       /* write POSIO0R - speed | size | ioport */
-                       pci_write_config_dword(dev, ITE_887x_POSIO0,
-                               ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
-                               ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
-                       /* write INTCBAR - ioport */
-                       pci_write_config_dword(dev, ITE_887x_INTCBAR,
-                                                               inta_addr[i]);
-                       ret = inb(inta_addr[i]);
-                       if (ret != 0xff) {
-                               /* ioport connected */
-                               break;
-                       }
-                       release_region(iobase->start, ITE_887x_IOSIZE);
-                       iobase = NULL;
-               }
-               i++;
-       }
-
-       if (!inta_addr[i]) {
-               printk(KERN_ERR "ite887x: could not find iobase\n");
-               return -ENODEV;
-       }
-
-       /* start of undocumented type checking (see parport_pc.c) */
-       type = inb(iobase->start + 0x18) & 0x0f;
-
-       switch (type) {
-       case 0x2:       /* ITE8871 (1P) */
-       case 0xa:       /* ITE8875 (1P) */
-               ret = 0;
-               break;
-       case 0xe:       /* ITE8872 (2S1P) */
-               ret = 2;
-               break;
-       case 0x6:       /* ITE8873 (1S) */
-               ret = 1;
-               break;
-       case 0x8:       /* ITE8874 (2S) */
-               ret = 2;
-               break;
-       default:
-               moan_device("Unknown ITE887x", dev);
-               ret = -ENODEV;
-       }
-
-       /* configure all serial ports */
-       for (i = 0; i < ret; i++) {
-               /* read the I/O port from the device */
-               pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
-                                                               &ioport);
-               ioport &= 0x0000FF00;   /* the actual base address */
-               pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
-                       ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
-                       ITE_887x_POSIO_IOSIZE_8 | ioport);
-
-               /* write the ioport to the UARTBAR */
-               pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
-               uartbar &= ~(0xffff << (16 * i));       /* clear half the reg */
-               uartbar |= (ioport << (16 * i));        /* set the ioport */
-               pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
-
-               /* get current config */
-               pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
-               /* disable interrupts (UARTx_Routing[3:0]) */
-               miscr &= ~(0xf << (12 - 4 * i));
-               /* activate the UART (UARTx_En) */
-               miscr |= 1 << (23 - i);
-               /* write new config with activated UART */
-               pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
-       }
-
-       if (ret <= 0) {
-               /* the device has no UARTs if we get here */
-               release_region(iobase->start, ITE_887x_IOSIZE);
-       }
-
-       return ret;
-}
-
-static void __devexit pci_ite887x_exit(struct pci_dev *dev)
-{
-       u32 ioport;
-       /* the ioport is bit 0-15 in POSIO0R */
-       pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
-       ioport &= 0xffff;
-       release_region(ioport, ITE_887x_IOSIZE);
-}
-
-/*
- * Oxford Semiconductor Inc.
- * Check that device is part of the Tornado range of devices, then determine
- * the number of ports available on the device.
- */
-static int pci_oxsemi_tornado_init(struct pci_dev *dev)
-{
-       u8 __iomem *p;
-       unsigned long deviceID;
-       unsigned int  number_uarts = 0;
-
-       /* OxSemi Tornado devices are all 0xCxxx */
-       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
-           (dev->device & 0xF000) != 0xC000)
-               return 0;
-
-       p = pci_iomap(dev, 0, 5);
-       if (p == NULL)
-               return -ENOMEM;
-
-       deviceID = ioread32(p);
-       /* Tornado device */
-       if (deviceID == 0x07000200) {
-               number_uarts = ioread8(p + 4);
-               printk(KERN_DEBUG
-                       "%d ports detected on Oxford PCI Express device\n",
-                                                               number_uarts);
-       }
-       pci_iounmap(dev, p);
-       return number_uarts;
-}
-
-static int
-pci_default_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       unsigned int bar, offset = board->first_offset, maxnr;
-
-       bar = FL_GET_BASE(board->flags);
-       if (board->flags & FL_BASE_BARS)
-               bar += idx;
-       else
-               offset += idx * board->uart_offset;
-
-       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
-               (board->reg_shift + 3);
-
-       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
-               return 1;
-
-       return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
-static int
-ce4100_serial_setup(struct serial_private *priv,
-                 const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
-{
-       int ret;
-
-       ret = setup_port(priv, port, 0, 0, board->reg_shift);
-       port->iotype = UPIO_MEM32;
-       port->type = PORT_XSCALE;
-       port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
-       port->regshift = 2;
-
-       return ret;
-}
-
-static int skip_tx_en_setup(struct serial_private *priv,
-                       const struct pciserial_board *board,
-                       struct uart_port *port, int idx)
-{
-       port->flags |= UPF_NO_TXEN_TEST;
-       printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
-                         "[%04x:%04x] subsystem [%04x:%04x]\n",
-                         priv->dev->vendor,
-                         priv->dev->device,
-                         priv->dev->subsystem_vendor,
-                         priv->dev->subsystem_device);
-
-       return pci_default_setup(priv, board, port, idx);
-}
-
-/* This should be in linux/pci_ids.h */
-#define PCI_VENDOR_ID_SBSMODULARIO     0x124B
-#define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
-#define PCI_DEVICE_ID_OCTPRO           0x0001
-#define PCI_SUBDEVICE_ID_OCTPRO232     0x0108
-#define PCI_SUBDEVICE_ID_OCTPRO422     0x0208
-#define PCI_SUBDEVICE_ID_POCTAL232     0x0308
-#define PCI_SUBDEVICE_ID_POCTAL422     0x0408
-#define PCI_VENDOR_ID_ADVANTECH                0x13fe
-#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
-#define PCI_DEVICE_ID_ADVANTECH_PCI3620        0x3620
-#define PCI_DEVICE_ID_TITAN_200I       0x8028
-#define PCI_DEVICE_ID_TITAN_400I       0x8048
-#define PCI_DEVICE_ID_TITAN_800I       0x8088
-#define PCI_DEVICE_ID_TITAN_800EH      0xA007
-#define PCI_DEVICE_ID_TITAN_800EHB     0xA008
-#define PCI_DEVICE_ID_TITAN_400EH      0xA009
-#define PCI_DEVICE_ID_TITAN_100E       0xA010
-#define PCI_DEVICE_ID_TITAN_200E       0xA012
-#define PCI_DEVICE_ID_TITAN_400E       0xA013
-#define PCI_DEVICE_ID_TITAN_800E       0xA014
-#define PCI_DEVICE_ID_TITAN_200EI      0xA016
-#define PCI_DEVICE_ID_TITAN_200EISI    0xA017
-#define PCI_DEVICE_ID_OXSEMI_16PCI958  0x9538
-
-/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
-#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
-
-/*
- * Master list of serial port init/setup/exit quirks.
- * This does not describe the general nature of the port.
- * (ie, baud base, number and location of ports, etc)
- *
- * This list is ordered alphabetically by vendor then device.
- * Specific entries must come before more generic entries.
- */
-static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
-       /*
-       * ADDI-DATA GmbH communication cards <info@addi-data.com>
-       */
-       {
-               .vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
-               .device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = addidata_apci7800_setup,
-       },
-       /*
-        * AFAVLAB cards - these may be called via parport_serial
-        *  It is not clear whether this applies to all products.
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_AFAVLAB,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = afavlab_setup,
-       },
-       /*
-        * HP Diva
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_HP,
-               .device         = PCI_DEVICE_ID_HP_DIVA,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_hp_diva_init,
-               .setup          = pci_hp_diva_setup,
-       },
-       /*
-        * Intel
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_80960_RP,
-               .subvendor      = 0xe4bf,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_inteli960ni_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_8257X_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_82573L_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_82573E_SOL,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = skip_tx_en_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_CE4100_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = ce4100_serial_setup,
-       },
-       /*
-        * ITE
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_ITE,
-               .device         = PCI_DEVICE_ID_ITE_8872,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ite887x_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ite887x_exit),
-       },
-       /*
-        * National Instruments
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI23216,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2328,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2324I,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PCI2322I,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_23216,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2328,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8420_2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8422_2324,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_DEVICE_ID_NI_PXI8422_2322,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8420_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_ni8420_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_NI,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_ni8430_init,
-               .setup          = pci_ni8430_setup,
-               .exit           = __devexit_p(pci_ni8430_exit),
-       },
-       /*
-        * Panacom
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_PANACOM,
-               .device         = PCI_DEVICE_ID_PANACOM_QUADMODEM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PANACOM,
-               .device         = PCI_DEVICE_ID_PANACOM_DUALMODEM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       /*
-        * PLX
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9030,
-               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_SUBVENDOR_ID_EXSYS,
-               .subdevice      = PCI_SUBDEVICE_ID_EXSYS_4055,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_SUBVENDOR_ID_KEYSPAN,
-               .subdevice      = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9050,
-               .subvendor      = PCI_VENDOR_ID_PLX,
-               .subdevice      = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_ROMULUS,
-               .subvendor      = PCI_VENDOR_ID_PLX,
-               .subdevice      = PCI_DEVICE_ID_PLX_ROMULUS,
-               .init           = pci_plx9050_init,
-               .setup          = pci_default_setup,
-               .exit           = __devexit_p(pci_plx9050_exit),
-       },
-       /*
-        * SBS Technologies, Inc., PMC-OCTALPRO 232
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO232,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., PMC-OCTALPRO 422
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO422,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., P-Octal 232
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_POCTAL232,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SBS Technologies, Inc., P-Octal 422
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
-               .device         = PCI_DEVICE_ID_OCTPRO,
-               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
-               .subdevice      = PCI_SUBDEVICE_ID_POCTAL422,
-               .init           = sbs_init,
-               .setup          = sbs_setup,
-               .exit           = __devexit_p(sbs_exit),
-       },
-       /*
-        * SIIG cards - these may be called via parport_serial
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_SIIG,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_siig_init,
-               .setup          = pci_siig_setup,
-       },
-       /*
-        * Titan cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_TITAN,
-               .device         = PCI_DEVICE_ID_TITAN_400L,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = titan_400l_800l_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_TITAN,
-               .device         = PCI_DEVICE_ID_TITAN_800L,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = titan_400l_800l_setup,
-       },
-       /*
-        * Timedia cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_TIMEDIA,
-               .device         = PCI_DEVICE_ID_TIMEDIA_1889,
-               .subvendor      = PCI_VENDOR_ID_TIMEDIA,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_timedia_init,
-               .setup          = pci_timedia_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_TIMEDIA,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_timedia_setup,
-       },
-       /*
-        * Xircom cards
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_XIRCOM,
-               .device         = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_xircom_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * Netmos cards - these may be called via parport_serial
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_NETMOS,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_netmos_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * For Oxford Semiconductor and Mainpine
-        */
-       {
-               .vendor         = PCI_VENDOR_ID_OXSEMI,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_oxsemi_tornado_init,
-               .setup          = pci_default_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_MAINPINE,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .init           = pci_oxsemi_tornado_init,
-               .setup          = pci_default_setup,
-       },
-       /*
-        * Default "match everything" terminator entry
-        */
-       {
-               .vendor         = PCI_ANY_ID,
-               .device         = PCI_ANY_ID,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       }
-};
-
-static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
-{
-       return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
-}
-
-static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
-{
-       struct pci_serial_quirk *quirk;
-
-       for (quirk = pci_serial_quirks; ; quirk++)
-               if (quirk_id_matches(quirk->vendor, dev->vendor) &&
-                   quirk_id_matches(quirk->device, dev->device) &&
-                   quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
-                   quirk_id_matches(quirk->subdevice, dev->subsystem_device))
-                       break;
-       return quirk;
-}
-
-static inline int get_pci_irq(struct pci_dev *dev,
-                               const struct pciserial_board *board)
-{
-       if (board->flags & FL_NOIRQ)
-               return 0;
-       else
-               return dev->irq;
-}
-
-/*
- * This is the configuration table for all of the PCI serial boards
- * which we support.  It is directly indexed by the pci_board_num_t enum
- * value, which is encoded in the pci_device_id PCI probe table's
- * driver_data member.
- *
- * The makeup of these names are:
- *  pbn_bn{_bt}_n_baud{_offsetinhex}
- *
- *  bn         = PCI BAR number
- *  bt         = Index using PCI BARs
- *  n          = number of serial ports
- *  baud       = baud rate
- *  offsetinhex        = offset for each sequential port (in hex)
- *
- * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
- *
- * Please note: in theory if n = 1, _bt infix should make no difference.
- * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
- */
-enum pci_board_num_t {
-       pbn_default = 0,
-
-       pbn_b0_1_115200,
-       pbn_b0_2_115200,
-       pbn_b0_4_115200,
-       pbn_b0_5_115200,
-       pbn_b0_8_115200,
-
-       pbn_b0_1_921600,
-       pbn_b0_2_921600,
-       pbn_b0_4_921600,
-
-       pbn_b0_2_1130000,
-
-       pbn_b0_4_1152000,
-
-       pbn_b0_2_1843200,
-       pbn_b0_4_1843200,
-
-       pbn_b0_2_1843200_200,
-       pbn_b0_4_1843200_200,
-       pbn_b0_8_1843200_200,
-
-       pbn_b0_1_4000000,
-
-       pbn_b0_bt_1_115200,
-       pbn_b0_bt_2_115200,
-       pbn_b0_bt_4_115200,
-       pbn_b0_bt_8_115200,
-
-       pbn_b0_bt_1_460800,
-       pbn_b0_bt_2_460800,
-       pbn_b0_bt_4_460800,
-
-       pbn_b0_bt_1_921600,
-       pbn_b0_bt_2_921600,
-       pbn_b0_bt_4_921600,
-       pbn_b0_bt_8_921600,
-
-       pbn_b1_1_115200,
-       pbn_b1_2_115200,
-       pbn_b1_4_115200,
-       pbn_b1_8_115200,
-       pbn_b1_16_115200,
-
-       pbn_b1_1_921600,
-       pbn_b1_2_921600,
-       pbn_b1_4_921600,
-       pbn_b1_8_921600,
-
-       pbn_b1_2_1250000,
-
-       pbn_b1_bt_1_115200,
-       pbn_b1_bt_2_115200,
-       pbn_b1_bt_4_115200,
-
-       pbn_b1_bt_2_921600,
-
-       pbn_b1_1_1382400,
-       pbn_b1_2_1382400,
-       pbn_b1_4_1382400,
-       pbn_b1_8_1382400,
-
-       pbn_b2_1_115200,
-       pbn_b2_2_115200,
-       pbn_b2_4_115200,
-       pbn_b2_8_115200,
-
-       pbn_b2_1_460800,
-       pbn_b2_4_460800,
-       pbn_b2_8_460800,
-       pbn_b2_16_460800,
-
-       pbn_b2_1_921600,
-       pbn_b2_4_921600,
-       pbn_b2_8_921600,
-
-       pbn_b2_8_1152000,
-
-       pbn_b2_bt_1_115200,
-       pbn_b2_bt_2_115200,
-       pbn_b2_bt_4_115200,
-
-       pbn_b2_bt_2_921600,
-       pbn_b2_bt_4_921600,
-
-       pbn_b3_2_115200,
-       pbn_b3_4_115200,
-       pbn_b3_8_115200,
-
-       pbn_b4_bt_2_921600,
-       pbn_b4_bt_4_921600,
-       pbn_b4_bt_8_921600,
-
-       /*
-        * Board-specific versions.
-        */
-       pbn_panacom,
-       pbn_panacom2,
-       pbn_panacom4,
-       pbn_exsys_4055,
-       pbn_plx_romulus,
-       pbn_oxsemi,
-       pbn_oxsemi_1_4000000,
-       pbn_oxsemi_2_4000000,
-       pbn_oxsemi_4_4000000,
-       pbn_oxsemi_8_4000000,
-       pbn_intel_i960,
-       pbn_sgi_ioc3,
-       pbn_computone_4,
-       pbn_computone_6,
-       pbn_computone_8,
-       pbn_sbsxrsio,
-       pbn_exar_XR17C152,
-       pbn_exar_XR17C154,
-       pbn_exar_XR17C158,
-       pbn_exar_ibm_saturn,
-       pbn_pasemi_1682M,
-       pbn_ni8430_2,
-       pbn_ni8430_4,
-       pbn_ni8430_8,
-       pbn_ni8430_16,
-       pbn_ADDIDATA_PCIe_1_3906250,
-       pbn_ADDIDATA_PCIe_2_3906250,
-       pbn_ADDIDATA_PCIe_4_3906250,
-       pbn_ADDIDATA_PCIe_8_3906250,
-       pbn_ce4100_1_115200,
-};
-
-/*
- * uart_offset - the space between channels
- * reg_shift   - describes how the UART registers are mapped
- *               to PCI memory by the card.
- * For example IER register on SBS, Inc. PMC-OctPro is located at
- * offset 0x10 from the UART base, while UART_IER is defined as 1
- * in include/linux/serial_reg.h,
- * see first lines of serial_in() and serial_out() in 8250.c
-*/
-
-static struct pciserial_board pci_boards[] __devinitdata = {
-       [pbn_default] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_1_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_2_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_5_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 5,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_8_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_1_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_2_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_921600] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1130000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1130000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_4_1152000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1152000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1843200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1843200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_4_1843200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1843200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_2_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_4_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_8_1843200_200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 1843200,
-               .uart_offset    = 0x200,
-       },
-       [pbn_b0_1_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 4000000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_8_115200] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_460800] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b0_bt_1_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_2_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_4_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b0_bt_8_921600] = {
-               .flags          = FL_BASE0|FL_BASE_BARS,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_16_115200] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 16,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_921600] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_1250000] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 1250000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_bt_1_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_bt_2_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_bt_4_115200] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_bt_2_921600] = {
-               .flags          = FL_BASE1|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b1_1_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 1,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_2_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 2,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_4_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 4,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-       [pbn_b1_8_1382400] = {
-               .flags          = FL_BASE1,
-               .num_ports      = 8,
-               .base_baud      = 1382400,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_1_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_2_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_115200] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_1_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_16_460800] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 16,
-               .base_baud      = 460800,
-               .uart_offset    = 8,
-        },
-
-       [pbn_b2_1_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_4_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_8_921600] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_8_1152000] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 8,
-               .base_baud      = 1152000,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_bt_1_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_2_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_4_115200] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b2_bt_2_921600] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b2_bt_4_921600] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b3_2_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 2,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b3_4_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_b3_8_115200] = {
-               .flags          = FL_BASE3,
-               .num_ports      = 8,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       [pbn_b4_bt_2_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b4_bt_4_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-       [pbn_b4_bt_8_921600] = {
-               .flags          = FL_BASE4,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 8,
-       },
-
-       /*
-        * Entries following this are board-specific.
-        */
-
-       /*
-        * Panacom - IOMEM
-        */
-       [pbn_panacom] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-       [pbn_panacom2] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-       [pbn_panacom4] = {
-               .flags          = FL_BASE2|FL_BASE_BARS,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x400,
-               .reg_shift      = 7,
-       },
-
-       [pbn_exsys_4055] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
-       /* I think this entry is broken - the first_offset looks wrong --rmk */
-       [pbn_plx_romulus] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 8 << 2,
-               .reg_shift      = 2,
-               .first_offset   = 0x03,
-       },
-
-       /*
-        * This board uses the size of PCI Base region 0 to
-        * signal now many ports are available
-        */
-       [pbn_oxsemi] = {
-               .flags          = FL_BASE0|FL_REGION_SZ_CAP,
-               .num_ports      = 32,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-       [pbn_oxsemi_1_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_2_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_4_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_oxsemi_8_4000000] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 4000000,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-
-
-       /*
-        * EKF addition for i960 Boards form EKF with serial port.
-        * Max 256 ports.
-        */
-       [pbn_intel_i960] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 32,
-               .base_baud      = 921600,
-               .uart_offset    = 8 << 2,
-               .reg_shift      = 2,
-               .first_offset   = 0x10000,
-       },
-       [pbn_sgi_ioc3] = {
-               .flags          = FL_BASE0|FL_NOIRQ,
-               .num_ports      = 1,
-               .base_baud      = 458333,
-               .uart_offset    = 8,
-               .reg_shift      = 0,
-               .first_offset   = 0x20178,
-       },
-
-       /*
-        * Computone - uses IOMEM.
-        */
-       [pbn_computone_4] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_computone_6] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 6,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_computone_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 0x40,
-               .reg_shift      = 2,
-               .first_offset   = 0x200,
-       },
-       [pbn_sbsxrsio] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 460800,
-               .uart_offset    = 256,
-               .reg_shift      = 4,
-       },
-       /*
-        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
-        *  Only basic 16550A support.
-        *  XR17C15[24] are not tested, but they should work.
-        */
-       [pbn_exar_XR17C152] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_XR17C154] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_XR17C158] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-       [pbn_exar_ibm_saturn] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .uart_offset    = 0x200,
-       },
-
-       /*
-        * PA Semi PWRficient PA6T-1682M on-chip UART
-        */
-       [pbn_pasemi_1682M] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 8333333,
-       },
-       /*
-        * National Instruments 843x
-        */
-       [pbn_ni8430_16] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 16,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_8] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_4] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       [pbn_ni8430_2] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 3686400,
-               .uart_offset    = 0x10,
-               .first_offset   = 0x800,
-       },
-       /*
-        * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
-        */
-       [pbn_ADDIDATA_PCIe_1_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_2_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 2,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_4_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 4,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ADDIDATA_PCIe_8_3906250] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 8,
-               .base_baud      = 3906250,
-               .uart_offset    = 0x200,
-               .first_offset   = 0x1000,
-       },
-       [pbn_ce4100_1_115200] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 921600,
-               .reg_shift      = 2,
-       },
-};
-
-static const struct pci_device_id softmodem_blacklist[] = {
-       { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
-       { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
-       { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs.  Returns 0 on success, 1 on failure.
- */
-static int __devinit
-serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
-{
-       const struct pci_device_id *blacklist;
-       int num_iomem, num_port, first_port = -1, i;
-
-       /*
-        * If it is not a communications device or the programming
-        * interface is greater than 6, give up.
-        *
-        * (Should we try to make guesses for multiport serial devices
-        * later?)
-        */
-       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
-            ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
-           (dev->class & 0xff) > 6)
-               return -ENODEV;
-
-       /*
-        * Do not access blacklisted devices that are known not to
-        * feature serial ports.
-        */
-       for (blacklist = softmodem_blacklist;
-            blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
-            blacklist++) {
-               if (dev->vendor == blacklist->vendor &&
-                   dev->device == blacklist->device)
-                       return -ENODEV;
-       }
-
-       num_iomem = num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
-                       num_port++;
-                       if (first_port == -1)
-                               first_port = i;
-               }
-               if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
-                       num_iomem++;
-       }
-
-       /*
-        * If there is 1 or 0 iomem regions, and exactly one port,
-        * use it.  We guess the number of ports based on the IO
-        * region size.
-        */
-       if (num_iomem <= 1 && num_port == 1) {
-               board->flags = first_port;
-               board->num_ports = pci_resource_len(dev, first_port) / 8;
-               return 0;
-       }
-
-       /*
-        * Now guess if we've got a board which indexes by BARs.
-        * Each IO BAR should be 8 bytes, and they should follow
-        * consecutively.
-        */
-       first_port = -1;
-       num_port = 0;
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
-                   pci_resource_len(dev, i) == 8 &&
-                   (first_port == -1 || (first_port + num_port) == i)) {
-                       num_port++;
-                       if (first_port == -1)
-                               first_port = i;
-               }
-       }
-
-       if (num_port > 1) {
-               board->flags = first_port | FL_BASE_BARS;
-               board->num_ports = num_port;
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
-static inline int
-serial_pci_matches(const struct pciserial_board *board,
-                  const struct pciserial_board *guessed)
-{
-       return
-           board->num_ports == guessed->num_ports &&
-           board->base_baud == guessed->base_baud &&
-           board->uart_offset == guessed->uart_offset &&
-           board->reg_shift == guessed->reg_shift &&
-           board->first_offset == guessed->first_offset;
-}
-
-struct serial_private *
-pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
-{
-       struct uart_port serial_port;
-       struct serial_private *priv;
-       struct pci_serial_quirk *quirk;
-       int rc, nr_ports, i;
-
-       nr_ports = board->num_ports;
-
-       /*
-        * Find an init and setup quirks.
-        */
-       quirk = find_quirk(dev);
-
-       /*
-        * Run the new-style initialization function.
-        * The initialization function returns:
-        *  <0  - error
-        *   0  - use board->num_ports
-        *  >0  - number of ports
-        */
-       if (quirk->init) {
-               rc = quirk->init(dev);
-               if (rc < 0) {
-                       priv = ERR_PTR(rc);
-                       goto err_out;
-               }
-               if (rc)
-                       nr_ports = rc;
-       }
-
-       priv = kzalloc(sizeof(struct serial_private) +
-                      sizeof(unsigned int) * nr_ports,
-                      GFP_KERNEL);
-       if (!priv) {
-               priv = ERR_PTR(-ENOMEM);
-               goto err_deinit;
-       }
-
-       priv->dev = dev;
-       priv->quirk = quirk;
-
-       memset(&serial_port, 0, sizeof(struct uart_port));
-       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       serial_port.uartclk = board->base_baud * 16;
-       serial_port.irq = get_pci_irq(dev, board);
-       serial_port.dev = &dev->dev;
-
-       for (i = 0; i < nr_ports; i++) {
-               if (quirk->setup(priv, board, &serial_port, i))
-                       break;
-
-#ifdef SERIAL_DEBUG_PCI
-               printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
-                      serial_port.iobase, serial_port.irq, serial_port.iotype);
-#endif
-
-               priv->line[i] = serial8250_register_port(&serial_port);
-               if (priv->line[i] < 0) {
-                       printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
-                       break;
-               }
-       }
-       priv->nr = i;
-       return priv;
-
-err_deinit:
-       if (quirk->exit)
-               quirk->exit(dev);
-err_out:
-       return priv;
-}
-EXPORT_SYMBOL_GPL(pciserial_init_ports);
-
-void pciserial_remove_ports(struct serial_private *priv)
-{
-       struct pci_serial_quirk *quirk;
-       int i;
-
-       for (i = 0; i < priv->nr; i++)
-               serial8250_unregister_port(priv->line[i]);
-
-       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
-               if (priv->remapped_bar[i])
-                       iounmap(priv->remapped_bar[i]);
-               priv->remapped_bar[i] = NULL;
-       }
-
-       /*
-        * Find the exit quirks.
-        */
-       quirk = find_quirk(priv->dev);
-       if (quirk->exit)
-               quirk->exit(priv->dev);
-
-       kfree(priv);
-}
-EXPORT_SYMBOL_GPL(pciserial_remove_ports);
-
-void pciserial_suspend_ports(struct serial_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->nr; i++)
-               if (priv->line[i] >= 0)
-                       serial8250_suspend_port(priv->line[i]);
-}
-EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
-
-void pciserial_resume_ports(struct serial_private *priv)
-{
-       int i;
-
-       /*
-        * Ensure that the board is correctly configured.
-        */
-       if (priv->quirk->init)
-               priv->quirk->init(priv->dev);
-
-       for (i = 0; i < priv->nr; i++)
-               if (priv->line[i] >= 0)
-                       serial8250_resume_port(priv->line[i]);
-}
-EXPORT_SYMBOL_GPL(pciserial_resume_ports);
-
-/*
- * Probe one serial board.  Unfortunately, there is no rhyme nor reason
- * to the arrangement of serial ports on a PCI card.
- */
-static int __devinit
-pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
-{
-       struct serial_private *priv;
-       const struct pciserial_board *board;
-       struct pciserial_board tmp;
-       int rc;
-
-       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
-               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
-                       ent->driver_data);
-               return -EINVAL;
-       }
-
-       board = &pci_boards[ent->driver_data];
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       if (ent->driver_data == pbn_default) {
-               /*
-                * Use a copy of the pci_board entry for this;
-                * avoid changing entries in the table.
-                */
-               memcpy(&tmp, board, sizeof(struct pciserial_board));
-               board = &tmp;
-
-               /*
-                * We matched one of our class entries.  Try to
-                * determine the parameters of this board.
-                */
-               rc = serial_pci_guess_board(dev, &tmp);
-               if (rc)
-                       goto disable;
-       } else {
-               /*
-                * We matched an explicit entry.  If we are able to
-                * detect this boards settings with our heuristic,
-                * then we no longer need this entry.
-                */
-               memcpy(&tmp, &pci_boards[pbn_default],
-                      sizeof(struct pciserial_board));
-               rc = serial_pci_guess_board(dev, &tmp);
-               if (rc == 0 && serial_pci_matches(board, &tmp))
-                       moan_device("Redundant entry in serial pci_table.",
-                                   dev);
-       }
-
-       priv = pciserial_init_ports(dev, board);
-       if (!IS_ERR(priv)) {
-               pci_set_drvdata(dev, priv);
-               return 0;
-       }
-
-       rc = PTR_ERR(priv);
-
- disable:
-       pci_disable_device(dev);
-       return rc;
-}
-
-static void __devexit pciserial_remove_one(struct pci_dev *dev)
-{
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       pci_set_drvdata(dev, NULL);
-
-       pciserial_remove_ports(priv);
-
-       pci_disable_device(dev);
-}
-
-#ifdef CONFIG_PM
-static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
-{
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       if (priv)
-               pciserial_suspend_ports(priv);
-
-       pci_save_state(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-       return 0;
-}
-
-static int pciserial_resume_one(struct pci_dev *dev)
-{
-       int err;
-       struct serial_private *priv = pci_get_drvdata(dev);
-
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-
-       if (priv) {
-               /*
-                * The device may have been disabled.  Re-enable it.
-                */
-               err = pci_enable_device(dev);
-               /* FIXME: We cannot simply error out here */
-               if (err)
-                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
-               pciserial_resume_ports(priv);
-       }
-       return 0;
-}
-#endif
-
-static struct pci_device_id serial_pci_tbl[] = {
-       /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
-       {       PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
-               PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
-               pbn_b2_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-               pbn_b1_8_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-               pbn_b1_4_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-               pbn_b1_2_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-               pbn_b1_8_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-               pbn_b1_4_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-               pbn_b1_2_1382400 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
-               pbn_b1_2_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
-               pbn_b1_8_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
-               pbn_b1_4_921600 },
-       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
-               pbn_b1_2_1250000 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
-               pbn_b0_2_1843200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
-               pbn_b0_4_1843200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_VENDOR_ID_AFAVLAB,
-               PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
-               pbn_b0_4_1152000 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
-               pbn_b0_2_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0,
-               pbn_b0_4_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0,
-               pbn_b0_8_1843200_200 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT,
-               0, 0, pbn_exar_ibm_saturn },
-
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_1_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_115200 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_115200 },
-
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       /*
-        * VScom SPCOM800, from sl@s.pl
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_8_921600 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_4_921600 },
-       /* Unknown card - subdevice 0x1584 */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_VENDOR_ID_PLX,
-               PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
-               pbn_b0_4_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_KEYSPAN,
-               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
-               pbn_panacom },
-       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_panacom4 },
-       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_panacom2 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_VENDOR_ID_ESDGMBH,
-               PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
-               pbn_b2_4_115200 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
-               pbn_b2_4_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
-               pbn_b2_16_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
-               pbn_b2_16_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
-               pbn_b2_4_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
-               pbn_b2_8_460800 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-               PCI_SUBVENDOR_ID_EXSYS,
-               PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
-               pbn_exsys_4055 },
-       /*
-        * Megawolf Romulus PCI Serial Card, from Mike Hudson
-        * (Exoray@isys.ca)
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-               0x10b5, 0x106a, 0, 0,
-               pbn_plx_romulus },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_4_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_2_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-               0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
-               0, 0,
-               pbn_b0_4_1152000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0x9505,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-
-               /*
-                * The below card is a little controversial since it is the
-                * subject of a PCI vendor/device ID clash.  (See
-                * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
-                * For now just used the hex ID 0x950a.
-                */
-       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
-               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
-               pbn_b0_2_115200 },
-       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_2_1130000 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
-               PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_115200 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
-               PCI_ANY_ID , PCI_ANY_ID, 0, 0,
-               pbn_b2_8_1152000 },
-
-       /*
-        * Oxford Semiconductor Inc. Tornado PCI express device range.
-        */
-       {       PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       /*
-        * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
-        */
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
-               PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       /*
-        * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
-        * from skokodyn@yahoo.com
-        */
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
-               pbn_sbsxrsio },
-       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
-               pbn_sbsxrsio },
-
-       /*
-        * Digitan DS560-558, from jimd@esoft.com
-        */
-       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_115200 },
-
-       /*
-        * Titan Electronic cards
-        *  The 400L and 800L have a custom setup quirk.
-        */
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_2_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b4_bt_8_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_1_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_4_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_8_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi_2_4000000 },
-
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_460800 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_921600 },
-
-       /*
-        * Computone devices submitted by Doug McNash dmcnash@computone.com
-        */
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-               0, 0, pbn_computone_4 },
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-               0, 0, pbn_computone_8 },
-       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-               0, 0, pbn_computone_6 },
-
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_oxsemi },
-       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_921600 },
-
-       /*
-        * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
-        */
-       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_115200 },
-       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_8_115200 },
-
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_4_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_2_460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_bt_1_460800 },
-
-       /*
-        * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
-        * Cards are identified by their subsystem vendor IDs, which
-        * (in hex) match the model number.
-        *
-        * Note that JC140x are RS422/485 cards which require ox950
-        * ACR = 0x10, and as such are not currently fully supported.
-        */
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1204, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1402, 0x0002, 0, 0,
-               pbn_b0_2_921600 }, */
-/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-               0x1404, 0x0004, 0, 0,
-               pbn_b0_4_921600 }, */
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-               0x1204, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
-               0x1208, 0x0004, 0, 0,
-               pbn_b0_4_921600 },
-       /*
-        * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
-        */
-       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_1382400 },
-
-       /*
-        * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
-        */
-       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_1_1382400 },
-
-       /*
-        * RAStel 2 port modem, gerg@moreton.com.au
-        */
-       {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_bt_2_115200 },
-
-       /*
-        * EKF addition for i960 Boards form EKF with serial port
-        */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
-               0xE4BF, PCI_ANY_ID, 0, 0,
-               pbn_intel_i960 },
-
-       /*
-        * Xircom Cardbus/Ethernet combos
-        */
-       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-       /*
-        * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
-        */
-       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-
-       /*
-        * Untested PCI modems, sent in from various folks...
-        */
-
-       /*
-        * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
-        */
-       {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
-               0x1048, 0x1500, 0, 0,
-               pbn_b1_1_115200 },
-
-       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-               0xFF00, 0, 0, 0,
-               pbn_sgi_ioc3 },
-
-       /*
-        * HP Diva card
-        */
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-               PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
-               pbn_b1_1_115200 },
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_5_115200 },
-       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b2_1_115200 },
-
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_2_115200 },
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_4_115200 },
-       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b3_8_115200 },
-
-       /*
-        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
-        */
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C152 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C154 },
-       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0,
-               0, pbn_exar_XR17C158 },
-
-       /*
-        * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
-        */
-       {       PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b0_1_115200 },
-       /*
-        * ITE
-        */
-       {       PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0, 0,
-               pbn_b1_bt_1_115200 },
-
-       /*
-        * IntaShield IS-200
-        */
-       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,   /* 135a.0811 */
-               pbn_b2_2_115200 },
-       /*
-        * IntaShield IS-400
-        */
-       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
-               pbn_b2_4_115200 },
-       /*
-        * Perle PCI-RAS cards
-        */
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
-               0, 0, pbn_b2_4_921600 },
-       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
-               0, 0, pbn_b2_8_921600 },
-
-       /*
-        * Mainpine series cards: Fairly standard layout but fools
-        * parts of the autodetect in some cases and uses otherwise
-        * unmatched communications subclasses in the PCI Express case
-        */
-
-       {       /* RockForceDUO */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUATRO */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0300,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceDUO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0400,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUATRO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForce+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0600,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForce+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0700,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceOCTO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0800,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceDUO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0C00,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceQUARTRO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x0D00,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceOCTO+ */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x1D00,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceD1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2000,
-               0, 0, pbn_b0_1_115200 },
-       {       /* RockForceF1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2100,
-               0, 0, pbn_b0_1_115200 },
-       {       /* RockForceD2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceF2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2300,
-               0, 0, pbn_b0_2_115200 },
-       {       /* RockForceD4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2400,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceF4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* RockForceD8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2600,
-               0, 0, pbn_b0_8_115200 },
-       {       /* RockForceF8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x2700,
-               0, 0, pbn_b0_8_115200 },
-       {       /* IQ Express D1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3000,
-               0, 0, pbn_b0_1_115200 },
-       {       /* IQ Express F1 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3100,
-               0, 0, pbn_b0_1_115200 },
-       {       /* IQ Express D2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3200,
-               0, 0, pbn_b0_2_115200 },
-       {       /* IQ Express F2 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3300,
-               0, 0, pbn_b0_2_115200 },
-       {       /* IQ Express D4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3400,
-               0, 0, pbn_b0_4_115200 },
-       {       /* IQ Express F4 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3500,
-               0, 0, pbn_b0_4_115200 },
-       {       /* IQ Express D8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3C00,
-               0, 0, pbn_b0_8_115200 },
-       {       /* IQ Express F8 */
-               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-               PCI_VENDOR_ID_MAINPINE, 0x3D00,
-               0, 0, pbn_b0_8_115200 },
-
-
-       /*
-        * PA Semi PA6T-1682M on-chip UART
-        */
-       {       PCI_VENDOR_ID_PASEMI, 0xa004,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_pasemi_1682M },
-
-       /*
-        * National Instruments
-        */
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_16_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_16_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_8_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_4_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_b1_bt_2_115200 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_8 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_8 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_16 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_2 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_ni8430_4 },
-
-       /*
-       * ADDI-DATA GmbH communication cards <info@addi-data.com>
-       */
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA_OLD,
-               PCI_DEVICE_ID_ADDIDATA_APCI7800,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b1_8_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_4_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_2_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_b0_8_115200 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7500,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_4_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7420,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_2_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7300,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_1_3906250 },
-
-       {       PCI_VENDOR_ID_ADDIDATA,
-               PCI_DEVICE_ID_ADDIDATA_APCIe7800,
-               PCI_ANY_ID,
-               PCI_ANY_ID,
-               0,
-               0,
-               pbn_ADDIDATA_PCIe_8_3906250 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
-               PCI_VENDOR_ID_IBM, 0x0299,
-               0, 0, pbn_b0_bt_2_115200 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
-               0xA000, 0x1000,
-               0, 0, pbn_b0_1_115200 },
-
-       /*
-        * Best Connectivity PCI Multi I/O cards
-        */
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-               0xA000, 0x1000,
-               0, 0, pbn_b0_1_115200 },
-
-       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-               0xA000, 0x3004,
-               0, 0, pbn_b0_bt_4_115200 },
-       /* Intel CE4100 */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
-               PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
-               pbn_ce4100_1_115200 },
-
-
-       /*
-        * These entries match devices with class COMMUNICATION_SERIAL,
-        * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
-        */
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_SERIAL << 8,
-               0xffff00, pbn_default },
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_MODEM << 8,
-               0xffff00, pbn_default },
-       {       PCI_ANY_ID, PCI_ANY_ID,
-               PCI_ANY_ID, PCI_ANY_ID,
-               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
-               0xffff00, pbn_default },
-       { 0, }
-};
-
-static struct pci_driver serial_pci_driver = {
-       .name           = "serial",
-       .probe          = pciserial_init_one,
-       .remove         = __devexit_p(pciserial_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = pciserial_suspend_one,
-       .resume         = pciserial_resume_one,
-#endif
-       .id_table       = serial_pci_tbl,
-};
-
-static int __init serial8250_pci_init(void)
-{
-       return pci_register_driver(&serial_pci_driver);
-}
-
-static void __exit serial8250_pci_exit(void)
-{
-       pci_unregister_driver(&serial_pci_driver);
-}
-
-module_init(serial8250_pci_init);
-module_exit(serial8250_pci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
-MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
deleted file mode 100644 (file)
index 4822cb5..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- *  linux/drivers/char/8250_pnp.c
- *
- *  Probe module for 8250/16550-type ISAPNP serial ports.
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King, All Rights Reserved.
- *
- *  Ported to the Linux PnP Layer - (C) Adam Belay.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pnp.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/serial_core.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-
-#include "8250.h"
-
-#define UNKNOWN_DEV 0x3000
-
-
-static const struct pnp_device_id pnp_dev_table[] = {
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "AAC000F",              0       },
-       /* Anchor Datacomm BV */
-       /* SXPro 144 External Data Fax Modem Plug & Play */
-       {       "ADC0001",              0       },
-       /* SXPro 288 External Data Fax Modem Plug & Play */
-       {       "ADC0002",              0       },
-       /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
-       {       "AEI0250",              0       },
-       /* Actiontec ISA PNP 56K X2 Fax Modem */
-       {       "AEI1240",              0       },
-       /* Rockwell 56K ACF II Fax+Data+Voice Modem */
-       {       "AKY1021",              0 /*SPCI_FL_NO_SHIRQ*/  },
-       /* AZT3005 PnP SOUND DEVICE */
-       {       "AZT4001",              0       },
-       /* Best Data Products Inc. Smart One 336F PnP Modem */
-       {       "BDP3336",              0       },
-       /*  Boca Research */
-       /* Boca Complete Ofc Communicator 14.4 Data-FAX */
-       {       "BRI0A49",              0       },
-       /* Boca Research 33,600 ACF Modem */
-       {       "BRI1400",              0       },
-       /* Boca 33.6 Kbps Internal FD34FSVD */
-       {       "BRI3400",              0       },
-       /* Boca 33.6 Kbps Internal FD34FSVD */
-       {       "BRI0A49",              0       },
-       /* Best Data Products Inc. Smart One 336F PnP Modem */
-       {       "BDP3336",              0       },
-       /* Computer Peripherals Inc */
-       /* EuroViVa CommCenter-33.6 SP PnP */
-       {       "CPI4050",              0       },
-       /* Creative Labs */
-       /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
-       {       "CTL3001",              0       },
-       /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
-       {       "CTL3011",              0       },
-       /* Davicom ISA 33.6K Modem */
-       {       "DAV0336",              0       },
-       /* Creative */
-       /* Creative Modem Blaster Flash56 DI5601-1 */
-       {       "DMB1032",              0       },
-       /* Creative Modem Blaster V.90 DI5660 */
-       {       "DMB2001",              0       },
-       /* E-Tech */
-       /* E-Tech CyberBULLET PC56RVP */
-       {       "ETT0002",              0       },
-       /* FUJITSU */
-       /* Fujitsu 33600 PnP-I2 R Plug & Play */
-       {       "FUJ0202",              0       },
-       /* Fujitsu FMV-FX431 Plug & Play */
-       {       "FUJ0205",              0       },
-       /* Fujitsu 33600 PnP-I4 R Plug & Play */
-       {       "FUJ0206",              0       },
-       /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
-       {       "FUJ0209",              0       },
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "GVC000F",              0       },
-       /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
-       {       "GVC0303",              0       },
-       /* Hayes */
-       /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
-       {       "HAY0001",              0       },
-       /* Hayes Optima 336 V.34 + FAX + Voice PnP */
-       {       "HAY000C",              0       },
-       /* Hayes Optima 336B V.34 + FAX + Voice PnP */
-       {       "HAY000D",              0       },
-       /* Hayes Accura 56K Ext Fax Modem PnP */
-       {       "HAY5670",              0       },
-       /* Hayes Accura 56K Ext Fax Modem PnP */
-       {       "HAY5674",              0       },
-       /* Hayes Accura 56K Fax Modem PnP */
-       {       "HAY5675",              0       },
-       /* Hayes 288, V.34 + FAX */
-       {       "HAYF000",              0       },
-       /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
-       {       "HAYF001",              0       },
-       /* IBM */
-       /* IBM Thinkpad 701 Internal Modem Voice */
-       {       "IBM0033",              0       },
-       /* Intertex */
-       /* Intertex 28k8 33k6 Voice EXT PnP */
-       {       "IXDC801",              0       },
-       /* Intertex 33k6 56k Voice EXT PnP */
-       {       "IXDC901",              0       },
-       /* Intertex 28k8 33k6 Voice SP EXT PnP */
-       {       "IXDD801",              0       },
-       /* Intertex 33k6 56k Voice SP EXT PnP */
-       {       "IXDD901",              0       },
-       /* Intertex 28k8 33k6 Voice SP INT PnP */
-       {       "IXDF401",              0       },
-       /* Intertex 28k8 33k6 Voice SP EXT PnP */
-       {       "IXDF801",              0       },
-       /* Intertex 33k6 56k Voice SP EXT PnP */
-       {       "IXDF901",              0       },
-       /* Kortex International */
-       /* KORTEX 28800 Externe PnP */
-       {       "KOR4522",              0       },
-       /* KXPro 33.6 Vocal ASVD PnP */
-       {       "KORF661",              0       },
-       /* Lasat */
-       /* LASAT Internet 33600 PnP */
-       {       "LAS4040",              0       },
-       /* Lasat Safire 560 PnP */
-       {       "LAS4540",              0       },
-       /* Lasat Safire 336  PnP */
-       {       "LAS5440",              0       },
-       /* Microcom, Inc. */
-       /* Microcom TravelPorte FAST V.34 Plug & Play */
-       {       "MNP0281",              0       },
-       /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
-       {       "MNP0336",              0       },
-       /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
-       {       "MNP0339",              0       },
-       /* Microcom DeskPorte 28.8P Plug & Play */
-       {       "MNP0342",              0       },
-       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-       {       "MNP0500",              0       },
-       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
-       {       "MNP0501",              0       },
-       /* Microcom DeskPorte 28.8S Internal Plug & Play */
-       {       "MNP0502",              0       },
-       /* Motorola */
-       /* Motorola BitSURFR Plug & Play */
-       {       "MOT1105",              0       },
-       /* Motorola TA210 Plug & Play */
-       {       "MOT1111",              0       },
-       /* Motorola HMTA 200 (ISDN) Plug & Play */
-       {       "MOT1114",              0       },
-       /* Motorola BitSURFR Plug & Play */
-       {       "MOT1115",              0       },
-       /* Motorola Lifestyle 28.8 Internal */
-       {       "MOT1190",              0       },
-       /* Motorola V.3400 Plug & Play */
-       {       "MOT1501",              0       },
-       /* Motorola Lifestyle 28.8 V.34 Plug & Play */
-       {       "MOT1502",              0       },
-       /* Motorola Power 28.8 V.34 Plug & Play */
-       {       "MOT1505",              0       },
-       /* Motorola ModemSURFR External 28.8 Plug & Play */
-       {       "MOT1509",              0       },
-       /* Motorola Premier 33.6 Desktop Plug & Play */
-       {       "MOT150A",              0       },
-       /* Motorola VoiceSURFR 56K External PnP */
-       {       "MOT150F",              0       },
-       /* Motorola ModemSURFR 56K External PnP */
-       {       "MOT1510",              0       },
-       /* Motorola ModemSURFR 56K Internal PnP */
-       {       "MOT1550",              0       },
-       /* Motorola ModemSURFR Internal 28.8 Plug & Play */
-       {       "MOT1560",              0       },
-       /* Motorola Premier 33.6 Internal Plug & Play */
-       {       "MOT1580",              0       },
-       /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
-       {       "MOT15B0",              0       },
-       /* Motorola VoiceSURFR 56K Internal PnP */
-       {       "MOT15F0",              0       },
-       /* Com 1 */
-       /*  Deskline K56 Phone System PnP */
-       {       "MVX00A1",              0       },
-       /* PC Rider K56 Phone System PnP */
-       {       "MVX00F2",              0       },
-       /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
-       {       "nEC8241",              0       },
-       /* Pace 56 Voice Internal Plug & Play Modem */
-       {       "PMC2430",              0       },
-       /* Generic */
-       /* Generic standard PC COM port  */
-       {       "PNP0500",              0       },
-       /* Generic 16550A-compatible COM port */
-       {       "PNP0501",              0       },
-       /* Compaq 14400 Modem */
-       {       "PNPC000",              0       },
-       /* Compaq 2400/9600 Modem */
-       {       "PNPC001",              0       },
-       /* Dial-Up Networking Serial Cable between 2 PCs */
-       {       "PNPC031",              0       },
-       /* Dial-Up Networking Parallel Cable between 2 PCs */
-       {       "PNPC032",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC100",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC101",              0       },
-       /*  Standard 28800 bps Modem*/
-       {       "PNPC102",              0       },
-       /*  Standard Modem*/
-       {       "PNPC103",              0       },
-       /*  Standard 9600 bps Modem*/
-       {       "PNPC104",              0       },
-       /*  Standard 14400 bps Modem*/
-       {       "PNPC105",              0       },
-       /*  Standard 28800 bps Modem*/
-       {       "PNPC106",              0       },
-       /*  Standard Modem */
-       {       "PNPC107",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC108",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC109",              0       },
-       /* Standard 28800 bps Modem */
-       {       "PNPC10A",              0       },
-       /* Standard Modem */
-       {       "PNPC10B",              0       },
-       /* Standard 9600 bps Modem */
-       {       "PNPC10C",              0       },
-       /* Standard 14400 bps Modem */
-       {       "PNPC10D",              0       },
-       /* Standard 28800 bps Modem */
-       {       "PNPC10E",              0       },
-       /* Standard Modem */
-       {       "PNPC10F",              0       },
-       /* Standard PCMCIA Card Modem */
-       {       "PNP2000",              0       },
-       /* Rockwell */
-       /* Modular Technology */
-       /* Rockwell 33.6 DPF Internal PnP */
-       /* Modular Technology 33.6 Internal PnP */
-       {       "ROK0030",              0       },
-       /* Kortex International */
-       /* KORTEX 14400 Externe PnP */
-       {       "ROK0100",              0       },
-       /* Rockwell 28.8 */
-       {       "ROK4120",              0       },
-       /* Viking Components, Inc */
-       /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
-       {       "ROK4920",              0       },
-       /* Rockwell */
-       /* British Telecom */
-       /* Modular Technology */
-       /* Rockwell 33.6 DPF External PnP */
-       /* BT Prologue 33.6 External PnP */
-       /* Modular Technology 33.6 External PnP */
-       {       "RSS00A0",              0       },
-       /* Viking 56K FAX INT */
-       {       "RSS0262",              0       },
-       /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
-       {       "RSS0250",              0       },
-       /* SupraExpress 28.8 Data/Fax PnP modem */
-       {       "SUP1310",              0       },
-       /* SupraExpress 336i PnP Voice Modem */
-       {       "SUP1381",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1421",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1590",              0       },
-       /* SupraExpress 336i Sp ASVD */
-       {       "SUP1620",              0       },
-       /* SupraExpress 33.6 Data/Fax PnP modem */
-       {       "SUP1760",              0       },
-       /* SupraExpress 56i Sp Intl */
-       {       "SUP2171",              0       },
-       /* Phoebe Micro */
-       /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
-       {       "TEX0011",              0       },
-       /* Archtek America Corp. */
-       /* Archtek SmartLink Modem 3334BT Plug & Play */
-       {       "UAC000F",              0       },
-       /* 3Com Corp. */
-       /* Gateway Telepath IIvi 33.6 */
-       {       "USR0000",              0       },
-       /* U.S. Robotics Sporster 33.6K Fax INT PnP */
-       {       "USR0002",              0       },
-       /*  Sportster Vi 14.4 PnP FAX Voicemail */
-       {       "USR0004",              0       },
-       /* U.S. Robotics 33.6K Voice INT PnP */
-       {       "USR0006",              0       },
-       /* U.S. Robotics 33.6K Voice EXT PnP */
-       {       "USR0007",              0       },
-       /* U.S. Robotics Courier V.Everything INT PnP */
-       {       "USR0009",              0       },
-       /* U.S. Robotics 33.6K Voice INT PnP */
-       {       "USR2002",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR2070",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP */
-       {       "USR2080",              0       },
-       /* U.S. Robotics 56K FAX INT */
-       {       "USR3031",              0       },
-       /* U.S. Robotics 56K FAX INT */
-       {       "USR3050",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR3070",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP */
-       {       "USR3080",              0       },
-       /* U.S. Robotics 56K Voice INT PnP */
-       {       "USR3090",              0       },
-       /* U.S. Robotics 56K Message  */
-       {       "USR9100",              0       },
-       /* U.S. Robotics 56K FAX EXT PnP*/
-       {       "USR9160",              0       },
-       /* U.S. Robotics 56K FAX INT PnP*/
-       {       "USR9170",              0       },
-       /* U.S. Robotics 56K Voice EXT PnP*/
-       {       "USR9180",              0       },
-       /* U.S. Robotics 56K Voice INT PnP*/
-       {       "USR9190",              0       },
-       /* Wacom tablets */
-       {       "WACFXXX",              0       },
-       /* Compaq touchscreen */
-       {       "FPI2002",              0 },
-       /* Fujitsu Stylistic touchscreens */
-       {       "FUJ02B2",              0 },
-       {       "FUJ02B3",              0 },
-       /* Fujitsu Stylistic LT touchscreens */
-       {       "FUJ02B4",              0 },
-       /* Passive Fujitsu Stylistic touchscreens */
-       {       "FUJ02B6",              0 },
-       {       "FUJ02B7",              0 },
-       {       "FUJ02B8",              0 },
-       {       "FUJ02B9",              0 },
-       {       "FUJ02BC",              0 },
-       /* Fujitsu Wacom Tablet PC device */
-       {       "FUJ02E5",              0       },
-       /* Fujitsu P-series tablet PC device */
-       {       "FUJ02E6",              0       },
-       /* Fujitsu Wacom 2FGT Tablet PC device */
-       {       "FUJ02E7",              0       },
-       /* Fujitsu Wacom 1FGT Tablet PC device */
-       {       "FUJ02E9",              0       },
-       /*
-        * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
-        * disguise)
-        */
-       {       "LTS0001",              0       },
-       /* Rockwell's (PORALiNK) 33600 INT PNP */
-       {       "WCI0003",              0       },
-       /* Unknown PnP modems */
-       {       "PNPCXXX",              UNKNOWN_DEV     },
-       /* More unknown PnP modems */
-       {       "PNPDXXX",              UNKNOWN_DEV     },
-       {       "",                     0       }
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-static char *modem_names[] __devinitdata = {
-       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
-       "56K", "56k", "K56", "33.6", "28.8", "14.4",
-       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
-       "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
-};
-
-static int __devinit check_name(char *name)
-{
-       char **tmp;
-
-       for (tmp = modem_names; *tmp; tmp++)
-               if (strstr(name, *tmp))
-                       return 1;
-
-       return 0;
-}
-
-static int __devinit check_resources(struct pnp_dev *dev)
-{
-       resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(base); i++) {
-               if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
-                       return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Given a complete unknown PnP device, try to use some heuristics to
- * detect modems. Currently use such heuristic set:
- *     - dev->name or dev->bus->name must contain "modem" substring;
- *     - device must have only one IO region (8 byte long) with base address
- *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
- *
- * Such detection looks very ugly, but can detect at least some of numerous
- * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
- * table.
- */
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
-{
-       if (!(check_name(pnp_dev_name(dev)) ||
-               (dev->card && check_name(dev->card->name))))
-                       return -ENODEV;
-
-       if (check_resources(dev))
-               return 0;
-
-       return -ENODEV;
-}
-
-static int __devinit
-serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-       struct uart_port port;
-       int ret, line, flags = dev_id->driver_data;
-
-       if (flags & UNKNOWN_DEV) {
-               ret = serial_pnp_guess_board(dev, &flags);
-               if (ret < 0)
-                       return ret;
-       }
-
-       memset(&port, 0, sizeof(struct uart_port));
-       if (pnp_irq_valid(dev, 0))
-               port.irq = pnp_irq(dev, 0);
-       if (pnp_port_valid(dev, 0)) {
-               port.iobase = pnp_port_start(dev, 0);
-               port.iotype = UPIO_PORT;
-       } else if (pnp_mem_valid(dev, 0)) {
-               port.mapbase = pnp_mem_start(dev, 0);
-               port.iotype = UPIO_MEM;
-               port.flags = UPF_IOREMAP;
-       } else
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_PNP
-       printk(KERN_DEBUG
-               "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
-                      port.iobase, port.mapbase, port.irq, port.iotype);
-#endif
-
-       port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
-               port.flags |= UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &dev->dev;
-
-       line = serial8250_register_port(&port);
-       if (line < 0)
-               return -ENODEV;
-
-       pnp_set_drvdata(dev, (void *)((long)line + 1));
-       return 0;
-}
-
-static void __devexit serial_pnp_remove(struct pnp_dev *dev)
-{
-       long line = (long)pnp_get_drvdata(dev);
-       if (line)
-               serial8250_unregister_port(line - 1);
-}
-
-#ifdef CONFIG_PM
-static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
-{
-       long line = (long)pnp_get_drvdata(dev);
-
-       if (!line)
-               return -ENODEV;
-       serial8250_suspend_port(line - 1);
-       return 0;
-}
-
-static int serial_pnp_resume(struct pnp_dev *dev)
-{
-       long line = (long)pnp_get_drvdata(dev);
-
-       if (!line)
-               return -ENODEV;
-       serial8250_resume_port(line - 1);
-       return 0;
-}
-#else
-#define serial_pnp_suspend NULL
-#define serial_pnp_resume NULL
-#endif /* CONFIG_PM */
-
-static struct pnp_driver serial_pnp_driver = {
-       .name           = "serial",
-       .probe          = serial_pnp_probe,
-       .remove         = __devexit_p(serial_pnp_remove),
-       .suspend        = serial_pnp_suspend,
-       .resume         = serial_pnp_resume,
-       .id_table       = pnp_dev_table,
-};
-
-static int __init serial8250_pnp_init(void)
-{
-       return pnp_register_driver(&serial_pnp_driver);
-}
-
-static void __exit serial8250_pnp_exit(void)
-{
-       pnp_unregister_driver(&serial_pnp_driver);
-}
-
-module_init(serial8250_pnp_init);
-module_exit(serial8250_pnp_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
deleted file mode 100644 (file)
index c1df767..0000000
+++ /dev/null
@@ -1,1598 +0,0 @@
-#
-# Serial device configuration
-#
-
-menu "Serial drivers"
-       depends on HAS_IOMEM
-
-#
-# The new 8250/16550 serial drivers
-config SERIAL_8250
-       tristate "8250/16550 and compatible serial support"
-       select SERIAL_CORE
-       ---help---
-         This selects whether you want to include the driver for the standard
-         serial ports.  The standard answer is Y.  People who might say N
-         here are those that are setting up dedicated Ethernet WWW/FTP
-         servers, or users that have one of the various bus mice instead of a
-         serial mouse and don't intend to use their machine's standard serial
-         port for anything.  (Note that the Cyclades and Stallion multi
-         serial port drivers do not need this driver built in for them to
-         work.)
-
-         To compile this driver as a module, choose M here: the
-         module will be called 8250.
-         [WARNING: Do not compile this driver as a module if you are using
-         non-standard serial ports, since the configuration information will
-         be lost when the driver is unloaded.  This limitation may be lifted
-         in the future.]
-
-         BTW1: If you have a mouseman serial mouse which is not recognized by
-         the X window system, try running gpm first.
-
-         BTW2: If you intend to use a software modem (also called Winmodem)
-         under Linux, forget it.  These modems are crippled and require
-         proprietary drivers which are only available under Windows.
-
-         Most people will say Y or M here, so that they can use serial mice,
-         modems and similar devices connecting to the standard serial ports.
-
-config SERIAL_8250_CONSOLE
-       bool "Console on 8250/16550 and compatible serial port"
-       depends on SERIAL_8250=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode). This could be useful if some terminal or printer is connected
-         to that serial port.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyS1". (Try "man bootparam" or see the documentation of
-         your boot loader (grub or lilo or loadlin) about how to pass options
-         to the kernel at boot time.)
-
-         If you don't have a VGA card installed and you say Y here, the
-         kernel will automatically use the first serial line, /dev/ttyS0, as
-         system console.
-
-         You can set that using a kernel command line option such as
-         "console=uart8250,io,0x3f8,9600n8"
-         "console=uart8250,mmio,0xff5e0000,115200n8".
-         and it will switch to normal serial console when the corresponding 
-         port is ready.
-         "earlycon=uart8250,io,0x3f8,9600n8"
-         "earlycon=uart8250,mmio,0xff5e0000,115200n8".
-         it will not only setup early console.
-
-         If unsure, say N.
-
-config FIX_EARLYCON_MEM
-       bool
-       depends on X86
-       default y
-
-config SERIAL_8250_GSC
-       tristate
-       depends on SERIAL_8250 && GSC
-       default SERIAL_8250
-
-config SERIAL_8250_PCI
-       tristate "8250/16550 PCI device support" if EMBEDDED
-       depends on SERIAL_8250 && PCI
-       default SERIAL_8250
-       help
-         This builds standard PCI serial support. You may be able to
-         disable this feature if you only need legacy serial support.
-         Saves about 9K.
-
-config SERIAL_8250_PNP
-       tristate "8250/16550 PNP device support" if EMBEDDED
-       depends on SERIAL_8250 && PNP
-       default SERIAL_8250
-       help
-         This builds standard PNP serial support. You may be able to
-         disable this feature if you only need legacy serial support.
-
-config SERIAL_8250_HP300
-       tristate
-       depends on SERIAL_8250 && HP300
-       default SERIAL_8250
-
-config SERIAL_8250_CS
-       tristate "8250/16550 PCMCIA device support"
-       depends on PCMCIA && SERIAL_8250
-       ---help---
-         Say Y here to enable support for 16-bit PCMCIA serial devices,
-         including serial port cards, modems, and the modem functions of
-         multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
-         credit-card size devices often used with laptops.)
-
-         To compile this driver as a module, choose M here: the
-         module will be called serial_cs.
-
-         If unsure, say N.
-
-config SERIAL_8250_NR_UARTS
-       int "Maximum number of 8250/16550 serial ports"
-       depends on SERIAL_8250
-       default "4"
-       help
-         Set this to the number of serial ports you want the driver
-         to support.  This includes any ports discovered via ACPI or
-         PCI enumeration and any ports that may be added at run-time
-         via hot-plug, or any ISA multi-port serial cards.
-
-config SERIAL_8250_RUNTIME_UARTS
-       int "Number of 8250/16550 serial ports to register at runtime"
-       depends on SERIAL_8250
-       range 0 SERIAL_8250_NR_UARTS
-       default "4"
-       help
-         Set this to the maximum number of serial ports you want
-         the kernel to register at boot time.  This can be overridden
-         with the module parameter "nr_uarts", or boot-time parameter
-         8250.nr_uarts
-
-config SERIAL_8250_EXTENDED
-       bool "Extended 8250/16550 serial driver options"
-       depends on SERIAL_8250
-       help
-         If you wish to use any non-standard features of the standard "dumb"
-         driver, say Y here. This includes HUB6 support, shared serial
-         interrupts, special multiport support, support for more than the
-         four COM 1/2/3/4 boards, etc.
-
-         Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about serial driver options. If unsure, say N.
-
-config SERIAL_8250_MANY_PORTS
-       bool "Support more than 4 legacy serial ports"
-       depends on SERIAL_8250_EXTENDED && !IA64
-       help
-         Say Y here if you have dumb serial boards other than the four
-         standard COM 1/2/3/4 ports. This may happen if you have an AST
-         FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
-         from <http://www.tldp.org/docs.html#howto>), or other custom
-         serial port hardware which acts similar to standard serial port
-         hardware. If you only use the standard COM 1/2/3/4 ports, you can
-         say N here to save some memory. You can also say Y if you have an
-         "intelligent" multiport card such as Cyclades, Digiboards, etc.
-
-#
-# Multi-port serial cards
-#
-
-config SERIAL_8250_FOURPORT
-       tristate "Support Fourport cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have an AST FourPort serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_fourport.
-
-config SERIAL_8250_ACCENT
-       tristate "Support Accent cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have an Accent Async serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_accent.
-
-config SERIAL_8250_BOCA
-       tristate "Support Boca cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have a Boca serial board.  Please read the Boca
-         mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_boca.
-
-config SERIAL_8250_EXAR_ST16C554
-       tristate "Support Exar ST16C554/554D Quad UART"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         The Uplogix Envoy TU301 uses this Exar Quad UART.  If you are
-         tinkering with your Envoy TU301, or have a machine with this UART,
-         say Y here.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_exar_st16c554.
-
-config SERIAL_8250_HUB6
-       tristate "Support Hub6 cards"
-       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
-       help
-         Say Y here if you have a HUB6 serial board.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_hub6.
-
-config SERIAL_8250_SHARE_IRQ
-       bool "Support for sharing serial interrupts"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Some serial boards have hardware support which allows multiple dumb
-         serial ports on the same board to share a single IRQ. To enable
-         support for this in the serial driver, say Y here.
-
-config SERIAL_8250_DETECT_IRQ
-       bool "Autodetect IRQ on standard ports (unsafe)"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Say Y here if you want the kernel to try to guess which IRQ
-         to use for your serial port.
-
-         This is considered unsafe; it is far better to configure the IRQ in
-         a boot script using the setserial command.
-
-         If unsure, say N.
-
-config SERIAL_8250_RSA
-       bool "Support RSA serial ports"
-       depends on SERIAL_8250_EXTENDED
-       help
-         ::: To be written :::
-
-config SERIAL_8250_MCA
-       tristate "Support 8250-type ports on MCA buses"
-       depends on SERIAL_8250 != n && MCA
-       help
-         Say Y here if you have a MCA serial ports.
-
-         To compile this driver as a module, choose M here: the module
-         will be called 8250_mca.
-
-config SERIAL_8250_ACORN
-       tristate "Acorn expansion card serial port support"
-       depends on ARCH_ACORN && SERIAL_8250
-       help
-         If you have an Atomwide Serial card or Serial Port card for an Acorn
-         system, say Y to this option.  The driver can handle 1, 2, or 3 port
-         cards.  If unsure, say N.
-
-config SERIAL_8250_RM9K
-       bool "Support for MIPS RM9xxx integrated serial port"
-       depends on SERIAL_8250 != n && SERIAL_RM9000
-       select SERIAL_8250_SHARE_IRQ
-       help
-         Selecting this option will add support for the integrated serial
-         port hardware found on MIPS RM9122 and similar processors.
-         If unsure, say N.
-
-comment "Non-8250 serial port support"
-
-config SERIAL_AMBA_PL010
-       tristate "ARM AMBA PL010 serial port support"
-       depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
-       select SERIAL_CORE
-       help
-         This selects the ARM(R) AMBA(R) PrimeCell PL010 UART.  If you have
-         an Integrator/AP or Integrator/PP2 platform, or if you have a
-         Cirrus Logic EP93xx CPU, say Y or M here.
-
-         If unsure, say N.
-
-config SERIAL_AMBA_PL010_CONSOLE
-       bool "Support for console on AMBA serial port"
-       depends on SERIAL_AMBA_PL010=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         Say Y here if you wish to use an AMBA PrimeCell UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyAM0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_AMBA_PL011
-       tristate "ARM AMBA PL011 serial port support"
-       depends on ARM_AMBA
-       select SERIAL_CORE
-       help
-         This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
-         an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
-         here.
-
-         If unsure, say N.
-
-config SERIAL_AMBA_PL011_CONSOLE
-       bool "Support for console on AMBA serial port"
-       depends on SERIAL_AMBA_PL011=y
-       select SERIAL_CORE_CONSOLE
-       ---help---
-         Say Y here if you wish to use an AMBA PrimeCell UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyAMA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SB1250_DUART
-       tristate "BCM1xxx on-chip DUART serial support"
-       depends on SIBYTE_SB1xxx_SOC=y
-       select SERIAL_CORE
-       default y
-       ---help---
-         Support for the asynchronous serial interface (DUART) included in
-         the BCM1250 and derived System-On-a-Chip (SOC) devices.  Note that
-         the letter D in DUART stands for "dual", which is how the device
-         is implemented.  Depending on the SOC configuration there may be
-         one or more DUARTs available of which all are handled.
-
-         If unsure, say Y.  To compile this driver as a module, choose M here:
-         the module will be called sb1250-duart.
-
-config SERIAL_SB1250_DUART_CONSOLE
-       bool "Support for console on a BCM1xxx DUART serial port"
-       depends on SERIAL_SB1250_DUART=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         If unsure, say Y.
-
-config SERIAL_ATMEL
-       bool "AT91 / AT32 on-chip serial port support"
-       depends on (ARM && ARCH_AT91) || AVR32
-       select SERIAL_CORE
-       help
-         This enables the driver for the on-chip UARTs of the Atmel
-         AT91 and AT32 processors.
-
-config SERIAL_ATMEL_CONSOLE
-       bool "Support for console on AT91 / AT32 serial port"
-       depends on SERIAL_ATMEL=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use an on-chip UART on a Atmel
-         AT91 or AT32 processor as the system console (the system
-         console is the device which receives all kernel messages and
-         warnings and which allows logins in single user mode).
-
-config SERIAL_ATMEL_PDC
-       bool "Support DMA transfers on AT91 / AT32 serial port"
-       depends on SERIAL_ATMEL
-       default y
-       help
-         Say Y here if you wish to use the PDC to do DMA transfers to
-         and from the Atmel AT91 / AT32 serial port. In order to
-         actually use DMA transfers, make sure that the use_dma_tx
-         and use_dma_rx members in the atmel_uart_data struct is set
-         appropriately for each port.
-
-         Note that break and error handling currently doesn't work
-         properly when DMA is enabled. Make sure that ports where
-         this matters don't use DMA.
-
-config SERIAL_ATMEL_TTYAT
-       bool "Install as device ttyATn instead of ttySn"
-       depends on SERIAL_ATMEL=y
-       help
-         Say Y here if you wish to have the internal AT91 / AT32 UARTs
-         appear as /dev/ttyATn (major 204, minor starting at 154)
-         instead of the normal /dev/ttySn (major 4, minor starting at
-         64). This is necessary if you also want other UARTs, such as
-         external 8250/16C550 compatible UARTs.
-         The ttySn nodes are legally reserved for the 8250 serial driver
-         but are often misused by other serial drivers.
-
-         To use this, you should create suitable ttyATn device nodes in
-         /dev/, and pass "console=ttyATn" to the kernel.
-
-         Say Y if you have an external 8250/16C550 UART.  If unsure, say N.
-
-config SERIAL_KS8695
-       bool "Micrel KS8695 (Centaur) serial port support"
-       depends on ARCH_KS8695
-       select SERIAL_CORE
-       help
-         This selects the Micrel Centaur KS8695 UART.  Say Y here.
-
-config SERIAL_KS8695_CONSOLE
-       bool "Support for console on KS8695 (Centaur) serial port"
-       depends on SERIAL_KS8695=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a KS8695 (Centaur) UART as the
-         system console (the system console is the device which
-         receives all kernel messages and warnings and which allows
-         logins in single user mode).
-
-config SERIAL_CLPS711X
-       tristate "CLPS711X serial port support"
-       depends on ARM && ARCH_CLPS711X
-       select SERIAL_CORE
-       help
-         ::: To be written :::
-
-config SERIAL_CLPS711X_CONSOLE
-       bool "Support for console on CLPS711X serial port"
-       depends on SERIAL_CLPS711X=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyCL1". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SAMSUNG
-       tristate "Samsung SoC serial support"
-       depends on ARM && PLAT_SAMSUNG
-       select SERIAL_CORE
-       help
-         Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
-         providing /dev/ttySAC0, 1 and 2 (note, some machines may not
-         provide all of these ports, depending on how the serial port
-         pins are configured.
-
-config SERIAL_SAMSUNG_UARTS_4
-       bool
-       depends on ARM && PLAT_SAMSUNG
-       default y if CPU_S3C2443
-       help
-         Internal node for the common case of 4 Samsung compatible UARTs
-
-config SERIAL_SAMSUNG_UARTS
-       int
-       depends on ARM && PLAT_SAMSUNG
-       default 2 if ARCH_S3C2400
-       default 6 if ARCH_S5P6450
-       default 4 if SERIAL_SAMSUNG_UARTS_4
-       default 3
-       help
-         Select the number of available UART ports for the Samsung S3C
-         serial driver
-       
-config SERIAL_SAMSUNG_DEBUG
-       bool "Samsung SoC serial debug"
-       depends on SERIAL_SAMSUNG && DEBUG_LL
-       help
-         Add support for debugging the serial driver. Since this is
-         generally being used as a console, we use our own output
-         routines that go via the low-level debug printascii()
-         function.
-
-config SERIAL_SAMSUNG_CONSOLE
-       bool "Support for console on Samsung SoC serial port"
-       depends on SERIAL_SAMSUNG=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Allow selection of the S3C24XX on-board serial ports for use as
-         an virtual console.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySACx". (Try "man bootparam" or see the documentation of
-         your boot loader about how to pass options to the kernel at
-         boot time.)
-
-config SERIAL_S3C2400
-       tristate "Samsung S3C2410 Serial port support"
-       depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400
-       default y if CPU_S3C2400
-       help
-         Serial port support for the Samsung S3C2400 SoC
-
-config SERIAL_S3C2410
-       tristate "Samsung S3C2410 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C2410
-       default y if CPU_S3C2410
-       help
-         Serial port support for the Samsung S3C2410 SoC
-
-config SERIAL_S3C2412
-       tristate "Samsung S3C2412/S3C2413 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C2412
-       default y if CPU_S3C2412
-       help
-         Serial port support for the Samsung S3C2412 and S3C2413 SoC
-
-config SERIAL_S3C2440
-       tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
-       default y if CPU_S3C2440
-       default y if CPU_S3C2442
-       select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
-       help
-         Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
-
-config SERIAL_S3C24A0
-       tristate "Samsung S3C24A0 Serial port support"
-       depends on SERIAL_SAMSUNG && CPU_S3C24A0
-       default y if CPU_S3C24A0
-       help
-         Serial port support for the Samsung S3C24A0 SoC
-
-config SERIAL_S3C6400
-       tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
-       select SERIAL_SAMSUNG_UARTS_4
-       default y
-       help
-         Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
-         and S5PC100 SoCs
-
-config SERIAL_S5PV210
-       tristate "Samsung S5PV210 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310)
-       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310)
-       default y
-       help
-         Serial port support for Samsung's S5P Family of SoC's
-
-
-config SERIAL_MAX3100
-       tristate "MAX3100 support"
-       depends on SPI
-       select SERIAL_CORE
-       help
-         MAX3100 chip support
-
-config SERIAL_MAX3107
-       tristate "MAX3107 support"
-       depends on SPI
-       select SERIAL_CORE
-       help
-         MAX3107 chip support
-
-config SERIAL_MAX3107_AAVA
-       tristate "MAX3107 AAVA platform support"
-       depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB
-       select SERIAL_CORE
-       help
-         Support for the MAX3107 chip configuration found on the AAVA
-         platform. Includes the extra initialisation and GPIO support
-         neded for this device.
-
-config SERIAL_DZ
-       bool "DECstation DZ serial driver"
-       depends on MACH_DECSTATION && 32BIT
-       select SERIAL_CORE
-       default y
-       ---help---
-         DZ11-family serial controllers for DECstations and VAXstations,
-         including the DC7085, M7814, and M7819.
-
-config SERIAL_DZ_CONSOLE
-       bool "Support console on DECstation DZ serial driver"
-       depends on SERIAL_DZ=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         Note that the firmware uses ttyS3 as the serial console on
-         DECstations that use this driver.
-
-         If unsure, say Y.
-
-config SERIAL_ZS
-       tristate "DECstation Z85C30 serial support"
-       depends on MACH_DECSTATION
-       select SERIAL_CORE
-       default y
-       ---help---
-         Support for the Zilog 85C350 serial communications controller used
-         for serial ports in newer DECstation systems.  These include the
-         DECsystem 5900 and all models of the DECstation and DECsystem 5000
-         systems except from model 200.
-
-         If unsure, say Y.  To compile this driver as a module, choose M here:
-         the module will be called zs.
-
-config SERIAL_ZS_CONSOLE
-       bool "Support for console on a DECstation Z85C30 serial port"
-       depends on SERIAL_ZS=y
-       select SERIAL_CORE_CONSOLE
-       default y
-       ---help---
-         If you say Y here, it will be possible to use a serial port as the
-         system console (the system console is the device which receives all
-         kernel messages and warnings and which allows logins in single user
-         mode).
-
-         Note that the firmware uses ttyS1 as the serial console on the
-         Maxine and ttyS3 on the others using this driver.
-
-         If unsure, say Y.
-
-config SERIAL_21285
-       tristate "DC21285 serial port support"
-       depends on ARM && FOOTBRIDGE
-       select SERIAL_CORE
-       help
-         If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
-         PCI bridge you can enable its onboard serial port by enabling this
-         option.
-
-config SERIAL_21285_CONSOLE
-       bool "Console on DC21285 serial port"
-       depends on SERIAL_21285=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the 21285 footbridge you can
-         make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyFB". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_MPSC
-       bool "Marvell MPSC serial port support"
-       depends on PPC32 && MV64X60
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the Marvell MPSC serial controller.
-
-config SERIAL_MPSC_CONSOLE
-       bool "Support for console on Marvell MPSC serial port"
-       depends on SERIAL_MPSC
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you want to support a serial console on a Marvell MPSC.
-
-config SERIAL_PXA
-       bool "PXA serial port support"
-       depends on ARCH_PXA || ARCH_MMP
-       select SERIAL_CORE
-       help
-         If you have a machine based on an Intel XScale PXA2xx CPU you
-         can enable its onboard serial ports by enabling this option.
-
-config SERIAL_PXA_CONSOLE
-       bool "Console on PXA serial port"
-       depends on SERIAL_PXA
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Intel XScale PXA
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SA1100
-       bool "SA1100 serial port support"
-       depends on ARM && ARCH_SA1100
-       select SERIAL_CORE
-       help
-         If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
-         can enable its onboard serial port by enabling this option.
-         Please read <file:Documentation/arm/SA1100/serial_UART> for further
-         info.
-
-config SERIAL_SA1100_CONSOLE
-       bool "Console on SA1100 serial port"
-       depends on SERIAL_SA1100
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the SA1100/SA1110 StrongARM
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_MRST_MAX3110
-       tristate "SPI UART driver for Max3110"
-       depends on SPI_DW_PCI
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       help
-         This is the UART protocol driver for the MAX3110 device on
-         the Intel Moorestown platform. On other systems use the max3100
-         driver.
-
-config SERIAL_MFD_HSU
-       tristate "Medfield High Speed UART support"
-       depends on PCI
-       select SERIAL_CORE
-
-config SERIAL_MFD_HSU_CONSOLE
-       boolean "Medfile HSU serial console support"
-       depends on SERIAL_MFD_HSU=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_BFIN
-       tristate "Blackfin serial port support"
-       depends on BLACKFIN
-       select SERIAL_CORE
-       select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
-       help
-         Add support for the built-in UARTs on the Blackfin.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bfin_5xx.
-
-config SERIAL_BFIN_CONSOLE
-       bool "Console on Blackfin serial port"
-       depends on SERIAL_BFIN=y
-       select SERIAL_CORE_CONSOLE
-
-choice
-       prompt "UART Mode"
-       depends on SERIAL_BFIN
-       default SERIAL_BFIN_DMA
-       help
-         This driver supports the built-in serial ports of the Blackfin family
-         of CPUs
-
-config SERIAL_BFIN_DMA
-       bool "DMA mode"
-       depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n
-       help
-         This driver works under DMA mode. If this option is selected, the
-         blackfin simple dma driver is also enabled.
-
-config SERIAL_BFIN_PIO
-       bool "PIO mode"
-       help
-         This driver works under PIO mode.
-
-endchoice
-
-config SERIAL_BFIN_UART0
-       bool "Enable UART0"
-       depends on SERIAL_BFIN
-       help
-         Enable UART0
-
-config BFIN_UART0_CTSRTS
-       bool "Enable UART0 hardware flow control"
-       depends on SERIAL_BFIN_UART0
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART1
-       bool "Enable UART1"
-       depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
-       help
-         Enable UART1
-
-config BFIN_UART1_CTSRTS
-       bool "Enable UART1 hardware flow control"
-       depends on SERIAL_BFIN_UART1
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART2
-       bool "Enable UART2"
-       depends on SERIAL_BFIN && (BF54x || BF538 || BF539)
-       help
-         Enable UART2
-
-config BFIN_UART2_CTSRTS
-       bool "Enable UART2 hardware flow control"
-       depends on SERIAL_BFIN_UART2
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_UART3
-       bool "Enable UART3"
-       depends on SERIAL_BFIN && (BF54x)
-       help
-         Enable UART3
-
-config BFIN_UART3_CTSRTS
-       bool "Enable UART3 hardware flow control"
-       depends on SERIAL_BFIN_UART3
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_IMX
-       bool "IMX serial port support"
-       depends on ARM && (ARCH_IMX || ARCH_MXC)
-       select SERIAL_CORE
-       select RATIONAL
-       help
-         If you have a machine based on a Motorola IMX CPU you
-         can enable its onboard serial port by enabling this option.
-
-config SERIAL_IMX_CONSOLE
-       bool "Console on IMX serial port"
-       depends on SERIAL_IMX
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Motorola IMX
-         CPU you can make it the console by answering Y to this option.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttySA0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_UARTLITE
-       tristate "Xilinx uartlite serial port support"
-       depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the Xilinx uartlite serial controller.
-
-         To compile this driver as a module, choose M here: the
-         module will be called uartlite.
-
-config SERIAL_UARTLITE_CONSOLE
-       bool "Support for console on Xilinx uartlite serial port"
-       depends on SERIAL_UARTLITE=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a Xilinx uartlite as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-config SERIAL_SUNCORE
-       bool
-       depends on SPARC
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       default y
-
-config SERIAL_SUNZILOG
-       tristate "Sun Zilog8530 serial support"
-       depends on SPARC
-       help
-         This driver supports the Zilog8530 serial ports found on many Sparc
-         systems.  Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_SUNZILOG_CONSOLE
-       bool "Console on Sun Zilog8530 serial port"
-       depends on SERIAL_SUNZILOG=y
-       help
-         If you would like to be able to use the Zilog8530 serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_SUNSU
-       tristate "Sun SU serial support"
-       depends on SPARC && PCI
-       help
-         This driver supports the 8250 serial ports that run the keyboard and
-         mouse on (PCI) UltraSPARC systems.  Say Y or M if you want to be able
-         to these serial ports.
-
-config SERIAL_SUNSU_CONSOLE
-       bool "Console on Sun SU serial port"
-       depends on SERIAL_SUNSU=y
-       help
-         If you would like to be able to use the SU serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_MUX
-       tristate "Serial MUX support"
-       depends on GSC
-       select SERIAL_CORE
-       default y
-       ---help---
-         Saying Y here will enable the hardware MUX serial driver for
-         the Nova, K class systems and D class with a 'remote control card'.
-         The hardware MUX is not 8250/16550 compatible therefore the
-         /dev/ttyB0 device is shared between the Serial MUX and the PDC
-         software console. The following steps need to be completed to use
-         the Serial MUX:
-
-           1. create the device entry (mknod /dev/ttyB0 c 11 0)
-           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
-           3. Add device ttyB0 to /etc/securetty (if you want to log on as
-                root on this console.)
-           4. Change the kernel command console parameter to: console=ttyB0
-
-config SERIAL_MUX_CONSOLE
-       bool "Support for console on serial MUX"
-       depends on SERIAL_MUX=y
-       select SERIAL_CORE_CONSOLE
-       default y
-
-config PDC_CONSOLE
-       bool "PDC software console support"
-       depends on PARISC && !SERIAL_MUX && VT
-       default n
-       help
-         Saying Y here will enable the software based PDC console to be 
-         used as the system console.  This is useful for machines in 
-         which the hardware based console has not been written yet.  The
-         following steps must be competed to use the PDC console:
-
-           1. create the device entry (mknod /dev/ttyB0 c 11 0)
-           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
-           3. Add device ttyB0 to /etc/securetty (if you want to log on as
-                root on this console.)
-           4. Change the kernel command console parameter to: console=ttyB0
-
-config SERIAL_SUNSAB
-       tristate "Sun Siemens SAB82532 serial support"
-       depends on SPARC && PCI
-       help
-         This driver supports the Siemens SAB82532 DUSCC serial ports on newer
-         (PCI) UltraSPARC systems.  Say Y or M if you want to be able to these
-         serial ports.
-
-config SERIAL_SUNSAB_CONSOLE
-       bool "Console on Sun Siemens SAB82532 serial port"
-       depends on SERIAL_SUNSAB=y
-       help
-         If you would like to be able to use the SAB82532 serial port
-         on your Sparc system as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_SUNHV
-       bool "Sun4v Hypervisor Console support"
-       depends on SPARC64
-       help
-         This driver supports the console device found on SUN4V Sparc
-         systems.  Say Y if you want to be able to use this device.
-
-config SERIAL_IP22_ZILOG
-       tristate "SGI Zilog8530 serial support"
-       depends on SGI_HAS_ZILOG
-       select SERIAL_CORE
-       help
-         This driver supports the Zilog8530 serial ports found on SGI
-         systems.  Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_IP22_ZILOG_CONSOLE
-       bool "Console on SGI Zilog8530 serial port"
-       depends on SERIAL_IP22_ZILOG=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_SH_SCI
-       tristate "SuperH SCI(F) serial port support"
-       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
-       select SERIAL_CORE
-
-config SERIAL_SH_SCI_NR_UARTS
-       int "Maximum number of SCI(F) serial ports"
-       depends on SERIAL_SH_SCI
-       default "2"
-
-config SERIAL_SH_SCI_CONSOLE
-       bool "Support for console on SuperH SCI(F)"
-       depends on SERIAL_SH_SCI=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_SH_SCI_DMA
-       bool "DMA support"
-       depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
-
-config SERIAL_PNX8XXX
-       bool "Enable PNX8XXX SoCs' UART Support"
-       depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
-       select SERIAL_CORE
-       help
-         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
-         and you want to use serial ports, say Y.  Otherwise, say N.
-
-config SERIAL_PNX8XXX_CONSOLE
-       bool "Enable PNX8XX0 serial console"
-       depends on SERIAL_PNX8XXX
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
-         and you want to use serial console, say Y. Otherwise, say N.
-
-config SERIAL_CORE
-       tristate
-
-config SERIAL_CORE_CONSOLE
-       bool
-
-config CONSOLE_POLL
-       bool
-
-config SERIAL_68328
-       bool "68328 serial support"
-       depends on M68328 || M68EZ328 || M68VZ328
-       help
-         This driver supports the built-in serial port of the Motorola 68328
-         (standard, EZ and VZ varieties).
-
-config SERIAL_68328_RTS_CTS
-       bool "Support RTS/CTS on 68328 serial port"
-       depends on SERIAL_68328
-
-config SERIAL_MCF
-       bool "Coldfire serial support"
-       depends on COLDFIRE
-       select SERIAL_CORE
-       help
-         This serial driver supports the Freescale Coldfire serial ports.
-
-config SERIAL_MCF_BAUDRATE
-       int "Default baudrate for Coldfire serial ports"
-       depends on SERIAL_MCF
-       default 19200
-       help
-         This setting lets you define what the default baudrate is for the
-         ColdFire serial ports. The usual default varies from board to board,
-         and this setting is a way of catering for that.
-
-config SERIAL_MCF_CONSOLE
-       bool "Coldfire serial console support"
-       depends on SERIAL_MCF
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a ColdFire internal serial port to be the system console.
-
-config SERIAL_68360_SMC
-       bool "68360 SMC uart support"
-       depends on M68360
-       help
-         This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
-       bool "68360 SCC uart support"
-       depends on M68360
-       help
-         This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
-       bool
-       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
-       default y
-
-config SERIAL_PMACZILOG
-       tristate "Mac or PowerMac z85c30 ESCC support"
-       depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
-       select SERIAL_CORE
-       help
-         This driver supports the Zilog z85C30 serial ports found on
-         (Power)Mac machines.
-         Say Y or M if you want to be able to these serial ports.
-
-config SERIAL_PMACZILOG_TTYS
-       bool "Use ttySn device nodes for Zilog z85c30"
-       depends on SERIAL_PMACZILOG
-       help
-         The pmac_zilog driver for the z85C30 chip on many powermacs
-         historically used the device numbers for /dev/ttySn.  The
-         8250 serial port driver also uses these numbers, which means
-         the two drivers being unable to coexist; you could not use
-         both z85C30 and 8250 type ports at the same time.
-
-         If this option is not selected, the pmac_zilog driver will
-         use the device numbers allocated for /dev/ttyPZn.  This allows
-         the pmac_zilog and 8250 drivers to co-exist, but may cause
-         existing userspace setups to break.  Programs that need to
-         access the built-in serial ports on powermacs will need to
-         be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
-
-         If you enable this option, any z85c30 ports in the system will
-         be registered as ttyS0 onwards as in the past, and you will be
-         unable to use the 8250 module for PCMCIA or other 16C550-style
-         UARTs.
-
-         Say N unless you need the z85c30 ports on your (Power)Mac
-         to appear as /dev/ttySn.
-
-config SERIAL_PMACZILOG_CONSOLE
-       bool "Console on Mac or PowerMac z85c30 serial port"
-       depends on SERIAL_PMACZILOG=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you would like to be able to use the z85c30 serial port
-         on your (Power)Mac as the console, you can do so by answering
-         Y to this option.
-
-config SERIAL_LH7A40X
-       tristate "Sharp LH7A40X embedded UART support"
-       depends on ARM && ARCH_LH7A40X
-       select SERIAL_CORE
-       help
-         This enables support for the three on-board UARTs of the
-         Sharp LH7A40X series CPUs.  Choose Y or M.
-
-config SERIAL_LH7A40X_CONSOLE
-       bool "Support for console on Sharp LH7A40X serial port"
-       depends on SERIAL_LH7A40X=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use one of the serial ports as the
-         system console--the system console is the device which
-         receives all kernel messages and warnings and which allows
-         logins in single user mode.
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the default system console, but
-         you can alter that using a kernel command line, for example
-         "console=ttyAM1".
-
-config SERIAL_CPM
-       tristate "CPM SCC/SMC serial port support"
-       depends on CPM2 || 8xx
-       select SERIAL_CORE
-       help
-         This driver supports the SCC and SMC serial ports on Motorola 
-         embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
-
-config SERIAL_CPM_CONSOLE
-       bool "Support for console on CPM SCC/SMC serial port"
-       depends on SERIAL_CPM=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you wish to use a SCC or SMC CPM UART as the system
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-
-         Even if you say Y here, the currently visible framebuffer console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyCPM0". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
-
-config SERIAL_SGI_L1_CONSOLE
-       bool "SGI Altix L1 serial console support"
-       depends on IA64_GENERIC || IA64_SGI_SN2
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       help
-               If you have an SGI Altix and you would like to use the system
-               controller serial port as your console (you want this!),
-               say Y.  Otherwise, say N.
-
-config SERIAL_MPC52xx
-       tristate "Freescale MPC52xx/MPC512x family PSC serial support"
-       depends on PPC_MPC52xx || PPC_MPC512x
-       select SERIAL_CORE
-       help
-         This driver supports MPC52xx and MPC512x PSC serial ports. If you would
-         like to use them, you must answer Y or M to this option. Note that
-         for use as console, it must be included in kernel and not as a
-         module.
-
-config SERIAL_MPC52xx_CONSOLE
-       bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
-       depends on SERIAL_MPC52xx=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Select this options if you'd like to use one of the PSC serial port
-         of the Freescale MPC52xx family as a console.
-
-config SERIAL_MPC52xx_CONSOLE_BAUD
-       int "Freescale MPC52xx/MPC512x family PSC serial port baud"
-       depends on SERIAL_MPC52xx_CONSOLE=y
-       default "9600"
-       help
-         Select the MPC52xx console baud rate.
-         This value is only used if the bootloader doesn't pass in the
-         console baudrate
-
-config SERIAL_ICOM
-       tristate "IBM Multiport Serial Adapter"
-       depends on PCI && (PPC_ISERIES || PPC_PSERIES)
-       select SERIAL_CORE
-       select FW_LOADER
-       help
-         This driver is for a family of multiport serial adapters
-         including 2 port RVX, 2 port internal modem, 4 port internal
-         modem and a split 1 port RVX and 1 port internal modem.
-
-         This driver can also be built as a module.  If so, the module
-         will be called icom.
-
-config SERIAL_M32R_SIO
-       bool "M32R SIO I/F"
-       depends on M32R
-       default y
-       select SERIAL_CORE
-       help
-         Say Y here if you want to use the M32R serial controller.
-
-config SERIAL_M32R_SIO_CONSOLE
-       bool "use SIO console"
-       depends on SERIAL_M32R_SIO=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Say Y here if you want to support a serial console.
-
-         If you use an M3T-M32700UT or an OPSPUT platform,
-         please say also y for SERIAL_M32R_PLDSIO.
-
-config SERIAL_M32R_PLDSIO
-       bool "M32R SIO I/F on a PLD"
-       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT)
-       default n
-       help
-         Say Y here if you want to use the M32R serial controller
-         on a PLD (Programmable Logic Device).
-
-         If you use an M3T-M32700UT or an OPSPUT platform,
-         please say Y.
-
-config SERIAL_TXX9
-       bool "TMPTX39XX/49XX SIO support"
-       depends on HAS_TXX9_SERIAL
-       select SERIAL_CORE
-       default y
-
-config HAS_TXX9_SERIAL
-       bool
-
-config SERIAL_TXX9_NR_UARTS
-       int "Maximum number of TMPTX39XX/49XX SIO ports"
-       depends on SERIAL_TXX9
-       default "6"
-
-config SERIAL_TXX9_CONSOLE
-       bool "TMPTX39XX/49XX SIO Console support"
-       depends on SERIAL_TXX9=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_TXX9_STDSERIAL
-       bool "TX39XX/49XX SIO act as standard serial"
-       depends on !SERIAL_8250 && SERIAL_TXX9
-
-config SERIAL_VR41XX
-       tristate "NEC VR4100 series Serial Interface Unit support"
-       depends on CPU_VR41XX
-       select SERIAL_CORE
-       help
-         If you have a NEC VR4100 series processor and you want to use
-         Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
-         (not include VR4111/VR4121 DSIU), say Y.  Otherwise, say N.
-
-config SERIAL_VR41XX_CONSOLE
-       bool "Enable NEC VR4100 series Serial Interface Unit console"
-       depends on SERIAL_VR41XX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have a NEC VR4100 series processor and you want to use
-         a console on a serial port, say Y.  Otherwise, say N.
-
-config SERIAL_JSM
-       tristate "Digi International NEO PCI Support"
-       depends on PCI
-       select SERIAL_CORE
-       help
-         This is a driver for Digi International's Neo series
-         of cards which provide multiple serial ports. You would need
-         something like this to connect more than two modems to your Linux
-         box, for instance in order to become a dial-in server. This driver
-         supports PCI boards only.
-
-         If you have a card like this, say Y here, otherwise say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called jsm.
-
-config SERIAL_SGI_IOC4
-       tristate "SGI IOC4 controller serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
-       select SERIAL_CORE
-       help
-               If you have an SGI Altix with an IOC4 based Base IO card
-               and wish to use the serial ports on this card, say Y.
-               Otherwise, say N.
-
-config SERIAL_SGI_IOC3
-       tristate "SGI Altix IOC3 serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
-       select SERIAL_CORE
-       help
-         If you have an SGI Altix with an IOC3 serial card,
-         say Y or M.  Otherwise, say N.
-
-config SERIAL_MSM
-       bool "MSM on-chip serial port support"
-       depends on ARM && ARCH_MSM
-       select SERIAL_CORE
-
-config SERIAL_MSM_CONSOLE
-       bool "MSM serial console support"
-       depends on SERIAL_MSM=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_VT8500
-       bool "VIA VT8500 on-chip serial port support"
-       depends on ARM && ARCH_VT8500
-       select SERIAL_CORE
-
-config SERIAL_VT8500_CONSOLE
-       bool "VIA VT8500 serial console support"
-       depends on SERIAL_VT8500=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_NETX
-       tristate "NetX serial port support"
-       depends on ARM && ARCH_NETX
-       select SERIAL_CORE
-       help
-         If you have a machine based on a Hilscher NetX SoC you
-         can enable its onboard serial port by enabling this option.
-
-          To compile this driver as a module, choose M here: the
-          module will be called netx-serial.
-
-config SERIAL_NETX_CONSOLE
-       bool "Console on NetX serial port"
-       depends on SERIAL_NETX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the Hilscher NetX SoC
-         you can make it the console by answering Y to this option.
-
-config SERIAL_OF_PLATFORM
-       tristate "Serial port on Open Firmware platform bus"
-       depends on OF
-       depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
-       help
-         If you have a PowerPC based system that has serial ports
-         on a platform specific bus, you should enable this option.
-         Currently, only 8250 compatible ports are supported, but
-         others can easily be added.
-
-config SERIAL_OMAP
-       tristate "OMAP serial port support"
-       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
-       select SERIAL_CORE
-       help
-         If you have a machine based on an Texas Instruments OMAP CPU you
-         can enable its onboard serial ports by enabling this option.
-
-         By enabling this option you take advantage of dma feature available
-         with the omap-serial driver. DMA support can be enabled from platform
-         data.
-
-config SERIAL_OMAP_CONSOLE
-       bool "Console on OMAP serial port"
-       depends on SERIAL_OMAP
-       select SERIAL_CORE_CONSOLE
-       help
-         Select this option if you would like to use omap serial port as
-         console.
-
-         Even if you say Y here, the currently visible virtual console
-         (/dev/tty0) will still be used as the system console by default, but
-         you can alter that using a kernel command line option such as
-         "console=ttyOx". (Try "man bootparam" or see the documentation of
-         your boot loader about how to pass options to the kernel at
-         boot time.)
-
-config SERIAL_OF_PLATFORM_NWPSERIAL
-       tristate "NWP serial port driver"
-       depends on PPC_OF && PPC_DCR
-       select SERIAL_OF_PLATFORM
-       select SERIAL_CORE_CONSOLE
-       select SERIAL_CORE
-       help
-         This driver supports the cell network processor nwp serial
-         device.
-
-config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-       bool "Console on NWP serial port"
-       depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Support for Console on the NWP serial ports.
-
-config SERIAL_QE
-       tristate "Freescale QUICC Engine serial port support"
-       depends on QUICC_ENGINE
-       select SERIAL_CORE
-       select FW_LOADER
-       default n
-       help
-         This driver supports the QE serial ports on Freescale embedded
-         PowerPC that contain a QUICC Engine.
-
-config SERIAL_SC26XX
-       tristate "SC2681/SC2692 serial port support"
-       depends on SNI_RM
-       select SERIAL_CORE
-       help
-         This is a driver for the onboard serial ports of
-         older RM400 machines.
-
-config SERIAL_SC26XX_CONSOLE
-       bool "Console on SC2681/SC2692 serial port"
-       depends on SERIAL_SC26XX
-       select SERIAL_CORE_CONSOLE
-       help
-         Support for Console on SC2681/SC2692 serial ports.
-
-config SERIAL_BFIN_SPORT
-       tristate "Blackfin SPORT emulate UART"
-       depends on BLACKFIN
-       select SERIAL_CORE
-       help
-         Enable SPORT emulate UART on Blackfin series.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bfin_sport_uart.
-
-config SERIAL_BFIN_SPORT_CONSOLE
-       bool "Console on Blackfin sport emulated uart"
-       depends on SERIAL_BFIN_SPORT=y
-       select SERIAL_CORE_CONSOLE
-
-config SERIAL_BFIN_SPORT0_UART
-       bool "Enable UART over SPORT0"
-       depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
-       help
-         Enable UART over SPORT0
-
-config SERIAL_BFIN_SPORT0_UART_CTSRTS
-       bool "Enable UART over SPORT0 hardware flow control"
-       depends on SERIAL_BFIN_SPORT0_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT1_UART
-       bool "Enable UART over SPORT1"
-       depends on SERIAL_BFIN_SPORT
-       help
-         Enable UART over SPORT1
-
-config SERIAL_BFIN_SPORT1_UART_CTSRTS
-       bool "Enable UART over SPORT1 hardware flow control"
-       depends on SERIAL_BFIN_SPORT1_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT2_UART
-       bool "Enable UART over SPORT2"
-       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
-       help
-         Enable UART over SPORT2
-
-config SERIAL_BFIN_SPORT2_UART_CTSRTS
-       bool "Enable UART over SPORT2 hardware flow control"
-       depends on SERIAL_BFIN_SPORT2_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_BFIN_SPORT3_UART
-       bool "Enable UART over SPORT3"
-       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
-       help
-         Enable UART over SPORT3
-
-config SERIAL_BFIN_SPORT3_UART_CTSRTS
-       bool "Enable UART over SPORT3 hardware flow control"
-       depends on SERIAL_BFIN_SPORT3_UART
-       help
-         Enable hardware flow control in the driver.
-
-config SERIAL_TIMBERDALE
-       tristate "Support for timberdale UART"
-       select SERIAL_CORE
-       ---help---
-       Add support for UART controller on timberdale.
-
-config SERIAL_BCM63XX
-       tristate "bcm63xx serial port support"
-       select SERIAL_CORE
-       depends on BCM63XX
-       help
-         If you have a bcm63xx CPU, you can enable its onboard
-         serial port by enabling this options.
-
-          To compile this driver as a module, choose M here: the
-          module will be called bcm963xx_uart.
-
-config SERIAL_BCM63XX_CONSOLE
-       bool "Console on bcm63xx serial port"
-       depends on SERIAL_BCM63XX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         If you have enabled the serial port on the bcm63xx CPU
-         you can make it the console by answering Y to this option.
-
-config SERIAL_GRLIB_GAISLER_APBUART
-       tristate "GRLIB APBUART serial support"
-       depends on OF
-       ---help---
-       Add support for the GRLIB APBUART serial port.
-
-config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
-       bool "Console on GRLIB APBUART serial port"
-       depends on SERIAL_GRLIB_GAISLER_APBUART=y
-       select SERIAL_CORE_CONSOLE
-       help
-       Support for running a console on the GRLIB APBUART
-
-config SERIAL_ALTERA_JTAGUART
-       tristate "Altera JTAG UART support"
-       select SERIAL_CORE
-       help
-         This driver supports the Altera JTAG UART port.
-
-config SERIAL_ALTERA_JTAGUART_CONSOLE
-       bool "Altera JTAG UART console support"
-       depends on SERIAL_ALTERA_JTAGUART=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a Altera JTAG UART port to be the system console.
-
-config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
-       bool "Bypass output when no connection"
-       depends on SERIAL_ALTERA_JTAGUART_CONSOLE
-       select SERIAL_CORE_CONSOLE
-       help
-         Bypass console output and keep going even if there is no
-         JTAG terminal connection with the host.
-
-config SERIAL_ALTERA_UART
-       tristate "Altera UART support"
-       select SERIAL_CORE
-       help
-         This driver supports the Altera softcore UART port.
-
-config SERIAL_ALTERA_UART_MAXPORTS
-       int "Maximum number of Altera UART ports"
-       depends on SERIAL_ALTERA_UART
-       default 4
-       help
-         This setting lets you define the maximum number of the Altera
-         UART ports. The usual default varies from board to board, and
-         this setting is a way of catering for that.
-
-config SERIAL_ALTERA_UART_BAUDRATE
-       int "Default baudrate for Altera UART ports"
-       depends on SERIAL_ALTERA_UART
-       default 115200
-       help
-         This setting lets you define what the default baudrate is for the
-         Altera UART ports. The usual default varies from board to board,
-         and this setting is a way of catering for that.
-
-config SERIAL_ALTERA_UART_CONSOLE
-       bool "Altera UART console support"
-       depends on SERIAL_ALTERA_UART=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Enable a Altera UART port to be the system console.
-
-config SERIAL_IFX6X60
-        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
-       depends on GPIOLIB && SPI && EXPERIMENTAL
-       help
-         Support for the IFX6x60 modem devices on Intel MID platforms.
-
-config SERIAL_PCH_UART
-       tristate "Intel EG20T PCH UART"
-       depends on PCI && DMADEVICES
-       select SERIAL_CORE
-       select PCH_DMA
-       help
-         This driver is for PCH(Platform controller Hub) UART of Intel EG20T
-         which is an IOH(Input/Output Hub) for x86 embedded processor.
-         Enabling PCH_DMA, this PCH UART works as DMA mode.
-endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
deleted file mode 100644 (file)
index 8ea92e9..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# Makefile for the kernel serial device drivers.
-#
-
-obj-$(CONFIG_SERIAL_CORE) += serial_core.o
-obj-$(CONFIG_SERIAL_21285) += 21285.o
-
-# These Sparc drivers have to appear before others such as 8250
-# which share ttySx minor node space.  Otherwise console device
-# names change and other unplesantries.
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
-
-obj-$(CONFIG_SERIAL_8250) += 8250.o
-obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
-obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
-obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
-obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
-obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
-obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
-obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
-obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
-obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
-obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
-obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
-obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
-obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
-obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
-obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
-obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
-obj-$(CONFIG_SERIAL_PXA) += pxa.o
-obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
-obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
-obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
-obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
-obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
-obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
-obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
-obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
-obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
-obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
-obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
-obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
-obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
-obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
-obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
-obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_MUX) += mux.o
-obj-$(CONFIG_SERIAL_68328) += 68328serial.o
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_MCF) += mcf.o
-obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
-obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
-obj-$(CONFIG_SERIAL_DZ) += dz.o
-obj-$(CONFIG_SERIAL_ZS) += zs.o
-obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
-obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
-obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
-obj-$(CONFIG_SERIAL_IMX) += imx.o
-obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
-obj-$(CONFIG_SERIAL_ICOM) += icom.o
-obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
-obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
-obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
-obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
-obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
-obj-$(CONFIG_SERIAL_JSM) += jsm/
-obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
-obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
-obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
-obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
-obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
-obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
-obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
-obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
-obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
-obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
-obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
-obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
-obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
-obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
-obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
-obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
-obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
-obj-$(CONFIG_SERIAL_MRST_MAX3110)      += mrst_max3110.o
-obj-$(CONFIG_SERIAL_MFD_HSU)   += mfd.o
-obj-$(CONFIG_SERIAL_IFX6X60)   += ifx6x60.o
-obj-$(CONFIG_SERIAL_PCH_UART)  += pch_uart.o
diff --git a/drivers/serial/altera_jtaguart.c b/drivers/serial/altera_jtaguart.c
deleted file mode 100644 (file)
index f9b49b5..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * altera_jtaguart.c -- Altera JTAG UART driver
- *
- * Based on mcf.c -- Freescale ColdFire UART driver
- *
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
- * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/altera_jtaguart.h>
-
-#define DRV_NAME "altera_jtaguart"
-
-/*
- * Altera JTAG UART register definitions according to the Altera JTAG UART
- * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
- */
-
-#define ALTERA_JTAGUART_SIZE                   8
-
-#define ALTERA_JTAGUART_DATA_REG               0
-
-#define ALTERA_JTAGUART_DATA_DATA_MSK          0x000000FF
-#define ALTERA_JTAGUART_DATA_RVALID_MSK                0x00008000
-#define ALTERA_JTAGUART_DATA_RAVAIL_MSK                0xFFFF0000
-#define ALTERA_JTAGUART_DATA_RAVAIL_OFF                16
-
-#define ALTERA_JTAGUART_CONTROL_REG            4
-
-#define ALTERA_JTAGUART_CONTROL_RE_MSK         0x00000001
-#define ALTERA_JTAGUART_CONTROL_WE_MSK         0x00000002
-#define ALTERA_JTAGUART_CONTROL_RI_MSK         0x00000100
-#define ALTERA_JTAGUART_CONTROL_RI_OFF         8
-#define ALTERA_JTAGUART_CONTROL_WI_MSK         0x00000200
-#define ALTERA_JTAGUART_CONTROL_AC_MSK         0x00000400
-#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK     0xFFFF0000
-#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF     16
-
-/*
- * Local per-uart structure.
- */
-struct altera_jtaguart {
-       struct uart_port port;
-       unsigned int sigs;      /* Local copy of line sigs */
-       unsigned long imr;      /* Local IMR mirror */
-};
-
-static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
-{
-       return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-}
-
-static void altera_jtaguart_start_tx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_stop_tx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_stop_rx(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-
-       pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void altera_jtaguart_enable_ms(struct uart_port *port)
-{
-}
-
-static void altera_jtaguart_set_termios(struct uart_port *port,
-                                       struct ktermios *termios,
-                                       struct ktermios *old)
-{
-       /* Just copy the old termios settings back */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-}
-
-static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char ch, flag;
-       unsigned long status;
-
-       while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
-              ALTERA_JTAGUART_DATA_RVALID_MSK) {
-               ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, 0, 0, ch, flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int pending, count;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       pending = uart_circ_chars_pending(xmit);
-       if (pending > 0) {
-               count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-                               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
-                       ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
-               if (count > pending)
-                       count = pending;
-               if (count > 0) {
-                       pending -= count;
-                       while (count--) {
-                               writel(xmit->buf[xmit->tail],
-                                      port->membase + ALTERA_JTAGUART_DATA_REG);
-                               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                               port->icount.tx++;
-                       }
-                       if (pending < WAKEUP_CHARS)
-                               uart_write_wakeup(port);
-               }
-       }
-
-       if (pending == 0) {
-               pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
-               writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-       }
-}
-
-static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned int isr;
-
-       isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
-              ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
-
-       spin_lock(&port->lock);
-
-       if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
-               altera_jtaguart_rx_chars(pp);
-       if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
-               altera_jtaguart_tx_chars(pp);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_RETVAL(isr);
-}
-
-static void altera_jtaguart_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ALTERA_JTAGUART;
-
-       /* Clear mask, so no surprise interrupts. */
-       writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-}
-
-static int altera_jtaguart_startup(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned long flags;
-       int ret;
-
-       ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
-                       DRV_NAME, port);
-       if (ret) {
-               pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
-                      "interrupt vector=%d\n", port->line, port->irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Enable RX interrupts now */
-       pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-static void altera_jtaguart_shutdown(struct uart_port *port)
-{
-       struct altera_jtaguart *pp =
-           container_of(port, struct altera_jtaguart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       free_irq(port->irq, port);
-}
-
-static const char *altera_jtaguart_type(struct uart_port *port)
-{
-       return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
-}
-
-static int altera_jtaguart_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-static void altera_jtaguart_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-static int altera_jtaguart_verify_port(struct uart_port *port,
-                                      struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
-               return -EINVAL;
-       return 0;
-}
-
-/*
- *     Define the basic serial functions we support.
- */
-static struct uart_ops altera_jtaguart_ops = {
-       .tx_empty       = altera_jtaguart_tx_empty,
-       .get_mctrl      = altera_jtaguart_get_mctrl,
-       .set_mctrl      = altera_jtaguart_set_mctrl,
-       .start_tx       = altera_jtaguart_start_tx,
-       .stop_tx        = altera_jtaguart_stop_tx,
-       .stop_rx        = altera_jtaguart_stop_rx,
-       .enable_ms      = altera_jtaguart_enable_ms,
-       .break_ctl      = altera_jtaguart_break_ctl,
-       .startup        = altera_jtaguart_startup,
-       .shutdown       = altera_jtaguart_shutdown,
-       .set_termios    = altera_jtaguart_set_termios,
-       .type           = altera_jtaguart_type,
-       .request_port   = altera_jtaguart_request_port,
-       .release_port   = altera_jtaguart_release_port,
-       .config_port    = altera_jtaguart_config_port,
-       .verify_port    = altera_jtaguart_verify_port,
-};
-
-#define ALTERA_JTAGUART_MAXPORTS 1
-static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
-
-#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
-
-int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
-                                      *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_jtaguart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_JTAGUART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-               port->ops = &altera_jtaguart_ops;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
-static void altera_jtaguart_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
-       unsigned long status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
-               if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       return; /* no connection activity */
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-               cpu_relax();
-               spin_lock_irqsave(&port->lock, flags);
-       }
-       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-#else
-static void altera_jtaguart_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
-               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               cpu_relax();
-               spin_lock_irqsave(&port->lock, flags);
-       }
-       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-#endif
-
-static void altera_jtaguart_console_write(struct console *co, const char *s,
-                                         unsigned int count)
-{
-       for (; count; count--, s++) {
-               altera_jtaguart_console_putc(co, *s);
-               if (*s == '\n')
-                       altera_jtaguart_console_putc(co, '\r');
-       }
-}
-
-static int __init altera_jtaguart_console_setup(struct console *co,
-                                               char *options)
-{
-       struct uart_port *port;
-
-       if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
-               return -EINVAL;
-       port = &altera_jtaguart_ports[co->index].port;
-       if (port->membase == 0)
-               return -ENODEV;
-       return 0;
-}
-
-static struct uart_driver altera_jtaguart_driver;
-
-static struct console altera_jtaguart_console = {
-       .name   = "ttyJ",
-       .write  = altera_jtaguart_console_write,
-       .device = uart_console_device,
-       .setup  = altera_jtaguart_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &altera_jtaguart_driver,
-};
-
-static int __init altera_jtaguart_console_init(void)
-{
-       register_console(&altera_jtaguart_console);
-       return 0;
-}
-
-console_initcall(altera_jtaguart_console_init);
-
-#define        ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
-
-#else
-
-#define        ALTERA_JTAGUART_CONSOLE NULL
-
-#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
-
-static struct uart_driver altera_jtaguart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "altera_jtaguart",
-       .dev_name       = "ttyJ",
-       .major          = ALTERA_JTAGUART_MAJOR,
-       .minor          = ALTERA_JTAGUART_MINOR,
-       .nr             = ALTERA_JTAGUART_MAXPORTS,
-       .cons           = ALTERA_JTAGUART_CONSOLE,
-};
-
-static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
-{
-       struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_jtaguart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_JTAGUART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->ops = &altera_jtaguart_ops;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-
-               uart_add_one_port(&altera_jtaguart_driver, port);
-       }
-
-       return 0;
-}
-
-static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
-               port = &altera_jtaguart_ports[i].port;
-               if (port)
-                       uart_remove_one_port(&altera_jtaguart_driver, port);
-       }
-
-       return 0;
-}
-
-static struct platform_driver altera_jtaguart_platform_driver = {
-       .probe  = altera_jtaguart_probe,
-       .remove = __devexit_p(altera_jtaguart_remove),
-       .driver = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init altera_jtaguart_init(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&altera_jtaguart_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&altera_jtaguart_platform_driver);
-       if (rc) {
-               uart_unregister_driver(&altera_jtaguart_driver);
-               return rc;
-       }
-       return 0;
-}
-
-static void __exit altera_jtaguart_exit(void)
-{
-       platform_driver_unregister(&altera_jtaguart_platform_driver);
-       uart_unregister_driver(&altera_jtaguart_driver);
-}
-
-module_init(altera_jtaguart_init);
-module_exit(altera_jtaguart_exit);
-
-MODULE_DESCRIPTION("Altera JTAG UART driver");
-MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
deleted file mode 100644 (file)
index 7212162..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * altera_uart.c -- Altera UART driver
- *
- * Based on mcf.c -- Freescale ColdFire UART driver
- *
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
- * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/altera_uart.h>
-
-#define DRV_NAME "altera_uart"
-#define SERIAL_ALTERA_MAJOR 204
-#define SERIAL_ALTERA_MINOR 213
-
-/*
- * Altera UART register definitions according to the Nios UART datasheet:
- * http://www.altera.com/literature/ds/ds_nios_uart.pdf
- */
-
-#define ALTERA_UART_SIZE               32
-
-#define ALTERA_UART_RXDATA_REG         0
-#define ALTERA_UART_TXDATA_REG         4
-#define ALTERA_UART_STATUS_REG         8
-#define ALTERA_UART_CONTROL_REG                12
-#define ALTERA_UART_DIVISOR_REG                16
-#define ALTERA_UART_EOP_REG            20
-
-#define ALTERA_UART_STATUS_PE_MSK      0x0001  /* parity error */
-#define ALTERA_UART_STATUS_FE_MSK      0x0002  /* framing error */
-#define ALTERA_UART_STATUS_BRK_MSK     0x0004  /* break */
-#define ALTERA_UART_STATUS_ROE_MSK     0x0008  /* RX overrun error */
-#define ALTERA_UART_STATUS_TOE_MSK     0x0010  /* TX overrun error */
-#define ALTERA_UART_STATUS_TMT_MSK     0x0020  /* TX shift register state */
-#define ALTERA_UART_STATUS_TRDY_MSK    0x0040  /* TX ready */
-#define ALTERA_UART_STATUS_RRDY_MSK    0x0080  /* RX ready */
-#define ALTERA_UART_STATUS_E_MSK       0x0100  /* exception condition */
-#define ALTERA_UART_STATUS_DCTS_MSK    0x0400  /* CTS logic-level change */
-#define ALTERA_UART_STATUS_CTS_MSK     0x0800  /* CTS logic state */
-#define ALTERA_UART_STATUS_EOP_MSK     0x1000  /* EOP written/read */
-
-                                               /* Enable interrupt on... */
-#define ALTERA_UART_CONTROL_PE_MSK     0x0001  /* ...parity error */
-#define ALTERA_UART_CONTROL_FE_MSK     0x0002  /* ...framing error */
-#define ALTERA_UART_CONTROL_BRK_MSK    0x0004  /* ...break */
-#define ALTERA_UART_CONTROL_ROE_MSK    0x0008  /* ...RX overrun */
-#define ALTERA_UART_CONTROL_TOE_MSK    0x0010  /* ...TX overrun */
-#define ALTERA_UART_CONTROL_TMT_MSK    0x0020  /* ...TX shift register empty */
-#define ALTERA_UART_CONTROL_TRDY_MSK   0x0040  /* ...TX ready */
-#define ALTERA_UART_CONTROL_RRDY_MSK   0x0080  /* ...RX ready */
-#define ALTERA_UART_CONTROL_E_MSK      0x0100  /* ...exception*/
-
-#define ALTERA_UART_CONTROL_TRBK_MSK   0x0200  /* TX break */
-#define ALTERA_UART_CONTROL_DCTS_MSK   0x0400  /* Interrupt on CTS change */
-#define ALTERA_UART_CONTROL_RTS_MSK    0x0800  /* RTS signal */
-#define ALTERA_UART_CONTROL_EOP_MSK    0x1000  /* Interrupt on EOP */
-
-/*
- * Local per-uart structure.
- */
-struct altera_uart {
-       struct uart_port port;
-       struct timer_list tmr;
-       unsigned int sigs;      /* Local copy of line sigs */
-       unsigned short imr;     /* Local IMR mirror */
-};
-
-static u32 altera_uart_readl(struct uart_port *port, int reg)
-{
-       struct altera_uart_platform_uart *platp = port->private_data;
-
-       return readl(port->membase + (reg << platp->bus_shift));
-}
-
-static void altera_uart_writel(struct uart_port *port, u32 dat, int reg)
-{
-       struct altera_uart_platform_uart *platp = port->private_data;
-
-       writel(dat, port->membase + (reg << platp->bus_shift));
-}
-
-static unsigned int altera_uart_tx_empty(struct uart_port *port)
-{
-       return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-               ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int altera_uart_get_mctrl(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned int sigs;
-
-       sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-            ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
-       sigs |= (pp->sigs & TIOCM_RTS);
-
-       return sigs;
-}
-
-static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->sigs = sigs;
-       if (sigs & TIOCM_RTS)
-               pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
-       else
-               pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_start_tx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_stop_tx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_stop_rx(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-}
-
-static void altera_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
-       else
-               pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
-       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void altera_uart_enable_ms(struct uart_port *port)
-{
-}
-
-static void altera_uart_set_termios(struct uart_port *port,
-                                   struct ktermios *termios,
-                                   struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, baudclk;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       baudclk = port->uartclk / baud;
-
-       if (old)
-               tty_termios_copy_hw(termios, old);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void altera_uart_rx_chars(struct altera_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char ch, flag;
-       unsigned short status;
-
-       while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) &
-              ALTERA_UART_STATUS_RRDY_MSK) {
-               ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (status & ALTERA_UART_STATUS_E_MSK) {
-                       altera_uart_writel(port, status,
-                                          ALTERA_UART_STATUS_REG);
-
-                       if (status & ALTERA_UART_STATUS_BRK_MSK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & ALTERA_UART_STATUS_PE_MSK) {
-                               port->icount.parity++;
-                       } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
-                               port->icount.overrun++;
-                       } else if (status & ALTERA_UART_STATUS_FE_MSK) {
-                               port->icount.frame++;
-                       }
-
-                       status &= port->read_status_mask;
-
-                       if (status & ALTERA_UART_STATUS_BRK_MSK)
-                               flag = TTY_BREAK;
-                       else if (status & ALTERA_UART_STATUS_PE_MSK)
-                               flag = TTY_PARITY;
-                       else if (status & ALTERA_UART_STATUS_FE_MSK)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
-                                flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-static void altera_uart_tx_chars(struct altera_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-              ALTERA_UART_STATUS_TRDY_MSK) {
-               if (xmit->head == xmit->tail)
-                       break;
-               altera_uart_writel(port, xmit->buf[xmit->tail],
-                      ALTERA_UART_TXDATA_REG);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (xmit->head == xmit->tail) {
-               pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
-               altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
-       }
-}
-
-static irqreturn_t altera_uart_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned int isr;
-
-       isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
-
-       spin_lock(&port->lock);
-       if (isr & ALTERA_UART_STATUS_RRDY_MSK)
-               altera_uart_rx_chars(pp);
-       if (isr & ALTERA_UART_STATUS_TRDY_MSK)
-               altera_uart_tx_chars(pp);
-       spin_unlock(&port->lock);
-
-       return IRQ_RETVAL(isr);
-}
-
-static void altera_uart_timer(unsigned long data)
-{
-       struct uart_port *port = (void *)data;
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-
-       altera_uart_interrupt(0, port);
-       mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
-}
-
-static void altera_uart_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ALTERA_UART;
-
-       /* Clear mask, so no surprise interrupts. */
-       altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG);
-       /* Clear status register */
-       altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG);
-}
-
-static int altera_uart_startup(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-       int ret;
-
-       if (!port->irq) {
-               setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port);
-               mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
-               return 0;
-       }
-
-       ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
-                       DRV_NAME, port);
-       if (ret) {
-               pr_err(DRV_NAME ": unable to attach Altera UART %d "
-                      "interrupt vector=%d\n", port->line, port->irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Enable RX interrupts now */
-       pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
-       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-static void altera_uart_shutdown(struct uart_port *port)
-{
-       struct altera_uart *pp = container_of(port, struct altera_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->irq)
-               free_irq(port->irq, port);
-       else
-               del_timer_sync(&pp->tmr);
-}
-
-static const char *altera_uart_type(struct uart_port *port)
-{
-       return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
-}
-
-static int altera_uart_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-static void altera_uart_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-static int altera_uart_verify_port(struct uart_port *port,
-                                  struct serial_struct *ser)
-{
-       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
-               return -EINVAL;
-       return 0;
-}
-
-/*
- *     Define the basic serial functions we support.
- */
-static struct uart_ops altera_uart_ops = {
-       .tx_empty       = altera_uart_tx_empty,
-       .get_mctrl      = altera_uart_get_mctrl,
-       .set_mctrl      = altera_uart_set_mctrl,
-       .start_tx       = altera_uart_start_tx,
-       .stop_tx        = altera_uart_stop_tx,
-       .stop_rx        = altera_uart_stop_rx,
-       .enable_ms      = altera_uart_enable_ms,
-       .break_ctl      = altera_uart_break_ctl,
-       .startup        = altera_uart_startup,
-       .shutdown       = altera_uart_shutdown,
-       .set_termios    = altera_uart_set_termios,
-       .type           = altera_uart_type,
-       .request_port   = altera_uart_request_port,
-       .release_port   = altera_uart_release_port,
-       .config_port    = altera_uart_config_port,
-       .verify_port    = altera_uart_verify_port,
-};
-
-static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
-
-#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
-
-int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
-               port = &altera_uart_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_ALTERA_UART;
-               port->mapbase = platp[i].mapbase;
-               port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = platp[i].uartclk;
-               port->flags = UPF_BOOT_AUTOCONF;
-               port->ops = &altera_uart_ops;
-               port->private_data = platp;
-       }
-
-       return 0;
-}
-
-static void altera_uart_console_putc(struct uart_port *port, const char c)
-{
-       while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
-                ALTERA_UART_STATUS_TRDY_MSK))
-               cpu_relax();
-
-       writel(c, port->membase + ALTERA_UART_TXDATA_REG);
-}
-
-static void altera_uart_console_write(struct console *co, const char *s,
-                                     unsigned int count)
-{
-       struct uart_port *port = &(altera_uart_ports + co->index)->port;
-
-       for (; count; count--, s++) {
-               altera_uart_console_putc(port, *s);
-               if (*s == '\n')
-                       altera_uart_console_putc(port, '\r');
-       }
-}
-
-static int __init altera_uart_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
-               return -EINVAL;
-       port = &altera_uart_ports[co->index].port;
-       if (!port->membase)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver altera_uart_driver;
-
-static struct console altera_uart_console = {
-       .name   = "ttyAL",
-       .write  = altera_uart_console_write,
-       .device = uart_console_device,
-       .setup  = altera_uart_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &altera_uart_driver,
-};
-
-static int __init altera_uart_console_init(void)
-{
-       register_console(&altera_uart_console);
-       return 0;
-}
-
-console_initcall(altera_uart_console_init);
-
-#define        ALTERA_UART_CONSOLE     (&altera_uart_console)
-
-#else
-
-#define        ALTERA_UART_CONSOLE     NULL
-
-#endif /* CONFIG_ALTERA_UART_CONSOLE */
-
-/*
- *     Define the altera_uart UART driver structure.
- */
-static struct uart_driver altera_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRV_NAME,
-       .dev_name       = "ttyAL",
-       .major          = SERIAL_ALTERA_MAJOR,
-       .minor          = SERIAL_ALTERA_MINOR,
-       .nr             = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
-       .cons           = ALTERA_UART_CONSOLE,
-};
-
-static int __devinit altera_uart_probe(struct platform_device *pdev)
-{
-       struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       struct resource *res_mem;
-       struct resource *res_irq;
-       int i = pdev->id;
-
-       /* -1 emphasizes that the platform must have one port, no .N suffix */
-       if (i == -1)
-               i = 0;
-
-       if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
-               return -EINVAL;
-
-       port = &altera_uart_ports[i].port;
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res_mem)
-               port->mapbase = res_mem->start;
-       else if (platp->mapbase)
-               port->mapbase = platp->mapbase;
-       else
-               return -EINVAL;
-
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res_irq)
-               port->irq = res_irq->start;
-       else if (platp->irq)
-               port->irq = platp->irq;
-
-       port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-       if (!port->membase)
-               return -ENOMEM;
-
-       port->line = i;
-       port->type = PORT_ALTERA_UART;
-       port->iotype = SERIAL_IO_MEM;
-       port->uartclk = platp->uartclk;
-       port->ops = &altera_uart_ops;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->private_data = platp;
-
-       uart_add_one_port(&altera_uart_driver, port);
-
-       return 0;
-}
-
-static int __devexit altera_uart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port = &altera_uart_ports[pdev->id].port;
-
-       uart_remove_one_port(&altera_uart_driver, port);
-       return 0;
-}
-
-static struct platform_driver altera_uart_platform_driver = {
-       .probe  = altera_uart_probe,
-       .remove = __devexit_p(altera_uart_remove),
-       .driver = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-               .pm     = NULL,
-       },
-};
-
-static int __init altera_uart_init(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&altera_uart_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&altera_uart_platform_driver);
-       if (rc) {
-               uart_unregister_driver(&altera_uart_driver);
-               return rc;
-       }
-       return 0;
-}
-
-static void __exit altera_uart_exit(void)
-{
-       platform_driver_unregister(&altera_uart_platform_driver);
-       uart_unregister_driver(&altera_uart_driver);
-}
-
-module_init(altera_uart_init);
-module_exit(altera_uart_exit);
-
-MODULE_DESCRIPTION("Altera UART driver");
-MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
deleted file mode 100644 (file)
index 2904aa0..0000000
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- *  linux/drivers/char/amba.c
- *
- *  Driver for AMBA serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This is a generic driver for ARM AMBA-type serial ports.  They
- * have a lot of 16550-like features, but are not register compatible.
- * Note that although they do have CTS, DCD and DSR inputs, they do
- * not have an RI input, nor do they have DTR or RTS outputs.  If
- * required, these have to be supplied via some other means (eg, GPIO)
- * and hooked into this driver.
- */
-
-#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/serial.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-#define UART_NR                8
-
-#define SERIAL_AMBA_MAJOR      204
-#define SERIAL_AMBA_MINOR      16
-#define SERIAL_AMBA_NR         UART_NR
-
-#define AMBA_ISR_PASS_LIMIT    256
-
-#define UART_RX_DATA(s)                (((s) & UART01x_FR_RXFE) == 0)
-#define UART_TX_READY(s)       (((s) & UART01x_FR_TXFF) == 0)
-
-#define UART_DUMMY_RSR_RX      256
-#define UART_PORT_SIZE         64
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_amba_port {
-       struct uart_port        port;
-       struct clk              *clk;
-       struct amba_device      *dev;
-       struct amba_pl010_data  *data;
-       unsigned int            old_status;
-};
-
-static void pl010_stop_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr &= ~UART010_CR_TIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_start_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr |= UART010_CR_TIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_stop_rx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_enable_ms(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readb(uap->port.membase + UART010_CR);
-       cr |= UART010_CR_MSIE;
-       writel(cr, uap->port.membase + UART010_CR);
-}
-
-static void pl010_rx_chars(struct uart_amba_port *uap)
-{
-       struct tty_struct *tty = uap->port.state->port.tty;
-       unsigned int status, ch, flag, rsr, max_count = 256;
-
-       status = readb(uap->port.membase + UART01x_FR);
-       while (UART_RX_DATA(status) && max_count--) {
-               ch = readb(uap->port.membase + UART01x_DR);
-               flag = TTY_NORMAL;
-
-               uap->port.icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
-               if (unlikely(rsr & UART01x_RSR_ANY)) {
-                       writel(0, uap->port.membase + UART01x_ECR);
-
-                       if (rsr & UART01x_RSR_BE) {
-                               rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto ignore_char;
-                       } else if (rsr & UART01x_RSR_PE)
-                               uap->port.icount.parity++;
-                       else if (rsr & UART01x_RSR_FE)
-                               uap->port.icount.frame++;
-                       if (rsr & UART01x_RSR_OE)
-                               uap->port.icount.overrun++;
-
-                       rsr &= uap->port.read_status_mask;
-
-                       if (rsr & UART01x_RSR_BE)
-                               flag = TTY_BREAK;
-                       else if (rsr & UART01x_RSR_PE)
-                               flag = TTY_PARITY;
-                       else if (rsr & UART01x_RSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&uap->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
-
-       ignore_char:
-               status = readb(uap->port.membase + UART01x_FR);
-       }
-       spin_unlock(&uap->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&uap->port.lock);
-}
-
-static void pl010_tx_chars(struct uart_amba_port *uap)
-{
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       int count;
-
-       if (uap->port.x_char) {
-               writel(uap->port.x_char, uap->port.membase + UART01x_DR);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
-               pl010_stop_tx(&uap->port);
-               return;
-       }
-
-       count = uap->port.fifosize >> 1;
-       do {
-               writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uap->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       if (uart_circ_empty(xmit))
-               pl010_stop_tx(&uap->port);
-}
-
-static void pl010_modem_status(struct uart_amba_port *uap)
-{
-       unsigned int status, delta;
-
-       writel(0, uap->port.membase + UART010_ICR);
-
-       status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       delta = status ^ uap->old_status;
-       uap->old_status = status;
-
-       if (!delta)
-               return;
-
-       if (delta & UART01x_FR_DCD)
-               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
-
-       if (delta & UART01x_FR_DSR)
-               uap->port.icount.dsr++;
-
-       if (delta & UART01x_FR_CTS)
-               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
-
-       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t pl010_int(int irq, void *dev_id)
-{
-       struct uart_amba_port *uap = dev_id;
-       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
-       int handled = 0;
-
-       spin_lock(&uap->port.lock);
-
-       status = readb(uap->port.membase + UART010_IIR);
-       if (status) {
-               do {
-                       if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
-                               pl010_rx_chars(uap);
-                       if (status & UART010_IIR_MIS)
-                               pl010_modem_status(uap);
-                       if (status & UART010_IIR_TIS)
-                               pl010_tx_chars(uap);
-
-                       if (pass_counter-- == 0)
-                               break;
-
-                       status = readb(uap->port.membase + UART010_IIR);
-               } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
-                                  UART010_IIR_TIS));
-               handled = 1;
-       }
-
-       spin_unlock(&uap->port.lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static unsigned int pl010_tx_empty(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status = readb(uap->port.membase + UART01x_FR);
-       return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pl010_get_mctrl(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int result = 0;
-       unsigned int status;
-
-       status = readb(uap->port.membase + UART01x_FR);
-       if (status & UART01x_FR_DCD)
-               result |= TIOCM_CAR;
-       if (status & UART01x_FR_DSR)
-               result |= TIOCM_DSR;
-       if (status & UART01x_FR_CTS)
-               result |= TIOCM_CTS;
-
-       return result;
-}
-
-static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (uap->data)
-               uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
-}
-
-static void pl010_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned long flags;
-       unsigned int lcr_h;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       lcr_h = readb(uap->port.membase + UART010_LCRH);
-       if (break_state == -1)
-               lcr_h |= UART01x_LCRH_BRK;
-       else
-               lcr_h &= ~UART01x_LCRH_BRK;
-       writel(lcr_h, uap->port.membase + UART010_LCRH);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-static int pl010_startup(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       int retval;
-
-       /*
-        * Try to enable the clock producer.
-        */
-       retval = clk_enable(uap->clk);
-       if (retval)
-               goto out;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
-       if (retval)
-               goto clk_dis;
-
-       /*
-        * initialise the old status of the modem signals
-        */
-       uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       /*
-        * Finally, enable interrupts
-        */
-       writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
-              uap->port.membase + UART010_CR);
-
-       return 0;
-
- clk_dis:
-       clk_disable(uap->clk);
- out:
-       return retval;
-}
-
-static void pl010_shutdown(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(uap->port.irq, uap);
-
-       /*
-        * disable all interrupts, disable the port
-        */
-       writel(0, uap->port.membase + UART010_CR);
-
-       /* disable break condition and fifos */
-       writel(readb(uap->port.membase + UART010_LCRH) &
-               ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
-              uap->port.membase + UART010_LCRH);
-
-       /*
-        * Shut down the clock producer
-        */
-       clk_disable(uap->clk);
-}
-
-static void
-pl010_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int lcr_h, old_cr;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr_h = UART01x_LCRH_WLEN_5;
-               break;
-       case CS6:
-               lcr_h = UART01x_LCRH_WLEN_6;
-               break;
-       case CS7:
-               lcr_h = UART01x_LCRH_WLEN_7;
-               break;
-       default: // CS8
-               lcr_h = UART01x_LCRH_WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               lcr_h |= UART01x_LCRH_STP2;
-       if (termios->c_cflag & PARENB) {
-               lcr_h |= UART01x_LCRH_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_h |= UART01x_LCRH_EPS;
-       }
-       if (uap->port.fifosize > 1)
-               lcr_h |= UART01x_LCRH_FEN;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       uap->port.read_status_mask = UART01x_RSR_OE;
-       if (termios->c_iflag & INPCK)
-               uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uap->port.read_status_mask |= UART01x_RSR_BE;
-
-       /*
-        * Characters to ignore
-        */
-       uap->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               uap->port.ignore_status_mask |= UART01x_RSR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       uap->port.ignore_status_mask |= UART01x_RSR_OE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
-
-       /* first, disable everything */
-       old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
-
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               old_cr |= UART010_CR_MSIE;
-
-       writel(0, uap->port.membase + UART010_CR);
-
-       /* Set baud rate */
-       quot -= 1;
-       writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
-       writel(quot & 0xff, uap->port.membase + UART010_LCRL);
-
-       /*
-        * ----------v----------v----------v----------v-----
-        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
-        * ----------^----------^----------^----------^-----
-        */
-       writel(lcr_h, uap->port.membase + UART010_LCRH);
-       writel(old_cr, uap->port.membase + UART010_CR);
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-static void pl010_set_ldisc(struct uart_port *port, int new)
-{
-       if (new == N_PPS) {
-               port->flags |= UPF_HARDPPS_CD;
-               pl010_enable_ms(port);
-       } else
-               port->flags &= ~UPF_HARDPPS_CD;
-}
-
-static const char *pl010_type(struct uart_port *port)
-{
-       return port->type == PORT_AMBA ? "AMBA" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void pl010_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'
- */
-static int pl010_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")
-                       != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pl010_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_AMBA;
-               pl010_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops amba_pl010_pops = {
-       .tx_empty       = pl010_tx_empty,
-       .set_mctrl      = pl010_set_mctrl,
-       .get_mctrl      = pl010_get_mctrl,
-       .stop_tx        = pl010_stop_tx,
-       .start_tx       = pl010_start_tx,
-       .stop_rx        = pl010_stop_rx,
-       .enable_ms      = pl010_enable_ms,
-       .break_ctl      = pl010_break_ctl,
-       .startup        = pl010_startup,
-       .shutdown       = pl010_shutdown,
-       .set_termios    = pl010_set_termios,
-       .set_ldisc      = pl010_set_ldisc,
-       .type           = pl010_type,
-       .release_port   = pl010_release_port,
-       .request_port   = pl010_request_port,
-       .config_port    = pl010_config_port,
-       .verify_port    = pl010_verify_port,
-};
-
-static struct uart_amba_port *amba_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
-
-static void pl010_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status;
-
-       do {
-               status = readb(uap->port.membase + UART01x_FR);
-               barrier();
-       } while (!UART_TX_READY(status));
-       writel(ch, uap->port.membase + UART01x_DR);
-}
-
-static void
-pl010_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_amba_port *uap = amba_ports[co->index];
-       unsigned int status, old_cr;
-
-       clk_enable(uap->clk);
-
-       /*
-        *      First save the CR then disable the interrupts
-        */
-       old_cr = readb(uap->port.membase + UART010_CR);
-       writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
-
-       uart_console_write(&uap->port, s, count, pl010_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = readb(uap->port.membase + UART01x_FR);
-               barrier();
-       } while (status & UART01x_FR_BUSY);
-       writel(old_cr, uap->port.membase + UART010_CR);
-
-       clk_disable(uap->clk);
-}
-
-static void __init
-pl010_console_get_options(struct uart_amba_port *uap, int *baud,
-                            int *parity, int *bits)
-{
-       if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
-               unsigned int lcr_h, quot;
-               lcr_h = readb(uap->port.membase + UART010_LCRH);
-
-               *parity = 'n';
-               if (lcr_h & UART01x_LCRH_PEN) {
-                       if (lcr_h & UART01x_LCRH_EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               quot = readb(uap->port.membase + UART010_LCRL) |
-                      readb(uap->port.membase + UART010_LCRM) << 8;
-               *baud = uap->port.uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init pl010_console_setup(struct console *co, char *options)
-{
-       struct uart_amba_port *uap;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       uap = amba_ports[co->index];
-       if (!uap)
-               return -ENODEV;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               pl010_console_get_options(uap, &baud, &parity, &bits);
-
-       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver amba_reg;
-static struct console amba_console = {
-       .name           = "ttyAM",
-       .write          = pl010_console_write,
-       .device         = uart_console_device,
-       .setup          = pl010_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &amba_reg,
-};
-
-#define AMBA_CONSOLE   &amba_console
-#else
-#define AMBA_CONSOLE   NULL
-#endif
-
-static struct uart_driver amba_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAM",
-       .dev_name               = "ttyAM",
-       .major                  = SERIAL_AMBA_MAJOR,
-       .minor                  = SERIAL_AMBA_MINOR,
-       .nr                     = UART_NR,
-       .cons                   = AMBA_CONSOLE,
-};
-
-static int pl010_probe(struct amba_device *dev, struct amba_id *id)
-{
-       struct uart_amba_port *uap;
-       void __iomem *base;
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == NULL)
-                       break;
-
-       if (i == ARRAY_SIZE(amba_ports)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
-       if (!uap) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       base = ioremap(dev->res.start, resource_size(&dev->res));
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       uap->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(uap->clk)) {
-               ret = PTR_ERR(uap->clk);
-               goto unmap;
-       }
-
-       uap->port.dev = &dev->dev;
-       uap->port.mapbase = dev->res.start;
-       uap->port.membase = base;
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = dev->irq[0];
-       uap->port.fifosize = 16;
-       uap->port.ops = &amba_pl010_pops;
-       uap->port.flags = UPF_BOOT_AUTOCONF;
-       uap->port.line = i;
-       uap->dev = dev;
-       uap->data = dev->dev.platform_data;
-
-       amba_ports[i] = uap;
-
-       amba_set_drvdata(dev, uap);
-       ret = uart_add_one_port(&amba_reg, &uap->port);
-       if (ret) {
-               amba_set_drvdata(dev, NULL);
-               amba_ports[i] = NULL;
-               clk_put(uap->clk);
- unmap:
-               iounmap(base);
- free:
-               kfree(uap);
-       }
- out:
-       return ret;
-}
-
-static int pl010_remove(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-       int i;
-
-       amba_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&amba_reg, &uap->port);
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == uap)
-                       amba_ports[i] = NULL;
-
-       iounmap(uap->port.membase);
-       clk_put(uap->clk);
-       kfree(uap);
-       return 0;
-}
-
-static int pl010_suspend(struct amba_device *dev, pm_message_t state)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (uap)
-               uart_suspend_port(&amba_reg, &uap->port);
-
-       return 0;
-}
-
-static int pl010_resume(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (uap)
-               uart_resume_port(&amba_reg, &uap->port);
-
-       return 0;
-}
-
-static struct amba_id pl010_ids[] = {
-       {
-               .id     = 0x00041010,
-               .mask   = 0x000fffff,
-       },
-       { 0, 0 },
-};
-
-static struct amba_driver pl010_driver = {
-       .drv = {
-               .name   = "uart-pl010",
-       },
-       .id_table       = pl010_ids,
-       .probe          = pl010_probe,
-       .remove         = pl010_remove,
-       .suspend        = pl010_suspend,
-       .resume         = pl010_resume,
-};
-
-static int __init pl010_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: AMBA driver\n");
-
-       ret = uart_register_driver(&amba_reg);
-       if (ret == 0) {
-               ret = amba_driver_register(&pl010_driver);
-               if (ret)
-                       uart_unregister_driver(&amba_reg);
-       }
-       return ret;
-}
-
-static void __exit pl010_exit(void)
-{
-       amba_driver_unregister(&pl010_driver);
-       uart_unregister_driver(&amba_reg);
-}
-
-module_init(pl010_init);
-module_exit(pl010_exit);
-
-MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("ARM AMBA serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
deleted file mode 100644 (file)
index e76d7d0..0000000
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- *  linux/drivers/char/amba.c
- *
- *  Driver for AMBA serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *  Copyright (C) 2010 ST-Ericsson SA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This is a generic driver for ARM AMBA-type serial ports.  They
- * have a lot of 16550-like features, but are not register compatible.
- * Note that although they do have CTS, DCD and DSR inputs, they do
- * not have an RI input, nor do they have DTR or RTS outputs.  If
- * required, these have to be supplied via some other means (eg, GPIO)
- * and hooked into this driver.
- */
-
-#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/serial.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#define UART_NR                        14
-
-#define SERIAL_AMBA_MAJOR      204
-#define SERIAL_AMBA_MINOR      64
-#define SERIAL_AMBA_NR         UART_NR
-
-#define AMBA_ISR_PASS_LIMIT    256
-
-#define UART_DR_ERROR          (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
-#define UART_DUMMY_DR_RX       (1 << 16)
-
-/* There is by now at least one vendor with differing details, so handle it */
-struct vendor_data {
-       unsigned int            ifls;
-       unsigned int            fifosize;
-       unsigned int            lcrh_tx;
-       unsigned int            lcrh_rx;
-       bool                    oversampling;
-       bool                    dma_threshold;
-};
-
-static struct vendor_data vendor_arm = {
-       .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
-       .fifosize               = 16,
-       .lcrh_tx                = UART011_LCRH,
-       .lcrh_rx                = UART011_LCRH,
-       .oversampling           = false,
-       .dma_threshold          = false,
-};
-
-static struct vendor_data vendor_st = {
-       .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
-       .fifosize               = 64,
-       .lcrh_tx                = ST_UART011_LCRH_TX,
-       .lcrh_rx                = ST_UART011_LCRH_RX,
-       .oversampling           = true,
-       .dma_threshold          = true,
-};
-
-/* Deals with DMA transactions */
-struct pl011_dmatx_data {
-       struct dma_chan         *chan;
-       struct scatterlist      sg;
-       char                    *buf;
-       bool                    queued;
-};
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_amba_port {
-       struct uart_port        port;
-       struct clk              *clk;
-       const struct vendor_data *vendor;
-       unsigned int            dmacr;          /* dma control reg */
-       unsigned int            im;             /* interrupt mask */
-       unsigned int            old_status;
-       unsigned int            fifosize;       /* vendor-specific */
-       unsigned int            lcrh_tx;        /* vendor-specific */
-       unsigned int            lcrh_rx;        /* vendor-specific */
-       bool                    autorts;
-       char                    type[12];
-#ifdef CONFIG_DMA_ENGINE
-       /* DMA stuff */
-       bool                    using_dma;
-       struct pl011_dmatx_data dmatx;
-#endif
-};
-
-/*
- * All the DMA operation mode stuff goes inside this ifdef.
- * This assumes that you have a generic DMA device interface,
- * no custom DMA interfaces are supported.
- */
-#ifdef CONFIG_DMA_ENGINE
-
-#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
-
-static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
-{
-       /* DMA is the sole user of the platform data right now */
-       struct amba_pl011_data *plat = uap->port.dev->platform_data;
-       struct dma_slave_config tx_conf = {
-               .dst_addr = uap->port.mapbase + UART01x_DR,
-               .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
-               .direction = DMA_TO_DEVICE,
-               .dst_maxburst = uap->fifosize >> 1,
-       };
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-
-       /* We need platform data */
-       if (!plat || !plat->dma_filter) {
-               dev_info(uap->port.dev, "no DMA platform data\n");
-               return;
-       }
-
-       /* Try to acquire a generic DMA engine slave channel */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
-       if (!chan) {
-               dev_err(uap->port.dev, "no TX DMA channel!\n");
-               return;
-       }
-
-       dmaengine_slave_config(chan, &tx_conf);
-       uap->dmatx.chan = chan;
-
-       dev_info(uap->port.dev, "DMA channel TX %s\n",
-                dma_chan_name(uap->dmatx.chan));
-}
-
-#ifndef MODULE
-/*
- * Stack up the UARTs and let the above initcall be done at device
- * initcall time, because the serial driver is called as an arch
- * initcall, and at this time the DMA subsystem is not yet registered.
- * At this point the driver will switch over to using DMA where desired.
- */
-struct dma_uap {
-       struct list_head node;
-       struct uart_amba_port *uap;
-};
-
-static LIST_HEAD(pl011_dma_uarts);
-
-static int __init pl011_dma_initcall(void)
-{
-       struct list_head *node, *tmp;
-
-       list_for_each_safe(node, tmp, &pl011_dma_uarts) {
-               struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
-               pl011_dma_probe_initcall(dmau->uap);
-               list_del(node);
-               kfree(dmau);
-       }
-       return 0;
-}
-
-device_initcall(pl011_dma_initcall);
-
-static void pl011_dma_probe(struct uart_amba_port *uap)
-{
-       struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
-       if (dmau) {
-               dmau->uap = uap;
-               list_add_tail(&dmau->node, &pl011_dma_uarts);
-       }
-}
-#else
-static void pl011_dma_probe(struct uart_amba_port *uap)
-{
-       pl011_dma_probe_initcall(uap);
-}
-#endif
-
-static void pl011_dma_remove(struct uart_amba_port *uap)
-{
-       /* TODO: remove the initcall if it has not yet executed */
-       if (uap->dmatx.chan)
-               dma_release_channel(uap->dmatx.chan);
-}
-
-
-/* Forward declare this for the refill routine */
-static int pl011_dma_tx_refill(struct uart_amba_port *uap);
-
-/*
- * The current DMA TX buffer has been sent.
- * Try to queue up another DMA buffer.
- */
-static void pl011_dma_tx_callback(void *data)
-{
-       struct uart_amba_port *uap = data;
-       struct pl011_dmatx_data *dmatx = &uap->dmatx;
-       unsigned long flags;
-       u16 dmacr;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       if (uap->dmatx.queued)
-               dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
-                            DMA_TO_DEVICE);
-
-       dmacr = uap->dmacr;
-       uap->dmacr = dmacr & ~UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       /*
-        * If TX DMA was disabled, it means that we've stopped the DMA for
-        * some reason (eg, XOFF received, or we want to send an X-char.)
-        *
-        * Note: we need to be careful here of a potential race between DMA
-        * and the rest of the driver - if the driver disables TX DMA while
-        * a TX buffer completing, we must update the tx queued status to
-        * get further refills (hence we check dmacr).
-        */
-       if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
-           uart_circ_empty(&uap->port.state->xmit)) {
-               uap->dmatx.queued = false;
-               spin_unlock_irqrestore(&uap->port.lock, flags);
-               return;
-       }
-
-       if (pl011_dma_tx_refill(uap) <= 0) {
-               /*
-                * We didn't queue a DMA buffer for some reason, but we
-                * have data pending to be sent.  Re-enable the TX IRQ.
-                */
-               uap->im |= UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-       }
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-/*
- * Try to refill the TX DMA buffer.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   1 if we queued up a TX DMA buffer.
- *   0 if we didn't want to handle this by DMA
- *  <0 on error
- */
-static int pl011_dma_tx_refill(struct uart_amba_port *uap)
-{
-       struct pl011_dmatx_data *dmatx = &uap->dmatx;
-       struct dma_chan *chan = dmatx->chan;
-       struct dma_device *dma_dev = chan->device;
-       struct dma_async_tx_descriptor *desc;
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       unsigned int count;
-
-       /*
-        * Try to avoid the overhead involved in using DMA if the
-        * transaction fits in the first half of the FIFO, by using
-        * the standard interrupt handling.  This ensures that we
-        * issue a uart_write_wakeup() at the appropriate time.
-        */
-       count = uart_circ_chars_pending(xmit);
-       if (count < (uap->fifosize >> 1)) {
-               uap->dmatx.queued = false;
-               return 0;
-       }
-
-       /*
-        * Bodge: don't send the last character by DMA, as this
-        * will prevent XON from notifying us to restart DMA.
-        */
-       count -= 1;
-
-       /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
-       if (count > PL011_DMA_BUFFER_SIZE)
-               count = PL011_DMA_BUFFER_SIZE;
-
-       if (xmit->tail < xmit->head)
-               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
-       else {
-               size_t first = UART_XMIT_SIZE - xmit->tail;
-               size_t second = xmit->head;
-
-               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
-               if (second)
-                       memcpy(&dmatx->buf[first], &xmit->buf[0], second);
-       }
-
-       dmatx->sg.length = count;
-
-       if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
-               uap->dmatx.queued = false;
-               dev_dbg(uap->port.dev, "unable to map TX DMA\n");
-               return -EBUSY;
-       }
-
-       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
-                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-               /*
-                * If DMA cannot be used right now, we complete this
-                * transaction via IRQ and let the TTY layer retry.
-                */
-               dev_dbg(uap->port.dev, "TX DMA busy\n");
-               return -EBUSY;
-       }
-
-       /* Some data to go along to the callback */
-       desc->callback = pl011_dma_tx_callback;
-       desc->callback_param = uap;
-
-       /* All errors should happen at prepare time */
-       dmaengine_submit(desc);
-
-       /* Fire the DMA transaction */
-       dma_dev->device_issue_pending(chan);
-
-       uap->dmacr |= UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       uap->dmatx.queued = true;
-
-       /*
-        * Now we know that DMA will fire, so advance the ring buffer
-        * with the stuff we just dispatched.
-        */
-       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
-       uap->port.icount.tx += count;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       return 1;
-}
-
-/*
- * We received a transmit interrupt without a pending X-char but with
- * pending characters.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   false if we want to use PIO to transmit
- *   true if we queued a DMA buffer
- */
-static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
-{
-       if (!uap->using_dma)
-               return false;
-
-       /*
-        * If we already have a TX buffer queued, but received a
-        * TX interrupt, it will be because we've just sent an X-char.
-        * Ensure the TX DMA is enabled and the TX IRQ is disabled.
-        */
-       if (uap->dmatx.queued) {
-               uap->dmacr |= UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-               uap->im &= ~UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-               return true;
-       }
-
-       /*
-        * We don't have a TX buffer queued, so try to queue one.
-        * If we succesfully queued a buffer, mask the TX IRQ.
-        */
-       if (pl011_dma_tx_refill(uap) > 0) {
-               uap->im &= ~UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-               return true;
-       }
-       return false;
-}
-
-/*
- * Stop the DMA transmit (eg, due to received XOFF).
- * Locking: called with port lock held and IRQs disabled.
- */
-static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
-{
-       if (uap->dmatx.queued) {
-               uap->dmacr &= ~UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       }
-}
-
-/*
- * Try to start a DMA transmit, or in the case of an XON/OFF
- * character queued for send, try to get that character out ASAP.
- * Locking: called with port lock held and IRQs disabled.
- * Returns:
- *   false if we want the TX IRQ to be enabled
- *   true if we have a buffer queued
- */
-static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
-{
-       u16 dmacr;
-
-       if (!uap->using_dma)
-               return false;
-
-       if (!uap->port.x_char) {
-               /* no X-char, try to push chars out in DMA mode */
-               bool ret = true;
-
-               if (!uap->dmatx.queued) {
-                       if (pl011_dma_tx_refill(uap) > 0) {
-                               uap->im &= ~UART011_TXIM;
-                               ret = true;
-                       } else {
-                               uap->im |= UART011_TXIM;
-                               ret = false;
-                       }
-                       writew(uap->im, uap->port.membase + UART011_IMSC);
-               } else if (!(uap->dmacr & UART011_TXDMAE)) {
-                       uap->dmacr |= UART011_TXDMAE;
-                       writew(uap->dmacr,
-                                      uap->port.membase + UART011_DMACR);
-               }
-               return ret;
-       }
-
-       /*
-        * We have an X-char to send.  Disable DMA to prevent it loading
-        * the TX fifo, and then see if we can stuff it into the FIFO.
-        */
-       dmacr = uap->dmacr;
-       uap->dmacr &= ~UART011_TXDMAE;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
-               /*
-                * No space in the FIFO, so enable the transmit interrupt
-                * so we know when there is space.  Note that once we've
-                * loaded the character, we should just re-enable DMA.
-                */
-               return false;
-       }
-
-       writew(uap->port.x_char, uap->port.membase + UART01x_DR);
-       uap->port.icount.tx++;
-       uap->port.x_char = 0;
-
-       /* Success - restore the DMA state */
-       uap->dmacr = dmacr;
-       writew(dmacr, uap->port.membase + UART011_DMACR);
-
-       return true;
-}
-
-/*
- * Flush the transmit buffer.
- * Locking: called with port lock held and IRQs disabled.
- */
-static void pl011_dma_flush_buffer(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (!uap->using_dma)
-               return;
-
-       /* Avoid deadlock with the DMA engine callback */
-       spin_unlock(&uap->port.lock);
-       dmaengine_terminate_all(uap->dmatx.chan);
-       spin_lock(&uap->port.lock);
-       if (uap->dmatx.queued) {
-               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
-                            DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-               uap->dmacr &= ~UART011_TXDMAE;
-               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       }
-}
-
-
-static void pl011_dma_startup(struct uart_amba_port *uap)
-{
-       if (!uap->dmatx.chan)
-               return;
-
-       uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
-       if (!uap->dmatx.buf) {
-               dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
-               uap->port.fifosize = uap->fifosize;
-               return;
-       }
-
-       sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
-
-       /* The DMA buffer is now the FIFO the TTY subsystem can use */
-       uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
-       uap->using_dma = true;
-
-       /* Turn on DMA error (RX/TX will be enabled on demand) */
-       uap->dmacr |= UART011_DMAONERR;
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-
-       /*
-        * ST Micro variants has some specific dma burst threshold
-        * compensation. Set this to 16 bytes, so burst will only
-        * be issued above/below 16 bytes.
-        */
-       if (uap->vendor->dma_threshold)
-               writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
-                              uap->port.membase + ST_UART011_DMAWM);
-}
-
-static void pl011_dma_shutdown(struct uart_amba_port *uap)
-{
-       if (!uap->using_dma)
-               return;
-
-       /* Disable RX and TX DMA */
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
-               barrier();
-
-       spin_lock_irq(&uap->port.lock);
-       uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
-       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
-       spin_unlock_irq(&uap->port.lock);
-
-       /* In theory, this should already be done by pl011_dma_flush_buffer */
-       dmaengine_terminate_all(uap->dmatx.chan);
-       if (uap->dmatx.queued) {
-               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
-                            DMA_TO_DEVICE);
-               uap->dmatx.queued = false;
-       }
-
-       kfree(uap->dmatx.buf);
-
-       uap->using_dma = false;
-}
-
-#else
-/* Blank functions if the DMA engine is not available */
-static inline void pl011_dma_probe(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_remove(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_startup(struct uart_amba_port *uap)
-{
-}
-
-static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
-{
-}
-
-static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
-{
-       return false;
-}
-
-static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
-{
-}
-
-static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
-{
-       return false;
-}
-
-#define pl011_dma_flush_buffer NULL
-#endif
-
-
-static void pl011_stop_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im &= ~UART011_TXIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       pl011_dma_tx_stop(uap);
-}
-
-static void pl011_start_tx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       if (!pl011_dma_tx_start(uap)) {
-               uap->im |= UART011_TXIM;
-               writew(uap->im, uap->port.membase + UART011_IMSC);
-       }
-}
-
-static void pl011_stop_rx(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
-                    UART011_PEIM|UART011_BEIM|UART011_OEIM);
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-}
-
-static void pl011_enable_ms(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-}
-
-static void pl011_rx_chars(struct uart_amba_port *uap)
-{
-       struct tty_struct *tty = uap->port.state->port.tty;
-       unsigned int status, ch, flag, max_count = 256;
-
-       status = readw(uap->port.membase + UART01x_FR);
-       while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
-               ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
-               flag = TTY_NORMAL;
-               uap->port.icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(ch & UART_DR_ERROR)) {
-                       if (ch & UART011_DR_BE) {
-                               ch &= ~(UART011_DR_FE | UART011_DR_PE);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto ignore_char;
-                       } else if (ch & UART011_DR_PE)
-                               uap->port.icount.parity++;
-                       else if (ch & UART011_DR_FE)
-                               uap->port.icount.frame++;
-                       if (ch & UART011_DR_OE)
-                               uap->port.icount.overrun++;
-
-                       ch &= uap->port.read_status_mask;
-
-                       if (ch & UART011_DR_BE)
-                               flag = TTY_BREAK;
-                       else if (ch & UART011_DR_PE)
-                               flag = TTY_PARITY;
-                       else if (ch & UART011_DR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&uap->port, ch & 255))
-                       goto ignore_char;
-
-               uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
-
-       ignore_char:
-               status = readw(uap->port.membase + UART01x_FR);
-       }
-       spin_unlock(&uap->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&uap->port.lock);
-}
-
-static void pl011_tx_chars(struct uart_amba_port *uap)
-{
-       struct circ_buf *xmit = &uap->port.state->xmit;
-       int count;
-
-       if (uap->port.x_char) {
-               writew(uap->port.x_char, uap->port.membase + UART01x_DR);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
-               pl011_stop_tx(&uap->port);
-               return;
-       }
-
-       /* If we are using DMA mode, try to send some characters. */
-       if (pl011_dma_tx_irq(uap))
-               return;
-
-       count = uap->fifosize >> 1;
-       do {
-               writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uap->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       if (uart_circ_empty(xmit))
-               pl011_stop_tx(&uap->port);
-}
-
-static void pl011_modem_status(struct uart_amba_port *uap)
-{
-       unsigned int status, delta;
-
-       status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       delta = status ^ uap->old_status;
-       uap->old_status = status;
-
-       if (!delta)
-               return;
-
-       if (delta & UART01x_FR_DCD)
-               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
-
-       if (delta & UART01x_FR_DSR)
-               uap->port.icount.dsr++;
-
-       if (delta & UART01x_FR_CTS)
-               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
-
-       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t pl011_int(int irq, void *dev_id)
-{
-       struct uart_amba_port *uap = dev_id;
-       unsigned long flags;
-       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
-       int handled = 0;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       status = readw(uap->port.membase + UART011_MIS);
-       if (status) {
-               do {
-                       writew(status & ~(UART011_TXIS|UART011_RTIS|
-                                         UART011_RXIS),
-                              uap->port.membase + UART011_ICR);
-
-                       if (status & (UART011_RTIS|UART011_RXIS))
-                               pl011_rx_chars(uap);
-                       if (status & (UART011_DSRMIS|UART011_DCDMIS|
-                                     UART011_CTSMIS|UART011_RIMIS))
-                               pl011_modem_status(uap);
-                       if (status & UART011_TXIS)
-                               pl011_tx_chars(uap);
-
-                       if (pass_counter-- == 0)
-                               break;
-
-                       status = readw(uap->port.membase + UART011_MIS);
-               } while (status != 0);
-               handled = 1;
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       return IRQ_RETVAL(handled);
-}
-
-static unsigned int pl01x_tx_empty(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status = readw(uap->port.membase + UART01x_FR);
-       return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int result = 0;
-       unsigned int status = readw(uap->port.membase + UART01x_FR);
-
-#define TIOCMBIT(uartbit, tiocmbit)    \
-       if (status & uartbit)           \
-               result |= tiocmbit
-
-       TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
-       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
-       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
-       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
-#undef TIOCMBIT
-       return result;
-}
-
-static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-
-       cr = readw(uap->port.membase + UART011_CR);
-
-#define        TIOCMBIT(tiocmbit, uartbit)             \
-       if (mctrl & tiocmbit)           \
-               cr |= uartbit;          \
-       else                            \
-               cr &= ~uartbit
-
-       TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
-       TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
-       TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
-       TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
-       TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
-
-       if (uap->autorts) {
-               /* We need to disable auto-RTS if we want to turn RTS off */
-               TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
-       }
-#undef TIOCMBIT
-
-       writew(cr, uap->port.membase + UART011_CR);
-}
-
-static void pl011_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned long flags;
-       unsigned int lcr_h;
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       lcr_h = readw(uap->port.membase + uap->lcrh_tx);
-       if (break_state == -1)
-               lcr_h |= UART01x_LCRH_BRK;
-       else
-               lcr_h &= ~UART01x_LCRH_BRK;
-       writew(lcr_h, uap->port.membase + uap->lcrh_tx);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int status;
-
-       status = readw(uap->port.membase + UART01x_FR);
-       if (status & UART01x_FR_RXFE)
-               return NO_POLL_CHAR;
-
-       return readw(uap->port.membase + UART01x_DR);
-}
-
-static void pl010_put_poll_char(struct uart_port *port,
-                        unsigned char ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
-               barrier();
-
-       writew(ch, uap->port.membase + UART01x_DR);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int pl011_startup(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
-       int retval;
-
-       /*
-        * Try to enable the clock producer.
-        */
-       retval = clk_enable(uap->clk);
-       if (retval)
-               goto out;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
-       if (retval)
-               goto clk_dis;
-
-       writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
-
-       /*
-        * Provoke TX FIFO interrupt into asserting.
-        */
-       cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
-       writew(cr, uap->port.membase + UART011_CR);
-       writew(0, uap->port.membase + UART011_FBRD);
-       writew(1, uap->port.membase + UART011_IBRD);
-       writew(0, uap->port.membase + uap->lcrh_rx);
-       if (uap->lcrh_tx != uap->lcrh_rx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(0, uap->port.membase + uap->lcrh_tx);
-       }
-       writew(0, uap->port.membase + UART01x_DR);
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
-               barrier();
-
-       cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
-       writew(cr, uap->port.membase + UART011_CR);
-
-       /* Clear pending error interrupts */
-       writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
-              uap->port.membase + UART011_ICR);
-
-       /*
-        * initialise the old status of the modem signals
-        */
-       uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
-
-       /* Startup DMA */
-       pl011_dma_startup(uap);
-
-       /*
-        * Finally, enable interrupts
-        */
-       spin_lock_irq(&uap->port.lock);
-       uap->im = UART011_RXIM | UART011_RTIM;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       spin_unlock_irq(&uap->port.lock);
-
-       return 0;
-
- clk_dis:
-       clk_disable(uap->clk);
- out:
-       return retval;
-}
-
-static void pl011_shutdown_channel(struct uart_amba_port *uap,
-                                       unsigned int lcrh)
-{
-      unsigned long val;
-
-      val = readw(uap->port.membase + lcrh);
-      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
-      writew(val, uap->port.membase + lcrh);
-}
-
-static void pl011_shutdown(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       /*
-        * disable all interrupts
-        */
-       spin_lock_irq(&uap->port.lock);
-       uap->im = 0;
-       writew(uap->im, uap->port.membase + UART011_IMSC);
-       writew(0xffff, uap->port.membase + UART011_ICR);
-       spin_unlock_irq(&uap->port.lock);
-
-       pl011_dma_shutdown(uap);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(uap->port.irq, uap);
-
-       /*
-        * disable the port
-        */
-       uap->autorts = false;
-       writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
-
-       /*
-        * disable break condition and fifos
-        */
-       pl011_shutdown_channel(uap, uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx)
-               pl011_shutdown_channel(uap, uap->lcrh_tx);
-
-       /*
-        * Shut down the clock producer
-        */
-       clk_disable(uap->clk);
-}
-
-static void
-pl011_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int lcr_h, old_cr;
-       unsigned long flags;
-       unsigned int baud, quot, clkdiv;
-
-       if (uap->vendor->oversampling)
-               clkdiv = 8;
-       else
-               clkdiv = 16;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0,
-                                 port->uartclk / clkdiv);
-
-       if (baud > port->uartclk/16)
-               quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
-       else
-               quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr_h = UART01x_LCRH_WLEN_5;
-               break;
-       case CS6:
-               lcr_h = UART01x_LCRH_WLEN_6;
-               break;
-       case CS7:
-               lcr_h = UART01x_LCRH_WLEN_7;
-               break;
-       default: // CS8
-               lcr_h = UART01x_LCRH_WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               lcr_h |= UART01x_LCRH_STP2;
-       if (termios->c_cflag & PARENB) {
-               lcr_h |= UART01x_LCRH_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_h |= UART01x_LCRH_EPS;
-       }
-       if (uap->fifosize > 1)
-               lcr_h |= UART01x_LCRH_FEN;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UART011_DR_OE | 255;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART011_DR_BE;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= UART011_DR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UART011_DR_OE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_DR_RX;
-
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               pl011_enable_ms(port);
-
-       /* first, disable everything */
-       old_cr = readw(port->membase + UART011_CR);
-       writew(0, port->membase + UART011_CR);
-
-       if (termios->c_cflag & CRTSCTS) {
-               if (old_cr & UART011_CR_RTS)
-                       old_cr |= UART011_CR_RTSEN;
-
-               old_cr |= UART011_CR_CTSEN;
-               uap->autorts = true;
-       } else {
-               old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
-               uap->autorts = false;
-       }
-
-       if (uap->vendor->oversampling) {
-               if (baud > port->uartclk / 16)
-                       old_cr |= ST_UART011_CR_OVSFACT;
-               else
-                       old_cr &= ~ST_UART011_CR_OVSFACT;
-       }
-
-       /* Set baud rate */
-       writew(quot & 0x3f, port->membase + UART011_FBRD);
-       writew(quot >> 6, port->membase + UART011_IBRD);
-
-       /*
-        * ----------v----------v----------v----------v-----
-        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
-        * ----------^----------^----------^----------^-----
-        */
-       writew(lcr_h, port->membase + uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(lcr_h, port->membase + uap->lcrh_tx);
-       }
-       writew(old_cr, port->membase + UART011_CR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pl011_type(struct uart_port *port)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       return uap->port.type == PORT_AMBA ? uap->type : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void pl010_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, SZ_4K);
-}
-
-/*
- * Request the memory region(s) being used by 'port'
- */
-static int pl010_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
-                       != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pl010_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_AMBA;
-               pl010_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops amba_pl011_pops = {
-       .tx_empty       = pl01x_tx_empty,
-       .set_mctrl      = pl011_set_mctrl,
-       .get_mctrl      = pl01x_get_mctrl,
-       .stop_tx        = pl011_stop_tx,
-       .start_tx       = pl011_start_tx,
-       .stop_rx        = pl011_stop_rx,
-       .enable_ms      = pl011_enable_ms,
-       .break_ctl      = pl011_break_ctl,
-       .startup        = pl011_startup,
-       .shutdown       = pl011_shutdown,
-       .flush_buffer   = pl011_dma_flush_buffer,
-       .set_termios    = pl011_set_termios,
-       .type           = pl011_type,
-       .release_port   = pl010_release_port,
-       .request_port   = pl010_request_port,
-       .config_port    = pl010_config_port,
-       .verify_port    = pl010_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = pl010_get_poll_char,
-       .poll_put_char = pl010_put_poll_char,
-#endif
-};
-
-static struct uart_amba_port *amba_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
-
-static void pl011_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_amba_port *uap = (struct uart_amba_port *)port;
-
-       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
-               barrier();
-       writew(ch, uap->port.membase + UART01x_DR);
-}
-
-static void
-pl011_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_amba_port *uap = amba_ports[co->index];
-       unsigned int status, old_cr, new_cr;
-
-       clk_enable(uap->clk);
-
-       /*
-        *      First save the CR then disable the interrupts
-        */
-       old_cr = readw(uap->port.membase + UART011_CR);
-       new_cr = old_cr & ~UART011_CR_CTSEN;
-       new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
-       writew(new_cr, uap->port.membase + UART011_CR);
-
-       uart_console_write(&uap->port, s, count, pl011_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = readw(uap->port.membase + UART01x_FR);
-       } while (status & UART01x_FR_BUSY);
-       writew(old_cr, uap->port.membase + UART011_CR);
-
-       clk_disable(uap->clk);
-}
-
-static void __init
-pl011_console_get_options(struct uart_amba_port *uap, int *baud,
-                            int *parity, int *bits)
-{
-       if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
-               unsigned int lcr_h, ibrd, fbrd;
-
-               lcr_h = readw(uap->port.membase + uap->lcrh_tx);
-
-               *parity = 'n';
-               if (lcr_h & UART01x_LCRH_PEN) {
-                       if (lcr_h & UART01x_LCRH_EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               ibrd = readw(uap->port.membase + UART011_IBRD);
-               fbrd = readw(uap->port.membase + UART011_FBRD);
-
-               *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
-
-               if (uap->vendor->oversampling) {
-                       if (readw(uap->port.membase + UART011_CR)
-                                 & ST_UART011_CR_OVSFACT)
-                               *baud *= 2;
-               }
-       }
-}
-
-static int __init pl011_console_setup(struct console *co, char *options)
-{
-       struct uart_amba_port *uap;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       uap = amba_ports[co->index];
-       if (!uap)
-               return -ENODEV;
-
-       uap->port.uartclk = clk_get_rate(uap->clk);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               pl011_console_get_options(uap, &baud, &parity, &bits);
-
-       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver amba_reg;
-static struct console amba_console = {
-       .name           = "ttyAMA",
-       .write          = pl011_console_write,
-       .device         = uart_console_device,
-       .setup          = pl011_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &amba_reg,
-};
-
-#define AMBA_CONSOLE   (&amba_console)
-#else
-#define AMBA_CONSOLE   NULL
-#endif
-
-static struct uart_driver amba_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAMA",
-       .dev_name               = "ttyAMA",
-       .major                  = SERIAL_AMBA_MAJOR,
-       .minor                  = SERIAL_AMBA_MINOR,
-       .nr                     = UART_NR,
-       .cons                   = AMBA_CONSOLE,
-};
-
-static int pl011_probe(struct amba_device *dev, struct amba_id *id)
-{
-       struct uart_amba_port *uap;
-       struct vendor_data *vendor = id->data;
-       void __iomem *base;
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == NULL)
-                       break;
-
-       if (i == ARRAY_SIZE(amba_ports)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
-       if (uap == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       base = ioremap(dev->res.start, resource_size(&dev->res));
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       uap->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(uap->clk)) {
-               ret = PTR_ERR(uap->clk);
-               goto unmap;
-       }
-
-       uap->vendor = vendor;
-       uap->lcrh_rx = vendor->lcrh_rx;
-       uap->lcrh_tx = vendor->lcrh_tx;
-       uap->fifosize = vendor->fifosize;
-       uap->port.dev = &dev->dev;
-       uap->port.mapbase = dev->res.start;
-       uap->port.membase = base;
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = dev->irq[0];
-       uap->port.fifosize = uap->fifosize;
-       uap->port.ops = &amba_pl011_pops;
-       uap->port.flags = UPF_BOOT_AUTOCONF;
-       uap->port.line = i;
-       pl011_dma_probe(uap);
-
-       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
-
-       amba_ports[i] = uap;
-
-       amba_set_drvdata(dev, uap);
-       ret = uart_add_one_port(&amba_reg, &uap->port);
-       if (ret) {
-               amba_set_drvdata(dev, NULL);
-               amba_ports[i] = NULL;
-               pl011_dma_remove(uap);
-               clk_put(uap->clk);
- unmap:
-               iounmap(base);
- free:
-               kfree(uap);
-       }
- out:
-       return ret;
-}
-
-static int pl011_remove(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-       int i;
-
-       amba_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&amba_reg, &uap->port);
-
-       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-               if (amba_ports[i] == uap)
-                       amba_ports[i] = NULL;
-
-       pl011_dma_remove(uap);
-       iounmap(uap->port.membase);
-       clk_put(uap->clk);
-       kfree(uap);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int pl011_suspend(struct amba_device *dev, pm_message_t state)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (!uap)
-               return -EINVAL;
-
-       return uart_suspend_port(&amba_reg, &uap->port);
-}
-
-static int pl011_resume(struct amba_device *dev)
-{
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-       if (!uap)
-               return -EINVAL;
-
-       return uart_resume_port(&amba_reg, &uap->port);
-}
-#endif
-
-static struct amba_id pl011_ids[] = {
-       {
-               .id     = 0x00041011,
-               .mask   = 0x000fffff,
-               .data   = &vendor_arm,
-       },
-       {
-               .id     = 0x00380802,
-               .mask   = 0x00ffffff,
-               .data   = &vendor_st,
-       },
-       { 0, 0 },
-};
-
-static struct amba_driver pl011_driver = {
-       .drv = {
-               .name   = "uart-pl011",
-       },
-       .id_table       = pl011_ids,
-       .probe          = pl011_probe,
-       .remove         = pl011_remove,
-#ifdef CONFIG_PM
-       .suspend        = pl011_suspend,
-       .resume         = pl011_resume,
-#endif
-};
-
-static int __init pl011_init(void)
-{
-       int ret;
-       printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
-
-       ret = uart_register_driver(&amba_reg);
-       if (ret == 0) {
-               ret = amba_driver_register(&pl011_driver);
-               if (ret)
-                       uart_unregister_driver(&amba_reg);
-       }
-       return ret;
-}
-
-static void __exit pl011_exit(void)
-{
-       amba_driver_unregister(&pl011_driver);
-       uart_unregister_driver(&amba_reg);
-}
-
-/*
- * While this can be a module, if builtin it's most likely the console
- * So let's leave module_exit but move module_init to an earlier place
- */
-arch_initcall(pl011_init);
-module_exit(pl011_exit);
-
-MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("ARM AMBA serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
deleted file mode 100644 (file)
index 095a5d5..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- *  Driver for GRLIB serial ports (APBUART)
- *
- *  Based on linux/drivers/serial/amba.c
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
- *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
- *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
- *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
- */
-
-#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/kthread.h>
-#include <linux/device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/serial_core.h>
-#include <asm/irq.h>
-
-#include "apbuart.h"
-
-#define SERIAL_APBUART_MAJOR   TTY_MAJOR
-#define SERIAL_APBUART_MINOR   64
-#define UART_DUMMY_RSR_RX      0x8000  /* for ignore all read */
-
-static void apbuart_tx_chars(struct uart_port *port);
-
-static void apbuart_stop_tx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr &= ~UART_CTRL_TI;
-       UART_PUT_CTRL(port, cr);
-}
-
-static void apbuart_start_tx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr |= UART_CTRL_TI;
-       UART_PUT_CTRL(port, cr);
-
-       if (UART_GET_STATUS(port) & UART_STATUS_THE)
-               apbuart_tx_chars(port);
-}
-
-static void apbuart_stop_rx(struct uart_port *port)
-{
-       unsigned int cr;
-
-       cr = UART_GET_CTRL(port);
-       cr &= ~(UART_CTRL_RI);
-       UART_PUT_CTRL(port, cr);
-}
-
-static void apbuart_enable_ms(struct uart_port *port)
-{
-       /* No modem status change interrupts for APBUART */
-}
-
-static void apbuart_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, rsr, flag;
-       unsigned int max_chars = port->fifosize;
-
-       status = UART_GET_STATUS(port);
-
-       while (UART_RX_DATA(status) && (max_chars--)) {
-
-               ch = UART_GET_CHAR(port);
-               flag = TTY_NORMAL;
-
-               port->icount.rx++;
-
-               rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
-               UART_PUT_STATUS(port, 0);
-               if (rsr & UART_STATUS_ERR) {
-
-                       if (rsr & UART_STATUS_BR) {
-                               rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       } else if (rsr & UART_STATUS_PE) {
-                               port->icount.parity++;
-                       } else if (rsr & UART_STATUS_FE) {
-                               port->icount.frame++;
-                       }
-                       if (rsr & UART_STATUS_OE)
-                               port->icount.overrun++;
-
-                       rsr &= port->read_status_mask;
-
-                       if (rsr & UART_STATUS_PE)
-                               flag = TTY_PARITY;
-                       else if (rsr & UART_STATUS_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
-
-
-             ignore_char:
-               status = UART_GET_STATUS(port);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
-static void apbuart_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       int count;
-
-       if (port->x_char) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               apbuart_stop_tx(port);
-               return;
-       }
-
-       /* amba: fill FIFO */
-       count = port->fifosize >> 1;
-       do {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               apbuart_stop_tx(port);
-}
-
-static irqreturn_t apbuart_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status;
-
-       spin_lock(&port->lock);
-
-       status = UART_GET_STATUS(port);
-       if (status & UART_STATUS_DR)
-               apbuart_rx_chars(port);
-       if (status & UART_STATUS_THE)
-               apbuart_tx_chars(port);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int apbuart_tx_empty(struct uart_port *port)
-{
-       unsigned int status = UART_GET_STATUS(port);
-       return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int apbuart_get_mctrl(struct uart_port *port)
-{
-       /* The GRLIB APBUART handles flow control in hardware */
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* The GRLIB APBUART handles flow control in hardware */
-}
-
-static void apbuart_break_ctl(struct uart_port *port, int break_state)
-{
-       /* We don't support sending break */
-}
-
-static int apbuart_startup(struct uart_port *port)
-{
-       int retval;
-       unsigned int cr;
-
-       /* Allocate the IRQ */
-       retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
-       if (retval)
-               return retval;
-
-       /* Finally, enable interrupts */
-       cr = UART_GET_CTRL(port);
-       UART_PUT_CTRL(port,
-                     cr | UART_CTRL_RE | UART_CTRL_TE |
-                     UART_CTRL_RI | UART_CTRL_TI);
-
-       return 0;
-}
-
-static void apbuart_shutdown(struct uart_port *port)
-{
-       unsigned int cr;
-
-       /* disable all interrupts, disable the port */
-       cr = UART_GET_CTRL(port);
-       UART_PUT_CTRL(port,
-                     cr & ~(UART_CTRL_RE | UART_CTRL_TE |
-                            UART_CTRL_RI | UART_CTRL_TI));
-
-       /* Free the interrupt */
-       free_irq(port->irq, port);
-}
-
-static void apbuart_set_termios(struct uart_port *port,
-                               struct ktermios *termios, struct ktermios *old)
-{
-       unsigned int cr;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /* Ask the core to calculate the divisor for us. */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       if (baud == 0)
-               panic("invalid baudrate %i\n", port->uartclk / 16);
-
-       /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
-       quot = (uart_get_divisor(port, baud)) * 2;
-       cr = UART_GET_CTRL(port);
-       cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
-
-       if (termios->c_cflag & PARENB) {
-               cr |= UART_CTRL_PE;
-               if ((termios->c_cflag & PARODD))
-                       cr |= UART_CTRL_PS;
-       }
-
-       /* Enable flow control. */
-       if (termios->c_cflag & CRTSCTS)
-               cr |= UART_CTRL_FL;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UART_STATUS_OE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
-
-       /* Characters to ignore */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
-
-       /* Ignore all characters if CREAD is not set. */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_RSR_RX;
-
-       /* Set baud rate */
-       quot -= 1;
-       UART_PUT_SCAL(port, quot);
-       UART_PUT_CTRL(port, cr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *apbuart_type(struct uart_port *port)
-{
-       return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
-}
-
-static void apbuart_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, 0x100);
-}
-
-static int apbuart_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
-           != NULL ? 0 : -EBUSY;
-       return 0;
-}
-
-/* Configure/autoconfigure the port */
-static void apbuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_APBUART;
-               apbuart_request_port(port);
-       }
-}
-
-/* Verify the new serial_struct (for TIOCSSERIAL) */
-static int apbuart_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= NR_IRQS)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops grlib_apbuart_ops = {
-       .tx_empty = apbuart_tx_empty,
-       .set_mctrl = apbuart_set_mctrl,
-       .get_mctrl = apbuart_get_mctrl,
-       .stop_tx = apbuart_stop_tx,
-       .start_tx = apbuart_start_tx,
-       .stop_rx = apbuart_stop_rx,
-       .enable_ms = apbuart_enable_ms,
-       .break_ctl = apbuart_break_ctl,
-       .startup = apbuart_startup,
-       .shutdown = apbuart_shutdown,
-       .set_termios = apbuart_set_termios,
-       .type = apbuart_type,
-       .release_port = apbuart_release_port,
-       .request_port = apbuart_request_port,
-       .config_port = apbuart_config_port,
-       .verify_port = apbuart_verify_port,
-};
-
-static struct uart_port grlib_apbuart_ports[UART_NR];
-static struct device_node *grlib_apbuart_nodes[UART_NR];
-
-static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
-{
-       int ctrl, loop = 0;
-       int status;
-       int fifosize;
-       unsigned long flags;
-
-       ctrl = UART_GET_CTRL(port);
-
-       /*
-        * Enable the transceiver and wait for it to be ready to send data.
-        * Clear interrupts so that this process will not be externally
-        * interrupted in the middle (which can cause the transceiver to
-        * drain prematurely).
-        */
-
-       local_irq_save(flags);
-
-       UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
-
-       while (!UART_TX_READY(UART_GET_STATUS(port)))
-               loop++;
-
-       /*
-        * Disable the transceiver so data isn't actually sent during the
-        * actual test.
-        */
-
-       UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
-
-       fifosize = 1;
-       UART_PUT_CHAR(port, 0);
-
-       /*
-        * So long as transmitting a character increments the tranceivier FIFO
-        * length the FIFO must be at least that big. These bytes will
-        * automatically drain off of the FIFO.
-        */
-
-       status = UART_GET_STATUS(port);
-       while (((status >> 20) & 0x3F) == fifosize) {
-               fifosize++;
-               UART_PUT_CHAR(port, 0);
-               status = UART_GET_STATUS(port);
-       }
-
-       fifosize--;
-
-       UART_PUT_CTRL(port, ctrl);
-       local_irq_restore(flags);
-
-       if (fifosize == 0)
-               fifosize = 1;
-
-       return fifosize;
-}
-
-static void apbuart_flush_fifo(struct uart_port *port)
-{
-       int i;
-
-       for (i = 0; i < port->fifosize; i++)
-               UART_GET_CHAR(port);
-}
-
-
-/* ======================================================================== */
-/* Console driver, if enabled                                               */
-/* ======================================================================== */
-
-#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
-
-static void apbuart_console_putchar(struct uart_port *port, int ch)
-{
-       unsigned int status;
-       do {
-               status = UART_GET_STATUS(port);
-       } while (!UART_TX_READY(status));
-       UART_PUT_CHAR(port, ch);
-}
-
-static void
-apbuart_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &grlib_apbuart_ports[co->index];
-       unsigned int status, old_cr, new_cr;
-
-       /* First save the CR then disable the interrupts */
-       old_cr = UART_GET_CTRL(port);
-       new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
-       UART_PUT_CTRL(port, new_cr);
-
-       uart_console_write(port, s, count, apbuart_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the TCR
-        */
-       do {
-               status = UART_GET_STATUS(port);
-       } while (!UART_TX_READY(status));
-       UART_PUT_CTRL(port, old_cr);
-}
-
-static void __init
-apbuart_console_get_options(struct uart_port *port, int *baud,
-                           int *parity, int *bits)
-{
-       if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
-
-               unsigned int quot, status;
-               status = UART_GET_STATUS(port);
-
-               *parity = 'n';
-               if (status & UART_CTRL_PE) {
-                       if ((status & UART_CTRL_PS) == 0)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               *bits = 8;
-               quot = UART_GET_SCAL(port) / 8;
-               *baud = port->uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init apbuart_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
-                co, co->index, options);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= grlib_apbuart_port_nr)
-               co->index = 0;
-
-       port = &grlib_apbuart_ports[co->index];
-
-       spin_lock_init(&port->lock);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               apbuart_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver grlib_apbuart_driver;
-
-static struct console grlib_apbuart_console = {
-       .name = "ttyS",
-       .write = apbuart_console_write,
-       .device = uart_console_device,
-       .setup = apbuart_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &grlib_apbuart_driver,
-};
-
-
-static int grlib_apbuart_configure(void);
-
-static int __init apbuart_console_init(void)
-{
-       if (grlib_apbuart_configure())
-               return -ENODEV;
-       register_console(&grlib_apbuart_console);
-       return 0;
-}
-
-console_initcall(apbuart_console_init);
-
-#define APBUART_CONSOLE        (&grlib_apbuart_console)
-#else
-#define APBUART_CONSOLE        NULL
-#endif
-
-static struct uart_driver grlib_apbuart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "serial",
-       .dev_name = "ttyS",
-       .major = SERIAL_APBUART_MAJOR,
-       .minor = SERIAL_APBUART_MINOR,
-       .nr = UART_NR,
-       .cons = APBUART_CONSOLE,
-};
-
-
-/* ======================================================================== */
-/* OF Platform Driver                                                       */
-/* ======================================================================== */
-
-static int __devinit apbuart_probe(struct platform_device *op,
-                                  const struct of_device_id *match)
-{
-       int i = -1;
-       struct uart_port *port = NULL;
-
-       i = 0;
-       for (i = 0; i < grlib_apbuart_port_nr; i++) {
-               if (op->dev.of_node == grlib_apbuart_nodes[i])
-                       break;
-       }
-
-       port = &grlib_apbuart_ports[i];
-       port->dev = &op->dev;
-
-       uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
-
-       apbuart_flush_fifo((struct uart_port *) port);
-
-       printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
-              (unsigned long long) port->mapbase, port->irq);
-       return 0;
-}
-
-static struct of_device_id __initdata apbuart_match[] = {
-       {
-        .name = "GAISLER_APBUART",
-        },
-       {
-        .name = "01_00c",
-        },
-       {},
-};
-
-static struct of_platform_driver grlib_apbuart_of_driver = {
-       .probe = apbuart_probe,
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "grlib-apbuart",
-               .of_match_table = apbuart_match,
-       },
-};
-
-
-static int grlib_apbuart_configure(void)
-{
-       struct device_node *np, *rp;
-       const u32 *prop;
-       int freq_khz, line = 0;
-
-       /* Get bus frequency */
-       rp = of_find_node_by_path("/");
-       if (!rp)
-               return -ENODEV;
-       rp = of_get_next_child(rp, NULL);
-       if (!rp)
-               return -ENODEV;
-       prop = of_get_property(rp, "clock-frequency", NULL);
-       if (!prop)
-               return -ENODEV;
-       freq_khz = *prop;
-
-       for_each_matching_node(np, apbuart_match) {
-               const int *irqs, *ampopts;
-               const struct amba_prom_registers *regs;
-               struct uart_port *port;
-               unsigned long addr;
-
-               ampopts = of_get_property(np, "ampopts", NULL);
-               if (ampopts && (*ampopts == 0))
-                       continue; /* Ignore if used by another OS instance */
-
-               irqs = of_get_property(np, "interrupts", NULL);
-               regs = of_get_property(np, "reg", NULL);
-
-               if (!irqs || !regs)
-                       continue;
-
-               grlib_apbuart_nodes[line] = np;
-
-               addr = regs->phys_addr;
-
-               port = &grlib_apbuart_ports[line];
-
-               port->mapbase = addr;
-               port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
-               port->irq = *irqs;
-               port->iotype = UPIO_MEM;
-               port->ops = &grlib_apbuart_ops;
-               port->flags = UPF_BOOT_AUTOCONF;
-               port->line = line;
-               port->uartclk = freq_khz * 1000;
-               port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
-               line++;
-
-               /* We support maximum UART_NR uarts ... */
-               if (line == UART_NR)
-                       break;
-       }
-
-       grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
-       return line ? 0 : -ENODEV;
-}
-
-static int __init grlib_apbuart_init(void)
-{
-       int ret;
-
-       /* Find all APBUARTS in device the tree and initialize their ports */
-       ret = grlib_apbuart_configure();
-       if (ret)
-               return ret;
-
-       printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
-
-       ret = uart_register_driver(&grlib_apbuart_driver);
-
-       if (ret) {
-               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
-                      __FILE__, ret);
-               return ret;
-       }
-
-       ret = of_register_platform_driver(&grlib_apbuart_of_driver);
-       if (ret) {
-               printk(KERN_ERR
-                      "%s: of_register_platform_driver failed (%i)\n",
-                      __FILE__, ret);
-               uart_unregister_driver(&grlib_apbuart_driver);
-               return ret;
-       }
-
-       return ret;
-}
-
-static void __exit grlib_apbuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < grlib_apbuart_port_nr; i++)
-               uart_remove_one_port(&grlib_apbuart_driver,
-                                    &grlib_apbuart_ports[i]);
-
-       uart_unregister_driver(&grlib_apbuart_driver);
-       of_unregister_platform_driver(&grlib_apbuart_of_driver);
-}
-
-module_init(grlib_apbuart_init);
-module_exit(grlib_apbuart_exit);
-
-MODULE_AUTHOR("Aeroflex Gaisler AB");
-MODULE_DESCRIPTION("GRLIB APBUART serial driver");
-MODULE_VERSION("2.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h
deleted file mode 100644 (file)
index 5faf87c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __GRLIB_APBUART_H__
-#define __GRLIB_APBUART_H__
-
-#include <asm/io.h>
-
-#define UART_NR                8
-static int grlib_apbuart_port_nr;
-
-struct grlib_apbuart_regs_map {
-       u32 data;
-       u32 status;
-       u32 ctrl;
-       u32 scaler;
-};
-
-struct amba_prom_registers {
-       unsigned int phys_addr;
-       unsigned int reg_size;
-};
-
-/*
- *  The following defines the bits in the APBUART Status Registers.
- */
-#define UART_STATUS_DR   0x00000001    /* Data Ready */
-#define UART_STATUS_TSE  0x00000002    /* TX Send Register Empty */
-#define UART_STATUS_THE  0x00000004    /* TX Hold Register Empty */
-#define UART_STATUS_BR   0x00000008    /* Break Error */
-#define UART_STATUS_OE   0x00000010    /* RX Overrun Error */
-#define UART_STATUS_PE   0x00000020    /* RX Parity Error */
-#define UART_STATUS_FE   0x00000040    /* RX Framing Error */
-#define UART_STATUS_ERR  0x00000078    /* Error Mask */
-
-/*
- *  The following defines the bits in the APBUART Ctrl Registers.
- */
-#define UART_CTRL_RE     0x00000001    /* Receiver enable */
-#define UART_CTRL_TE     0x00000002    /* Transmitter enable */
-#define UART_CTRL_RI     0x00000004    /* Receiver interrupt enable */
-#define UART_CTRL_TI     0x00000008    /* Transmitter irq */
-#define UART_CTRL_PS     0x00000010    /* Parity select */
-#define UART_CTRL_PE     0x00000020    /* Parity enable */
-#define UART_CTRL_FL     0x00000040    /* Flow control enable */
-#define UART_CTRL_LB     0x00000080    /* Loopback enable */
-
-#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
-
-#define APBBASE_DATA_P(port)   (&(APBBASE(port)->data))
-#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
-#define APBBASE_CTRL_P(port)   (&(APBBASE(port)->ctrl))
-#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
-
-#define UART_GET_CHAR(port)    (__raw_readl(APBBASE_DATA_P(port)))
-#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
-#define UART_GET_STATUS(port)  (__raw_readl(APBBASE_STATUS_P(port)))
-#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
-#define UART_GET_CTRL(port)    (__raw_readl(APBBASE_CTRL_P(port)))
-#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
-#define UART_GET_SCAL(port)    (__raw_readl(APBBASE_SCALAR_P(port)))
-#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
-
-#define UART_RX_DATA(s)                (((s) & UART_STATUS_DR) != 0)
-#define UART_TX_READY(s)       (((s) & UART_STATUS_THE) != 0)
-
-#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
deleted file mode 100644 (file)
index 2a1d52f..0000000
+++ /dev/null
@@ -1,1813 +0,0 @@
-/*
- *  linux/drivers/char/atmel_serial.c
- *
- *  Driver for Atmel AT91 / AT32 Serial ports
- *  Copyright (C) 2003 Rick Bronson
- *
- *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  DMA support added by Chip Coldwell.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty_flip.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/atmel_pdc.h>
-#include <linux/atmel_serial.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-#include <asm/ioctls.h>
-
-#include <asm/mach/serial_at91.h>
-#include <mach/board.h>
-
-#ifdef CONFIG_ARM
-#include <mach/cpu.h>
-#include <mach/gpio.h>
-#endif
-
-#define PDC_BUFFER_SIZE                512
-/* Revisit: We should calculate this based on the actual port settings */
-#define PDC_RX_TIMEOUT         (3 * 10)                /* 3 bytes */
-
-#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-static void atmel_start_rx(struct uart_port *port);
-static void atmel_stop_rx(struct uart_port *port);
-
-#ifdef CONFIG_SERIAL_ATMEL_TTYAT
-
-/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
- * should coexist with the 8250 driver, such as if we have an external 16C550
- * UART. */
-#define SERIAL_ATMEL_MAJOR     204
-#define MINOR_START            154
-#define ATMEL_DEVICENAME       "ttyAT"
-
-#else
-
-/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
- * name, but it is legally reserved for the 8250 driver. */
-#define SERIAL_ATMEL_MAJOR     TTY_MAJOR
-#define MINOR_START            64
-#define ATMEL_DEVICENAME       "ttyS"
-
-#endif
-
-#define ATMEL_ISR_PASS_LIMIT   256
-
-/* UART registers. CR is write-only, hence no GET macro */
-#define UART_PUT_CR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_CR)
-#define UART_GET_MR(port)      __raw_readl((port)->membase + ATMEL_US_MR)
-#define UART_PUT_MR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_MR)
-#define UART_PUT_IER(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IER)
-#define UART_PUT_IDR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IDR)
-#define UART_GET_IMR(port)     __raw_readl((port)->membase + ATMEL_US_IMR)
-#define UART_GET_CSR(port)     __raw_readl((port)->membase + ATMEL_US_CSR)
-#define UART_GET_CHAR(port)    __raw_readl((port)->membase + ATMEL_US_RHR)
-#define UART_PUT_CHAR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_THR)
-#define UART_GET_BRGR(port)    __raw_readl((port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_BRGR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_RTOR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
-#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
-
- /* PDC registers */
-#define UART_PUT_PTCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
-#define UART_GET_PTSR(port)    __raw_readl((port)->membase + ATMEL_PDC_PTSR)
-
-#define UART_PUT_RPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
-#define UART_GET_RPR(port)     __raw_readl((port)->membase + ATMEL_PDC_RPR)
-#define UART_PUT_RCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
-#define UART_PUT_RNPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
-#define UART_PUT_RNCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
-
-#define UART_PUT_TPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
-#define UART_PUT_TCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
-#define UART_GET_TCR(port)     __raw_readl((port)->membase + ATMEL_PDC_TCR)
-
-static int (*atmel_open_hook)(struct uart_port *);
-static void (*atmel_close_hook)(struct uart_port *);
-
-struct atmel_dma_buffer {
-       unsigned char   *buf;
-       dma_addr_t      dma_addr;
-       unsigned int    dma_size;
-       unsigned int    ofs;
-};
-
-struct atmel_uart_char {
-       u16             status;
-       u16             ch;
-};
-
-#define ATMEL_SERIAL_RINGSIZE 1024
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct atmel_uart_port {
-       struct uart_port        uart;           /* uart */
-       struct clk              *clk;           /* uart clock */
-       int                     may_wakeup;     /* cached value of device_may_wakeup for times we need to disable it */
-       u32                     backup_imr;     /* IMR saved during suspend */
-       int                     break_active;   /* break being received */
-
-       short                   use_dma_rx;     /* enable PDC receiver */
-       short                   pdc_rx_idx;     /* current PDC RX buffer */
-       struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
-
-       short                   use_dma_tx;     /* enable PDC transmitter */
-       struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
-
-       struct tasklet_struct   tasklet;
-       unsigned int            irq_status;
-       unsigned int            irq_status_prev;
-
-       struct circ_buf         rx_ring;
-
-       struct serial_rs485     rs485;          /* rs485 settings */
-       unsigned int            tx_done_mask;
-};
-
-static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
-
-#ifdef SUPPORT_SYSRQ
-static struct console atmel_console;
-#endif
-
-static inline struct atmel_uart_port *
-to_atmel_uart_port(struct uart_port *uart)
-{
-       return container_of(uart, struct atmel_uart_port, uart);
-}
-
-#ifdef CONFIG_SERIAL_ATMEL_PDC
-static bool atmel_use_dma_rx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       return atmel_port->use_dma_rx;
-}
-
-static bool atmel_use_dma_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       return atmel_port->use_dma_tx;
-}
-#else
-static bool atmel_use_dma_rx(struct uart_port *port)
-{
-       return false;
-}
-
-static bool atmel_use_dma_tx(struct uart_port *port)
-{
-       return false;
-}
-#endif
-
-/* Enable or disable the rs485 support */
-void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int mode;
-
-       spin_lock(&port->lock);
-
-       /* Disable interrupts */
-       UART_PUT_IDR(port, atmel_port->tx_done_mask);
-
-       mode = UART_GET_MR(port);
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       atmel_port->rs485 = *rs485conf;
-
-       if (rs485conf->flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-               if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-               if (atmel_use_dma_tx(port))
-                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
-                               ATMEL_US_TXBUFE;
-               else
-                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
-       }
-       UART_PUT_MR(port, mode);
-
-       /* Enable interrupts */
-       UART_PUT_IER(port, atmel_port->tx_done_mask);
-
-       spin_unlock(&port->lock);
-
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
- */
-static u_int atmel_tx_empty(struct uart_port *port)
-{
-       return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
-}
-
-/*
- * Set state of the modem control output lines
- */
-static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       unsigned int control = 0;
-       unsigned int mode;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-#ifdef CONFIG_ARCH_AT91RM9200
-       if (cpu_is_at91rm9200()) {
-               /*
-                * AT91RM9200 Errata #39: RTS0 is not internally connected
-                * to PA21. We need to drive the pin manually.
-                */
-               if (port->mapbase == AT91RM9200_BASE_US0) {
-                       if (mctrl & TIOCM_RTS)
-                               at91_set_gpio_value(AT91_PIN_PA21, 0);
-                       else
-                               at91_set_gpio_value(AT91_PIN_PA21, 1);
-               }
-       }
-#endif
-
-       if (mctrl & TIOCM_RTS)
-               control |= ATMEL_US_RTSEN;
-       else
-               control |= ATMEL_US_RTSDIS;
-
-       if (mctrl & TIOCM_DTR)
-               control |= ATMEL_US_DTREN;
-       else
-               control |= ATMEL_US_DTRDIS;
-
-       UART_PUT_CR(port, control);
-
-       /* Local loopback mode? */
-       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
-       if (mctrl & TIOCM_LOOP)
-               mode |= ATMEL_US_CHMODE_LOC_LOOP;
-       else
-               mode |= ATMEL_US_CHMODE_NORMAL;
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-       }
-       UART_PUT_MR(port, mode);
-}
-
-/*
- * Get state of the modem control input lines
- */
-static u_int atmel_get_mctrl(struct uart_port *port)
-{
-       unsigned int status, ret = 0;
-
-       status = UART_GET_CSR(port);
-
-       /*
-        * The control signals are active low.
-        */
-       if (!(status & ATMEL_US_DCD))
-               ret |= TIOCM_CD;
-       if (!(status & ATMEL_US_CTS))
-               ret |= TIOCM_CTS;
-       if (!(status & ATMEL_US_DSR))
-               ret |= TIOCM_DSR;
-       if (!(status & ATMEL_US_RI))
-               ret |= TIOCM_RI;
-
-       return ret;
-}
-
-/*
- * Stop transmitting.
- */
-static void atmel_stop_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               /* disable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-       }
-       /* Disable interrupts */
-       UART_PUT_IDR(port, atmel_port->tx_done_mask);
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-               atmel_start_rx(port);
-}
-
-/*
- * Start transmitting.
- */
-static void atmel_start_tx(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
-                       /* The transmitter is already running.  Yes, we
-                          really need this.*/
-                       return;
-
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-                       atmel_stop_rx(port);
-
-               /* re-enable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-       }
-       /* Enable interrupts */
-       UART_PUT_IER(port, atmel_port->tx_done_mask);
-}
-
-/*
- * start receiving - port is in process of being opened.
- */
-static void atmel_start_rx(struct uart_port *port)
-{
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);  /* reset status and receiver */
-
-       if (atmel_use_dma_rx(port)) {
-               /* enable PDC controller */
-               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
-                       port->read_status_mask);
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
-       } else {
-               UART_PUT_IER(port, ATMEL_US_RXRDY);
-       }
-}
-
-/*
- * Stop receiving - port is in process of being closed.
- */
-static void atmel_stop_rx(struct uart_port *port)
-{
-       if (atmel_use_dma_rx(port)) {
-               /* disable PDC receive */
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
-               UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
-                       port->read_status_mask);
-       } else {
-               UART_PUT_IDR(port, ATMEL_US_RXRDY);
-       }
-}
-
-/*
- * Enable modem status interrupts
- */
-static void atmel_enable_ms(struct uart_port *port)
-{
-       UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
-                       | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
-}
-
-/*
- * Control the transmission of a break signal
- */
-static void atmel_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state != 0)
-               UART_PUT_CR(port, ATMEL_US_STTBRK);     /* start break */
-       else
-               UART_PUT_CR(port, ATMEL_US_STPBRK);     /* stop break */
-}
-
-/*
- * Stores the incoming character in the ring buffer
- */
-static void
-atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
-                    unsigned int ch)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *ring = &atmel_port->rx_ring;
-       struct atmel_uart_char *c;
-
-       if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
-               /* Buffer overflow, ignore char */
-               return;
-
-       c = &((struct atmel_uart_char *)ring->buf)[ring->head];
-       c->status       = status;
-       c->ch           = ch;
-
-       /* Make sure the character is stored before we update head. */
-       smp_wmb();
-
-       ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
-}
-
-/*
- * Deal with parity, framing and overrun errors.
- */
-static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
-{
-       /* clear error */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-
-       if (status & ATMEL_US_RXBRK) {
-               /* ignore side-effect */
-               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-               port->icount.brk++;
-       }
-       if (status & ATMEL_US_PARE)
-               port->icount.parity++;
-       if (status & ATMEL_US_FRAME)
-               port->icount.frame++;
-       if (status & ATMEL_US_OVRE)
-               port->icount.overrun++;
-}
-
-/*
- * Characters received (called from interrupt handler)
- */
-static void atmel_rx_chars(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, ch;
-
-       status = UART_GET_CSR(port);
-       while (status & ATMEL_US_RXRDY) {
-               ch = UART_GET_CHAR(port);
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
-                            || atmel_port->break_active)) {
-
-                       /* clear error */
-                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-
-                       if (status & ATMEL_US_RXBRK
-                           && !atmel_port->break_active) {
-                               atmel_port->break_active = 1;
-                               UART_PUT_IER(port, ATMEL_US_RXBRK);
-                       } else {
-                               /*
-                                * This is either the end-of-break
-                                * condition or we've received at
-                                * least one character without RXBRK
-                                * being set. In both cases, the next
-                                * RXBRK will indicate start-of-break.
-                                */
-                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
-                               status &= ~ATMEL_US_RXBRK;
-                               atmel_port->break_active = 0;
-                       }
-               }
-
-               atmel_buffer_rx_char(port, status, ch);
-               status = UART_GET_CSR(port);
-       }
-
-       tasklet_schedule(&atmel_port->tasklet);
-}
-
-/*
- * Transmit characters (called from tasklet with TXRDY interrupt
- * disabled)
- */
-static void atmel_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (!uart_circ_empty(xmit))
-               /* Enable interrupts */
-               UART_PUT_IER(port, atmel_port->tx_done_mask);
-}
-
-/*
- * receive interrupt handler.
- */
-static void
-atmel_handle_receive(struct uart_port *port, unsigned int pending)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_rx(port)) {
-               /*
-                * PDC receive. Just schedule the tasklet and let it
-                * figure out the details.
-                *
-                * TODO: We're not handling error flags correctly at
-                * the moment.
-                */
-               if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
-                       UART_PUT_IDR(port, (ATMEL_US_ENDRX
-                                               | ATMEL_US_TIMEOUT));
-                       tasklet_schedule(&atmel_port->tasklet);
-               }
-
-               if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
-                               ATMEL_US_FRAME | ATMEL_US_PARE))
-                       atmel_pdc_rxerr(port, pending);
-       }
-
-       /* Interrupt receive */
-       if (pending & ATMEL_US_RXRDY)
-               atmel_rx_chars(port);
-       else if (pending & ATMEL_US_RXBRK) {
-               /*
-                * End of break detected. If it came along with a
-                * character, atmel_rx_chars will handle it.
-                */
-               UART_PUT_CR(port, ATMEL_US_RSTSTA);
-               UART_PUT_IDR(port, ATMEL_US_RXBRK);
-               atmel_port->break_active = 0;
-       }
-}
-
-/*
- * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
- */
-static void
-atmel_handle_transmit(struct uart_port *port, unsigned int pending)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (pending & atmel_port->tx_done_mask) {
-               /* Either PDC or interrupt transmission */
-               UART_PUT_IDR(port, atmel_port->tx_done_mask);
-               tasklet_schedule(&atmel_port->tasklet);
-       }
-}
-
-/*
- * status flags interrupt handler.
- */
-static void
-atmel_handle_status(struct uart_port *port, unsigned int pending,
-                   unsigned int status)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
-                               | ATMEL_US_CTSIC)) {
-               atmel_port->irq_status = status;
-               tasklet_schedule(&atmel_port->tasklet);
-       }
-}
-
-/*
- * Interrupt handler
- */
-static irqreturn_t atmel_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status, pending, pass_counter = 0;
-
-       do {
-               status = UART_GET_CSR(port);
-               pending = status & UART_GET_IMR(port);
-               if (!pending)
-                       break;
-
-               atmel_handle_receive(port, pending);
-               atmel_handle_status(port, pending, status);
-               atmel_handle_transmit(port, pending);
-       } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
-
-       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/*
- * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
- */
-static void atmel_tx_dma(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *xmit = &port->state->xmit;
-       struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-       int count;
-
-       /* nothing left to transmit? */
-       if (UART_GET_TCR(port))
-               return;
-
-       xmit->tail += pdc->ofs;
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       port->icount.tx += pdc->ofs;
-       pdc->ofs = 0;
-
-       /* more to transmit - setup next transfer */
-
-       /* disable PDC transmit */
-       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-
-       if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
-               dma_sync_single_for_device(port->dev,
-                                          pdc->dma_addr,
-                                          pdc->dma_size,
-                                          DMA_TO_DEVICE);
-
-               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               pdc->ofs = count;
-
-               UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
-               UART_PUT_TCR(port, count);
-               /* re-enable PDC transmit */
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-               /* Enable interrupts */
-               UART_PUT_IER(port, atmel_port->tx_done_mask);
-       } else {
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-                       /* DMA done, stop TX, start RX for RS485 */
-                       atmel_start_rx(port);
-               }
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void atmel_rx_from_ring(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct circ_buf *ring = &atmel_port->rx_ring;
-       unsigned int flg;
-       unsigned int status;
-
-       while (ring->head != ring->tail) {
-               struct atmel_uart_char c;
-
-               /* Make sure c is loaded after head. */
-               smp_rmb();
-
-               c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
-
-               ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
-
-               port->icount.rx++;
-               status = c.status;
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
-                       if (status & ATMEL_US_RXBRK) {
-                               /* ignore side-effect */
-                               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       }
-                       if (status & ATMEL_US_PARE)
-                               port->icount.parity++;
-                       if (status & ATMEL_US_FRAME)
-                               port->icount.frame++;
-                       if (status & ATMEL_US_OVRE)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-
-                       if (status & ATMEL_US_RXBRK)
-                               flg = TTY_BREAK;
-                       else if (status & ATMEL_US_PARE)
-                               flg = TTY_PARITY;
-                       else if (status & ATMEL_US_FRAME)
-                               flg = TTY_FRAME;
-               }
-
-
-               if (uart_handle_sysrq_char(port, c.ch))
-                       continue;
-
-               uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
-       }
-
-       /*
-        * Drop the lock here since it might end up calling
-        * uart_start(), which takes the lock.
-        */
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(port->state->port.tty);
-       spin_lock(&port->lock);
-}
-
-static void atmel_rx_from_dma(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       struct atmel_dma_buffer *pdc;
-       int rx_idx = atmel_port->pdc_rx_idx;
-       unsigned int head;
-       unsigned int tail;
-       unsigned int count;
-
-       do {
-               /* Reset the UART timeout early so that we don't miss one */
-               UART_PUT_CR(port, ATMEL_US_STTTO);
-
-               pdc = &atmel_port->pdc_rx[rx_idx];
-               head = UART_GET_RPR(port) - pdc->dma_addr;
-               tail = pdc->ofs;
-
-               /* If the PDC has switched buffers, RPR won't contain
-                * any address within the current buffer. Since head
-                * is unsigned, we just need a one-way comparison to
-                * find out.
-                *
-                * In this case, we just need to consume the entire
-                * buffer and resubmit it for DMA. This will clear the
-                * ENDRX bit as well, so that we can safely re-enable
-                * all interrupts below.
-                */
-               head = min(head, pdc->dma_size);
-
-               if (likely(head != tail)) {
-                       dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
-                                       pdc->dma_size, DMA_FROM_DEVICE);
-
-                       /*
-                        * head will only wrap around when we recycle
-                        * the DMA buffer, and when that happens, we
-                        * explicitly set tail to 0. So head will
-                        * always be greater than tail.
-                        */
-                       count = head - tail;
-
-                       tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
-
-                       dma_sync_single_for_device(port->dev, pdc->dma_addr,
-                                       pdc->dma_size, DMA_FROM_DEVICE);
-
-                       port->icount.rx += count;
-                       pdc->ofs = head;
-               }
-
-               /*
-                * If the current buffer is full, we need to check if
-                * the next one contains any additional data.
-                */
-               if (head >= pdc->dma_size) {
-                       pdc->ofs = 0;
-                       UART_PUT_RNPR(port, pdc->dma_addr);
-                       UART_PUT_RNCR(port, pdc->dma_size);
-
-                       rx_idx = !rx_idx;
-                       atmel_port->pdc_rx_idx = rx_idx;
-               }
-       } while (head >= pdc->dma_size);
-
-       /*
-        * Drop the lock here since it might end up calling
-        * uart_start(), which takes the lock.
-        */
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&port->lock);
-
-       UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-}
-
-/*
- * tasklet handling tty stuff outside the interrupt handler.
- */
-static void atmel_tasklet_func(unsigned long data)
-{
-       struct uart_port *port = (struct uart_port *)data;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status;
-       unsigned int status_change;
-
-       /* The interrupt handler does not take the lock */
-       spin_lock(&port->lock);
-
-       if (atmel_use_dma_tx(port))
-               atmel_tx_dma(port);
-       else
-               atmel_tx_chars(port);
-
-       status = atmel_port->irq_status;
-       status_change = status ^ atmel_port->irq_status_prev;
-
-       if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
-                               | ATMEL_US_DCD | ATMEL_US_CTS)) {
-               /* TODO: All reads to CSR will clear these interrupts! */
-               if (status_change & ATMEL_US_RI)
-                       port->icount.rng++;
-               if (status_change & ATMEL_US_DSR)
-                       port->icount.dsr++;
-               if (status_change & ATMEL_US_DCD)
-                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
-               if (status_change & ATMEL_US_CTS)
-                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
-
-               wake_up_interruptible(&port->state->port.delta_msr_wait);
-
-               atmel_port->irq_status_prev = status;
-       }
-
-       if (atmel_use_dma_rx(port))
-               atmel_rx_from_dma(port);
-       else
-               atmel_rx_from_ring(port);
-
-       spin_unlock(&port->lock);
-}
-
-/*
- * Perform initialization and enable port for reception
- */
-static int atmel_startup(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       int retval;
-
-       /*
-        * Ensure that no interrupts are enabled otherwise when
-        * request_irq() is called we could get stuck trying to
-        * handle an unexpected interrupt
-        */
-       UART_PUT_IDR(port, -1);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
-                       tty ? tty->name : "atmel_serial", port);
-       if (retval) {
-               printk("atmel_serial: atmel_startup - Can't get irq\n");
-               return retval;
-       }
-
-       /*
-        * Initialize DMA (if necessary)
-        */
-       if (atmel_use_dma_rx(port)) {
-               int i;
-
-               for (i = 0; i < 2; i++) {
-                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-                       pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
-                       if (pdc->buf == NULL) {
-                               if (i != 0) {
-                                       dma_unmap_single(port->dev,
-                                               atmel_port->pdc_rx[0].dma_addr,
-                                               PDC_BUFFER_SIZE,
-                                               DMA_FROM_DEVICE);
-                                       kfree(atmel_port->pdc_rx[0].buf);
-                               }
-                               free_irq(port->irq, port);
-                               return -ENOMEM;
-                       }
-                       pdc->dma_addr = dma_map_single(port->dev,
-                                                      pdc->buf,
-                                                      PDC_BUFFER_SIZE,
-                                                      DMA_FROM_DEVICE);
-                       pdc->dma_size = PDC_BUFFER_SIZE;
-                       pdc->ofs = 0;
-               }
-
-               atmel_port->pdc_rx_idx = 0;
-
-               UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
-               UART_PUT_RCR(port, PDC_BUFFER_SIZE);
-
-               UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
-               UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
-       }
-       if (atmel_use_dma_tx(port)) {
-               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-               struct circ_buf *xmit = &port->state->xmit;
-
-               pdc->buf = xmit->buf;
-               pdc->dma_addr = dma_map_single(port->dev,
-                                              pdc->buf,
-                                              UART_XMIT_SIZE,
-                                              DMA_TO_DEVICE);
-               pdc->dma_size = UART_XMIT_SIZE;
-               pdc->ofs = 0;
-       }
-
-       /*
-        * If there is a specific "open" function (to register
-        * control line interrupts)
-        */
-       if (atmel_open_hook) {
-               retval = atmel_open_hook(port);
-               if (retval) {
-                       free_irq(port->irq, port);
-                       return retval;
-               }
-       }
-
-       /* Save current CSR for comparison in atmel_tasklet_func() */
-       atmel_port->irq_status_prev = UART_GET_CSR(port);
-       atmel_port->irq_status = atmel_port->irq_status_prev;
-
-       /*
-        * Finally, enable the serial port
-        */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       /* enable xmit & rcvr */
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       if (atmel_use_dma_rx(port)) {
-               /* set UART timeout */
-               UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-               UART_PUT_CR(port, ATMEL_US_STTTO);
-
-               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-               /* enable PDC controller */
-               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
-       } else {
-               /* enable receive only */
-               UART_PUT_IER(port, ATMEL_US_RXRDY);
-       }
-
-       return 0;
-}
-
-/*
- * Disable the port
- */
-static void atmel_shutdown(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       /*
-        * Ensure everything is stopped.
-        */
-       atmel_stop_rx(port);
-       atmel_stop_tx(port);
-
-       /*
-        * Shut-down the DMA.
-        */
-       if (atmel_use_dma_rx(port)) {
-               int i;
-
-               for (i = 0; i < 2; i++) {
-                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-                       dma_unmap_single(port->dev,
-                                        pdc->dma_addr,
-                                        pdc->dma_size,
-                                        DMA_FROM_DEVICE);
-                       kfree(pdc->buf);
-               }
-       }
-       if (atmel_use_dma_tx(port)) {
-               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-
-               dma_unmap_single(port->dev,
-                                pdc->dma_addr,
-                                pdc->dma_size,
-                                DMA_TO_DEVICE);
-       }
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-       UART_PUT_IDR(port, -1);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(port->irq, port);
-
-       /*
-        * If there is a specific "close" function (to unregister
-        * control line interrupts)
-        */
-       if (atmel_close_hook)
-               atmel_close_hook(port);
-}
-
-/*
- * Flush any TX data submitted for DMA. Called when the TX circular
- * buffer is reset.
- */
-static void atmel_flush_buffer(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_dma_tx(port)) {
-               UART_PUT_TCR(port, 0);
-               atmel_port->pdc_tx.ofs = 0;
-       }
-}
-
-/*
- * Power / Clock management.
- */
-static void atmel_serial_pm(struct uart_port *port, unsigned int state,
-                           unsigned int oldstate)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       switch (state) {
-       case 0:
-               /*
-                * Enable the peripheral clock for this serial port.
-                * This is called on uart_open() or a resume event.
-                */
-               clk_enable(atmel_port->clk);
-
-               /* re-enable interrupts if we disabled some on suspend */
-               UART_PUT_IER(port, atmel_port->backup_imr);
-               break;
-       case 3:
-               /* Back up the interrupt mask and disable all interrupts */
-               atmel_port->backup_imr = UART_GET_IMR(port);
-               UART_PUT_IDR(port, -1);
-
-               /*
-                * Disable the peripheral clock for this serial port.
-                * This is called on uart_close() or a suspend event.
-                */
-               clk_disable(atmel_port->clk);
-               break;
-       default:
-               printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
-       }
-}
-
-/*
- * Change the port parameters
- */
-static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int mode, imr, quot, baud;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       /* Get current mode register */
-       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
-                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
-                                       | ATMEL_US_USMODE);
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
-               quot /= 8;
-               mode |= ATMEL_US_USCLKS_MCK_DIV8;
-       }
-
-       /* byte size */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               mode |= ATMEL_US_CHRL_5;
-               break;
-       case CS6:
-               mode |= ATMEL_US_CHRL_6;
-               break;
-       case CS7:
-               mode |= ATMEL_US_CHRL_7;
-               break;
-       default:
-               mode |= ATMEL_US_CHRL_8;
-               break;
-       }
-
-       /* stop bits */
-       if (termios->c_cflag & CSTOPB)
-               mode |= ATMEL_US_NBSTOP_2;
-
-       /* parity */
-       if (termios->c_cflag & PARENB) {
-               /* Mark or Space parity */
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               mode |= ATMEL_US_PAR_MARK;
-                       else
-                               mode |= ATMEL_US_PAR_SPACE;
-               } else if (termios->c_cflag & PARODD)
-                       mode |= ATMEL_US_PAR_ODD;
-               else
-                       mode |= ATMEL_US_PAR_EVEN;
-       } else
-               mode |= ATMEL_US_PAR_NONE;
-
-       /* hardware handshake (RTS/CTS) */
-       if (termios->c_cflag & CRTSCTS)
-               mode |= ATMEL_US_USMODE_HWHS;
-       else
-               mode |= ATMEL_US_USMODE_NORMAL;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->read_status_mask = ATMEL_US_OVRE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= ATMEL_US_RXBRK;
-
-       if (atmel_use_dma_rx(port))
-               /* need to enable error interrupts */
-               UART_PUT_IER(port, port->read_status_mask);
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= ATMEL_US_RXBRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= ATMEL_US_OVRE;
-       }
-       /* TODO: Ignore all characters if CREAD is set.*/
-
-       /* update the per-port timeout */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * save/disable interrupts. The tty layer will ensure that the
-        * transmitter is empty if requested by the caller, so there's
-        * no need to wait for it here.
-        */
-       imr = UART_GET_IMR(port);
-       UART_PUT_IDR(port, -1);
-
-       /* disable receiver and transmitter */
-       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
-
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-       }
-
-       /* set the parity, stop bits and data size */
-       UART_PUT_MR(port, mode);
-
-       /* set the baud rate */
-       UART_PUT_BRGR(port, quot);
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       /* restore interrupts */
-       UART_PUT_IER(port, imr);
-
-       /* CTS flow-control and modem-status interrupts */
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               port->ops->enable_ms(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return string describing the specified port
- */
-static const char *atmel_type(struct uart_port *port)
-{
-       return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void atmel_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-       release_mem_region(port->mapbase, size);
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int atmel_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-       if (!request_mem_region(port->mapbase, size, "atmel_serial"))
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_mem_region(port->mapbase, size);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void atmel_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_ATMEL;
-               atmel_request_port(port);
-       }
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
-               ret = -EINVAL;
-       if (port->irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (port->uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)port->mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (port->iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int atmel_poll_get_char(struct uart_port *port)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
-               cpu_relax();
-
-       return UART_GET_CHAR(port);
-}
-
-static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
-               cpu_relax();
-
-       UART_PUT_CHAR(port, ch);
-}
-#endif
-
-static int
-atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
-{
-       struct serial_rs485 rs485conf;
-
-       switch (cmd) {
-       case TIOCSRS485:
-               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-
-               atmel_config_rs485(port, &rs485conf);
-               break;
-
-       case TIOCGRS485:
-               if (copy_to_user((struct serial_rs485 *) arg,
-                                       &(to_atmel_uart_port(port)->rs485),
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-
-
-static struct uart_ops atmel_pops = {
-       .tx_empty       = atmel_tx_empty,
-       .set_mctrl      = atmel_set_mctrl,
-       .get_mctrl      = atmel_get_mctrl,
-       .stop_tx        = atmel_stop_tx,
-       .start_tx       = atmel_start_tx,
-       .stop_rx        = atmel_stop_rx,
-       .enable_ms      = atmel_enable_ms,
-       .break_ctl      = atmel_break_ctl,
-       .startup        = atmel_startup,
-       .shutdown       = atmel_shutdown,
-       .flush_buffer   = atmel_flush_buffer,
-       .set_termios    = atmel_set_termios,
-       .type           = atmel_type,
-       .release_port   = atmel_release_port,
-       .request_port   = atmel_request_port,
-       .config_port    = atmel_config_port,
-       .verify_port    = atmel_verify_port,
-       .pm             = atmel_serial_pm,
-       .ioctl          = atmel_ioctl,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = atmel_poll_get_char,
-       .poll_put_char  = atmel_poll_put_char,
-#endif
-};
-
-/*
- * Configure the port from the platform device resource info.
- */
-static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
-                                     struct platform_device *pdev)
-{
-       struct uart_port *port = &atmel_port->uart;
-       struct atmel_uart_data *data = pdev->dev.platform_data;
-
-       port->iotype            = UPIO_MEM;
-       port->flags             = UPF_BOOT_AUTOCONF;
-       port->ops               = &atmel_pops;
-       port->fifosize          = 1;
-       port->line              = pdev->id;
-       port->dev               = &pdev->dev;
-       port->mapbase   = pdev->resource[0].start;
-       port->irq       = pdev->resource[1].start;
-
-       tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
-                       (unsigned long)port);
-
-       memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
-
-       if (data->regs)
-               /* Already mapped by setup code */
-               port->membase = data->regs;
-       else {
-               port->flags     |= UPF_IOREMAP;
-               port->membase   = NULL;
-       }
-
-       /* for console, the clock could already be configured */
-       if (!atmel_port->clk) {
-               atmel_port->clk = clk_get(&pdev->dev, "usart");
-               clk_enable(atmel_port->clk);
-               port->uartclk = clk_get_rate(atmel_port->clk);
-               clk_disable(atmel_port->clk);
-               /* only enable clock when USART is in use */
-       }
-
-       atmel_port->use_dma_rx = data->use_dma_rx;
-       atmel_port->use_dma_tx = data->use_dma_tx;
-       atmel_port->rs485       = data->rs485;
-       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
-               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-       else if (atmel_use_dma_tx(port)) {
-               port->fifosize = PDC_BUFFER_SIZE;
-               atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
-       } else {
-               atmel_port->tx_done_mask = ATMEL_US_TXRDY;
-       }
-}
-
-/*
- * Register board-specific modem-control line handlers.
- */
-void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
-{
-       if (fns->enable_ms)
-               atmel_pops.enable_ms = fns->enable_ms;
-       if (fns->get_mctrl)
-               atmel_pops.get_mctrl = fns->get_mctrl;
-       if (fns->set_mctrl)
-               atmel_pops.set_mctrl = fns->set_mctrl;
-       atmel_open_hook         = fns->open;
-       atmel_close_hook        = fns->close;
-       atmel_pops.pm           = fns->pm;
-       atmel_pops.set_wake     = fns->set_wake;
-}
-
-#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
-static void atmel_console_putchar(struct uart_port *port, int ch)
-{
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
-               cpu_relax();
-       UART_PUT_CHAR(port, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void atmel_console_write(struct console *co, const char *s, u_int count)
-{
-       struct uart_port *port = &atmel_ports[co->index].uart;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, imr;
-       unsigned int pdc_tx;
-
-       /*
-        * First, save IMR and then disable interrupts
-        */
-       imr = UART_GET_IMR(port);
-       UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
-
-       /* Store PDC transmit status and disable it */
-       pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
-       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-
-       uart_console_write(port, s, count, atmel_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore IMR
-        */
-       do {
-               status = UART_GET_CSR(port);
-       } while (!(status & ATMEL_US_TXRDY));
-
-       /* Restore PDC transmit status */
-       if (pdc_tx)
-               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-
-       /* set interrupts back the way they were */
-       UART_PUT_IER(port, imr);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init atmel_console_get_options(struct uart_port *port, int *baud,
-                                            int *parity, int *bits)
-{
-       unsigned int mr, quot;
-
-       /*
-        * If the baud rate generator isn't running, the port wasn't
-        * initialized by the boot loader.
-        */
-       quot = UART_GET_BRGR(port) & ATMEL_US_CD;
-       if (!quot)
-               return;
-
-       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
-       if (mr == ATMEL_US_CHRL_8)
-               *bits = 8;
-       else
-               *bits = 7;
-
-       mr = UART_GET_MR(port) & ATMEL_US_PAR;
-       if (mr == ATMEL_US_PAR_EVEN)
-               *parity = 'e';
-       else if (mr == ATMEL_US_PAR_ODD)
-               *parity = 'o';
-
-       /*
-        * The serial core only rounds down when matching this to a
-        * supported baud rate. Make sure we don't end up slightly
-        * lower than one of those, as it would make us fall through
-        * to a much lower baud rate than we really want.
-        */
-       *baud = port->uartclk / (16 * (quot - 1));
-}
-
-static int __init atmel_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &atmel_ports[co->index].uart;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (port->membase == NULL) {
-               /* Port not initialized yet - delay setup */
-               return -ENODEV;
-       }
-
-       clk_enable(atmel_ports[co->index].clk);
-
-       UART_PUT_IDR(port, -1);
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               atmel_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver atmel_uart;
-
-static struct console atmel_console = {
-       .name           = ATMEL_DEVICENAME,
-       .write          = atmel_console_write,
-       .device         = uart_console_device,
-       .setup          = atmel_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &atmel_uart,
-};
-
-#define ATMEL_CONSOLE_DEVICE   (&atmel_console)
-
-/*
- * Early console initialization (before VM subsystem initialized).
- */
-static int __init atmel_console_init(void)
-{
-       if (atmel_default_console_device) {
-               add_preferred_console(ATMEL_DEVICENAME,
-                                     atmel_default_console_device->id, NULL);
-               atmel_init_port(&atmel_ports[atmel_default_console_device->id],
-                               atmel_default_console_device);
-               register_console(&atmel_console);
-       }
-
-       return 0;
-}
-
-console_initcall(atmel_console_init);
-
-/*
- * Late console initialization.
- */
-static int __init atmel_late_console_init(void)
-{
-       if (atmel_default_console_device
-           && !(atmel_console.flags & CON_ENABLED))
-               register_console(&atmel_console);
-
-       return 0;
-}
-
-core_initcall(atmel_late_console_init);
-
-static inline bool atmel_is_console_port(struct uart_port *port)
-{
-       return port->cons && port->cons->index == port->line;
-}
-
-#else
-#define ATMEL_CONSOLE_DEVICE   NULL
-
-static inline bool atmel_is_console_port(struct uart_port *port)
-{
-       return false;
-}
-#endif
-
-static struct uart_driver atmel_uart = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "atmel_serial",
-       .dev_name       = ATMEL_DEVICENAME,
-       .major          = SERIAL_ATMEL_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ATMEL_MAX_UART,
-       .cons           = ATMEL_CONSOLE_DEVICE,
-};
-
-#ifdef CONFIG_PM
-static bool atmel_serial_clk_will_stop(void)
-{
-#ifdef CONFIG_ARCH_AT91
-       return at91_suspend_entering_slow_clock();
-#else
-       return false;
-#endif
-}
-
-static int atmel_serial_suspend(struct platform_device *pdev,
-                               pm_message_t state)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_is_console_port(port) && console_suspend_enabled) {
-               /* Drain the TX shifter */
-               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-                       cpu_relax();
-       }
-
-       /* we can not wake up if we're running on slow clock */
-       atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
-       if (atmel_serial_clk_will_stop())
-               device_set_wakeup_enable(&pdev->dev, 0);
-
-       uart_suspend_port(&atmel_uart, port);
-
-       return 0;
-}
-
-static int atmel_serial_resume(struct platform_device *pdev)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       uart_resume_port(&atmel_uart, port);
-       device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
-
-       return 0;
-}
-#else
-#define atmel_serial_suspend NULL
-#define atmel_serial_resume NULL
-#endif
-
-static int __devinit atmel_serial_probe(struct platform_device *pdev)
-{
-       struct atmel_uart_port *port;
-       void *data;
-       int ret;
-
-       BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
-
-       port = &atmel_ports[pdev->id];
-       port->backup_imr = 0;
-
-       atmel_init_port(port, pdev);
-
-       if (!atmel_use_dma_rx(&port->uart)) {
-               ret = -ENOMEM;
-               data = kmalloc(sizeof(struct atmel_uart_char)
-                               * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
-               if (!data)
-                       goto err_alloc_ring;
-               port->rx_ring.buf = data;
-       }
-
-       ret = uart_add_one_port(&atmel_uart, &port->uart);
-       if (ret)
-               goto err_add_port;
-
-#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
-       if (atmel_is_console_port(&port->uart)
-                       && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
-               /*
-                * The serial core enabled the clock for us, so undo
-                * the clk_enable() in atmel_console_setup()
-                */
-               clk_disable(port->clk);
-       }
-#endif
-
-       device_init_wakeup(&pdev->dev, 1);
-       platform_set_drvdata(pdev, port);
-
-       if (port->rs485.flags & SER_RS485_ENABLED) {
-               UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
-               UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
-       }
-
-       return 0;
-
-err_add_port:
-       kfree(port->rx_ring.buf);
-       port->rx_ring.buf = NULL;
-err_alloc_ring:
-       if (!atmel_is_console_port(&port->uart)) {
-               clk_put(port->clk);
-               port->clk = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit atmel_serial_remove(struct platform_device *pdev)
-{
-       struct uart_port *port = platform_get_drvdata(pdev);
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       int ret = 0;
-
-       device_init_wakeup(&pdev->dev, 0);
-       platform_set_drvdata(pdev, NULL);
-
-       ret = uart_remove_one_port(&atmel_uart, port);
-
-       tasklet_kill(&atmel_port->tasklet);
-       kfree(atmel_port->rx_ring.buf);
-
-       /* "port" is allocated statically, so we shouldn't free it */
-
-       clk_put(atmel_port->clk);
-
-       return ret;
-}
-
-static struct platform_driver atmel_serial_driver = {
-       .probe          = atmel_serial_probe,
-       .remove         = __devexit_p(atmel_serial_remove),
-       .suspend        = atmel_serial_suspend,
-       .resume         = atmel_serial_resume,
-       .driver         = {
-               .name   = "atmel_usart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init atmel_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&atmel_uart);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&atmel_serial_driver);
-       if (ret)
-               uart_unregister_driver(&atmel_uart);
-
-       return ret;
-}
-
-static void __exit atmel_serial_exit(void)
-{
-       platform_driver_unregister(&atmel_serial_driver);
-       uart_unregister_driver(&atmel_uart);
-}
-
-module_init(atmel_serial_init);
-module_exit(atmel_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atmel_usart");
diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/serial/bcm63xx_uart.c
deleted file mode 100644 (file)
index a1a0e55..0000000
+++ /dev/null
@@ -1,891 +0,0 @@
-/*
- * 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.
- *
- * Derived from many drivers using generic_serial interface.
- *
- * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
- *
- *  Serial driver for BCM63xx integrated UART.
- *
- * Hardware flow control was _not_ tested since I only have RX/TX on
- * my board.
- */
-
-#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/clk.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-
-#include <bcm63xx_clk.h>
-#include <bcm63xx_irq.h>
-#include <bcm63xx_regs.h>
-#include <bcm63xx_io.h>
-
-#define BCM63XX_NR_UARTS       2
-
-static struct uart_port ports[BCM63XX_NR_UARTS];
-
-/*
- * rx interrupt mask / stat
- *
- * mask:
- *  - rx fifo full
- *  - rx fifo above threshold
- *  - rx fifo not empty for too long
- */
-#define UART_RX_INT_MASK       (UART_IR_MASK(UART_IR_RXOVER) |         \
-                               UART_IR_MASK(UART_IR_RXTHRESH) |        \
-                               UART_IR_MASK(UART_IR_RXTIMEOUT))
-
-#define UART_RX_INT_STAT       (UART_IR_STAT(UART_IR_RXOVER) |         \
-                               UART_IR_STAT(UART_IR_RXTHRESH) |        \
-                               UART_IR_STAT(UART_IR_RXTIMEOUT))
-
-/*
- * tx interrupt mask / stat
- *
- * mask:
- * - tx fifo empty
- * - tx fifo below threshold
- */
-#define UART_TX_INT_MASK       (UART_IR_MASK(UART_IR_TXEMPTY) |        \
-                               UART_IR_MASK(UART_IR_TXTRESH))
-
-#define UART_TX_INT_STAT       (UART_IR_STAT(UART_IR_TXEMPTY) |        \
-                               UART_IR_STAT(UART_IR_TXTRESH))
-
-/*
- * external input interrupt
- *
- * mask: any edge on CTS, DCD
- */
-#define UART_EXTINP_INT_MASK   (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \
-                                UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD))
-
-/*
- * handy uart register accessor
- */
-static inline unsigned int bcm_uart_readl(struct uart_port *port,
-                                        unsigned int offset)
-{
-       return bcm_readl(port->membase + offset);
-}
-
-static inline void bcm_uart_writel(struct uart_port *port,
-                                 unsigned int value, unsigned int offset)
-{
-       bcm_writel(value, port->membase + offset);
-}
-
-/*
- * serial core request to check if uart tx fifo is empty
- */
-static unsigned int bcm_uart_tx_empty(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
-}
-
-/*
- * serial core request to set RTS and DTR pin state and loopback mode
- */
-static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
-       /* invert of written value is reflected on the pin */
-       if (!(mctrl & TIOCM_DTR))
-               val |= UART_MCTL_DTR_MASK;
-       if (!(mctrl & TIOCM_RTS))
-               val |= UART_MCTL_RTS_MASK;
-       bcm_uart_writel(port, val, UART_MCTL_REG);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       if (mctrl & TIOCM_LOOP)
-               val |= UART_CTL_LOOPBACK_MASK;
-       else
-               val &= ~UART_CTL_LOOPBACK_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * serial core request to return RI, CTS, DCD and DSR pin state
- */
-static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int val, mctrl;
-
-       mctrl = 0;
-       val = bcm_uart_readl(port, UART_EXTINP_REG);
-       if (val & UART_EXTINP_RI_MASK)
-               mctrl |= TIOCM_RI;
-       if (val & UART_EXTINP_CTS_MASK)
-               mctrl |= TIOCM_CTS;
-       if (val & UART_EXTINP_DCD_MASK)
-               mctrl |= TIOCM_CD;
-       if (val & UART_EXTINP_DSR_MASK)
-               mctrl |= TIOCM_DSR;
-       return mctrl;
-}
-
-/*
- * serial core request to disable tx ASAP (used for flow control)
- */
-static void bcm_uart_stop_tx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~(UART_CTL_TXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to (re)enable tx
- */
-static void bcm_uart_start_tx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val |= UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= UART_CTL_TXEN_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * serial core request to stop rx, called before port shutdown
- */
-static void bcm_uart_stop_rx(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_RX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to enable modem status interrupt reporting
- */
-static void bcm_uart_enable_ms(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val |= UART_IR_MASK(UART_IR_EXTIP);
-       bcm_uart_writel(port, val, UART_IR_REG);
-}
-
-/*
- * serial core request to start/stop emitting break char
- */
-static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       unsigned int val;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       if (ctl)
-               val |= UART_CTL_XMITBRK_MASK;
-       else
-               val &= ~UART_CTL_XMITBRK_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * return port type in string format
- */
-static const char *bcm_uart_type(struct uart_port *port)
-{
-       return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL;
-}
-
-/*
- * read all chars in rx fifo and send them to core
- */
-static void bcm_uart_do_rx(struct uart_port *port)
-{
-       struct tty_struct *tty;
-       unsigned int max_count;
-
-       /* limit number of char read in interrupt, should not be
-        * higher than fifo size anyway since we're much faster than
-        * serial port */
-       max_count = 32;
-       tty = port->state->port.tty;
-       do {
-               unsigned int iestat, c, cstat;
-               char flag;
-
-               /* get overrun/fifo empty information from ier
-                * register */
-               iestat = bcm_uart_readl(port, UART_IR_REG);
-               if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
-                       break;
-
-               cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
-               port->icount.rx++;
-               flag = TTY_NORMAL;
-               c &= 0xff;
-
-               if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
-                       /* do stats first */
-                       if (cstat & UART_FIFO_BRKDET_MASK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       }
-
-                       if (cstat & UART_FIFO_PARERR_MASK)
-                               port->icount.parity++;
-                       if (cstat & UART_FIFO_FRAMEERR_MASK)
-                               port->icount.frame++;
-
-                       /* update flag wrt read_status_mask */
-                       cstat &= port->read_status_mask;
-                       if (cstat & UART_FIFO_BRKDET_MASK)
-                               flag = TTY_BREAK;
-                       if (cstat & UART_FIFO_FRAMEERR_MASK)
-                               flag = TTY_FRAME;
-                       if (cstat & UART_FIFO_PARERR_MASK)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(port, c))
-                       continue;
-
-               if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
-                       port->icount.overrun++;
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-
-               if ((cstat & port->ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, c, flag);
-
-       } while (--max_count);
-
-       tty_flip_buffer_push(tty);
-}
-
-/*
- * fill tx fifo with chars to send, stop when fifo is about to be full
- * or when all chars have been sent.
- */
-static void bcm_uart_do_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-       unsigned int val, max_count;
-
-       if (port->x_char) {
-               bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_tx_stopped(port)) {
-               bcm_uart_stop_tx(port);
-               return;
-       }
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit))
-               goto txq_empty;
-
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
-       max_count = port->fifosize - val;
-
-       while (max_count--) {
-               unsigned int c;
-
-               c = xmit->buf[xmit->tail];
-               bcm_uart_writel(port, c, UART_FIFO_REG);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               goto txq_empty;
-       return;
-
-txq_empty:
-       /* nothing to send, disable transmit interrupt */
-       val = bcm_uart_readl(port, UART_IR_REG);
-       val &= ~UART_TX_INT_MASK;
-       bcm_uart_writel(port, val, UART_IR_REG);
-       return;
-}
-
-/*
- * process uart interrupt
- */
-static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port;
-       unsigned int irqstat;
-
-       port = dev_id;
-       spin_lock(&port->lock);
-
-       irqstat = bcm_uart_readl(port, UART_IR_REG);
-       if (irqstat & UART_RX_INT_STAT)
-               bcm_uart_do_rx(port);
-
-       if (irqstat & UART_TX_INT_STAT)
-               bcm_uart_do_tx(port);
-
-       if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
-               unsigned int estat;
-
-               estat = bcm_uart_readl(port, UART_EXTINP_REG);
-               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
-                       uart_handle_cts_change(port,
-                                              estat & UART_EXTINP_CTS_MASK);
-               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
-                       uart_handle_dcd_change(port,
-                                              estat & UART_EXTINP_DCD_MASK);
-       }
-
-       spin_unlock(&port->lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * enable rx & tx operation on uart
- */
-static void bcm_uart_enable(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * disable rx & tx operation on uart
- */
-static void bcm_uart_disable(struct uart_port *port)
-{
-       unsigned int val;
-
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
-                UART_CTL_RXEN_MASK);
-       bcm_uart_writel(port, val, UART_CTL_REG);
-}
-
-/*
- * clear all unread data in rx fifo and unsent data in tx fifo
- */
-static void bcm_uart_flush(struct uart_port *port)
-{
-       unsigned int val;
-
-       /* empty rx and tx fifo */
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       /* read any pending char to make sure all irq status are
-        * cleared */
-       (void)bcm_uart_readl(port, UART_FIFO_REG);
-}
-
-/*
- * serial core request to initialize uart and start rx operation
- */
-static int bcm_uart_startup(struct uart_port *port)
-{
-       unsigned int val;
-       int ret;
-
-       /* mask all irq and flush port */
-       bcm_uart_disable(port);
-       bcm_uart_writel(port, 0, UART_IR_REG);
-       bcm_uart_flush(port);
-
-       /* clear any pending external input interrupt */
-       (void)bcm_uart_readl(port, UART_EXTINP_REG);
-
-       /* set rx/tx fifo thresh to fifo half size */
-       val = bcm_uart_readl(port, UART_MCTL_REG);
-       val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
-       val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
-       val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
-       bcm_uart_writel(port, val, UART_MCTL_REG);
-
-       /* set rx fifo timeout to 1 char time */
-       val = bcm_uart_readl(port, UART_CTL_REG);
-       val &= ~UART_CTL_RXTMOUTCNT_MASK;
-       val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
-       bcm_uart_writel(port, val, UART_CTL_REG);
-
-       /* report any edge on dcd and cts */
-       val = UART_EXTINP_INT_MASK;
-       val |= UART_EXTINP_DCD_NOSENSE_MASK;
-       val |= UART_EXTINP_CTS_NOSENSE_MASK;
-       bcm_uart_writel(port, val, UART_EXTINP_REG);
-
-       /* register irq and enable rx interrupts */
-       ret = request_irq(port->irq, bcm_uart_interrupt, 0,
-                         bcm_uart_type(port), port);
-       if (ret)
-               return ret;
-       bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
-       bcm_uart_enable(port);
-       return 0;
-}
-
-/*
- * serial core request to flush & disable uart
- */
-static void bcm_uart_shutdown(struct uart_port *port)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       bcm_uart_writel(port, 0, UART_IR_REG);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       bcm_uart_disable(port);
-       bcm_uart_flush(port);
-       free_irq(port->irq, port);
-}
-
-/*
- * serial core request to change current uart setting
- */
-static void bcm_uart_set_termios(struct uart_port *port,
-                                struct ktermios *new,
-                                struct ktermios *old)
-{
-       unsigned int ctl, baud, quot, ier;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* disable uart while changing speed */
-       bcm_uart_disable(port);
-       bcm_uart_flush(port);
-
-       /* update Control register */
-       ctl = bcm_uart_readl(port, UART_CTL_REG);
-       ctl &= ~UART_CTL_BITSPERSYM_MASK;
-
-       switch (new->c_cflag & CSIZE) {
-       case CS5:
-               ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       case CS6:
-               ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       case CS7:
-               ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       default:
-               ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
-               break;
-       }
-
-       ctl &= ~UART_CTL_STOPBITS_MASK;
-       if (new->c_cflag & CSTOPB)
-               ctl |= UART_CTL_STOPBITS_2;
-       else
-               ctl |= UART_CTL_STOPBITS_1;
-
-       ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
-       if (new->c_cflag & PARENB)
-               ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
-       ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
-       if (new->c_cflag & PARODD)
-               ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
-       bcm_uart_writel(port, ctl, UART_CTL_REG);
-
-       /* update Baudword register */
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud) - 1;
-       bcm_uart_writel(port, quot, UART_BAUD_REG);
-
-       /* update Interrupt register */
-       ier = bcm_uart_readl(port, UART_IR_REG);
-
-       ier &= ~UART_IR_MASK(UART_IR_EXTIP);
-       if (UART_ENABLE_MS(port, new->c_cflag))
-               ier |= UART_IR_MASK(UART_IR_EXTIP);
-
-       bcm_uart_writel(port, ier, UART_IR_REG);
-
-       /* update read/ignore mask */
-       port->read_status_mask = UART_FIFO_VALID_MASK;
-       if (new->c_iflag & INPCK) {
-               port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
-               port->read_status_mask |= UART_FIFO_PARERR_MASK;
-       }
-       if (new->c_iflag & (BRKINT))
-               port->read_status_mask |= UART_FIFO_BRKDET_MASK;
-
-       port->ignore_status_mask = 0;
-       if (new->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
-       if (new->c_iflag & IGNBRK)
-               port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
-       if (!(new->c_cflag & CREAD))
-               port->ignore_status_mask |= UART_FIFO_VALID_MASK;
-
-       uart_update_timeout(port, new->c_cflag, baud);
-       bcm_uart_enable(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * serial core request to claim uart iomem
- */
-static int bcm_uart_request_port(struct uart_port *port)
-{
-       unsigned int size;
-
-       size = RSET_UART_SIZE;
-       if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
-               dev_err(port->dev, "Memory region busy\n");
-               return -EBUSY;
-       }
-
-       port->membase = ioremap(port->mapbase, size);
-       if (!port->membase) {
-               dev_err(port->dev, "Unable to map registers\n");
-               release_mem_region(port->mapbase, size);
-               return -EBUSY;
-       }
-       return 0;
-}
-
-/*
- * serial core request to release uart iomem
- */
-static void bcm_uart_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, RSET_UART_SIZE);
-       iounmap(port->membase);
-}
-
-/*
- * serial core request to do any port required autoconfiguration
- */
-static void bcm_uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               if (bcm_uart_request_port(port))
-                       return;
-               port->type = PORT_BCM63XX;
-       }
-}
-
-/*
- * serial core request to check that port information in serinfo are
- * suitable
- */
-static int bcm_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *serinfo)
-{
-       if (port->type != PORT_BCM63XX)
-               return -EINVAL;
-       if (port->irq != serinfo->irq)
-               return -EINVAL;
-       if (port->iotype != serinfo->io_type)
-               return -EINVAL;
-       if (port->mapbase != (unsigned long)serinfo->iomem_base)
-               return -EINVAL;
-       return 0;
-}
-
-/* serial core callbacks */
-static struct uart_ops bcm_uart_ops = {
-       .tx_empty       = bcm_uart_tx_empty,
-       .get_mctrl      = bcm_uart_get_mctrl,
-       .set_mctrl      = bcm_uart_set_mctrl,
-       .start_tx       = bcm_uart_start_tx,
-       .stop_tx        = bcm_uart_stop_tx,
-       .stop_rx        = bcm_uart_stop_rx,
-       .enable_ms      = bcm_uart_enable_ms,
-       .break_ctl      = bcm_uart_break_ctl,
-       .startup        = bcm_uart_startup,
-       .shutdown       = bcm_uart_shutdown,
-       .set_termios    = bcm_uart_set_termios,
-       .type           = bcm_uart_type,
-       .release_port   = bcm_uart_release_port,
-       .request_port   = bcm_uart_request_port,
-       .config_port    = bcm_uart_config_port,
-       .verify_port    = bcm_uart_verify_port,
-};
-
-
-
-#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int tmout;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       tmout = 10000;
-       while (--tmout) {
-               unsigned int val;
-
-               val = bcm_uart_readl(port, UART_IR_REG);
-               if (val & UART_IR_STAT(UART_IR_TXEMPTY))
-                       break;
-               udelay(1);
-       }
-
-       /* Wait up to 1s for flow control if necessary */
-       if (port->flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout) {
-                       unsigned int val;
-
-                       val = bcm_uart_readl(port, UART_EXTINP_REG);
-                       if (val & UART_EXTINP_CTS_MASK)
-                               break;
-                       udelay(1);
-               }
-       }
-}
-
-/*
- * output given char
- */
-static void bcm_console_putchar(struct uart_port *port, int ch)
-{
-       wait_for_xmitr(port);
-       bcm_uart_writel(port, ch, UART_FIFO_REG);
-}
-
-/*
- * console core request to output given string
- */
-static void bcm_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       int locked;
-
-       port = &ports[co->index];
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               /* bcm_uart_interrupt() already took the lock */
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else {
-               spin_lock(&port->lock);
-               locked = 1;
-       }
-
-       /* call helper to deal with \r\n */
-       uart_console_write(port, s, count, bcm_console_putchar);
-
-       /* and wait for char to be transmitted */
-       wait_for_xmitr(port);
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-/*
- * console core request to setup given console, find matching uart
- * port and setup it.
- */
-static int bcm_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= BCM63XX_NR_UARTS)
-               return -EINVAL;
-       port = &ports[co->index];
-       if (!port->membase)
-               return -ENODEV;
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver bcm_uart_driver;
-
-static struct console bcm63xx_console = {
-       .name           = "ttyS",
-       .write          = bcm_console_write,
-       .device         = uart_console_device,
-       .setup          = bcm_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &bcm_uart_driver,
-};
-
-static int __init bcm63xx_console_init(void)
-{
-       register_console(&bcm63xx_console);
-       return 0;
-}
-
-console_initcall(bcm63xx_console_init);
-
-#define BCM63XX_CONSOLE        (&bcm63xx_console)
-#else
-#define BCM63XX_CONSOLE        NULL
-#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
-
-static struct uart_driver bcm_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "bcm63xx_uart",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = BCM63XX_NR_UARTS,
-       .cons           = BCM63XX_CONSOLE,
-};
-
-/*
- * platform driver probe/remove callback
- */
-static int __devinit bcm_uart_probe(struct platform_device *pdev)
-{
-       struct resource *res_mem, *res_irq;
-       struct uart_port *port;
-       struct clk *clk;
-       int ret;
-
-       if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
-               return -EINVAL;
-
-       if (ports[pdev->id].membase)
-               return -EBUSY;
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res_mem)
-               return -ENODEV;
-
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res_irq)
-               return -ENODEV;
-
-       clk = clk_get(&pdev->dev, "periph");
-       if (IS_ERR(clk))
-               return -ENODEV;
-
-       port = &ports[pdev->id];
-       memset(port, 0, sizeof(*port));
-       port->iotype = UPIO_MEM;
-       port->mapbase = res_mem->start;
-       port->irq = res_irq->start;
-       port->ops = &bcm_uart_ops;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->dev = &pdev->dev;
-       port->fifosize = 16;
-       port->uartclk = clk_get_rate(clk) / 2;
-       port->line = pdev->id;
-       clk_put(clk);
-
-       ret = uart_add_one_port(&bcm_uart_driver, port);
-       if (ret) {
-               ports[pdev->id].membase = 0;
-               return ret;
-       }
-       platform_set_drvdata(pdev, port);
-       return 0;
-}
-
-static int __devexit bcm_uart_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-
-       port = platform_get_drvdata(pdev);
-       uart_remove_one_port(&bcm_uart_driver, port);
-       platform_set_drvdata(pdev, NULL);
-       /* mark port as free */
-       ports[pdev->id].membase = 0;
-       return 0;
-}
-
-/*
- * platform driver stuff
- */
-static struct platform_driver bcm_uart_platform_driver = {
-       .probe  = bcm_uart_probe,
-       .remove = __devexit_p(bcm_uart_remove),
-       .driver = {
-               .owner = THIS_MODULE,
-               .name  = "bcm63xx_uart",
-       },
-};
-
-static int __init bcm_uart_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&bcm_uart_driver);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&bcm_uart_platform_driver);
-       if (ret)
-               uart_unregister_driver(&bcm_uart_driver);
-
-       return ret;
-}
-
-static void __exit bcm_uart_exit(void)
-{
-       platform_driver_unregister(&bcm_uart_platform_driver);
-       uart_unregister_driver(&bcm_uart_driver);
-}
-
-module_init(bcm_uart_init);
-module_exit(bcm_uart_exit);
-
-MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
-MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
deleted file mode 100644 (file)
index e381b89..0000000
+++ /dev/null
@@ -1,1600 +0,0 @@
-/*
- * Blackfin On-Chip Serial Driver
- *
- * Copyright 2006-2010 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#define DRIVER_NAME "bfin-uart"
-#define pr_fmt(fmt) DRIVER_NAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/gfp.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/kgdb.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/portmux.h>
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-
-#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
-#include <asm/bfin_serial.h>
-
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
-/* UART name and device definitions */
-#define BFIN_SERIAL_DEV_NAME   "ttyBF"
-#define BFIN_SERIAL_MAJOR      204
-#define BFIN_SERIAL_MINOR      64
-
-static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS];
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-
-# ifndef CONFIG_SERIAL_BFIN_PIO
-#  error KGDB only support UART in PIO mode.
-# endif
-
-static int kgdboc_port_line;
-static int kgdboc_break_enabled;
-#endif
-/*
- * Setup for console. Argument comes from the menuconfig
- */
-#define DMA_RX_XCOUNT          512
-#define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
-
-#define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
-#else
-static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
-#endif
-
-static void bfin_serial_reset_irda(struct uart_port *port);
-
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->cts_pin < 0)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       /* CTS PIN is negative assertive. */
-       if (UART_GET_CTS(uart))
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->rts_pin < 0)
-               return;
-
-       /* RTS PIN is negative assertive. */
-       if (mctrl & TIOCM_RTS)
-               UART_ENABLE_RTS(uart);
-       else
-               UART_DISABLE_RTS(uart);
-}
-
-/*
- * Handle any change of modem status signal.
- */
-static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       unsigned int status;
-
-       status = bfin_serial_get_mctrl(&uart->port);
-       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       uart->scts = 1;
-       UART_CLEAR_SCTS(uart);
-       UART_CLEAR_IER(uart, EDSSI);
-#endif
-
-       return IRQ_HANDLED;
-}
-#else
-static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-#endif
-
-/*
- * interrupts are disabled on entry
- */
-static void bfin_serial_stop_tx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       struct circ_buf *xmit = &uart->port.state->xmit;
-#endif
-
-       while (!(UART_GET_LSR(uart) & TEMT))
-               cpu_relax();
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       disable_dma(uart->tx_dma_channel);
-       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-       uart->port.icount.tx += uart->tx_count;
-       uart->tx_count = 0;
-       uart->tx_done = 1;
-#else
-#ifdef CONFIG_BF54x
-       /* Clear TFI bit */
-       UART_PUT_LSR(uart, TFI);
-#endif
-       UART_CLEAR_IER(uart, ETBEI);
-#endif
-}
-
-/*
- * port is locked and interrupts are disabled
- */
-static void bfin_serial_start_tx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       struct tty_struct *tty = uart->port.state->port.tty;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
-       /*
-        * To avoid losting RX interrupt, we reset IR function
-        * before sending data.
-        */
-       if (tty->termios->c_line == N_IRDA)
-               bfin_serial_reset_irda(port);
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       if (uart->tx_done)
-               bfin_serial_dma_tx_chars(uart);
-#else
-       UART_SET_IER(uart, ETBEI);
-       bfin_serial_tx_chars(uart);
-#endif
-}
-
-/*
- * Interrupts are enabled
- */
-static void bfin_serial_stop_rx(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       UART_CLEAR_IER(uart, ERBFI);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void bfin_serial_enable_ms(struct uart_port *port)
-{
-}
-
-
-#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
-# define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
-# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
-#else
-# define UART_GET_ANOMALY_THRESHOLD(uart)    0
-# define UART_SET_ANOMALY_THRESHOLD(uart, v)
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_PIO
-static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
-{
-       struct tty_struct *tty = NULL;
-       unsigned int status, ch, flg;
-       static struct timeval anomaly_start = { .tv_sec = 0 };
-
-       status = UART_GET_LSR(uart);
-       UART_CLEAR_LSR(uart);
-
-       ch = UART_GET_CHAR(uart);
-       uart->port.icount.rx++;
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       if (kgdb_connected && kgdboc_port_line == uart->port.line
-               && kgdboc_break_enabled)
-               if (ch == 0x3) {/* Ctrl + C */
-                       kgdb_breakpoint();
-                       return;
-               }
-
-       if (!uart->port.state || !uart->port.state->port.tty)
-               return;
-#endif
-       tty = uart->port.state->port.tty;
-
-       if (ANOMALY_05000363) {
-               /* The BF533 (and BF561) family of processors have a nice anomaly
-                * where they continuously generate characters for a "single" break.
-                * We have to basically ignore this flood until the "next" valid
-                * character comes across.  Due to the nature of the flood, it is
-                * not possible to reliably catch bytes that are sent too quickly
-                * after this break.  So application code talking to the Blackfin
-                * which sends a break signal must allow at least 1.5 character
-                * times after the end of the break for things to stabilize.  This
-                * timeout was picked as it must absolutely be larger than 1
-                * character time +/- some percent.  So 1.5 sounds good.  All other
-                * Blackfin families operate properly.  Woo.
-                */
-               if (anomaly_start.tv_sec) {
-                       struct timeval curr;
-                       suseconds_t usecs;
-
-                       if ((~ch & (~ch + 1)) & 0xff)
-                               goto known_good_char;
-
-                       do_gettimeofday(&curr);
-                       if (curr.tv_sec - anomaly_start.tv_sec > 1)
-                               goto known_good_char;
-
-                       usecs = 0;
-                       if (curr.tv_sec != anomaly_start.tv_sec)
-                               usecs += USEC_PER_SEC;
-                       usecs += curr.tv_usec - anomaly_start.tv_usec;
-
-                       if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
-                               goto known_good_char;
-
-                       if (ch)
-                               anomaly_start.tv_sec = 0;
-                       else
-                               anomaly_start = curr;
-
-                       return;
-
- known_good_char:
-                       status &= ~BI;
-                       anomaly_start.tv_sec = 0;
-               }
-       }
-
-       if (status & BI) {
-               if (ANOMALY_05000363)
-                       if (bfin_revid() < 5)
-                               do_gettimeofday(&anomaly_start);
-               uart->port.icount.brk++;
-               if (uart_handle_break(&uart->port))
-                       goto ignore_char;
-               status &= ~(PE | FE);
-       }
-       if (status & PE)
-               uart->port.icount.parity++;
-       if (status & OE)
-               uart->port.icount.overrun++;
-       if (status & FE)
-               uart->port.icount.frame++;
-
-       status &= uart->port.read_status_mask;
-
-       if (status & BI)
-               flg = TTY_BREAK;
-       else if (status & PE)
-               flg = TTY_PARITY;
-       else if (status & FE)
-               flg = TTY_FRAME;
-       else
-               flg = TTY_NORMAL;
-
-       if (uart_handle_sysrq_char(&uart->port, ch))
-               goto ignore_char;
-
-       uart_insert_char(&uart->port, status, OE, ch, flg);
-
- ignore_char:
-       tty_flip_buffer_push(tty);
-}
-
-static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
-{
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
-               /* Clear TFI bit */
-               UART_PUT_LSR(uart, TFI);
-#endif
-               /* Anomaly notes:
-                *  05000215 -  we always clear ETBEI within last UART TX
-                *              interrupt to end a string. It is always set
-                *              when start a new tx.
-                */
-               UART_CLEAR_IER(uart, ETBEI);
-               return;
-       }
-
-       if (uart->port.x_char) {
-               UART_PUT_CHAR(uart, uart->port.x_char);
-               uart->port.icount.tx++;
-               uart->port.x_char = 0;
-       }
-
-       while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
-               UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               uart->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uart->port);
-}
-
-static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-
-       spin_lock(&uart->port.lock);
-       while (UART_GET_LSR(uart) & DR)
-               bfin_serial_rx_chars(uart);
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-       spin_lock(&uart->port.lock);
-       if (UART_GET_LSR(uart) & THRE)
-               bfin_serial_tx_chars(uart);
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
-{
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-       uart->tx_done = 0;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-               uart->tx_count = 0;
-               uart->tx_done = 1;
-               return;
-       }
-
-       if (uart->port.x_char) {
-               UART_PUT_CHAR(uart, uart->port.x_char);
-               uart->port.icount.tx++;
-               uart->port.x_char = 0;
-       }
-
-       uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
-       if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
-               uart->tx_count = UART_XMIT_SIZE - xmit->tail;
-       blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
-                                       (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
-       set_dma_config(uart->tx_dma_channel,
-               set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
-                       INTR_ON_BUF,
-                       DIMENSION_LINEAR,
-                       DATA_SIZE_8,
-                       DMA_SYNC_RESTART));
-       set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
-       set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
-       set_dma_x_modify(uart->tx_dma_channel, 1);
-       SSYNC();
-       enable_dma(uart->tx_dma_channel);
-
-       UART_SET_IER(uart, ETBEI);
-}
-
-static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
-{
-       struct tty_struct *tty = uart->port.state->port.tty;
-       int i, flg, status;
-
-       status = UART_GET_LSR(uart);
-       UART_CLEAR_LSR(uart);
-
-       uart->port.icount.rx +=
-               CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
-               UART_XMIT_SIZE);
-
-       if (status & BI) {
-               uart->port.icount.brk++;
-               if (uart_handle_break(&uart->port))
-                       goto dma_ignore_char;
-               status &= ~(PE | FE);
-       }
-       if (status & PE)
-               uart->port.icount.parity++;
-       if (status & OE)
-               uart->port.icount.overrun++;
-       if (status & FE)
-               uart->port.icount.frame++;
-
-       status &= uart->port.read_status_mask;
-
-       if (status & BI)
-               flg = TTY_BREAK;
-       else if (status & PE)
-               flg = TTY_PARITY;
-       else if (status & FE)
-               flg = TTY_FRAME;
-       else
-               flg = TTY_NORMAL;
-
-       for (i = uart->rx_dma_buf.tail; ; i++) {
-               if (i >= UART_XMIT_SIZE)
-                       i = 0;
-               if (i == uart->rx_dma_buf.head)
-                       break;
-               if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
-                       uart_insert_char(&uart->port, status, OE,
-                               uart->rx_dma_buf.buf[i], flg);
-       }
-
- dma_ignore_char:
-       tty_flip_buffer_push(tty);
-}
-
-void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
-{
-       int x_pos, pos;
-
-       dma_disable_irq(uart->tx_dma_channel);
-       dma_disable_irq(uart->rx_dma_channel);
-       spin_lock_bh(&uart->port.lock);
-
-       /* 2D DMA RX buffer ring is used. Because curr_y_count and
-        * curr_x_count can't be read as an atomic operation,
-        * curr_y_count should be read before curr_x_count. When
-        * curr_x_count is read, curr_y_count may already indicate
-        * next buffer line. But, the position calculated here is
-        * still indicate the old line. The wrong position data may
-        * be smaller than current buffer tail, which cause garbages
-        * are received if it is not prohibit.
-        */
-       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
-       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
-       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
-               uart->rx_dma_nrows = 0;
-       x_pos = DMA_RX_XCOUNT - x_pos;
-       if (x_pos == DMA_RX_XCOUNT)
-               x_pos = 0;
-
-       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-       /* Ignore receiving data if new position is in the same line of
-        * current buffer tail and small.
-        */
-       if (pos > uart->rx_dma_buf.tail ||
-               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
-               uart->rx_dma_buf.head = pos;
-               bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
-       }
-
-       spin_unlock_bh(&uart->port.lock);
-       dma_enable_irq(uart->tx_dma_channel);
-       dma_enable_irq(uart->rx_dma_channel);
-
-       mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
-}
-
-static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       struct circ_buf *xmit = &uart->port.state->xmit;
-
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
-       spin_lock(&uart->port.lock);
-       if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
-               disable_dma(uart->tx_dma_channel);
-               clear_dma_irqstat(uart->tx_dma_channel);
-               /* Anomaly notes:
-                *  05000215 -  we always clear ETBEI within last UART TX
-                *              interrupt to end a string. It is always set
-                *              when start a new tx.
-                */
-               UART_CLEAR_IER(uart, ETBEI);
-               xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-               uart->port.icount.tx += uart->tx_count;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&uart->port);
-
-               bfin_serial_dma_tx_chars(uart);
-       }
-
-       spin_unlock(&uart->port.lock);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
-{
-       struct bfin_serial_port *uart = dev_id;
-       unsigned short irqstat;
-       int x_pos, pos;
-
-       spin_lock(&uart->port.lock);
-       irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
-       clear_dma_irqstat(uart->rx_dma_channel);
-
-       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
-       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
-       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
-               uart->rx_dma_nrows = 0;
-
-       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
-       if (pos > uart->rx_dma_buf.tail ||
-               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
-               uart->rx_dma_buf.head = pos;
-               bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
-       }
-
-       spin_unlock(&uart->port.lock);
-
-       return IRQ_HANDLED;
-}
-#endif
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int bfin_serial_tx_empty(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short lsr;
-
-       lsr = UART_GET_LSR(uart);
-       if (lsr & TEMT)
-               return TIOCSER_TEMT;
-       else
-               return 0;
-}
-
-static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       u16 lcr = UART_GET_LCR(uart);
-       if (break_state)
-               lcr |= SB;
-       else
-               lcr &= ~SB;
-       UART_PUT_LCR(uart, lcr);
-       SSYNC();
-}
-
-static int bfin_serial_startup(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       dma_addr_t dma_handle;
-
-       if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
-               printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
-               return -EBUSY;
-       }
-
-       if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
-               printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
-               free_dma(uart->rx_dma_channel);
-               return -EBUSY;
-       }
-
-       set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
-       set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
-
-       uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
-       uart->rx_dma_buf.head = 0;
-       uart->rx_dma_buf.tail = 0;
-       uart->rx_dma_nrows = 0;
-
-       set_dma_config(uart->rx_dma_channel,
-               set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
-                               INTR_ON_ROW, DIMENSION_2D,
-                               DATA_SIZE_8,
-                               DMA_SYNC_RESTART));
-       set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
-       set_dma_x_modify(uart->rx_dma_channel, 1);
-       set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
-       set_dma_y_modify(uart->rx_dma_channel, 1);
-       set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
-       enable_dma(uart->rx_dma_channel);
-
-       uart->rx_dma_timer.data = (unsigned long)(uart);
-       uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
-       uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
-       add_timer(&(uart->rx_dma_timer));
-#else
-# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
-               kgdboc_break_enabled = 0;
-       else {
-# endif
-       if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
-            "BFIN_UART_RX", uart)) {
-               printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
-               return -EBUSY;
-       }
-
-       if (request_irq
-           (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
-            "BFIN_UART_TX", uart)) {
-               printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
-               free_irq(uart->port.irq, uart);
-               return -EBUSY;
-       }
-
-# ifdef CONFIG_BF54x
-       {
-               /*
-                * UART2 and UART3 on BF548 share interrupt PINs and DMA
-                * controllers with SPORT2 and SPORT3. UART rx and tx
-                * interrupts are generated in PIO mode only when configure
-                * their peripheral mapping registers properly, which means
-                * request corresponding DMA channels in PIO mode as well.
-                */
-               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
-
-               switch (uart->port.irq) {
-               case IRQ_UART3_RX:
-                       uart_dma_ch_rx = CH_UART3_RX;
-                       uart_dma_ch_tx = CH_UART3_TX;
-                       break;
-               case IRQ_UART2_RX:
-                       uart_dma_ch_rx = CH_UART2_RX;
-                       uart_dma_ch_tx = CH_UART2_TX;
-                       break;
-               default:
-                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
-                       break;
-               };
-
-               if (uart_dma_ch_rx &&
-                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
-                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
-                       return -EBUSY;
-               }
-               if (uart_dma_ch_tx &&
-                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
-                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
-                       free_dma(uart_dma_ch_rx);
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
-                       return -EBUSY;
-               }
-       }
-# endif
-# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       }
-# endif
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       if (uart->cts_pin >= 0) {
-               if (request_irq(gpio_to_irq(uart->cts_pin),
-                       bfin_serial_mctrl_cts_int,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
-                       uart->cts_pin = -1;
-                       pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
-               }
-       }
-       if (uart->rts_pin >= 0) {
-               gpio_direction_output(uart->rts_pin, 0);
-       }
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
-               bfin_serial_mctrl_cts_int,
-               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
-               uart->cts_pin = -1;
-               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
-       }
-
-       /* CTS RTS PINs are negative assertive. */
-       UART_PUT_MCR(uart, ACTS);
-       UART_SET_IER(uart, EDSSI);
-#endif
-
-       UART_SET_IER(uart, ERBFI);
-       return 0;
-}
-
-static void bfin_serial_shutdown(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       disable_dma(uart->tx_dma_channel);
-       free_dma(uart->tx_dma_channel);
-       disable_dma(uart->rx_dma_channel);
-       free_dma(uart->rx_dma_channel);
-       del_timer(&(uart->rx_dma_timer));
-       dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
-#else
-#ifdef CONFIG_BF54x
-       switch (uart->port.irq) {
-       case IRQ_UART3_RX:
-               free_dma(CH_UART3_RX);
-               free_dma(CH_UART3_TX);
-               break;
-       case IRQ_UART2_RX:
-               free_dma(CH_UART2_RX);
-               free_dma(CH_UART2_TX);
-               break;
-       default:
-               break;
-       };
-#endif
-       free_irq(uart->port.irq, uart);
-       free_irq(uart->port.irq+1, uart);
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       if (uart->cts_pin >= 0)
-               free_irq(gpio_to_irq(uart->cts_pin), uart);
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->cts_pin >= 0)
-               free_irq(uart->status_irq, uart);
-#endif
-}
-
-static void
-bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned short val, ier, lcr = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS8:
-               lcr = WLS(8);
-               break;
-       case CS7:
-               lcr = WLS(7);
-               break;
-       case CS6:
-               lcr = WLS(6);
-               break;
-       case CS5:
-               lcr = WLS(5);
-               break;
-       default:
-               printk(KERN_ERR "%s: word lengh not supported\n",
-                       __func__);
-       }
-
-       /* Anomaly notes:
-        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
-        */
-       if (termios->c_cflag & CSTOPB) {
-               if (ANOMALY_05000231)
-                       printk(KERN_WARNING "STOP bits other than 1 is not "
-                               "supported in case of anomaly 05000231.\n");
-               else
-                       lcr |= STB;
-       }
-       if (termios->c_cflag & PARENB)
-               lcr |= PEN;
-       if (!(termios->c_cflag & PARODD))
-               lcr |= EPS;
-       if (termios->c_cflag & CMSPAR)
-               lcr |= STP;
-
-       spin_lock_irqsave(&uart->port.lock, flags);
-
-       port->read_status_mask = OE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (FE | PE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= BI;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= FE | PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= OE;
-       }
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       /* If discipline is not IRDA, apply ANOMALY_05000230 */
-       if (termios->c_line != N_IRDA)
-               quot -= ANOMALY_05000230;
-
-       UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
-
-       /* Disable UART */
-       ier = UART_GET_IER(uart);
-       UART_DISABLE_INTS(uart);
-
-       /* Set DLAB in LCR to Access DLL and DLH */
-       UART_SET_DLAB(uart);
-
-       UART_PUT_DLL(uart, quot & 0xFF);
-       UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
-       SSYNC();
-
-       /* Clear DLAB in LCR to Access THR RBR IER */
-       UART_CLEAR_DLAB(uart);
-
-       UART_PUT_LCR(uart, lcr);
-
-       /* Enable UART */
-       UART_ENABLE_INTS(uart, ier);
-
-       val = UART_GET_GCTL(uart);
-       val |= UCEN;
-       UART_PUT_GCTL(uart, val);
-
-       /* Port speed changed, update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&uart->port.lock, flags);
-}
-
-static const char *bfin_serial_type(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void bfin_serial_release_port(struct uart_port *port)
-{
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int bfin_serial_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void bfin_serial_config_port(struct uart_port *port, int flags)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           bfin_serial_request_port(&uart->port) == 0)
-               uart->port.type = PORT_BFIN;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_BFIN and PORT_UNKNOWN
- */
-static int
-bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return 0;
-}
-
-/*
- * Enable the IrDA function if tty->ldisc.num is N_IRDA.
- * In other cases, disable IrDA function.
- */
-static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short val;
-
-       switch (ld) {
-       case N_IRDA:
-               val = UART_GET_GCTL(uart);
-               val |= (IREN | RPOLC);
-               UART_PUT_GCTL(uart, val);
-               break;
-       default:
-               val = UART_GET_GCTL(uart);
-               val &= ~(IREN | RPOLC);
-               UART_PUT_GCTL(uart, val);
-       }
-}
-
-static void bfin_serial_reset_irda(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned short val;
-
-       val = UART_GET_GCTL(uart);
-       val &= ~(IREN | RPOLC);
-       UART_PUT_GCTL(uart, val);
-       SSYNC();
-       val |= (IREN | RPOLC);
-       UART_PUT_GCTL(uart, val);
-       SSYNC();
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/* Anomaly notes:
- *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
- *             losing other bits of UART_LSR is not a problem here.
- */
-static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-
-       while (!(UART_GET_LSR(uart) & THRE))
-               cpu_relax();
-
-       UART_CLEAR_DLAB(uart);
-       UART_PUT_CHAR(uart, (unsigned char)chr);
-}
-
-static int bfin_serial_poll_get_char(struct uart_port *port)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       unsigned char chr;
-
-       while (!(UART_GET_LSR(uart) & DR))
-               cpu_relax();
-
-       UART_CLEAR_DLAB(uart);
-       chr = UART_GET_CHAR(uart);
-
-       return chr;
-}
-#endif
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-static void bfin_kgdboc_port_shutdown(struct uart_port *port)
-{
-       if (kgdboc_break_enabled) {
-               kgdboc_break_enabled = 0;
-               bfin_serial_shutdown(port);
-       }
-}
-
-static int bfin_kgdboc_port_startup(struct uart_port *port)
-{
-       kgdboc_port_line = port->line;
-       kgdboc_break_enabled = !bfin_serial_startup(port);
-       return 0;
-}
-#endif
-
-static struct uart_ops bfin_serial_pops = {
-       .tx_empty       = bfin_serial_tx_empty,
-       .set_mctrl      = bfin_serial_set_mctrl,
-       .get_mctrl      = bfin_serial_get_mctrl,
-       .stop_tx        = bfin_serial_stop_tx,
-       .start_tx       = bfin_serial_start_tx,
-       .stop_rx        = bfin_serial_stop_rx,
-       .enable_ms      = bfin_serial_enable_ms,
-       .break_ctl      = bfin_serial_break_ctl,
-       .startup        = bfin_serial_startup,
-       .shutdown       = bfin_serial_shutdown,
-       .set_termios    = bfin_serial_set_termios,
-       .set_ldisc      = bfin_serial_set_ldisc,
-       .type           = bfin_serial_type,
-       .release_port   = bfin_serial_release_port,
-       .request_port   = bfin_serial_request_port,
-       .config_port    = bfin_serial_config_port,
-       .verify_port    = bfin_serial_verify_port,
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
-       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
-       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
-#endif
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_put_char  = bfin_serial_poll_put_char,
-       .poll_get_char  = bfin_serial_poll_get_char,
-#endif
-};
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
-                          int *parity, int *bits)
-{
-       unsigned short status;
-
-       status = UART_GET_IER(uart) & (ERBFI | ETBEI);
-       if (status == (ERBFI | ETBEI)) {
-               /* ok, the port was enabled */
-               u16 lcr, dlh, dll;
-
-               lcr = UART_GET_LCR(uart);
-
-               *parity = 'n';
-               if (lcr & PEN) {
-                       if (lcr & EPS)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-               switch (lcr & 0x03) {
-                       case 0: *bits = 5; break;
-                       case 1: *bits = 6; break;
-                       case 2: *bits = 7; break;
-                       case 3: *bits = 8; break;
-               }
-               /* Set DLAB in LCR to Access DLL and DLH */
-               UART_SET_DLAB(uart);
-
-               dll = UART_GET_DLL(uart);
-               dlh = UART_GET_DLH(uart);
-
-               /* Clear DLAB in LCR to Access THR RBR IER */
-               UART_CLEAR_DLAB(uart);
-
-               *baud = get_sclk() / (16*(dll | dlh << 8));
-       }
-       pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
-}
-
-static struct uart_driver bfin_serial_reg;
-
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       while (!(UART_GET_LSR(uart) & THRE))
-               barrier();
-       UART_PUT_CHAR(uart, ch);
-}
-
-#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
-                defined (CONFIG_EARLY_PRINTK) */
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-#define CLASS_BFIN_CONSOLE     "bfin-console"
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct bfin_serial_port *uart = bfin_serial_ports[co->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&uart->port.lock, flags);
-       uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
-       spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
-static int __init
-bfin_serial_console_setup(struct console *co, char *options)
-{
-       struct bfin_serial_port *uart;
-       int baud = 57600;
-       int bits = 8;
-       int parity = 'n';
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-       int flow = 'r';
-# else
-       int flow = 'n';
-# endif
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS)
-               return -ENODEV;
-
-       uart = bfin_serial_ports[co->index];
-       if (!uart)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               bfin_serial_console_get_options(uart, &baud, &parity, &bits);
-
-       return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-}
-
-static struct console bfin_serial_console = {
-       .name           = BFIN_SERIAL_DEV_NAME,
-       .write          = bfin_serial_console_write,
-       .device         = uart_console_device,
-       .setup          = bfin_serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &bfin_serial_reg,
-};
-#define BFIN_SERIAL_CONSOLE    &bfin_serial_console
-#else
-#define BFIN_SERIAL_CONSOLE    NULL
-#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
-
-#ifdef CONFIG_EARLY_PRINTK
-static struct bfin_serial_port bfin_earlyprintk_port;
-#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk"
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count)
-{
-       unsigned long flags;
-
-       if (bfin_earlyprintk_port.port.line != co->index)
-               return;
-
-       spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags);
-       uart_console_write(&bfin_earlyprintk_port.port, s, count,
-               bfin_serial_console_putchar);
-       spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags);
-}
-
-/*
- * This should have a .setup or .early_setup in it, but then things get called
- * without the command line options, and the baud rate gets messed up - so
- * don't let the common infrastructure play with things. (see calls to setup
- * & earlysetup in ./kernel/printk.c:register_console()
- */
-static struct __initdata console bfin_early_serial_console = {
-       .name = "early_BFuart",
-       .write = bfin_earlyprintk_console_write,
-       .device = uart_console_device,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data  = &bfin_serial_reg,
-};
-#endif
-
-static struct uart_driver bfin_serial_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = DRIVER_NAME,
-       .dev_name               = BFIN_SERIAL_DEV_NAME,
-       .major                  = BFIN_SERIAL_MAJOR,
-       .minor                  = BFIN_SERIAL_MINOR,
-       .nr                     = BFIN_UART_NR_PORTS,
-       .cons                   = BFIN_SERIAL_CONSOLE,
-};
-
-static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       return uart_suspend_port(&bfin_serial_reg, &uart->port);
-}
-
-static int bfin_serial_resume(struct platform_device *pdev)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       return uart_resume_port(&bfin_serial_reg, &uart->port);
-}
-
-static int bfin_serial_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct bfin_serial_port *uart = NULL;
-       int ret = 0;
-
-       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
-               dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n");
-               return -ENOENT;
-       }
-
-       if (bfin_serial_ports[pdev->id] == NULL) {
-
-               uart = kzalloc(sizeof(*uart), GFP_KERNEL);
-               if (!uart) {
-                       dev_err(&pdev->dev,
-                               "fail to malloc bfin_serial_port\n");
-                       return -ENOMEM;
-               }
-               bfin_serial_ports[pdev->id] = uart;
-
-#ifdef CONFIG_EARLY_PRINTK
-               if (!(bfin_earlyprintk_port.port.membase
-                       && bfin_earlyprintk_port.port.line == pdev->id)) {
-                       /*
-                        * If the peripheral PINs of current port is allocated
-                        * in earlyprintk probe stage, don't do it again.
-                        */
-#endif
-               ret = peripheral_request_list(
-                       (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "fail to request bfin serial peripherals\n");
-                       goto out_error_free_mem;
-               }
-#ifdef CONFIG_EARLY_PRINTK
-               }
-#endif
-
-               spin_lock_init(&uart->port.lock);
-               uart->port.uartclk   = get_sclk();
-               uart->port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
-               uart->port.ops       = &bfin_serial_pops;
-               uart->port.line      = pdev->id;
-               uart->port.iotype    = UPIO_MEM;
-               uart->port.flags     = UPF_BOOT_AUTOCONF;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-                       ret = -ENOENT;
-                       goto out_error_free_peripherals;
-               }
-
-               uart->port.membase = ioremap(res->start,
-                       res->end - res->start);
-               if (!uart->port.membase) {
-                       dev_err(&pdev->dev, "Cannot map uart IO\n");
-                       ret = -ENXIO;
-                       goto out_error_free_peripherals;
-               }
-               uart->port.mapbase = res->start;
-
-               uart->port.irq = platform_get_irq(pdev, 0);
-               if (uart->port.irq < 0) {
-                       dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-               uart->status_irq = platform_get_irq(pdev, 1);
-               if (uart->status_irq < 0) {
-                       dev_err(&pdev->dev, "No uart status IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
-               uart->tx_done       = 1;
-               uart->tx_count      = 0;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "No uart TX DMA channel specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-               uart->tx_dma_channel = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "No uart RX DMA channel specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-               uart->rx_dma_channel = res->start;
-
-               init_timer(&(uart->rx_dma_timer));
-#endif
-
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
-       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
-               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-               if (res == NULL)
-                       uart->cts_pin = -1;
-               else
-                       uart->cts_pin = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
-               if (res == NULL)
-                       uart->rts_pin = -1;
-               else
-                       uart->rts_pin = res->start;
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
-               if (uart->rts_pin >= 0)
-                       gpio_request(uart->rts_pin, DRIVER_NAME);
-# endif
-#endif
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       if (!is_early_platform_device(pdev)) {
-#endif
-               uart = bfin_serial_ports[pdev->id];
-               uart->port.dev = &pdev->dev;
-               dev_set_drvdata(&pdev->dev, uart);
-               ret = uart_add_one_port(&bfin_serial_reg, &uart->port);
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       }
-#endif
-
-       if (!ret)
-               return 0;
-
-       if (uart) {
-out_error_unmap:
-               iounmap(uart->port.membase);
-out_error_free_peripherals:
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-out_error_free_mem:
-               kfree(uart);
-               bfin_serial_ports[pdev->id] = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit bfin_serial_remove(struct platform_device *pdev)
-{
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       if (uart) {
-               uart_remove_one_port(&bfin_serial_reg, &uart->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (uart->rts_pin >= 0)
-                       gpio_free(uart->rts_pin);
-#endif
-               iounmap(uart->port.membase);
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-               kfree(uart);
-               bfin_serial_ports[pdev->id] = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver bfin_serial_driver = {
-       .probe          = bfin_serial_probe,
-       .remove         = __devexit_p(bfin_serial_remove),
-       .suspend        = bfin_serial_suspend,
-       .resume         = bfin_serial_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
-static __initdata struct early_platform_driver early_bfin_serial_driver = {
-       .class_str = CLASS_BFIN_CONSOLE,
-       .pdrv = &bfin_serial_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-static int __init bfin_serial_rs_console_init(void)
-{
-       early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME);
-
-       early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0);
-
-       register_console(&bfin_serial_console);
-
-       return 0;
-}
-console_initcall(bfin_serial_rs_console_init);
-#endif
-
-#ifdef CONFIG_EARLY_PRINTK
-/*
- * Memory can't be allocated dynamically during earlyprink init stage.
- * So, do individual probe for earlyprink with a static uart port variable.
- */
-static int bfin_earlyprintk_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       int ret;
-
-       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
-               dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n");
-               return -ENOENT;
-       }
-
-       ret = peripheral_request_list(
-               (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
-       if (ret) {
-               dev_err(&pdev->dev,
-                               "fail to request bfin serial peripherals\n");
-                       return ret;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-               ret = -ENOENT;
-               goto out_error_free_peripherals;
-       }
-
-       bfin_earlyprintk_port.port.membase = ioremap(res->start,
-                       res->end - res->start);
-       if (!bfin_earlyprintk_port.port.membase) {
-               dev_err(&pdev->dev, "Cannot map uart IO\n");
-               ret = -ENXIO;
-               goto out_error_free_peripherals;
-       }
-       bfin_earlyprintk_port.port.mapbase = res->start;
-       bfin_earlyprintk_port.port.line = pdev->id;
-       bfin_earlyprintk_port.port.uartclk = get_sclk();
-       bfin_earlyprintk_port.port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
-       spin_lock_init(&bfin_earlyprintk_port.port.lock);
-
-       return 0;
-
-out_error_free_peripherals:
-       peripheral_free_list(
-               (unsigned short *)pdev->dev.platform_data);
-
-       return ret;
-}
-
-static struct platform_driver bfin_earlyprintk_driver = {
-       .probe          = bfin_earlyprintk_probe,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
-       .class_str = CLASS_BFIN_EARLYPRINTK,
-       .pdrv = &bfin_earlyprintk_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-struct console __init *bfin_earlyserial_init(unsigned int port,
-                                               unsigned int cflag)
-{
-       struct ktermios t;
-       char port_name[20];
-
-       if (port < 0 || port >= BFIN_UART_NR_PORTS)
-               return NULL;
-
-       /*
-        * Only probe resource of the given port in earlyprintk boot arg.
-        * The expected port id should be indicated in port name string.
-        */
-       snprintf(port_name, 20, DRIVER_NAME ".%d", port);
-       early_platform_driver_register(&early_bfin_earlyprintk_driver,
-               port_name);
-       early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0);
-
-       if (!bfin_earlyprintk_port.port.membase)
-               return NULL;
-
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-       /*
-        * If we are using early serial, don't let the normal console rewind
-        * log buffer, since that causes things to be printed multiple times
-        */
-       bfin_serial_console.flags &= ~CON_PRINTBUFFER;
-#endif
-
-       bfin_early_serial_console.index = port;
-       t.c_cflag = cflag;
-       t.c_iflag = 0;
-       t.c_oflag = 0;
-       t.c_lflag = ICANON;
-       t.c_line = port;
-       bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t);
-
-       return &bfin_early_serial_console;
-}
-#endif /* CONFIG_EARLY_PRINTK */
-
-static int __init bfin_serial_init(void)
-{
-       int ret;
-
-       pr_info("Blackfin serial driver\n");
-
-       ret = uart_register_driver(&bfin_serial_reg);
-       if (ret) {
-               pr_err("failed to register %s:%d\n",
-                       bfin_serial_reg.driver_name, ret);
-       }
-
-       ret = platform_driver_register(&bfin_serial_driver);
-       if (ret) {
-               pr_err("fail to register bfin uart\n");
-               uart_unregister_driver(&bfin_serial_reg);
-       }
-
-       return ret;
-}
-
-static void __exit bfin_serial_exit(void)
-{
-       platform_driver_unregister(&bfin_serial_driver);
-       uart_unregister_driver(&bfin_serial_reg);
-}
-
-
-module_init(bfin_serial_init);
-module_exit(bfin_serial_exit);
-
-MODULE_AUTHOR("Sonic Zhang, Aubrey Li");
-MODULE_DESCRIPTION("Blackfin generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
-MODULE_ALIAS("platform:bfin-uart");
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
deleted file mode 100644 (file)
index e95c524..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Blackfin On-Chip Sport Emulated UART Driver
- *
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-/*
- * This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
- * This application note describe how to implement a UART on a Sharc DSP,
- * but this driver is implemented on Blackfin Processor.
- * Transmit Frame Sync is not used by this driver to transfer data out.
- */
-
-/* #define DEBUG */
-
-#define DRV_NAME "bfin-sport-uart"
-#define DEVICE_NAME    "ttySS"
-#define pr_fmt(fmt) DRV_NAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-
-#include <asm/bfin_sport.h>
-#include <asm/delay.h>
-#include <asm/portmux.h>
-
-#include "bfin_sport_uart.h"
-
-struct sport_uart_port {
-       struct uart_port        port;
-       int                     err_irq;
-       unsigned short          csize;
-       unsigned short          rxmask;
-       unsigned short          txmask1;
-       unsigned short          txmask2;
-       unsigned char           stopb;
-/*     unsigned char           parib; */
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       int cts_pin;
-       int rts_pin;
-#endif
-};
-
-static int sport_uart_tx_chars(struct sport_uart_port *up);
-static void sport_stop_tx(struct uart_port *port);
-
-static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
-{
-       pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value,
-               up->txmask1, up->txmask2);
-
-       /* Place Start and Stop bits */
-       __asm__ __volatile__ (
-               "%[val] <<= 1;"
-               "%[val] = %[val] & %[mask1];"
-               "%[val] = %[val] | %[mask2];"
-               : [val]"+d"(value)
-               : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2)
-               : "ASTAT"
-       );
-       pr_debug("%s value:%x\n", __func__, value);
-
-       SPORT_PUT_TX(up, value);
-}
-
-static inline unsigned char rx_one_byte(struct sport_uart_port *up)
-{
-       unsigned int value;
-       unsigned char extract;
-       u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
-
-       if ((up->csize + up->stopb) > 7)
-               value = SPORT_GET_RX32(up);
-       else
-               value = SPORT_GET_RX(up);
-
-       pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value,
-               up->csize, up->rxmask);
-
-       /* Extract data */
-       __asm__ __volatile__ (
-               "%[extr] = 0;"
-               "%[mask1] = %[rxmask];"
-               "%[mask2] = 0x0200(Z);"
-               "%[shift] = 0;"
-               "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
-               ".Lloop_s:"
-               "%[tmp] = extract(%[val], %[mask1].L)(Z);"
-               "%[tmp] <<= %[shift];"
-               "%[extr] = %[extr] | %[tmp];"
-               "%[mask1] = %[mask1] - %[mask2];"
-               ".Lloop_e:"
-               "%[shift] += 1;"
-               : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp),
-                 [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2)
-               : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize)
-               : "ASTAT", "LB0", "LC0", "LT0"
-       );
-
-       pr_debug("      extract:%x\n", extract);
-       return extract;
-}
-
-static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
-{
-       int tclkdiv, rclkdiv;
-       unsigned int sclk = get_sclk();
-
-       /* Set TCR1 and TCR2, TFSR is not enabled for uart */
-       SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
-       SPORT_PUT_TCR2(up, size + 1);
-       pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
-
-       /* Set RCR1 and RCR2 */
-       SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
-       SPORT_PUT_RCR2(up, (size + 1) * 2 - 1);
-       pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
-
-       tclkdiv = sclk / (2 * baud_rate) - 1;
-       /* The actual uart baud rate of devices vary between +/-2%. The sport
-        * RX sample rate should be faster than the double of the worst case,
-        * otherwise, wrong data are received. So, set sport RX clock to be
-        * 3% faster.
-        */
-       rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1;
-       SPORT_PUT_TCLKDIV(up, tclkdiv);
-       SPORT_PUT_RCLKDIV(up, rclkdiv);
-       SSYNC();
-       pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n",
-                       __func__, sclk, baud_rate, tclkdiv, rclkdiv);
-
-       return 0;
-}
-
-static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch;
-
-       spin_lock(&up->port.lock);
-
-       while (SPORT_GET_STAT(up) & RXNE) {
-               ch = rx_one_byte(up);
-               up->port.icount.rx++;
-
-               if (!uart_handle_sysrq_char(&up->port, ch))
-                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-       tty_flip_buffer_push(tty);
-
-       spin_unlock(&up->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-
-       spin_lock(&up->port.lock);
-       sport_uart_tx_chars(up);
-       spin_unlock(&up->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int stat = SPORT_GET_STAT(up);
-
-       spin_lock(&up->port.lock);
-
-       /* Overflow in RX FIFO */
-       if (stat & ROVF) {
-               up->port.icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
-       }
-       /* These should not happen */
-       if (stat & (TOVF | TUVF | RUVF)) {
-               pr_err("SPORT Error:%s %s %s\n",
-                      (stat & TOVF) ? "TX overflow" : "",
-                      (stat & TUVF) ? "TX underflow" : "",
-                      (stat & RUVF) ? "RX underflow" : "");
-               SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-               SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
-       }
-       SSYNC();
-
-       spin_unlock(&up->port.lock);
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-static unsigned int sport_get_mctrl(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       if (up->cts_pin < 0)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       /* CTS PIN is negative assertive. */
-       if (SPORT_UART_GET_CTS(up))
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       if (up->rts_pin < 0)
-               return;
-
-       /* RTS PIN is negative assertive. */
-       if (mctrl & TIOCM_RTS)
-               SPORT_UART_ENABLE_RTS(up);
-       else
-               SPORT_UART_DISABLE_RTS(up);
-}
-
-/*
- * Handle any change of modem status signal.
- */
-static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
-       unsigned int status;
-
-       status = sport_get_mctrl(&up->port);
-       uart_handle_cts_change(&up->port, status & TIOCM_CTS);
-
-       return IRQ_HANDLED;
-}
-#else
-static unsigned int sport_get_mctrl(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-       return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
-}
-
-static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       pr_debug("%s enter\n", __func__);
-}
-#endif
-
-/* Reqeust IRQ, Setup clock */
-static int sport_startup(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       int ret;
-
-       pr_debug("%s enter\n", __func__);
-       ret = request_irq(up->port.irq, sport_uart_rx_irq, 0,
-               "SPORT_UART_RX", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT RX interrupt\n");
-               return ret;
-       }
-
-       ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0,
-               "SPORT_UART_TX", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT TX interrupt\n");
-               goto fail1;
-       }
-
-       ret = request_irq(up->err_irq, sport_uart_err_irq, 0,
-               "SPORT_UART_STATUS", up);
-       if (ret) {
-               dev_err(port->dev, "unable to request SPORT status interrupt\n");
-               goto fail2;
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       if (up->cts_pin >= 0) {
-               if (request_irq(gpio_to_irq(up->cts_pin),
-                       sport_mctrl_cts_int,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
-                       up->cts_pin = -1;
-                       dev_info(port->dev, "Unable to attach BlackFin UART \
-                               over SPORT CTS interrupt. So, disable it.\n");
-               }
-       }
-       if (up->rts_pin >= 0)
-               gpio_direction_output(up->rts_pin, 0);
-#endif
-
-       return 0;
- fail2:
-       free_irq(up->port.irq+1, up);
- fail1:
-       free_irq(up->port.irq, up);
-
-       return ret;
-}
-
-/*
- * sport_uart_tx_chars
- *
- * ret 1 means need to enable sport.
- * ret 0 means do nothing.
- */
-static int sport_uart_tx_chars(struct sport_uart_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       if (SPORT_GET_STAT(up) & TXF)
-               return 0;
-
-       if (up->port.x_char) {
-               tx_one_byte(up, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               /* The waiting loop to stop SPORT TX from TX interrupt is
-                * too long. This may block SPORT RX interrupts and cause
-                * RX FIFO overflow. So, do stop sport TX only after the last
-                * char in TX FIFO is moved into the shift register.
-                */
-               if (SPORT_GET_STAT(up) & TXHRE)
-                       sport_stop_tx(&up->port);
-               return 0;
-       }
-
-       while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
-               tx_one_byte(up, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
-               up->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return 1;
-}
-
-static unsigned int sport_tx_empty(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       unsigned int stat;
-
-       stat = SPORT_GET_STAT(up);
-       pr_debug("%s stat:%04x\n", __func__, stat);
-       if (stat & TXHRE) {
-               return TIOCSER_TEMT;
-       } else
-               return 0;
-}
-
-static void sport_stop_tx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-
-       if (!(SPORT_GET_TCR1(up) & TSPEN))
-               return;
-
-       /* Although the hold register is empty, last byte is still in shift
-        * register and not sent out yet. So, put a dummy data into TX FIFO.
-        * Then, sport tx stops when last byte is shift out and the dummy
-        * data is moved into the shift register.
-        */
-       SPORT_PUT_TX(up, 0xffff);
-       while (!(SPORT_GET_STAT(up) & TXHRE))
-               cpu_relax();
-
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-       SSYNC();
-
-       return;
-}
-
-static void sport_start_tx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-
-       /* Write data into SPORT FIFO before enable SPROT to transmit */
-       if (sport_uart_tx_chars(up)) {
-               /* Enable transmit, then an interrupt will generated */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-               SSYNC();
-       }
-
-       pr_debug("%s exit\n", __func__);
-}
-
-static void sport_stop_rx(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       /* Disable sport to stop rx */
-       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
-       SSYNC();
-}
-
-static void sport_enable_ms(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static void sport_break_ctl(struct uart_port *port, int break_state)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static void sport_shutdown(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       dev_dbg(port->dev, "%s enter\n", __func__);
-
-       /* Disable sport */
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
-       SSYNC();
-
-       free_irq(up->port.irq, up);
-       free_irq(up->port.irq+1, up);
-       free_irq(up->err_irq, up);
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       if (up->cts_pin >= 0)
-               free_irq(gpio_to_irq(up->cts_pin), up);
-#endif
-}
-
-static const char *sport_type(struct uart_port *port)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL;
-}
-
-static void sport_release_port(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-}
-
-static int sport_request_port(struct uart_port *port)
-{
-       pr_debug("%s enter\n", __func__);
-       return 0;
-}
-
-static void sport_config_port(struct uart_port *port, int flags)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       pr_debug("%s enter\n", __func__);
-       up->port.type = PORT_BFIN_SPORT;
-}
-
-static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       pr_debug("%s enter\n", __func__);
-       return 0;
-}
-
-static void sport_set_termios(struct uart_port *port,
-               struct ktermios *termios, struct ktermios *old)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-       unsigned long flags;
-       int i;
-
-       pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS8:
-               up->csize = 8;
-               break;
-       case CS7:
-               up->csize = 7;
-               break;
-       case CS6:
-               up->csize = 6;
-               break;
-       case CS5:
-               up->csize = 5;
-               break;
-       default:
-               pr_warning("requested word length not supported\n");
-       }
-
-       if (termios->c_cflag & CSTOPB) {
-               up->stopb = 1;
-       }
-       if (termios->c_cflag & PARENB) {
-               pr_warning("PAREN bits is not supported yet\n");
-               /* up->parib = 1; */
-       }
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       port->read_status_mask = 0;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-
-       /* RX extract mask */
-       up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
-       /* TX masks, 8 bit data and 1 bit stop for example:
-        * mask1 = b#0111111110
-        * mask2 = b#1000000000
-        */
-       for (i = 0, up->txmask1 = 0; i < up->csize; i++)
-               up->txmask1 |= (1<<i);
-       up->txmask2 = (1<<i);
-       if (up->stopb) {
-               ++i;
-               up->txmask2 |= (1<<i);
-       }
-       up->txmask1 <<= 1;
-       up->txmask2 <<= 1;
-       /* uart baud rate */
-       port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
-
-       /* Disable UART */
-       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
-
-       sport_uart_setup(up, up->csize + up->stopb, port->uartclk);
-
-       /* driver TX line high after config, one dummy data is
-        * necessary to stop sport after shift one byte
-        */
-       SPORT_PUT_TX(up, 0xffff);
-       SPORT_PUT_TX(up, 0xffff);
-       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-       SSYNC();
-       while (!(SPORT_GET_STAT(up) & TXHRE))
-               cpu_relax();
-       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
-       SSYNC();
-
-       /* Port speed changed, update the per-port timeout. */
-       uart_update_timeout(port, termios->c_cflag, port->uartclk);
-
-       /* Enable sport rx */
-       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN);
-       SSYNC();
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-struct uart_ops sport_uart_ops = {
-       .tx_empty       = sport_tx_empty,
-       .set_mctrl      = sport_set_mctrl,
-       .get_mctrl      = sport_get_mctrl,
-       .stop_tx        = sport_stop_tx,
-       .start_tx       = sport_start_tx,
-       .stop_rx        = sport_stop_rx,
-       .enable_ms      = sport_enable_ms,
-       .break_ctl      = sport_break_ctl,
-       .startup        = sport_startup,
-       .shutdown       = sport_shutdown,
-       .set_termios    = sport_set_termios,
-       .type           = sport_type,
-       .release_port   = sport_release_port,
-       .request_port   = sport_request_port,
-       .config_port    = sport_config_port,
-       .verify_port    = sport_verify_port,
-};
-
-#define BFIN_SPORT_UART_MAX_PORTS 4
-
-static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-#define CLASS_BFIN_SPORT_CONSOLE       "bfin-sport-console"
-
-static int __init
-sport_uart_console_setup(struct console *co, char *options)
-{
-       struct sport_uart_port *up;
-       int baud = 57600;
-       int bits = 8;
-       int parity = 'n';
-# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-       int flow = 'r';
-# else
-       int flow = 'n';
-# endif
-
-       /* Check whether an invalid uart number has been specified */
-       if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
-               return -ENODEV;
-
-       up = bfin_sport_uart_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static void sport_uart_console_putchar(struct uart_port *port, int ch)
-{
-       struct sport_uart_port *up = (struct sport_uart_port *)port;
-
-       while (SPORT_GET_STAT(up) & TXF)
-               barrier();
-
-       tx_one_byte(up, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-sport_uart_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct sport_uart_port *up = bfin_sport_uart_ports[co->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (SPORT_GET_TCR1(up) & TSPEN)
-               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
-       else {
-               /* dummy data to start sport */
-               while (SPORT_GET_STAT(up) & TXF)
-                       barrier();
-               SPORT_PUT_TX(up, 0xffff);
-               /* Enable transmit, then an interrupt will generated */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
-               SSYNC();
-
-               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
-
-               /* Although the hold register is empty, last byte is still in shift
-                * register and not sent out yet. So, put a dummy data into TX FIFO.
-                * Then, sport tx stops when last byte is shift out and the dummy
-                * data is moved into the shift register.
-                */
-               while (SPORT_GET_STAT(up) & TXF)
-                       barrier();
-               SPORT_PUT_TX(up, 0xffff);
-               while (!(SPORT_GET_STAT(up) & TXHRE))
-                       barrier();
-
-               /* Stop sport tx transfer */
-               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
-               SSYNC();
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver sport_uart_reg;
-
-static struct console sport_uart_console = {
-       .name           = DEVICE_NAME,
-       .write          = sport_uart_console_write,
-       .device         = uart_console_device,
-       .setup          = sport_uart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &sport_uart_reg,
-};
-
-#define SPORT_UART_CONSOLE     (&sport_uart_console)
-#else
-#define SPORT_UART_CONSOLE     NULL
-#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */
-
-
-static struct uart_driver sport_uart_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRV_NAME,
-       .dev_name       = DEVICE_NAME,
-       .major          = 204,
-       .minor          = 84,
-       .nr             = BFIN_SPORT_UART_MAX_PORTS,
-       .cons           = SPORT_UART_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int sport_uart_suspend(struct device *dev)
-{
-       struct sport_uart_port *sport = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s enter\n", __func__);
-       if (sport)
-               uart_suspend_port(&sport_uart_reg, &sport->port);
-
-       return 0;
-}
-
-static int sport_uart_resume(struct device *dev)
-{
-       struct sport_uart_port *sport = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s enter\n", __func__);
-       if (sport)
-               uart_resume_port(&sport_uart_reg, &sport->port);
-
-       return 0;
-}
-
-static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
-       .suspend        = sport_uart_suspend,
-       .resume         = sport_uart_resume,
-};
-#endif
-
-static int __devinit sport_uart_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct sport_uart_port *sport;
-       int ret = 0;
-
-       dev_dbg(&pdev->dev, "%s enter\n", __func__);
-
-       if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) {
-               dev_err(&pdev->dev, "Wrong sport uart platform device id.\n");
-               return -ENOENT;
-       }
-
-       if (bfin_sport_uart_ports[pdev->id] == NULL) {
-               bfin_sport_uart_ports[pdev->id] =
-                       kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
-               sport = bfin_sport_uart_ports[pdev->id];
-               if (!sport) {
-                       dev_err(&pdev->dev,
-                               "Fail to malloc sport_uart_port\n");
-                       return -ENOMEM;
-               }
-
-               ret = peripheral_request_list(
-                       (unsigned short *)pdev->dev.platform_data, DRV_NAME);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Fail to request SPORT peripherals\n");
-                       goto out_error_free_mem;
-               }
-
-               spin_lock_init(&sport->port.lock);
-               sport->port.fifosize  = SPORT_TX_FIFO_SIZE,
-               sport->port.ops       = &sport_uart_ops;
-               sport->port.line      = pdev->id;
-               sport->port.iotype    = UPIO_MEM;
-               sport->port.flags     = UPF_BOOT_AUTOCONF;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res == NULL) {
-                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
-                       ret = -ENOENT;
-                       goto out_error_free_peripherals;
-               }
-
-               sport->port.membase = ioremap(res->start, resource_size(res));
-               if (!sport->port.membase) {
-                       dev_err(&pdev->dev, "Cannot map sport IO\n");
-                       ret = -ENXIO;
-                       goto out_error_free_peripherals;
-               }
-               sport->port.mapbase = res->start;
-
-               sport->port.irq = platform_get_irq(pdev, 0);
-               if (sport->port.irq < 0) {
-                       dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-
-               sport->err_irq = platform_get_irq(pdev, 1);
-               if (sport->err_irq < 0) {
-                       dev_err(&pdev->dev, "No sport status IRQ specified\n");
-                       ret = -ENOENT;
-                       goto out_error_unmap;
-               }
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-               if (res == NULL)
-                       sport->cts_pin = -1;
-               else
-                       sport->cts_pin = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
-               if (res == NULL)
-                       sport->rts_pin = -1;
-               else
-                       sport->rts_pin = res->start;
-
-               if (sport->rts_pin >= 0)
-                       gpio_request(sport->rts_pin, DRV_NAME);
-#endif
-       }
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-       if (!is_early_platform_device(pdev)) {
-#endif
-               sport = bfin_sport_uart_ports[pdev->id];
-               sport->port.dev = &pdev->dev;
-               dev_set_drvdata(&pdev->dev, sport);
-               ret = uart_add_one_port(&sport_uart_reg, &sport->port);
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-       }
-#endif
-       if (!ret)
-               return 0;
-
-       if (sport) {
-out_error_unmap:
-               iounmap(sport->port.membase);
-out_error_free_peripherals:
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-out_error_free_mem:
-               kfree(sport);
-               bfin_sport_uart_ports[pdev->id] = NULL;
-       }
-
-       return ret;
-}
-
-static int __devexit sport_uart_remove(struct platform_device *pdev)
-{
-       struct sport_uart_port *sport = platform_get_drvdata(pdev);
-
-       dev_dbg(&pdev->dev, "%s enter\n", __func__);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       if (sport) {
-               uart_remove_one_port(&sport_uart_reg, &sport->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (sport->rts_pin >= 0)
-                       gpio_free(sport->rts_pin);
-#endif
-               iounmap(sport->port.membase);
-               peripheral_free_list(
-                       (unsigned short *)pdev->dev.platform_data);
-               kfree(sport);
-               bfin_sport_uart_ports[pdev->id] = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver sport_uart_driver = {
-       .probe          = sport_uart_probe,
-       .remove         = __devexit_p(sport_uart_remove),
-       .driver         = {
-               .name   = DRV_NAME,
-#ifdef CONFIG_PM
-               .pm     = &bfin_sport_uart_dev_pm_ops,
-#endif
-       },
-};
-
-#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-static __initdata struct early_platform_driver early_sport_uart_driver = {
-       .class_str = CLASS_BFIN_SPORT_CONSOLE,
-       .pdrv = &sport_uart_driver,
-       .requested_id = EARLY_PLATFORM_ID_UNSET,
-};
-
-static int __init sport_uart_rs_console_init(void)
-{
-       early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
-
-       early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
-               BFIN_SPORT_UART_MAX_PORTS, 0);
-
-       register_console(&sport_uart_console);
-
-       return 0;
-}
-console_initcall(sport_uart_rs_console_init);
-#endif
-
-static int __init sport_uart_init(void)
-{
-       int ret;
-
-       pr_info("Blackfin uart over sport driver\n");
-
-       ret = uart_register_driver(&sport_uart_reg);
-       if (ret) {
-               pr_err("failed to register %s:%d\n",
-                               sport_uart_reg.driver_name, ret);
-               return ret;
-       }
-
-       ret = platform_driver_register(&sport_uart_driver);
-       if (ret) {
-               pr_err("failed to register sport uart driver:%d\n", ret);
-               uart_unregister_driver(&sport_uart_reg);
-       }
-
-       return ret;
-}
-module_init(sport_uart_init);
-
-static void __exit sport_uart_exit(void)
-{
-       platform_driver_unregister(&sport_uart_driver);
-       uart_unregister_driver(&sport_uart_reg);
-}
-module_exit(sport_uart_exit);
-
-MODULE_AUTHOR("Sonic Zhang, Roy Huang");
-MODULE_DESCRIPTION("Blackfin serial over SPORT driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
deleted file mode 100644 (file)
index 6d06ce1..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Blackfin On-Chip Sport Emulated UART Driver
- *
- * Copyright 2006-2008 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-/*
- * This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
- * This application note describe how to implement a UART on a Sharc DSP,
- * but this driver is implemented on Blackfin Processor.
- * Transmit Frame Sync is not used by this driver to transfer data out.
- */
-
-#ifndef _BFIN_SPORT_UART_H
-#define _BFIN_SPORT_UART_H
-
-#define OFFSET_TCR1            0x00    /* Transmit Configuration 1 Register */
-#define OFFSET_TCR2            0x04    /* Transmit Configuration 2 Register */
-#define OFFSET_TCLKDIV         0x08    /* Transmit Serial Clock Divider Register */
-#define OFFSET_TFSDIV          0x0C    /* Transmit Frame Sync Divider Register */
-#define OFFSET_TX              0x10    /* Transmit Data Register               */
-#define OFFSET_RX              0x18    /* Receive Data Register                */
-#define OFFSET_RCR1            0x20    /* Receive Configuration 1 Register     */
-#define OFFSET_RCR2            0x24    /* Receive Configuration 2 Register     */
-#define OFFSET_RCLKDIV         0x28    /* Receive Serial Clock Divider Register */
-#define OFFSET_RFSDIV          0x2c    /* Receive Frame Sync Divider Register */
-#define OFFSET_STAT            0x30    /* Status Register                      */
-
-#define SPORT_GET_TCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR1))
-#define SPORT_GET_TCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR2))
-#define SPORT_GET_TCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
-#define SPORT_GET_TFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
-#define SPORT_GET_TX(sport)            bfin_read16(((sport)->port.membase + OFFSET_TX))
-#define SPORT_GET_RX(sport)            bfin_read16(((sport)->port.membase + OFFSET_RX))
-/*
- * If another interrupt fires while doing a 32-bit read from RX FIFO,
- * a fake RX underflow error will be generated.  So disable interrupts
- * to prevent interruption while reading the FIFO.
- */
-#define SPORT_GET_RX32(sport) \
-({ \
-       unsigned int __ret; \
-       if (ANOMALY_05000473) \
-               local_irq_disable(); \
-       __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
-       if (ANOMALY_05000473) \
-               local_irq_enable(); \
-       __ret; \
-})
-#define SPORT_GET_RCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR1))
-#define SPORT_GET_RCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR2))
-#define SPORT_GET_RCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
-#define SPORT_GET_RFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
-#define SPORT_GET_STAT(sport)          bfin_read16(((sport)->port.membase + OFFSET_STAT))
-
-#define SPORT_PUT_TCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
-#define SPORT_PUT_TCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
-#define SPORT_PUT_TCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
-#define SPORT_PUT_TFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
-#define SPORT_PUT_TX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_TX), v)
-#define SPORT_PUT_RX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_RX), v)
-#define SPORT_PUT_RCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
-#define SPORT_PUT_RCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
-#define SPORT_PUT_RCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
-#define SPORT_PUT_RFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
-#define SPORT_PUT_STAT(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
-
-#define SPORT_TX_FIFO_SIZE     8
-
-#define SPORT_UART_GET_CTS(x)          gpio_get_value(x->cts_pin)
-#define SPORT_UART_DISABLE_RTS(x)      gpio_set_value(x->rts_pin, 1)
-#define SPORT_UART_ENABLE_RTS(x)       gpio_set_value(x->rts_pin, 0)
-
-#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
-       || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
-# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
-#endif
-
-#endif /* _BFIN_SPORT_UART_H */
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
deleted file mode 100644 (file)
index b6acd19..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- *  linux/drivers/char/clps711x.c
- *
- *  Driver for CLPS711x serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/hardware/clps7111.h>
-
-#define UART_NR                2
-
-#define SERIAL_CLPS711X_MAJOR  204
-#define SERIAL_CLPS711X_MINOR  40
-#define SERIAL_CLPS711X_NR     UART_NR
-
-/*
- * We use the relevant SYSCON register as a base address for these ports.
- */
-#define UBRLCR(port)           ((port)->iobase + UBRLCR1 - SYSCON1)
-#define UARTDR(port)           ((port)->iobase + UARTDR1 - SYSCON1)
-#define SYSFLG(port)           ((port)->iobase + SYSFLG1 - SYSCON1)
-#define SYSCON(port)           ((port)->iobase + SYSCON1 - SYSCON1)
-
-#define TX_IRQ(port)           ((port)->irq)
-#define RX_IRQ(port)           ((port)->irq + 1)
-
-#define UART_ANY_ERR           (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
-#define tx_enabled(port)       ((port)->unused[0])
-
-static void clps711xuart_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               disable_irq(TX_IRQ(port));
-               tx_enabled(port) = 0;
-       }
-}
-
-static void clps711xuart_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(TX_IRQ(port));
-               tx_enabled(port) = 1;
-       }
-}
-
-static void clps711xuart_stop_rx(struct uart_port *port)
-{
-       disable_irq(RX_IRQ(port));
-}
-
-static void clps711xuart_enable_ms(struct uart_port *port)
-{
-}
-
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = clps_readl(SYSFLG(port));
-       while (!(status & SYSFLG_URXFE)) {
-               ch = clps_readl(UARTDR(port));
-
-               port->icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               if (unlikely(ch & UART_ANY_ERR)) {
-                       if (ch & UARTDR_PARERR)
-                               port->icount.parity++;
-                       else if (ch & UARTDR_FRMERR)
-                               port->icount.frame++;
-                       if (ch & UARTDR_OVERR)
-                               port->icount.overrun++;
-
-                       ch &= port->read_status_mask;
-
-                       if (ch & UARTDR_PARERR)
-                               flg = TTY_PARITY;
-                       else if (ch & UARTDR_FRMERR)
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       port->sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               /*
-                * CHECK: does overrun affect the current character?
-                * ASSUMPTION: it does not.
-                */
-               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
-
-       ignore_char:
-               status = clps_readl(SYSFLG(port));
-       }
-       tty_flip_buffer_push(tty);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count;
-
-       if (port->x_char) {
-               clps_writel(port->x_char, UARTDR(port));
-               port->icount.tx++;
-               port->x_char = 0;
-               return IRQ_HANDLED;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               clps711xuart_stop_tx(port);
-               return IRQ_HANDLED;
-       }
-
-       count = port->fifosize >> 1;
-       do {
-               clps_writel(xmit->buf[xmit->tail], UARTDR(port));
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               clps711xuart_stop_tx(port);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int clps711xuart_tx_empty(struct uart_port *port)
-{
-       unsigned int status = clps_readl(SYSFLG(port));
-       return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
-{
-       unsigned int port_addr;
-       unsigned int result = 0;
-       unsigned int status;
-
-       port_addr = SYSFLG(port);
-       if (port_addr == SYSFLG1) {
-               status = clps_readl(SYSFLG1);
-               if (status & SYSFLG1_DCD)
-                       result |= TIOCM_CAR;
-               if (status & SYSFLG1_DSR)
-                       result |= TIOCM_DSR;
-               if (status & SYSFLG1_CTS)
-                       result |= TIOCM_CTS;
-       }
-
-       return result;
-}
-
-static void
-clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int ubrlcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-       ubrlcr = clps_readl(UBRLCR(port));
-       if (break_state == -1)
-               ubrlcr |= UBRLCR_BREAK;
-       else
-               ubrlcr &= ~UBRLCR_BREAK;
-       clps_writel(ubrlcr, UBRLCR(port));
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int clps711xuart_startup(struct uart_port *port)
-{
-       unsigned int syscon;
-       int retval;
-
-       tx_enabled(port) = 1;
-
-       /*
-        * Allocate the IRQs
-        */
-       retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
-                            "clps711xuart_tx", port);
-       if (retval)
-               return retval;
-
-       retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
-                            "clps711xuart_rx", port);
-       if (retval) {
-               free_irq(TX_IRQ(port), port);
-               return retval;
-       }
-
-       /*
-        * enable the port
-        */
-       syscon = clps_readl(SYSCON(port));
-       syscon |= SYSCON_UARTEN;
-       clps_writel(syscon, SYSCON(port));
-
-       return 0;
-}
-
-static void clps711xuart_shutdown(struct uart_port *port)
-{
-       unsigned int ubrlcr, syscon;
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(TX_IRQ(port), port);   /* TX interrupt */
-       free_irq(RX_IRQ(port), port);   /* RX interrupt */
-
-       /*
-        * disable the port
-        */
-       syscon = clps_readl(SYSCON(port));
-       syscon &= ~SYSCON_UARTEN;
-       clps_writel(syscon, SYSCON(port));
-
-       /*
-        * disable break condition and fifos
-        */
-       ubrlcr = clps_readl(UBRLCR(port));
-       ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
-       clps_writel(ubrlcr, UBRLCR(port));
-}
-
-static void
-clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
-                        struct ktermios *old)
-{
-       unsigned int ubrlcr, baud, quot;
-       unsigned long flags;
-
-       /*
-        * We don't implement CREAD.
-        */
-       termios->c_cflag |= CREAD;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               ubrlcr = UBRLCR_WRDLEN5;
-               break;
-       case CS6:
-               ubrlcr = UBRLCR_WRDLEN6;
-               break;
-       case CS7:
-               ubrlcr = UBRLCR_WRDLEN7;
-               break;
-       default: // CS8
-               ubrlcr = UBRLCR_WRDLEN8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               ubrlcr |= UBRLCR_XSTOP;
-       if (termios->c_cflag & PARENB) {
-               ubrlcr |= UBRLCR_PRTEN;
-               if (!(termios->c_cflag & PARODD))
-                       ubrlcr |= UBRLCR_EVENPRT;
-       }
-       if (port->fifosize > 1)
-               ubrlcr |= UBRLCR_FIFOEN;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = UARTDR_OVERR;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
-       if (termios->c_iflag & IGNBRK) {
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns to (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UARTDR_OVERR;
-       }
-
-       quot -= 1;
-
-       clps_writel(ubrlcr | quot, UBRLCR(port));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *clps711xuart_type(struct uart_port *port)
-{
-       return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void clps711xuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE)
-               port->type = PORT_CLPS711X;
-}
-
-static void clps711xuart_release_port(struct uart_port *port)
-{
-}
-
-static int clps711xuart_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static struct uart_ops clps711x_pops = {
-       .tx_empty       = clps711xuart_tx_empty,
-       .set_mctrl      = clps711xuart_set_mctrl_null,
-       .get_mctrl      = clps711xuart_get_mctrl,
-       .stop_tx        = clps711xuart_stop_tx,
-       .start_tx       = clps711xuart_start_tx,
-       .stop_rx        = clps711xuart_stop_rx,
-       .enable_ms      = clps711xuart_enable_ms,
-       .break_ctl      = clps711xuart_break_ctl,
-       .startup        = clps711xuart_startup,
-       .shutdown       = clps711xuart_shutdown,
-       .set_termios    = clps711xuart_set_termios,
-       .type           = clps711xuart_type,
-       .config_port    = clps711xuart_config_port,
-       .release_port   = clps711xuart_release_port,
-       .request_port   = clps711xuart_request_port,
-};
-
-static struct uart_port clps711x_ports[UART_NR] = {
-       {
-               .iobase         = SYSCON1,
-               .irq            = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
-               .uartclk        = 3686400,
-               .fifosize       = 16,
-               .ops            = &clps711x_pops,
-               .line           = 0,
-               .flags          = UPF_BOOT_AUTOCONF,
-       },
-       {
-               .iobase         = SYSCON2,
-               .irq            = IRQ_UTXINT2, /* IRQ_URXINT2 */
-               .uartclk        = 3686400,
-               .fifosize       = 16,
-               .ops            = &clps711x_pops,
-               .line           = 1,
-               .flags          = UPF_BOOT_AUTOCONF,
-       }
-};
-
-#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-static void clps711xuart_console_putchar(struct uart_port *port, int ch)
-{
-       while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
-               barrier();
-       clps_writel(ch, UARTDR(port));
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- *
- *     Note that this is called with interrupts already disabled
- */
-static void
-clps711xuart_console_write(struct console *co, const char *s,
-                          unsigned int count)
-{
-       struct uart_port *port = clps711x_ports + co->index;
-       unsigned int status, syscon;
-
-       /*
-        *      Ensure that the port is enabled.
-        */
-       syscon = clps_readl(SYSCON(port));
-       clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
-
-       uart_console_write(port, s, count, clps711xuart_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the uart state.
-        */
-       do {
-               status = clps_readl(SYSFLG(port));
-       } while (status & SYSFLG_UBUSY);
-
-       clps_writel(syscon, SYSCON(port));
-}
-
-static void __init
-clps711xuart_console_get_options(struct uart_port *port, int *baud,
-                                int *parity, int *bits)
-{
-       if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
-               unsigned int ubrlcr, quot;
-
-               ubrlcr = clps_readl(UBRLCR(port));
-
-               *parity = 'n';
-               if (ubrlcr & UBRLCR_PRTEN) {
-                       if (ubrlcr & UBRLCR_EVENPRT)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
-                       *bits = 7;
-               else
-                       *bits = 8;
-
-               quot = ubrlcr & UBRLCR_BAUD_MASK;
-               *baud = port->uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init clps711xuart_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       port = uart_get_console(clps711x_ports, UART_NR, co);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               clps711xuart_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver clps711x_reg;
-static struct console clps711x_console = {
-       .name           = "ttyCL",
-       .write          = clps711xuart_console_write,
-       .device         = uart_console_device,
-       .setup          = clps711xuart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &clps711x_reg,
-};
-
-static int __init clps711xuart_console_init(void)
-{
-       register_console(&clps711x_console);
-       return 0;
-}
-console_initcall(clps711xuart_console_init);
-
-#define CLPS711X_CONSOLE       &clps711x_console
-#else
-#define CLPS711X_CONSOLE       NULL
-#endif
-
-static struct uart_driver clps711x_reg = {
-       .driver_name            = "ttyCL",
-       .dev_name               = "ttyCL",
-       .major                  = SERIAL_CLPS711X_MAJOR,
-       .minor                  = SERIAL_CLPS711X_MINOR,
-       .nr                     = UART_NR,
-
-       .cons                   = CLPS711X_CONSOLE,
-};
-
-static int __init clps711xuart_init(void)
-{
-       int ret, i;
-
-       printk(KERN_INFO "Serial: CLPS711x driver\n");
-
-       ret = uart_register_driver(&clps711x_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
-
-       return 0;
-}
-
-static void __exit clps711xuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
-
-       uart_unregister_driver(&clps711x_reg);
-}
-
-module_init(clps711xuart_init);
-module_exit(clps711xuart_exit);
-
-MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/serial/cpm_uart/Makefile b/drivers/serial/cpm_uart/Makefile
deleted file mode 100644 (file)
index e072724..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the Motorola 8xx FEC ethernet controller
-#
-
-obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
-
-# Select the correct platform objects.
-cpm_uart-objs-$(CONFIG_CPM2)   += cpm_uart_cpm2.o
-cpm_uart-objs-$(CONFIG_8xx)    += cpm_uart_cpm1.o
-
-cpm_uart-objs  := cpm_uart_core.o $(cpm_uart-objs-y)
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
deleted file mode 100644 (file)
index b754dcf..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.h
- *
- *  Driver for CPM (SCC/SMC) serial ports
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *
- *  2006 (c) MontaVista Software, Inc.
- *     Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-#ifndef CPM_UART_H
-#define CPM_UART_H
-
-#include <linux/platform_device.h>
-#include <linux/fs_uart_pd.h>
-
-#if defined(CONFIG_CPM2)
-#include "cpm_uart_cpm2.h"
-#elif defined(CONFIG_8xx)
-#include "cpm_uart_cpm1.h"
-#endif
-
-#define SERIAL_CPM_MAJOR       204
-#define SERIAL_CPM_MINOR       46
-
-#define IS_SMC(pinfo)          (pinfo->flags & FLAG_SMC)
-#define IS_DISCARDING(pinfo)   (pinfo->flags & FLAG_DISCARDING)
-#define FLAG_DISCARDING        0x00000004      /* when set, don't discard */
-#define FLAG_SMC       0x00000002
-#define FLAG_CONSOLE   0x00000001
-
-#define UART_SMC1      fsid_smc1_uart
-#define UART_SMC2      fsid_smc2_uart
-#define UART_SCC1      fsid_scc1_uart
-#define UART_SCC2      fsid_scc2_uart
-#define UART_SCC3      fsid_scc3_uart
-#define UART_SCC4      fsid_scc4_uart
-
-#define UART_NR                fs_uart_nr
-
-#define RX_NUM_FIFO    4
-#define RX_BUF_SIZE    32
-#define TX_NUM_FIFO    4
-#define TX_BUF_SIZE    32
-
-#define SCC_WAIT_CLOSING 100
-
-#define GPIO_CTS       0
-#define GPIO_RTS       1
-#define GPIO_DCD       2
-#define GPIO_DSR       3
-#define GPIO_DTR       4
-#define GPIO_RI                5
-
-#define NUM_GPIOS      (GPIO_RI+1)
-
-struct uart_cpm_port {
-       struct uart_port        port;
-       u16                     rx_nrfifos;
-       u16                     rx_fifosize;
-       u16                     tx_nrfifos;
-       u16                     tx_fifosize;
-       smc_t __iomem           *smcp;
-       smc_uart_t __iomem      *smcup;
-       scc_t __iomem           *sccp;
-       scc_uart_t __iomem      *sccup;
-       cbd_t __iomem           *rx_bd_base;
-       cbd_t __iomem           *rx_cur;
-       cbd_t __iomem           *tx_bd_base;
-       cbd_t __iomem           *tx_cur;
-       unsigned char           *tx_buf;
-       unsigned char           *rx_buf;
-       u32                     flags;
-       struct clk              *clk;
-       u8                      brg;
-       uint                     dp_addr;
-       void                    *mem_addr;
-       dma_addr_t               dma_addr;
-       u32                     mem_size;
-       /* wait on close if needed */
-       int                     wait_closing;
-       /* value to combine with opcode to form cpm command */
-       u32                     command;
-       int                     gpios[NUM_GPIOS];
-};
-
-extern int cpm_uart_nr;
-extern struct uart_cpm_port cpm_uart_ports[UART_NR];
-
-/* these are located in their respective files */
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np);
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram);
-int cpm_uart_init_portdesc(void);
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
-
-void smc1_lineif(struct uart_cpm_port *pinfo);
-void smc2_lineif(struct uart_cpm_port *pinfo);
-void scc1_lineif(struct uart_cpm_port *pinfo);
-void scc2_lineif(struct uart_cpm_port *pinfo);
-void scc3_lineif(struct uart_cpm_port *pinfo);
-void scc4_lineif(struct uart_cpm_port *pinfo);
-
-/*
-   virtual to phys transtalion
-*/
-static inline unsigned long cpu2cpm_addr(void *addr,
-                                         struct uart_cpm_port *pinfo)
-{
-       int offset;
-       u32 val = (u32)addr;
-       u32 mem = (u32)pinfo->mem_addr;
-       /* sane check */
-       if (likely(val >= mem && val < mem + pinfo->mem_size)) {
-               offset = val - mem;
-               return pinfo->dma_addr + offset;
-       }
-       /* something nasty happened */
-       BUG();
-       return 0;
-}
-
-static inline void *cpm2cpu_addr(unsigned long addr,
-                                 struct uart_cpm_port *pinfo)
-{
-       int offset;
-       u32 val = addr;
-       u32 dma = (u32)pinfo->dma_addr;
-       /* sane check */
-       if (likely(val >= dma && val < dma + pinfo->mem_size)) {
-               offset = val - dma;
-               return pinfo->mem_addr + offset;
-       }
-       /* something nasty happened */
-       BUG();
-       return NULL;
-}
-
-
-#endif /* CPM_UART_H */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
deleted file mode 100644 (file)
index 8692ff9..0000000
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; core driver
- *
- *  Based on arch/ppc/cpm2_io/uart.c by Dan Malek
- *  Based on ppc8xx.c by Thomas Gleixner
- *  Based on drivers/serial/amba.c by Russell King
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2005-2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-#include <linux/fs_uart_pd.h>
-#include <linux/of_platform.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/fs_pd.h>
-#include <asm/udbg.h>
-
-#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include "cpm_uart.h"
-
-
-/**************************************************************/
-
-static int  cpm_uart_tx_pump(struct uart_port *port);
-static void cpm_uart_init_smc(struct uart_cpm_port *pinfo);
-static void cpm_uart_init_scc(struct uart_cpm_port *pinfo);
-static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
-
-/**************************************************************/
-
-#define HW_BUF_SPD_THRESHOLD    9600
-
-/*
- * Check, if transmit buffers are processed
-*/
-static unsigned int cpm_uart_tx_empty(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       cbd_t __iomem *bdp = pinfo->tx_bd_base;
-       int ret = 0;
-
-       while (1) {
-               if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
-                       break;
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
-                       ret = TIOCSER_TEMT;
-                       break;
-               }
-               bdp++;
-       }
-
-       pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
-
-       return ret;
-}
-
-static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (pinfo->gpios[GPIO_RTS] >= 0)
-               gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
-
-       if (pinfo->gpios[GPIO_DTR] >= 0)
-               gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
-}
-
-static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       if (pinfo->gpios[GPIO_CTS] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
-                       mctrl &= ~TIOCM_CTS;
-       }
-
-       if (pinfo->gpios[GPIO_DSR] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
-                       mctrl &= ~TIOCM_DSR;
-       }
-
-       if (pinfo->gpios[GPIO_DCD] >= 0) {
-               if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
-                       mctrl &= ~TIOCM_CAR;
-       }
-
-       if (pinfo->gpios[GPIO_RI] >= 0) {
-               if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
-                       mctrl |= TIOCM_RNG;
-       }
-
-       return mctrl;
-}
-
-/*
- * Stop transmitter
- */
-static void cpm_uart_stop_tx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:stop tx\n", port->line);
-
-       if (IS_SMC(pinfo))
-               clrbits8(&smcp->smc_smcm, SMCM_TX);
-       else
-               clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
-}
-
-/*
- * Start transmitter
- */
-static void cpm_uart_start_tx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:start tx\n", port->line);
-
-       if (IS_SMC(pinfo)) {
-               if (in_8(&smcp->smc_smcm) & SMCM_TX)
-                       return;
-       } else {
-               if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
-                       return;
-       }
-
-       if (cpm_uart_tx_pump(port) != 0) {
-               if (IS_SMC(pinfo)) {
-                       setbits8(&smcp->smc_smcm, SMCM_TX);
-               } else {
-                       setbits16(&sccp->scc_sccm, UART_SCCM_TX);
-               }
-       }
-}
-
-/*
- * Stop receiver
- */
-static void cpm_uart_stop_rx(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:stop rx\n", port->line);
-
-       if (IS_SMC(pinfo))
-               clrbits8(&smcp->smc_smcm, SMCM_RX);
-       else
-               clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
-}
-
-/*
- * Enable Modem status interrupts
- */
-static void cpm_uart_enable_ms(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:enable ms\n", port->line);
-}
-
-/*
- * Generate a break.
- */
-static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
-               break_state);
-
-       if (break_state)
-               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-       else
-               cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
-}
-
-/*
- * Transmit characters, refill buffer descriptor, if possible
- */
-static void cpm_uart_int_tx(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:TX INT\n", port->line);
-
-       cpm_uart_tx_pump(port);
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- * Receive characters
- */
-static void cpm_uart_int_rx(struct uart_port *port)
-{
-       int i;
-       unsigned char ch;
-       u8 *cp;
-       struct tty_struct *tty = port->state->port.tty;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       cbd_t __iomem *bdp;
-       u16 status;
-       unsigned int flg;
-
-       pr_debug("CPM uart[%d]:RX INT\n", port->line);
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = pinfo->rx_cur;
-       for (;;) {
-#ifdef CONFIG_CONSOLE_POLL
-               if (unlikely(serial_polled)) {
-                       serial_polled = 0;
-                       return;
-               }
-#endif
-               /* get status */
-               status = in_be16(&bdp->cbd_sc);
-               /* If this one is empty, return happy */
-               if (status & BD_SC_EMPTY)
-                       break;
-
-               /* get number of characters, and check spce in flip-buffer */
-               i = in_be16(&bdp->cbd_datlen);
-
-               /* If we have not enough room in tty flip buffer, then we try
-                * later, which will be the next rx-interrupt or a timeout
-                */
-               if(tty_buffer_request_room(tty, i) < i) {
-                       printk(KERN_WARNING "No room in flip buffer\n");
-                       return;
-               }
-
-               /* get pointer */
-               cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-
-               /* loop through the buffer */
-               while (i-- > 0) {
-                       ch = *cp++;
-                       port->icount.rx++;
-                       flg = TTY_NORMAL;
-
-                       if (status &
-                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
-                               goto handle_error;
-                       if (uart_handle_sysrq_char(port, ch))
-                               continue;
-#ifdef CONFIG_CONSOLE_POLL
-                       if (unlikely(serial_polled)) {
-                               serial_polled = 0;
-                               return;
-                       }
-#endif
-                     error_return:
-                       tty_insert_flip_char(tty, ch, flg);
-
-               }               /* End while (i--) */
-
-               /* This BD is ready to be used again. Clear status. get next */
-               clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
-                                       BD_SC_OV | BD_SC_ID);
-               setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->rx_bd_base;
-               else
-                       bdp++;
-
-       } /* End for (;;) */
-
-       /* Write back buffer pointer */
-       pinfo->rx_cur = bdp;
-
-       /* activate BH processing */
-       tty_flip_buffer_push(tty);
-
-       return;
-
-       /* Error processing */
-
-      handle_error:
-       /* Statistics */
-       if (status & BD_SC_BR)
-               port->icount.brk++;
-       if (status & BD_SC_PR)
-               port->icount.parity++;
-       if (status & BD_SC_FR)
-               port->icount.frame++;
-       if (status & BD_SC_OV)
-               port->icount.overrun++;
-
-       /* Mask out ignored conditions */
-       status &= port->read_status_mask;
-
-       /* Handle the remaining ones */
-       if (status & BD_SC_BR)
-               flg = TTY_BREAK;
-       else if (status & BD_SC_PR)
-               flg = TTY_PARITY;
-       else if (status & BD_SC_FR)
-               flg = TTY_FRAME;
-
-       /* overrun does not affect the current character ! */
-       if (status & BD_SC_OV) {
-               ch = 0;
-               flg = TTY_OVERRUN;
-               /* We skip this buffer */
-               /* CHECK: Is really nothing senseful there */
-               /* ASSUMPTION: it contains nothing valid */
-               i = 0;
-       }
-#ifdef SUPPORT_SYSRQ
-       port->sysrq = 0;
-#endif
-       goto error_return;
-}
-
-/*
- * Asynchron mode interrupt handler
- */
-static irqreturn_t cpm_uart_int(int irq, void *data)
-{
-       u8 events;
-       struct uart_port *port = data;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:IRQ\n", port->line);
-
-       if (IS_SMC(pinfo)) {
-               events = in_8(&smcp->smc_smce);
-               out_8(&smcp->smc_smce, events);
-               if (events & SMCM_BRKE)
-                       uart_handle_break(port);
-               if (events & SMCM_RX)
-                       cpm_uart_int_rx(port);
-               if (events & SMCM_TX)
-                       cpm_uart_int_tx(port);
-       } else {
-               events = in_be16(&sccp->scc_scce);
-               out_be16(&sccp->scc_scce, events);
-               if (events & UART_SCCM_BRKE)
-                       uart_handle_break(port);
-               if (events & UART_SCCM_RX)
-                       cpm_uart_int_rx(port);
-               if (events & UART_SCCM_TX)
-                       cpm_uart_int_tx(port);
-       }
-       return (events) ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static int cpm_uart_startup(struct uart_port *port)
-{
-       int retval;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:startup\n", port->line);
-
-       /* If the port is not the console, make sure rx is disabled. */
-       if (!(pinfo->flags & FLAG_CONSOLE)) {
-               /* Disable UART rx */
-               if (IS_SMC(pinfo)) {
-                       clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN);
-                       clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
-               } else {
-                       clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
-                       clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
-               }
-               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-       }
-       /* Install interrupt handler. */
-       retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
-       if (retval)
-               return retval;
-
-       /* Startup rx-int */
-       if (IS_SMC(pinfo)) {
-               setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
-               setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
-       } else {
-               setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
-               setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
-       }
-
-       return 0;
-}
-
-inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(pinfo->wait_closing);
-}
-
-/*
- * Shutdown the uart
- */
-static void cpm_uart_shutdown(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       pr_debug("CPM uart[%d]:shutdown\n", port->line);
-
-       /* free interrupt handler */
-       free_irq(port->irq, port);
-
-       /* If the port is not the console, disable Rx and Tx. */
-       if (!(pinfo->flags & FLAG_CONSOLE)) {
-               /* Wait for all the BDs marked sent */
-               while(!cpm_uart_tx_empty(port)) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(2);
-               }
-
-               if (pinfo->wait_closing)
-                       cpm_uart_wait_until_send(pinfo);
-
-               /* Stop uarts */
-               if (IS_SMC(pinfo)) {
-                       smc_t __iomem *smcp = pinfo->smcp;
-                       clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-                       clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               } else {
-                       scc_t __iomem *sccp = pinfo->sccp;
-                       clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-                       clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               }
-
-               /* Shut them really down and reinit buffer descriptors */
-               if (IS_SMC(pinfo)) {
-                       out_be16(&pinfo->smcup->smc_brkcr, 0);
-                       cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-               } else {
-                       out_be16(&pinfo->sccup->scc_brkcr, 0);
-                       cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
-               }
-
-               cpm_uart_initbd(pinfo);
-       }
-}
-
-static void cpm_uart_set_termios(struct uart_port *port,
-                                 struct ktermios *termios,
-                                 struct ktermios *old)
-{
-       int baud;
-       unsigned long flags;
-       u16 cval, scval, prev_mode;
-       int bits, sbits;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       smc_t __iomem *smcp = pinfo->smcp;
-       scc_t __iomem *sccp = pinfo->sccp;
-
-       pr_debug("CPM uart[%d]:set_termios\n", port->line);
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       if (baud <= HW_BUF_SPD_THRESHOLD ||
-           (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
-               pinfo->rx_fifosize = 1;
-       else
-               pinfo->rx_fifosize = RX_BUF_SIZE;
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-       cval = 0;
-       scval = 0;
-
-       /* byte size */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               bits = 5;
-               break;
-       case CS6:
-               bits = 6;
-               break;
-       case CS7:
-               bits = 7;
-               break;
-       case CS8:
-               bits = 8;
-               break;
-               /* Never happens, but GCC is too dumb to figure it out */
-       default:
-               bits = 8;
-               break;
-       }
-       sbits = bits - 5;
-
-       if (termios->c_cflag & CSTOPB) {
-               cval |= SMCMR_SL;       /* Two stops */
-               scval |= SCU_PSMR_SL;
-               bits++;
-       }
-
-       if (termios->c_cflag & PARENB) {
-               cval |= SMCMR_PEN;
-               scval |= SCU_PSMR_PEN;
-               bits++;
-               if (!(termios->c_cflag & PARODD)) {
-                       cval |= SMCMR_PM_EVEN;
-                       scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
-               }
-       }
-
-       /*
-        * Update the timeout
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Set up parity check flag
-        */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-       port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
-               port->read_status_mask |= BD_SC_BR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->read_status_mask &= ~BD_SC_EMPTY;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Start bit has not been added (so don't, because we would just
-        * subtract it later), and we need to add one for the number of
-        * stops bits (there is always at least one).
-        */
-       bits++;
-       if (IS_SMC(pinfo)) {
-               /*
-                * MRBLR can be changed while an SMC/SCC is operating only
-                * if it is done in a single bus cycle with one 16-bit move
-                * (not two 8-bit bus cycles back-to-back). This occurs when
-                * the cp shifts control to the next RxBD, so the change does
-                * not take effect immediately. To guarantee the exact RxBD
-                * on which the change occurs, change MRBLR only while the
-                * SMC/SCC receiver is disabled.
-                */
-               out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
-
-               /* Set the mode register.  We want to keep a copy of the
-                * enables, because we want to put them back if they were
-                * present.
-                */
-               prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN);
-               /* Output in *one* operation, so we don't interrupt RX/TX if they
-                * were already enabled. */
-               out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
-                   SMCMR_SM_UART | prev_mode);
-       } else {
-               out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
-               out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
-       }
-
-       if (pinfo->clk)
-               clk_set_rate(pinfo->clk, baud);
-       else
-               cpm_set_brg(pinfo->brg - 1, baud);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *cpm_uart_type(struct uart_port *port)
-{
-       pr_debug("CPM uart[%d]:uart_type\n", port->line);
-
-       return port->type == PORT_CPM ? "CPM UART" : NULL;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int cpm_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *ser)
-{
-       int ret = 0;
-
-       pr_debug("CPM uart[%d]:verify_port\n", port->line);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-/*
- * Transmit characters, refill buffer descriptor, if possible
- */
-static int cpm_uart_tx_pump(struct uart_port *port)
-{
-       cbd_t __iomem *bdp;
-       u8 *p;
-       int count;
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       /* Handle xon/xoff */
-       if (port->x_char) {
-               /* Pick next descriptor and fill from buffer */
-               bdp = pinfo->tx_cur;
-
-               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-
-               *p++ = port->x_char;
-
-               out_be16(&bdp->cbd_datlen, 1);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->tx_bd_base;
-               else
-                       bdp++;
-               pinfo->tx_cur = bdp;
-
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               cpm_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Pick next descriptor and fill from buffer */
-       bdp = pinfo->tx_cur;
-
-       while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
-              xmit->tail != xmit->head) {
-               count = 0;
-               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
-               while (count < pinfo->tx_fifosize) {
-                       *p++ = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                       port->icount.tx++;
-                       count++;
-                       if (xmit->head == xmit->tail)
-                               break;
-               }
-               out_be16(&bdp->cbd_datlen, count);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = pinfo->tx_bd_base;
-               else
-                       bdp++;
-       }
-       pinfo->tx_cur = bdp;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit)) {
-               cpm_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * init buffer descriptors
- */
-static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
-{
-       int i;
-       u8 *mem_addr;
-       cbd_t __iomem *bdp;
-
-       pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       mem_addr = pinfo->mem_addr;
-       bdp = pinfo->rx_cur = pinfo->rx_bd_base;
-       for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
-               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-               out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
-               mem_addr += pinfo->rx_fifosize;
-       }
-
-       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
-       bdp = pinfo->tx_cur = pinfo->tx_bd_base;
-       for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
-               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-               out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
-               mem_addr += pinfo->tx_fifosize;
-       }
-
-       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
-       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
-}
-
-static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
-{
-       scc_t __iomem *scp;
-       scc_uart_t __iomem *sup;
-
-       pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
-
-       scp = pinfo->sccp;
-       sup = pinfo->sccup;
-
-       /* Store address */
-       out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
-                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
-       out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
-                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
-
-       /* Set up the uart parameters in the
-        * parameter ram.
-        */
-
-       cpm_set_scc_fcr(sup);
-
-       out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
-       out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
-       out_be16(&sup->scc_brkcr, 1);
-       out_be16(&sup->scc_parec, 0);
-       out_be16(&sup->scc_frmec, 0);
-       out_be16(&sup->scc_nosec, 0);
-       out_be16(&sup->scc_brkec, 0);
-       out_be16(&sup->scc_uaddr1, 0);
-       out_be16(&sup->scc_uaddr2, 0);
-       out_be16(&sup->scc_toseq, 0);
-       out_be16(&sup->scc_char1, 0x8000);
-       out_be16(&sup->scc_char2, 0x8000);
-       out_be16(&sup->scc_char3, 0x8000);
-       out_be16(&sup->scc_char4, 0x8000);
-       out_be16(&sup->scc_char5, 0x8000);
-       out_be16(&sup->scc_char6, 0x8000);
-       out_be16(&sup->scc_char7, 0x8000);
-       out_be16(&sup->scc_char8, 0x8000);
-       out_be16(&sup->scc_rccm, 0xc0ff);
-
-       /* Send the CPM an initialize command.
-        */
-       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
-       /* Set UART mode, 8 bit, no parity, one stop.
-        * Enable receive and transmit.
-        */
-       out_be32(&scp->scc_gsmrh, 0);
-       out_be32(&scp->scc_gsmrl,
-                SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
-       /* Enable rx interrupts  and clear all pending events.  */
-       out_be16(&scp->scc_sccm, 0);
-       out_be16(&scp->scc_scce, 0xffff);
-       out_be16(&scp->scc_dsr, 0x7e7e);
-       out_be16(&scp->scc_psmr, 0x3000);
-
-       setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-}
-
-static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
-{
-       smc_t __iomem *sp;
-       smc_uart_t __iomem *up;
-
-       pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
-
-       sp = pinfo->smcp;
-       up = pinfo->smcup;
-
-       /* Store address */
-       out_be16(&pinfo->smcup->smc_rbase,
-                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
-       out_be16(&pinfo->smcup->smc_tbase,
-                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
-
-/*
- *  In case SMC1 is being relocated...
- */
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
-       out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
-       out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
-       out_be32(&up->smc_rstate, 0);
-       out_be32(&up->smc_tstate, 0);
-       out_be16(&up->smc_brkcr, 1);              /* number of break chars */
-       out_be16(&up->smc_brkec, 0);
-#endif
-
-       /* Set up the uart parameters in the
-        * parameter ram.
-        */
-       cpm_set_smc_fcr(up);
-
-       /* Using idle character time requires some additional tuning.  */
-       out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
-       out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
-       out_be16(&up->smc_brklen, 0);
-       out_be16(&up->smc_brkec, 0);
-       out_be16(&up->smc_brkcr, 1);
-
-       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
-       /* Set UART mode, 8 bit, no parity, one stop.
-        * Enable receive and transmit.
-        */
-       out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
-
-       /* Enable only rx interrupts clear all pending events. */
-       out_8(&sp->smc_smcm, 0);
-       out_8(&sp->smc_smce, 0xff);
-
-       setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-}
-
-/*
- * Initialize port. This is called from early_console stuff
- * so we have to be careful here !
- */
-static int cpm_uart_request_port(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       int ret;
-
-       pr_debug("CPM uart[%d]:request port\n", port->line);
-
-       if (pinfo->flags & FLAG_CONSOLE)
-               return 0;
-
-       if (IS_SMC(pinfo)) {
-               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-       } else {
-               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-       }
-
-       ret = cpm_uart_allocbuf(pinfo, 0);
-
-       if (ret)
-               return ret;
-
-       cpm_uart_initbd(pinfo);
-       if (IS_SMC(pinfo))
-               cpm_uart_init_smc(pinfo);
-       else
-               cpm_uart_init_scc(pinfo);
-
-       return 0;
-}
-
-static void cpm_uart_release_port(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (!(pinfo->flags & FLAG_CONSOLE))
-               cpm_uart_freebuf(pinfo);
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void cpm_uart_config_port(struct uart_port *port, int flags)
-{
-       pr_debug("CPM uart[%d]:config_port\n", port->line);
-
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_CPM;
-               cpm_uart_request_port(port);
-       }
-}
-
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE)
-/*
- * Write a string to the serial port
- * Note that this is called with interrupts already disabled
- */
-static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
-               const char *string, u_int count)
-{
-       unsigned int i;
-       cbd_t __iomem *bdp, *bdbase;
-       unsigned char *cpm_outp_addr;
-
-       /* Get the address of the host memory buffer.
-        */
-       bdp = pinfo->tx_cur;
-       bdbase = pinfo->tx_bd_base;
-
-       /*
-        * Now, do each character.  This is not as bad as it looks
-        * since this is a holding FIFO and not a transmitting FIFO.
-        * We could add the complexity of filling the entire transmit
-        * buffer, but we would just wait longer between accesses......
-        */
-       for (i = 0; i < count; i++, string++) {
-               /* Wait for transmitter fifo to empty.
-                * Ready indicates output is ready, and xmt is doing
-                * that, not that it is ready for us to send.
-                */
-               while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-                       ;
-
-               /* Send the character out.
-                * If the buffer address is in the CPM DPRAM, don't
-                * convert it.
-                */
-               cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
-                                       pinfo);
-               *cpm_outp_addr = *string;
-
-               out_be16(&bdp->cbd_datlen, 1);
-               setbits16(&bdp->cbd_sc, BD_SC_READY);
-
-               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                       bdp = bdbase;
-               else
-                       bdp++;
-
-               /* if a LF, also do CR... */
-               if (*string == 10) {
-                       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-                               ;
-
-                       cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
-                                               pinfo);
-                       *cpm_outp_addr = 13;
-
-                       out_be16(&bdp->cbd_datlen, 1);
-                       setbits16(&bdp->cbd_sc, BD_SC_READY);
-
-                       if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
-                               bdp = bdbase;
-                       else
-                               bdp++;
-               }
-       }
-
-       /*
-        * Finally, Wait for transmitter & holding register to empty
-        *  and restore the IER
-        */
-       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
-               ;
-
-       pinfo->tx_cur = bdp;
-}
-#endif
-
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-#define GDB_BUF_SIZE   512     /* power of 2, please */
-
-static char poll_buf[GDB_BUF_SIZE];
-static char *pollp;
-static int poll_chars;
-
-static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
-{
-       u_char          c, *cp;
-       volatile cbd_t  *bdp;
-       int             i;
-
-       /* Get the address of the host memory buffer.
-        */
-       bdp = pinfo->rx_cur;
-       while (bdp->cbd_sc & BD_SC_EMPTY)
-               ;
-
-       /* If the buffer address is in the CPM DPRAM, don't
-        * convert it.
-        */
-       cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
-       if (obuf) {
-               i = c = bdp->cbd_datlen;
-               while (i-- > 0)
-                       *obuf++ = *cp++;
-       } else
-               c = *cp;
-       bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
-       bdp->cbd_sc |= BD_SC_EMPTY;
-
-       if (bdp->cbd_sc & BD_SC_WRAP)
-               bdp = pinfo->rx_bd_base;
-       else
-               bdp++;
-       pinfo->rx_cur = (cbd_t *)bdp;
-
-       return (int)c;
-}
-
-static int cpm_get_poll_char(struct uart_port *port)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-
-       if (!serial_polled) {
-               serial_polled = 1;
-               poll_chars = 0;
-       }
-       if (poll_chars <= 0) {
-               poll_chars = poll_wait_key(poll_buf, pinfo);
-               pollp = poll_buf;
-       }
-       poll_chars--;
-       return *pollp++;
-}
-
-static void cpm_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-       static char ch[2];
-
-       ch[0] = (char)c;
-       cpm_uart_early_write(pinfo, ch, 1);
-}
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops cpm_uart_pops = {
-       .tx_empty       = cpm_uart_tx_empty,
-       .set_mctrl      = cpm_uart_set_mctrl,
-       .get_mctrl      = cpm_uart_get_mctrl,
-       .stop_tx        = cpm_uart_stop_tx,
-       .start_tx       = cpm_uart_start_tx,
-       .stop_rx        = cpm_uart_stop_rx,
-       .enable_ms      = cpm_uart_enable_ms,
-       .break_ctl      = cpm_uart_break_ctl,
-       .startup        = cpm_uart_startup,
-       .shutdown       = cpm_uart_shutdown,
-       .set_termios    = cpm_uart_set_termios,
-       .type           = cpm_uart_type,
-       .release_port   = cpm_uart_release_port,
-       .request_port   = cpm_uart_request_port,
-       .config_port    = cpm_uart_config_port,
-       .verify_port    = cpm_uart_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = cpm_get_poll_char,
-       .poll_put_char = cpm_put_poll_char,
-#endif
-};
-
-struct uart_cpm_port cpm_uart_ports[UART_NR];
-
-static int cpm_uart_init_port(struct device_node *np,
-                              struct uart_cpm_port *pinfo)
-{
-       const u32 *data;
-       void __iomem *mem, *pram;
-       int len;
-       int ret;
-       int i;
-
-       data = of_get_property(np, "clock", NULL);
-       if (data) {
-               struct clk *clk = clk_get(NULL, (const char*)data);
-               if (!IS_ERR(clk))
-                       pinfo->clk = clk;
-       }
-       if (!pinfo->clk) {
-               data = of_get_property(np, "fsl,cpm-brg", &len);
-               if (!data || len != 4) {
-                       printk(KERN_ERR "CPM UART %s has no/invalid "
-                                       "fsl,cpm-brg property.\n", np->name);
-                       return -EINVAL;
-               }
-               pinfo->brg = *data;
-       }
-
-       data = of_get_property(np, "fsl,cpm-command", &len);
-       if (!data || len != 4) {
-               printk(KERN_ERR "CPM UART %s has no/invalid "
-                               "fsl,cpm-command property.\n", np->name);
-               return -EINVAL;
-       }
-       pinfo->command = *data;
-
-       mem = of_iomap(np, 0);
-       if (!mem)
-               return -ENOMEM;
-
-       if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
-           of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
-               pinfo->sccp = mem;
-               pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np);
-       } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
-                  of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
-               pinfo->flags |= FLAG_SMC;
-               pinfo->smcp = mem;
-               pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np);
-       } else {
-               ret = -ENODEV;
-               goto out_mem;
-       }
-
-       if (!pram) {
-               ret = -ENOMEM;
-               goto out_mem;
-       }
-
-       pinfo->tx_nrfifos = TX_NUM_FIFO;
-       pinfo->tx_fifosize = TX_BUF_SIZE;
-       pinfo->rx_nrfifos = RX_NUM_FIFO;
-       pinfo->rx_fifosize = RX_BUF_SIZE;
-
-       pinfo->port.uartclk = ppc_proc_freq;
-       pinfo->port.mapbase = (unsigned long)mem;
-       pinfo->port.type = PORT_CPM;
-       pinfo->port.ops = &cpm_uart_pops,
-       pinfo->port.iotype = UPIO_MEM;
-       pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
-       spin_lock_init(&pinfo->port.lock);
-
-       pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
-       if (pinfo->port.irq == NO_IRQ) {
-               ret = -EINVAL;
-               goto out_pram;
-       }
-
-       for (i = 0; i < NUM_GPIOS; i++)
-               pinfo->gpios[i] = of_get_gpio(np, i);
-
-#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
-       udbg_putc = NULL;
-#endif
-
-       return cpm_uart_request_port(&pinfo->port);
-
-out_pram:
-       cpm_uart_unmap_pram(pinfo, pram);
-out_mem:
-       iounmap(mem);
-       return ret;
-}
-
-#ifdef CONFIG_SERIAL_CPM_CONSOLE
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     Note that this is called with interrupts already disabled
- */
-static void cpm_uart_console_write(struct console *co, const char *s,
-                                  u_int count)
-{
-       struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
-       unsigned long flags;
-       int nolock = oops_in_progress;
-
-       if (unlikely(nolock)) {
-               local_irq_save(flags);
-       } else {
-               spin_lock_irqsave(&pinfo->port.lock, flags);
-       }
-
-       cpm_uart_early_write(pinfo, s, count);
-
-       if (unlikely(nolock)) {
-               local_irq_restore(flags);
-       } else {
-               spin_unlock_irqrestore(&pinfo->port.lock, flags);
-       }
-}
-
-
-static int __init cpm_uart_console_setup(struct console *co, char *options)
-{
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-       struct uart_cpm_port *pinfo;
-       struct uart_port *port;
-
-       struct device_node *np = NULL;
-       int i = 0;
-
-       if (co->index >= UART_NR) {
-               printk(KERN_ERR "cpm_uart: console index %d too high\n",
-                      co->index);
-               return -ENODEV;
-       }
-
-       do {
-               np = of_find_node_by_type(np, "serial");
-               if (!np)
-                       return -ENODEV;
-
-               if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
-                   !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
-                       i--;
-       } while (i++ != co->index);
-
-       pinfo = &cpm_uart_ports[co->index];
-
-       pinfo->flags |= FLAG_CONSOLE;
-       port = &pinfo->port;
-
-       ret = cpm_uart_init_port(np, pinfo);
-       of_node_put(np);
-       if (ret)
-               return ret;
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       } else {
-               if ((baud = uart_baudrate()) == -1)
-                       baud = 9600;
-       }
-
-       if (IS_SMC(pinfo)) {
-               out_be16(&pinfo->smcup->smc_brkcr, 0);
-               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
-               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
-       } else {
-               out_be16(&pinfo->sccup->scc_brkcr, 0);
-               cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
-               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
-               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-       }
-
-       ret = cpm_uart_allocbuf(pinfo, 1);
-
-       if (ret)
-               return ret;
-
-       cpm_uart_initbd(pinfo);
-
-       if (IS_SMC(pinfo))
-               cpm_uart_init_smc(pinfo);
-       else
-               cpm_uart_init_scc(pinfo);
-
-       uart_set_options(port, co, baud, parity, bits, flow);
-       cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
-
-       return 0;
-}
-
-static struct uart_driver cpm_reg;
-static struct console cpm_scc_uart_console = {
-       .name           = "ttyCPM",
-       .write          = cpm_uart_console_write,
-       .device         = uart_console_device,
-       .setup          = cpm_uart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &cpm_reg,
-};
-
-static int __init cpm_uart_console_init(void)
-{
-       register_console(&cpm_scc_uart_console);
-       return 0;
-}
-
-console_initcall(cpm_uart_console_init);
-
-#define CPM_UART_CONSOLE       &cpm_scc_uart_console
-#else
-#define CPM_UART_CONSOLE       NULL
-#endif
-
-static struct uart_driver cpm_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyCPM",
-       .dev_name       = "ttyCPM",
-       .major          = SERIAL_CPM_MAJOR,
-       .minor          = SERIAL_CPM_MINOR,
-       .cons           = CPM_UART_CONSOLE,
-       .nr             = UART_NR,
-};
-
-static int probe_index;
-
-static int __devinit cpm_uart_probe(struct platform_device *ofdev,
-                                    const struct of_device_id *match)
-{
-       int index = probe_index++;
-       struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
-       int ret;
-
-       pinfo->port.line = index;
-
-       if (index >= UART_NR)
-               return -ENODEV;
-
-       dev_set_drvdata(&ofdev->dev, pinfo);
-
-       /* initialize the device pointer for the port */
-       pinfo->port.dev = &ofdev->dev;
-
-       ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
-       if (ret)
-               return ret;
-
-       return uart_add_one_port(&cpm_reg, &pinfo->port);
-}
-
-static int __devexit cpm_uart_remove(struct platform_device *ofdev)
-{
-       struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
-       return uart_remove_one_port(&cpm_reg, &pinfo->port);
-}
-
-static struct of_device_id cpm_uart_match[] = {
-       {
-               .compatible = "fsl,cpm1-smc-uart",
-       },
-       {
-               .compatible = "fsl,cpm1-scc-uart",
-       },
-       {
-               .compatible = "fsl,cpm2-smc-uart",
-       },
-       {
-               .compatible = "fsl,cpm2-scc-uart",
-       },
-       {}
-};
-
-static struct of_platform_driver cpm_uart_driver = {
-       .driver = {
-               .name = "cpm_uart",
-               .owner = THIS_MODULE,
-               .of_match_table = cpm_uart_match,
-       },
-       .probe = cpm_uart_probe,
-       .remove = cpm_uart_remove,
- };
-
-static int __init cpm_uart_init(void)
-{
-       int ret = uart_register_driver(&cpm_reg);
-       if (ret)
-               return ret;
-
-       ret = of_register_platform_driver(&cpm_uart_driver);
-       if (ret)
-               uart_unregister_driver(&cpm_reg);
-
-       return ret;
-}
-
-static void __exit cpm_uart_exit(void)
-{
-       of_unregister_platform_driver(&cpm_uart_driver);
-       uart_unregister_driver(&cpm_reg);
-}
-
-module_init(cpm_uart_init);
-module_exit(cpm_uart_exit);
-
-MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
-MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
deleted file mode 100644 (file)
index 3fc1d66..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/gfp.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/fs_pd.h>
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include <linux/of.h>
-
-#include "cpm_uart.h"
-
-/**************************************************************/
-
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
-{
-       cpm_command(port->command, cmd);
-}
-
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np)
-{
-       return of_iomap(np, 1);
-}
-
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
-{
-       iounmap(pram);
-}
-
-/*
- * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
- * receive buffer descriptors from dual port ram, and a character
- * buffer area from host mem. If we are allocating for the console we need
- * to do it from bootmem
- */
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
-{
-       int dpmemsz, memsz;
-       u8 *dp_mem;
-       unsigned long dp_offset;
-       u8 *mem_addr;
-       dma_addr_t dma_addr = 0;
-
-       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
-
-       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
-       dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_ERR_VALUE(dp_offset)) {
-               printk(KERN_ERR
-                      "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-       dp_mem = cpm_dpram_addr(dp_offset);
-
-       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
-           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
-       if (is_con) {
-               /* was hostalloc but changed cause it blows away the */
-               /* large tlb mapping when pinning the kernel area    */
-               mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
-               dma_addr = (u32)cpm_dpram_phys(mem_addr);
-       } else
-               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
-                                             GFP_KERNEL);
-
-       if (mem_addr == NULL) {
-               cpm_dpfree(dp_offset);
-               printk(KERN_ERR
-                      "cpm_uart_cpm1.c: could not allocate coherent memory\n");
-               return -ENOMEM;
-       }
-
-       pinfo->dp_addr = dp_offset;
-       pinfo->mem_addr = mem_addr;             /*  virtual address*/
-       pinfo->dma_addr = dma_addr;             /*  physical address*/
-       pinfo->mem_size = memsz;
-
-       pinfo->rx_buf = mem_addr;
-       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
-                                                      * pinfo->rx_fifosize);
-
-       pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
-       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
-
-       return 0;
-}
-
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
-{
-       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                                         pinfo->rx_fifosize) +
-                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
-                                        pinfo->tx_fifosize), pinfo->mem_addr,
-                         pinfo->dma_addr);
-
-       cpm_dpfree(pinfo->dp_addr);
-}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
deleted file mode 100644 (file)
index 10eecd6..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
- *
- * Driver for CPM (SCC/SMC) serial ports
- *
- * definitions for cpm1
- *
- */
-
-#ifndef CPM_UART_CPM1_H
-#define CPM_UART_CPM1_H
-
-#include <asm/cpm1.h>
-
-static inline void cpm_set_brg(int brg, int baud)
-{
-       cpm_setbrg(brg, baud);
-}
-
-static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
-{
-       out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
-       out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
-}
-
-static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
-{
-       out_8(&up->smc_rfcr, SMC_EB);
-       out_8(&up->smc_tfcr, SMC_EB);
-}
-
-#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
-
-#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
deleted file mode 100644 (file)
index 814ac00..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *  linux/drivers/serial/cpm_uart_cpm2.c
- *
- *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
- *
- *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
- *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
- *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
- *            (C) 2004 Intracom, S.A.
- *            (C) 2006 MontaVista Software, Inc.
- *             Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/bootmem.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/fs_pd.h>
-#include <asm/prom.h>
-
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-
-#include "cpm_uart.h"
-
-/**************************************************************/
-
-void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
-{
-       cpm_command(port->command, cmd);
-}
-
-void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
-                               struct device_node *np)
-{
-       void __iomem *pram;
-       unsigned long offset;
-       struct resource res;
-       resource_size_t len;
-
-       /* Don't remap parameter RAM if it has already been initialized
-        * during console setup.
-        */
-       if (IS_SMC(port) && port->smcup)
-               return port->smcup;
-       else if (!IS_SMC(port) && port->sccup)
-               return port->sccup;
-
-       if (of_address_to_resource(np, 1, &res))
-               return NULL;
-
-       len = resource_size(&res);
-       pram = ioremap(res.start, len);
-       if (!pram)
-               return NULL;
-
-       if (!IS_SMC(port))
-               return pram;
-
-       if (len != 2) {
-               printk(KERN_WARNING "cpm_uart[%d]: device tree references "
-                       "SMC pram, using boot loader/wrapper pram mapping. "
-                       "Please fix your device tree to reference the pram "
-                       "base register instead.\n",
-                       port->port.line);
-               return pram;
-       }
-
-       offset = cpm_dpalloc(PROFF_SMC_SIZE, 64);
-       out_be16(pram, offset);
-       iounmap(pram);
-       return cpm_muram_addr(offset);
-}
-
-void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
-{
-       if (!IS_SMC(port))
-               iounmap(pram);
-}
-
-/*
- * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
- * receive buffer descriptors from dual port ram, and a character
- * buffer area from host mem. If we are allocating for the console we need
- * to do it from bootmem
- */
-int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
-{
-       int dpmemsz, memsz;
-       u8 __iomem *dp_mem;
-       unsigned long dp_offset;
-       u8 *mem_addr;
-       dma_addr_t dma_addr = 0;
-
-       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
-
-       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
-       dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_ERR_VALUE(dp_offset)) {
-               printk(KERN_ERR
-                      "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-
-       dp_mem = cpm_dpram_addr(dp_offset);
-
-       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
-           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
-       if (is_con) {
-               mem_addr = kzalloc(memsz, GFP_NOWAIT);
-               dma_addr = virt_to_bus(mem_addr);
-       }
-       else
-               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
-                                             GFP_KERNEL);
-
-       if (mem_addr == NULL) {
-               cpm_dpfree(dp_offset);
-               printk(KERN_ERR
-                      "cpm_uart_cpm.c: could not allocate coherent memory\n");
-               return -ENOMEM;
-       }
-
-       pinfo->dp_addr = dp_offset;
-       pinfo->mem_addr = mem_addr;
-       pinfo->dma_addr = dma_addr;
-       pinfo->mem_size = memsz;
-
-       pinfo->rx_buf = mem_addr;
-       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
-                                                      * pinfo->rx_fifosize);
-
-       pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
-       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
-
-       return 0;
-}
-
-void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
-{
-       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                                         pinfo->rx_fifosize) +
-                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
-                                        pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
-                         pinfo->dma_addr);
-
-       cpm_dpfree(pinfo->dp_addr);
-}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
deleted file mode 100644 (file)
index 7194c63..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
- *
- * Driver for CPM (SCC/SMC) serial ports
- *
- * definitions for cpm2
- *
- */
-
-#ifndef CPM_UART_CPM2_H
-#define CPM_UART_CPM2_H
-
-#include <asm/cpm2.h>
-
-static inline void cpm_set_brg(int brg, int baud)
-{
-       cpm_setbrg(brg, baud);
-}
-
-static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
-{
-       out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
-       out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
-}
-
-static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
-{
-       out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
-       out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
-}
-
-#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
-
-#endif
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
deleted file mode 100644 (file)
index bcc31f2..0000000
+++ /dev/null
@@ -1,4573 +0,0 @@
-/*
- * Serial port driver for the ETRAX 100LX chip
- *
- *    Copyright (C) 1998-2007  Axis Communications AB
- *
- *    Many, many authors. Based once upon a time on serial.c for 16x50.
- *
- */
-
-static char *serial_version = "$Revision: 1.25 $";
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-
-#include <arch/svinto.h>
-
-/* non-arch dependent serial structures are in linux/serial.h */
-#include <linux/serial.h>
-/* while we keep our own stuff (struct e100_serial) in a local .h file */
-#include "crisv10.h"
-#include <asm/fasttimer.h>
-#include <arch/io_interface_mux.h>
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-#ifndef CONFIG_ETRAX_FAST_TIMER
-#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
-#endif
-#endif
-
-#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
-           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
-#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
-#endif
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
-#endif
-
-/*
- * All of the compatibilty code so we can compile serial.c against
- * older kernels is hidden in serial_compat.h
- */
-#if defined(LOCAL_HEADERS)
-#include "serial_compat.h"
-#endif
-
-struct tty_driver *serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-//#define SERIAL_DEBUG_INTR
-//#define SERIAL_DEBUG_OPEN
-//#define SERIAL_DEBUG_FLOW
-//#define SERIAL_DEBUG_DATA
-//#define SERIAL_DEBUG_THROTTLE
-//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
-//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
-
-/* Enable this to use serial interrupts to handle when you
-   expect the first received event on the serial port to
-   be an error, break or similar. Used to be able to flash IRMA
-   from eLinux */
-#define SERIAL_HANDLE_EARLY_ERRORS
-
-/* Currently 16 descriptors x 128 bytes = 2048 bytes */
-#define SERIAL_DESCR_BUF_SIZE 256
-
-#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
-#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
-
-/* We don't want to load the system with massive fast timer interrupt
- * on high baudrates so limit it to 250 us (4kHz) */
-#define MIN_FLUSH_TIME_USEC 250
-
-/* Add an x here to log a lot of timer stuff */
-#define TIMERD(x)
-/* Debug details of interrupt handling */
-#define DINTR1(x)  /* irq on/off, errors */
-#define DINTR2(x)    /* tx and rx */
-/* Debug flip buffer stuff */
-#define DFLIP(x)
-/* Debug flow control and overview of data flow */
-#define DFLOW(x)
-#define DBAUD(x)
-#define DLOG_INT_TRIG(x)
-
-//#define DEBUG_LOG_INCLUDED
-#ifndef DEBUG_LOG_INCLUDED
-#define DEBUG_LOG(line, string, value)
-#else
-struct debug_log_info
-{
-       unsigned long time;
-       unsigned long timer_data;
-//  int line;
-       const char *string;
-       int value;
-};
-#define DEBUG_LOG_SIZE 4096
-
-struct debug_log_info debug_log[DEBUG_LOG_SIZE];
-int debug_log_pos = 0;
-
-#define DEBUG_LOG(_line, _string, _value) do { \
-  if ((_line) == SERIAL_DEBUG_LINE) {\
-    debug_log_func(_line, _string, _value); \
-  }\
-}while(0)
-
-void debug_log_func(int line, const char *string, int value)
-{
-       if (debug_log_pos < DEBUG_LOG_SIZE) {
-               debug_log[debug_log_pos].time = jiffies;
-               debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
-//    debug_log[debug_log_pos].line = line;
-               debug_log[debug_log_pos].string = string;
-               debug_log[debug_log_pos].value = value;
-               debug_log_pos++;
-       }
-       /*printk(string, value);*/
-}
-#endif
-
-#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
-/* Default number of timer ticks before flushing rx fifo
- * When using "little data, low latency applications: use 0
- * When using "much data applications (PPP)" use ~5
- */
-#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
-#endif
-
-unsigned long timer_data_to_ns(unsigned long timer_data);
-
-static void change_speed(struct e100_serial *info);
-static void rs_throttle(struct tty_struct * tty);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int rs_write(struct tty_struct *tty,
-               const unsigned char *buf, int count);
-#ifdef CONFIG_ETRAX_RS485
-static int e100_write_rs485(struct tty_struct *tty,
-               const unsigned char *buf, int count);
-#endif
-static int get_lsr_info(struct e100_serial *info, unsigned int *value);
-
-
-#define DEF_BAUD 115200   /* 115.2 kbit/s */
-#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
-/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
-#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
-
-/* offsets from R_SERIALx_CTRL */
-
-#define REG_DATA 0
-#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
-#define REG_TR_DATA 0
-#define REG_STATUS 1
-#define REG_TR_CTRL 1
-#define REG_REC_CTRL 2
-#define REG_BAUD 3
-#define REG_XOFF 4  /* this is a 32 bit register */
-
-/* The bitfields are the same for all serial ports */
-#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
-#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
-#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
-#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
-#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
-
-#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
-
-/* Values for info->errorcode */
-#define ERRCODE_SET_BREAK    (TTY_BREAK)
-#define ERRCODE_INSERT        0x100
-#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
-
-#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
-
-/*
- * General note regarding the use of IO_* macros in this file:
- *
- * We will use the bits defined for DMA channel 6 when using various
- * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
- * the same for all channels (which of course they are).
- *
- * We will also use the bits defined for serial port 0 when writing commands
- * to the different ports, as these bits too are the same for all ports.
- */
-
-
-/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
-static const unsigned long e100_ser_int_mask = 0
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
-#endif
-;
-unsigned long r_alt_ser_baudrate_shadow = 0;
-
-/* this is the data for the four serial ports in the etrax100 */
-/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
-/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
-
-static struct e100_serial rs_table[] = {
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL0_CTRL,
-         .irq         = 1U << 12, /* uses DMA 6 and 7 */
-         .oclrintradr = R_DMA_CH6_CLR_INTR,
-         .ofirstadr   = R_DMA_CH6_FIRST,
-         .ocmdadr     = R_DMA_CH6_CMD,
-         .ostatusadr  = R_DMA_CH6_STATUS,
-         .iclrintradr = R_DMA_CH7_CLR_INTR,
-         .ifirstadr   = R_DMA_CH7_FIRST,
-         .icmdadr     = R_DMA_CH7_CMD,
-         .idescradr   = R_DMA_CH7_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 2,
-         .dma_owner   = dma_ser0,
-         .io_if       = if_serial_0,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER0_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 0 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER0_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 0 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
-
-},  /* ttyS0 */
-#ifndef CONFIG_SVINTO_SIM
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL1_CTRL,
-         .irq         = 1U << 16, /* uses DMA 8 and 9 */
-         .oclrintradr = R_DMA_CH8_CLR_INTR,
-         .ofirstadr   = R_DMA_CH8_FIRST,
-         .ocmdadr     = R_DMA_CH8_CMD,
-         .ostatusadr  = R_DMA_CH8_STATUS,
-         .iclrintradr = R_DMA_CH9_CLR_INTR,
-         .ifirstadr   = R_DMA_CH9_FIRST,
-         .icmdadr     = R_DMA_CH9_CMD,
-         .idescradr   = R_DMA_CH9_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 3,
-         .dma_owner   = dma_ser1,
-         .io_if       = if_serial_1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-          .enabled  = 1,
-         .io_if_description = "ser1",
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER1_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 1 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER1_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 1 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_in_irq_nbr = 0,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
-},  /* ttyS1 */
-
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL2_CTRL,
-         .irq         = 1U << 4,  /* uses DMA 2 and 3 */
-         .oclrintradr = R_DMA_CH2_CLR_INTR,
-         .ofirstadr   = R_DMA_CH2_FIRST,
-         .ocmdadr     = R_DMA_CH2_CMD,
-         .ostatusadr  = R_DMA_CH2_STATUS,
-         .iclrintradr = R_DMA_CH3_CLR_INTR,
-         .ifirstadr   = R_DMA_CH3_FIRST,
-         .icmdadr     = R_DMA_CH3_CMD,
-         .idescradr   = R_DMA_CH3_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 0,
-         .dma_owner   = dma_ser2,
-         .io_if       = if_serial_2,
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-          .enabled  = 1,
-         .io_if_description = "ser2",
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER2_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 2 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER2_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 2 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL,
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
- },  /* ttyS2 */
-
-       { .baud        = DEF_BAUD,
-         .ioport        = (unsigned char *)R_SERIAL3_CTRL,
-         .irq         = 1U << 8,  /* uses DMA 4 and 5 */
-         .oclrintradr = R_DMA_CH4_CLR_INTR,
-         .ofirstadr   = R_DMA_CH4_FIRST,
-         .ocmdadr     = R_DMA_CH4_CMD,
-         .ostatusadr  = R_DMA_CH4_STATUS,
-         .iclrintradr = R_DMA_CH5_CLR_INTR,
-         .ifirstadr   = R_DMA_CH5_FIRST,
-         .icmdadr     = R_DMA_CH5_CMD,
-         .idescradr   = R_DMA_CH5_DESCR,
-         .flags       = STD_FLAGS,
-         .rx_ctrl     = DEF_RX,
-         .tx_ctrl     = DEF_TX,
-         .iseteop     = 1,
-         .dma_owner   = dma_ser3,
-         .io_if       = if_serial_3,
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-          .enabled  = 1,
-         .io_if_description = "ser3",
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
-         .dma_out_enabled = 1,
-         .dma_out_nbr = SER3_TX_DMA_NBR,
-         .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
-         .dma_out_irq_description = "serial 3 dma tr",
-#else
-         .dma_out_enabled = 0,
-         .dma_out_nbr = UINT_MAX,
-         .dma_out_irq_nbr = 0,
-         .dma_out_irq_flags = 0,
-         .dma_out_irq_description = NULL,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
-         .dma_in_enabled = 1,
-         .dma_in_nbr = SER3_RX_DMA_NBR,
-         .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
-         .dma_in_irq_description = "serial 3 dma rec",
-#else
-         .dma_in_enabled = 0,
-         .dma_in_nbr = UINT_MAX,
-         .dma_in_irq_nbr = 0,
-         .dma_in_irq_flags = 0,
-         .dma_in_irq_description = NULL
-#endif
-#else
-          .enabled  = 0,
-         .io_if_description = NULL,
-         .dma_out_enabled = 0,
-         .dma_in_enabled = 0
-#endif
- }   /* ttyS3 */
-#endif
-};
-
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static struct fast_timer fast_timers[NR_PORTS];
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
-#define PROCSTAT(x) x
-struct ser_statistics_type {
-       int overrun_cnt;
-       int early_errors_cnt;
-       int ser_ints_ok_cnt;
-       int errors_cnt;
-       unsigned long int processing_flip;
-       unsigned long processing_flip_still_room;
-       unsigned long int timeout_flush_cnt;
-       int rx_dma_ints;
-       int tx_dma_ints;
-       int rx_tot;
-       int tx_tot;
-};
-
-static struct ser_statistics_type ser_stat[NR_PORTS];
-
-#else
-
-#define PROCSTAT(x)
-
-#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
-
-/* RS-485 */
-#if defined(CONFIG_ETRAX_RS485)
-#ifdef CONFIG_ETRAX_FAST_TIMER
-static struct fast_timer fast_timers_rs485[NR_PORTS];
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
-#endif
-#endif
-
-/* Info and macros needed for each ports extra control/status signals. */
-#define E100_STRUCT_PORT(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (R_PORT_PA_DATA): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (R_PORT_PB_DATA):&dummy_ser[line]))
-
-#define E100_STRUCT_SHADOW(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (&port_pa_data_shadow): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (&port_pb_data_shadow):&dummy_ser[line]))
-#define E100_STRUCT_MASK(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
-
-#define DUMMY_DTR_MASK 1
-#define DUMMY_RI_MASK  2
-#define DUMMY_DSR_MASK 4
-#define DUMMY_CD_MASK  8
-static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
-
-/* If not all status pins are used or disabled, use mixed mode */
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-
-#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
-
-#if SER0_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
-
-#if SER0_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT0 */
-
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-
-#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
-
-#if SER1_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
-
-#if SER1_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT1 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-
-#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
-
-#if SER2_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
-
-#if SER2_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT2 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-
-#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
-
-#if SER3_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
-
-#if SER3_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT3 */
-
-
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
-#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-#endif
-
-#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-/* The pins can be mixed on PA and PB */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-
-
-struct control_pins
-{
-       volatile unsigned char *dtr_port;
-       unsigned char          *dtr_shadow;
-       volatile unsigned char *ri_port;
-       unsigned char          *ri_shadow;
-       volatile unsigned char *dsr_port;
-       unsigned char          *dsr_shadow;
-       volatile unsigned char *cd_port;
-       unsigned char          *cd_shadow;
-
-       unsigned char dtr_mask;
-       unsigned char ri_mask;
-       unsigned char dsr_mask;
-       unsigned char cd_mask;
-};
-
-static const struct control_pins e100_modem_pins[NR_PORTS] =
-{
-       /* Ser 0 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-       E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
-       E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
-       E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
-       E100_STRUCT_MASK(0,DTR),
-       E100_STRUCT_MASK(0,RI),
-       E100_STRUCT_MASK(0,DSR),
-       E100_STRUCT_MASK(0,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(0)
-#endif
-       },
-
-       /* Ser 1 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-       E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
-       E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
-       E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
-       E100_STRUCT_MASK(1,DTR),
-       E100_STRUCT_MASK(1,RI),
-       E100_STRUCT_MASK(1,DSR),
-       E100_STRUCT_MASK(1,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(1)
-#endif
-       },
-
-       /* Ser 2 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-       E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
-       E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
-       E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
-       E100_STRUCT_MASK(2,DTR),
-       E100_STRUCT_MASK(2,RI),
-       E100_STRUCT_MASK(2,DSR),
-       E100_STRUCT_MASK(2,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(2)
-#endif
-       },
-
-       /* Ser 3 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-       E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
-       E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
-       E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
-       E100_STRUCT_MASK(3,DTR),
-       E100_STRUCT_MASK(3,RI),
-       E100_STRUCT_MASK(3,DSR),
-       E100_STRUCT_MASK(3,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(3)
-#endif
-       }
-};
-#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-/* All pins are on either PA or PB for each serial port */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-
-
-struct control_pins
-{
-       volatile unsigned char *port;
-       unsigned char          *shadow;
-
-       unsigned char dtr_mask;
-       unsigned char ri_mask;
-       unsigned char dsr_mask;
-       unsigned char cd_mask;
-};
-
-#define dtr_port port
-#define dtr_shadow shadow
-#define ri_port port
-#define ri_shadow shadow
-#define dsr_port port
-#define dsr_shadow shadow
-#define cd_port port
-#define cd_shadow shadow
-
-static const struct control_pins e100_modem_pins[NR_PORTS] =
-{
-       /* Ser 0 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-       E100_STRUCT_MASK(0,DTR),
-       E100_STRUCT_MASK(0,RI),
-       E100_STRUCT_MASK(0,DSR),
-       E100_STRUCT_MASK(0,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(0)
-#endif
-       },
-
-       /* Ser 1 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-       E100_STRUCT_MASK(1,DTR),
-       E100_STRUCT_MASK(1,RI),
-       E100_STRUCT_MASK(1,DSR),
-       E100_STRUCT_MASK(1,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(1)
-#endif
-       },
-
-       /* Ser 2 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-       E100_STRUCT_MASK(2,DTR),
-       E100_STRUCT_MASK(2,RI),
-       E100_STRUCT_MASK(2,DSR),
-       E100_STRUCT_MASK(2,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(2)
-#endif
-       },
-
-       /* Ser 3 */
-       {
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-       E100_STRUCT_MASK(3,DTR),
-       E100_STRUCT_MASK(3,RI),
-       E100_STRUCT_MASK(3,DSR),
-       E100_STRUCT_MASK(3,CD)
-#else
-       CONTROL_PINS_PORT_NOT_USED(3)
-#endif
-       }
-};
-#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-#define E100_RTS_MASK 0x20
-#define E100_CTS_MASK 0x40
-
-/* All serial port signals are active low:
- * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
- * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
- *
- * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
- */
-
-/* Output */
-#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
-/* Input */
-#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK)
-
-/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
-/* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
-
-/* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
-
-/* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
-
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
-/* Calculate the chartime depending on baudrate, numbor of bits etc. */
-static void update_char_time(struct e100_serial * info)
-{
-       tcflag_t cflags = info->port.tty->termios->c_cflag;
-       int bits;
-
-       /* calc. number of bits / data byte */
-       /* databits + startbit and 1 stopbit */
-       if ((cflags & CSIZE) == CS7)
-               bits = 9;
-       else
-               bits = 10;
-
-       if (cflags & CSTOPB)     /* 2 stopbits ? */
-               bits++;
-
-       if (cflags & PARENB)     /* parity bit ? */
-               bits++;
-
-       /* calc timeout */
-       info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
-       info->flush_time_usec = 4*info->char_time_usec;
-       if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
-               info->flush_time_usec = MIN_FLUSH_TIME_USEC;
-
-}
-
-/*
- * This function maps from the Bxxxx defines in asm/termbits.h into real
- * baud rates.
- */
-
-static int
-cflag_to_baud(unsigned int cflag)
-{
-       static int baud_table[] = {
-               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
-               4800, 9600, 19200, 38400 };
-
-       static int ext_baud_table[] = {
-               0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
-                0, 0, 0, 0, 0, 0, 0, 0 };
-
-       if (cflag & CBAUDEX)
-               return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-       else
-               return baud_table[cflag & CBAUD];
-}
-
-/* and this maps to an etrax100 hardware baud constant */
-
-static unsigned char
-cflag_to_etrax_baud(unsigned int cflag)
-{
-       char retval;
-
-       static char baud_table[] = {
-               -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
-
-       static char ext_baud_table[] = {
-               -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
-
-       if (cflag & CBAUDEX)
-               retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-       else
-               retval = baud_table[cflag & CBAUD];
-
-       if (retval < 0) {
-               printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
-               retval = 5; /* choose default 9600 instead */
-       }
-
-       return retval | (retval << 4); /* choose same for both TX and RX */
-}
-
-
-/* Various static support functions */
-
-/* Functions to set or clear DTR/RTS on the requested line */
-/* It is complicated by the fact that RTS is a serial port register, while
- * DTR might not be implemented in the HW at all, and if it is, it can be on
- * any general port.
- */
-
-
-static inline void
-e100_dtr(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       unsigned char mask = e100_modem_pins[info->line].dtr_mask;
-
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
-       printk("ser%i shadow before 0x%02X get: %i\n",
-              info->line, *e100_modem_pins[info->line].dtr_shadow,
-              E100_DTR_GET(info));
-#endif
-       /* DTR is active low */
-       {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].dtr_shadow &= ~mask;
-               *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
-               local_irq_restore(flags);
-       }
-
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i shadow after 0x%02X get: %i\n",
-              info->line, *e100_modem_pins[info->line].dtr_shadow,
-              E100_DTR_GET(info));
-#endif
-#endif
-}
-
-/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
- *                                          0=0V    , 1=3.3V
- */
-static inline void
-e100_rts(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       unsigned long flags;
-       local_irq_save(flags);
-       info->rx_ctrl &= ~E100_RTS_MASK;
-       info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
-       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
-       local_irq_restore(flags);
-#ifdef SERIAL_DEBUG_IO
-       printk("ser%i rts %i\n", info->line, set);
-#endif
-#endif
-}
-
-
-/* If this behaves as a modem, RI and CD is an output */
-static inline void
-e100_ri_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* RI is active low */
-       {
-               unsigned char mask = e100_modem_pins[info->line].ri_mask;
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].ri_shadow &= ~mask;
-               *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
-               local_irq_restore(flags);
-       }
-#endif
-}
-static inline void
-e100_cd_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* CD is active low */
-       {
-               unsigned char mask = e100_modem_pins[info->line].cd_mask;
-               unsigned long flags;
-
-               local_irq_save(flags);
-               *e100_modem_pins[info->line].cd_shadow &= ~mask;
-               *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
-               *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
-               local_irq_restore(flags);
-       }
-#endif
-}
-
-static inline void
-e100_disable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* disable the receiver */
-       info->ioport[REG_REC_CTRL] =
-               (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-static inline void
-e100_enable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-       /* enable the receiver */
-       info->ioport[REG_REC_CTRL] =
-               (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
-
-static inline void
-e100_disable_rxdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("rxdma_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
-}
-
-static inline void
-e100_enable_rxdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("rxdma_irq(%d): 1\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
-}
-
-/* the tx DMA uses only dma_descr interrupt */
-
-static void e100_disable_txdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("txdma_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_CLR = info->irq;
-}
-
-static void e100_enable_txdma_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("txdma_irq(%d): 1\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
-       *R_IRQ_MASK2_SET = info->irq;
-}
-
-static void e100_disable_txdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       /* Disable output DMA channel for the serial port in question
-        * ( set to something other than serialX)
-        */
-       local_irq_save(flags);
-       DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
-       if (info->line == 0) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
-                   IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
-               }
-       } else if (info->line == 1) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
-                   IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
-               }
-       } else if (info->line == 2) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
-                   IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
-               }
-       } else if (info->line == 3) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
-                   IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
-               }
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-
-static void e100_enable_txdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
-       /* Enable output DMA channel for the serial port in question */
-       if (info->line == 0) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
-       } else if (info->line == 1) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
-       } else if (info->line == 2) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
-       } else if (info->line == 3) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-static void e100_disable_rxdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       /* Disable input DMA channel for the serial port in question
-        * ( set to something other than serialX)
-        */
-       local_irq_save(flags);
-       if (info->line == 0) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
-                   IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
-               }
-       } else if (info->line == 1) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
-                   IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
-               }
-       } else if (info->line == 2) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
-                   IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
-               }
-       } else if (info->line == 3) {
-               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
-                   IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
-                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
-               }
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-
-static void e100_enable_rxdma_channel(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /* Enable input DMA channel for the serial port in question */
-       if (info->line == 0) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
-       } else if (info->line == 1) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
-       } else if (info->line == 2) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
-       } else if (info->line == 3) {
-               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
-       }
-       *R_GEN_CONFIG = genconfig_shadow;
-       local_irq_restore(flags);
-}
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-/* in order to detect and fix errors on the first byte
-   we have to use the serial interrupts as well. */
-
-static inline void
-e100_disable_serial_data_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
-       *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
-}
-
-static inline void
-e100_enable_serial_data_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_irq(%d): 1\n",info->line);
-       printk("**** %d = %d\n",
-              (8+2*info->line),
-              (1U << (8+2*info->line)));
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
-       *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
-}
-#endif
-
-static inline void
-e100_disable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_tx_irq(%d): 0\n",info->line);
-#endif
-       DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
-       *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
-}
-
-static inline void
-e100_enable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-       printk("ser_tx_irq(%d): 1\n",info->line);
-       printk("**** %d = %d\n",
-              (8+1+2*info->line),
-              (1U << (8+1+2*info->line)));
-#endif
-       DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
-       *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
-}
-
-static inline void e100_enable_rx_irq(struct e100_serial *info)
-{
-       if (info->uses_dma_in)
-               e100_enable_rxdma_irq(info);
-       else
-               e100_enable_serial_data_irq(info);
-}
-static inline void e100_disable_rx_irq(struct e100_serial *info)
-{
-       if (info->uses_dma_in)
-               e100_disable_rxdma_irq(info);
-       else
-               e100_disable_serial_data_irq(info);
-}
-
-#if defined(CONFIG_ETRAX_RS485)
-/* Enable RS-485 mode on selected port. This is UGLY. */
-static int
-e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-       *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-       REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
-                      rs485_port_g_bit, 1);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                      CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
-       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                      CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
-#endif
-
-       info->rs485 = *r;
-
-       /* Maximum delay before RTS equal to 1000 */
-       if (info->rs485.delay_rts_before_send >= 1000)
-               info->rs485.delay_rts_before_send = 1000;
-
-/*     printk("rts: on send = %i, after = %i, enabled = %i",
-                   info->rs485.rts_on_send,
-                   info->rs485.rts_after_sent,
-                   info->rs485.enabled
-       );
-*/
-       return 0;
-}
-
-static int
-e100_write_rs485(struct tty_struct *tty,
-                 const unsigned char *buf, int count)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-       int old_value = (info->rs485.flags) & SER_RS485_ENABLED;
-
-       /* rs485 is always implicitly enabled if we're using the ioctl()
-        * but it doesn't have to be set in the serial_rs485
-        * (to be backward compatible with old apps)
-        * So we store, set and restore it.
-        */
-       info->rs485.flags |= SER_RS485_ENABLED;
-       /* rs_write now deals with RS485 if enabled */
-       count = rs_write(tty, buf, count);
-       if (!old_value)
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-       return count;
-}
-
-#ifdef CONFIG_ETRAX_FAST_TIMER
-/* Timer function to toggle RTS when using FAST_TIMER */
-static void rs485_toggle_rts_timer_function(unsigned long data)
-{
-       struct e100_serial *info = (struct e100_serial *)data;
-
-       fast_timers_rs485[info->line].function = NULL;
-       e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-       e100_enable_rx(info);
-       e100_enable_rx_irq(info);
-#endif
-}
-#endif
-#endif /* CONFIG_ETRAX_RS485 */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter using the XOFF registers, as necessary.
- * ------------------------------------------------------------
- */
-
-static void
-rs_stop(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       if (info) {
-               unsigned long flags;
-               unsigned long xoff;
-
-               local_irq_save(flags);
-               DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
-                               CIRC_CNT(info->xmit.head,
-                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
-
-               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
-                               STOP_CHAR(info->port.tty));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
-               if (tty->termios->c_iflag & IXON ) {
-                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-               }
-
-               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-               local_irq_restore(flags);
-       }
-}
-
-static void
-rs_start(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       if (info) {
-               unsigned long flags;
-               unsigned long xoff;
-
-               local_irq_save(flags);
-               DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
-                               CIRC_CNT(info->xmit.head,
-                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
-               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-               if (tty->termios->c_iflag & IXON ) {
-                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-               }
-
-               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-               if (!info->uses_dma_out &&
-                   info->xmit.head != info->xmit.tail && info->xmit.buf)
-                       e100_enable_serial_tx_ready_irq(info);
-
-               local_irq_restore(flags);
-       }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct e100_serial *info, int event)
-{
-       if (info->event & (1 << event))
-               return;
-       info->event |= 1 << event;
-       schedule_work(&info->work);
-}
-
-/* The output DMA channel is free - use it to send as many chars as possible
- * NOTES:
- *   We don't pay attention to info->x_char, which means if the TTY wants to
- *   use XON/XOFF it will set info->x_char but we won't send any X char!
- *
- *   To implement this, we'd just start a DMA send of 1 byte pointing at a
- *   buffer containing the X char, and skip updating xmit. We'd also have to
- *   check if the last sent char was the X char when we enter this function
- *   the next time, to avoid updating xmit with the sent X value.
- */
-
-static void
-transmit_chars_dma(struct e100_serial *info)
-{
-       unsigned int c, sentl;
-       struct etrax_dma_descr *descr;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* This will output too little if tail is not 0 always since
-        * we don't reloop to send the other part. Anyway this SHOULD be a
-        * no-op - transmit_chars_dma would never really be called during sim
-        * since rs_write does not write into the xmit buffer then.
-        */
-       if (info->xmit.tail)
-               printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
-       if (info->xmit.head != info->xmit.tail) {
-               SIMCOUT(info->xmit.buf + info->xmit.tail,
-                       CIRC_CNT(info->xmit.head,
-                                info->xmit.tail,
-                                SERIAL_XMIT_SIZE));
-               info->xmit.head = info->xmit.tail;  /* move back head */
-               info->tr_running = 0;
-       }
-       return;
-#endif
-       /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-       *info->oclrintradr =
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-#ifdef SERIAL_DEBUG_INTR
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("tc\n");
-#endif
-       if (!info->tr_running) {
-               /* weirdo... we shouldn't get here! */
-               printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
-               return;
-       }
-
-       descr = &info->tr_descr;
-
-       /* first get the amount of bytes sent during the last DMA transfer,
-          and update xmit accordingly */
-
-       /* if the stop bit was not set, all data has been sent */
-       if (!(descr->status & d_stop)) {
-               sentl = descr->sw_len;
-       } else
-               /* otherwise we find the amount of data sent here */
-               sentl = descr->hw_len;
-
-       DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
-
-       /* update stats */
-       info->icount.tx += sentl;
-
-       /* update xmit buffer */
-       info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
-
-       /* if there is only a few chars left in the buf, wake up the blocked
-          write if any */
-       if (CIRC_CNT(info->xmit.head,
-                    info->xmit.tail,
-                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-       /* find out the largest amount of consecutive bytes we want to send now */
-
-       c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-
-       /* Don't send all in one DMA transfer - divide it so we wake up
-        * application before all is sent
-        */
-
-       if (c >= 4*WAKEUP_CHARS)
-               c = c/2;
-
-       if (c <= 0) {
-               /* our job here is done, don't schedule any new DMA transfer */
-               info->tr_running = 0;
-
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-               if (info->rs485.flags & SER_RS485_ENABLED) {
-                       /* Set a short timer to toggle RTS */
-                       start_one_shot_timer(&fast_timers_rs485[info->line],
-                                            rs485_toggle_rts_timer_function,
-                                            (unsigned long)info,
-                                            info->char_time_usec*2,
-                                            "RS-485");
-               }
-#endif /* RS485 */
-               return;
-       }
-
-       /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
-       /* set up the descriptor correctly for output */
-       DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
-       descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
-       descr->sw_len = c;
-       descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
-       descr->status = 0;
-
-       *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
-       *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
-       /* DMA is now running (hopefully) */
-} /* transmit_chars_dma */
-
-static void
-start_transmit(struct e100_serial *info)
-{
-#if 0
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("x\n");
-#endif
-
-       info->tr_descr.sw_len = 0;
-       info->tr_descr.hw_len = 0;
-       info->tr_descr.status = 0;
-       info->tr_running = 1;
-       if (info->uses_dma_out)
-               transmit_chars_dma(info);
-       else
-               e100_enable_serial_tx_ready_irq(info);
-} /* start_transmit */
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static int serial_fast_timer_started = 0;
-static int serial_fast_timer_expired = 0;
-static void flush_timeout_function(unsigned long data);
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
-  unsigned long timer_flags; \
-  local_irq_save(timer_flags); \
-  if (fast_timers[info->line].function == NULL) { \
-    serial_fast_timer_started++; \
-    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
-    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
-    start_one_shot_timer(&fast_timers[info->line], \
-                         flush_timeout_function, \
-                         (unsigned long)info, \
-                         (usec), \
-                         string); \
-  } \
-  else { \
-    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
-  } \
-  local_irq_restore(timer_flags); \
-}
-#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
-
-#else
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
-#define START_FLUSH_FAST_TIMER(info, string)
-#endif
-
-static struct etrax_recv_buffer *
-alloc_recv_buffer(unsigned int size)
-{
-       struct etrax_recv_buffer *buffer;
-
-       if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
-               return NULL;
-
-       buffer->next = NULL;
-       buffer->length = 0;
-       buffer->error = TTY_NORMAL;
-
-       return buffer;
-}
-
-static void
-append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (!info->first_recv_buffer)
-               info->first_recv_buffer = buffer;
-       else
-               info->last_recv_buffer->next = buffer;
-
-       info->last_recv_buffer = buffer;
-
-       info->recv_cnt += buffer->length;
-       if (info->recv_cnt > info->max_recv_cnt)
-               info->max_recv_cnt = info->recv_cnt;
-
-       local_irq_restore(flags);
-}
-
-static int
-add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
-{
-       struct etrax_recv_buffer *buffer;
-       if (info->uses_dma_in) {
-               if (!(buffer = alloc_recv_buffer(4)))
-                       return 0;
-
-               buffer->length = 1;
-               buffer->error = flag;
-               buffer->buffer[0] = data;
-
-               append_recv_buffer(info, buffer);
-
-               info->icount.rx++;
-       } else {
-               struct tty_struct *tty = info->port.tty;
-               tty_insert_flip_char(tty, data, flag);
-               info->icount.rx++;
-       }
-
-       return 1;
-}
-
-static unsigned int handle_descr_data(struct e100_serial *info,
-                                     struct etrax_dma_descr *descr,
-                                     unsigned int recvl)
-{
-       struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
-
-       if (info->recv_cnt + recvl > 65536) {
-               printk(KERN_CRIT
-                      "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
-               return 0;
-       }
-
-       buffer->length = recvl;
-
-       if (info->errorcode == ERRCODE_SET_BREAK)
-               buffer->error = TTY_BREAK;
-       info->errorcode = 0;
-
-       append_recv_buffer(info, buffer);
-
-       if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-               panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
-
-       descr->buf = virt_to_phys(buffer->buffer);
-
-       return recvl;
-}
-
-static unsigned int handle_all_descr_data(struct e100_serial *info)
-{
-       struct etrax_dma_descr *descr;
-       unsigned int recvl;
-       unsigned int ret = 0;
-
-       while (1)
-       {
-               descr = &info->rec_descr[info->cur_rec_descr];
-
-               if (descr == phys_to_virt(*info->idescradr))
-                       break;
-
-               if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
-                       info->cur_rec_descr = 0;
-
-               /* find out how many bytes were read */
-
-               /* if the eop bit was not set, all data has been received */
-               if (!(descr->status & d_eop)) {
-                       recvl = descr->sw_len;
-               } else {
-                       /* otherwise we find the amount of data received here */
-                       recvl = descr->hw_len;
-               }
-
-               /* Reset the status information */
-               descr->status = 0;
-
-               DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
-                       if (info->port.tty->stopped) {
-                               unsigned char *buf = phys_to_virt(descr->buf);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
-                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
-                       }
-                       );
-
-               /* update stats */
-               info->icount.rx += recvl;
-
-               ret += handle_descr_data(info, descr, recvl);
-       }
-
-       return ret;
-}
-
-static void receive_chars_dma(struct e100_serial *info)
-{
-       struct tty_struct *tty;
-       unsigned char rstat;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       return;
-#endif
-
-       /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-       *info->iclrintradr =
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-       tty = info->port.tty;
-       if (!tty) /* Something wrong... */
-               return;
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       if (info->uses_dma_in)
-               e100_enable_serial_data_irq(info);
-#endif
-
-       if (info->errorcode == ERRCODE_INSERT_BREAK)
-               add_char_and_flag(info, '\0', TTY_BREAK);
-
-       handle_all_descr_data(info);
-
-       /* Read the status register to detect errors */
-       rstat = info->ioport[REG_STATUS];
-       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
-       }
-
-       if (rstat & SER_ERROR_MASK) {
-               /* If we got an error, we must reset it by reading the
-                * data_in field
-                */
-               unsigned char data = info->ioport[REG_DATA];
-
-               PROCSTAT(ser_stat[info->line].errors_cnt++);
-               DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
-                         ((rstat & SER_ERROR_MASK) << 8) | data);
-
-               if (rstat & SER_PAR_ERR_MASK)
-                       add_char_and_flag(info, data, TTY_PARITY);
-               else if (rstat & SER_OVERRUN_MASK)
-                       add_char_and_flag(info, data, TTY_OVERRUN);
-               else if (rstat & SER_FRAMING_ERR_MASK)
-                       add_char_and_flag(info, data, TTY_FRAME);
-       }
-
-       START_FLUSH_FAST_TIMER(info, "receive_chars");
-
-       /* Restart the receiving DMA */
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-}
-
-static int start_recv_dma(struct e100_serial *info)
-{
-       struct etrax_dma_descr *descr = info->rec_descr;
-       struct etrax_recv_buffer *buffer;
-        int i;
-
-       /* Set up the receiving descriptors */
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
-               if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-                       panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
-
-               descr[i].ctrl = d_int;
-               descr[i].buf = virt_to_phys(buffer->buffer);
-               descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
-               descr[i].hw_len = 0;
-               descr[i].status = 0;
-               descr[i].next = virt_to_phys(&descr[i+1]);
-       }
-
-       /* Link the last descriptor to the first */
-       descr[i-1].next = virt_to_phys(&descr[0]);
-
-       /* Start with the first descriptor in the list */
-       info->cur_rec_descr = 0;
-
-       /* Start the DMA */
-       *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
-       /* Input DMA should be running now */
-       return 1;
-}
-
-static void
-start_receive(struct e100_serial *info)
-{
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       return;
-#endif
-       if (info->uses_dma_in) {
-               /* reset the input dma channel to be sure it works */
-
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               start_recv_dma(info);
-       }
-}
-
-
-/* the bits in the MASK2 register are laid out like this:
-   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
-   where I is the input channel and O is the output channel for the port.
-   info->irq is the bit number for the DMAO_DESCR so to check the others we
-   shift info->irq to the left.
-*/
-
-/* dma output channel interrupt handler
-   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
-   DMA8(ser1) when they have finished a descriptor with the intr flag set.
-*/
-
-static irqreturn_t
-tr_interrupt(int irq, void *dev_id)
-{
-       struct e100_serial *info;
-       unsigned long ireg;
-       int i;
-       int handled = 0;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       {
-               const char *s = "What? tr_interrupt in simulator??\n";
-               SIMCOUT(s,strlen(s));
-       }
-       return IRQ_HANDLED;
-#endif
-
-       /* find out the line that caused this irq and get it from rs_table */
-
-       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (!info->enabled || !info->uses_dma_out)
-                       continue;
-               /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
-               if (ireg & info->irq) {
-                       handled = 1;
-                       /* we can send a new dma bunch. make it so. */
-                       DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
-                       /* Read jiffies_usec first,
-                        * we want this time to be as late as possible
-                        */
-                       PROCSTAT(ser_stat[info->line].tx_dma_ints++);
-                       info->last_tx_active_usec = GET_JIFFIES_USEC();
-                       info->last_tx_active = jiffies;
-                       transmit_chars_dma(info);
-               }
-
-               /* FIXME: here we should really check for a change in the
-                  status lines and if so call status_handle(info) */
-       }
-       return IRQ_RETVAL(handled);
-} /* tr_interrupt */
-
-/* dma input channel interrupt handler */
-
-static irqreturn_t
-rec_interrupt(int irq, void *dev_id)
-{
-       struct e100_serial *info;
-       unsigned long ireg;
-       int i;
-       int handled = 0;
-
-#ifdef CONFIG_SVINTO_SIM
-       /* No receive in the simulator.  Will probably be when the rest of
-        * the serial interface works, and this piece will just be removed.
-        */
-       {
-               const char *s = "What? rec_interrupt in simulator??\n";
-               SIMCOUT(s,strlen(s));
-       }
-       return IRQ_HANDLED;
-#endif
-
-       /* find out the line that caused this irq and get it from rs_table */
-
-       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (!info->enabled || !info->uses_dma_in)
-                       continue;
-               /* check for both dma_eop and dma_descr for the input dma channel */
-               if (ireg & ((info->irq << 2) | (info->irq << 3))) {
-                       handled = 1;
-                       /* we have received something */
-                       receive_chars_dma(info);
-               }
-
-               /* FIXME: here we should really check for a change in the
-                  status lines and if so call status_handle(info) */
-       }
-       return IRQ_RETVAL(handled);
-} /* rec_interrupt */
-
-static int force_eop_if_needed(struct e100_serial *info)
-{
-       /* We check data_avail bit to determine if data has
-        * arrived since last time
-        */
-       unsigned char rstat = info->ioport[REG_STATUS];
-
-       /* error or datavail? */
-       if (rstat & SER_ERROR_MASK) {
-               /* Some error has occurred. If there has been valid data, an
-                * EOP interrupt will be made automatically. If no data, the
-                * normal ser_interrupt should be enabled and handle it.
-                * So do nothing!
-                */
-               DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
-                         rstat | (info->line << 8));
-               return 0;
-       }
-
-       if (rstat & SER_DATA_AVAIL_MASK) {
-               /* Ok data, no error, count it */
-               TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
-                         rstat | (info->line << 8)));
-               /* Read data to clear status flags */
-               (void)info->ioport[REG_DATA];
-
-               info->forced_eop = 0;
-               START_FLUSH_FAST_TIMER(info, "magic");
-               return 0;
-       }
-
-       /* hit the timeout, force an EOP for the input
-        * dma channel if we haven't already
-        */
-       if (!info->forced_eop) {
-               info->forced_eop = 1;
-               PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
-               TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
-               FORCE_EOP(info);
-       }
-
-       return 1;
-}
-
-static void flush_to_flip_buffer(struct e100_serial *info)
-{
-       struct tty_struct *tty;
-       struct etrax_recv_buffer *buffer;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       tty = info->port.tty;
-
-       if (!tty) {
-               local_irq_restore(flags);
-               return;
-       }
-
-       while ((buffer = info->first_recv_buffer) != NULL) {
-               unsigned int count = buffer->length;
-
-               tty_insert_flip_string(tty, buffer->buffer, count);
-               info->recv_cnt -= count;
-
-               if (count == buffer->length) {
-                       info->first_recv_buffer = buffer->next;
-                       kfree(buffer);
-               } else {
-                       buffer->length -= count;
-                       memmove(buffer->buffer, buffer->buffer + count, buffer->length);
-                       buffer->error = TTY_NORMAL;
-               }
-       }
-
-       if (!info->first_recv_buffer)
-               info->last_recv_buffer = NULL;
-
-       local_irq_restore(flags);
-
-       /* This includes a check for low-latency */
-       tty_flip_buffer_push(tty);
-}
-
-static void check_flush_timeout(struct e100_serial *info)
-{
-       /* Flip what we've got (if we can) */
-       flush_to_flip_buffer(info);
-
-       /* We might need to flip later, but not to fast
-        * since the system is busy processing input... */
-       if (info->first_recv_buffer)
-               START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
-
-       /* Force eop last, since data might have come while we're processing
-        * and if we started the slow timer above, we won't start a fast
-        * below.
-        */
-       force_eop_if_needed(info);
-}
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static void flush_timeout_function(unsigned long data)
-{
-       struct e100_serial *info = (struct e100_serial *)data;
-
-       fast_timers[info->line].function = NULL;
-       serial_fast_timer_expired++;
-       TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
-       TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
-       check_flush_timeout(info);
-}
-
-#else
-
-/* dma fifo/buffer timeout handler
-   forces an end-of-packet for the dma input channel if no chars
-   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
-*/
-
-static struct timer_list flush_timer;
-
-static void
-timed_flush_handler(unsigned long ptr)
-{
-       struct e100_serial *info;
-       int i;
-
-#ifdef CONFIG_SVINTO_SIM
-       return;
-#endif
-
-       for (i = 0; i < NR_PORTS; i++) {
-               info = rs_table + i;
-               if (info->uses_dma_in)
-                       check_flush_timeout(info);
-       }
-
-       /* restart flush timer */
-       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
-}
-#endif
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-
-/* If there is an error (ie break) when the DMA is running and
- * there are no bytes in the fifo the DMA is stopped and we get no
- * eop interrupt. Thus we have to monitor the first bytes on a DMA
- * transfer, and if it is without error we can turn the serial
- * interrupts off.
- */
-
-/*
-BREAK handling on ETRAX 100:
-ETRAX will generate interrupt although there is no stop bit between the
-characters.
-
-Depending on how long the break sequence is, the end of the breaksequence
-will look differently:
-| indicates start/end of a character.
-
-B= Break character (0x00) with framing error.
-E= Error byte with parity error received after B characters.
-F= "Faked" valid byte received immediately after B characters.
-V= Valid byte
-
-1.
-    B          BL         ___________________________ V
-.._|__________|__________|                           |valid data |
-
-Multiple frame errors with data == 0x00 (B),
-the timing matches up "perfectly" so no extra ending char is detected.
-The RXD pin is 1 in the last interrupt, in that case
-we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
-know if another byte will come and this really is case 2. below
-(e.g F=0xFF or 0xFE)
-If RXD pin is 0 we can expect another character (see 2. below).
-
-
-2.
-
-    B          B          E or F__________________..__ V
-.._|__________|__________|______    |                 |valid data
-                          "valid" or
-                          parity error
-
-Multiple frame errors with data == 0x00 (B),
-but the part of the break trigs is interpreted as a start bit (and possibly
-some 0 bits followed by a number of 1 bits and a stop bit).
-Depending on parity settings etc. this last character can be either
-a fake "valid" char (F) or have a parity error (E).
-
-If the character is valid it will be put in the buffer,
-we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
-will set the flags so the tty will handle it,
-if it's an error byte it will not be put in the buffer
-and we set info->errorcode = ERRCODE_INSERT_BREAK.
-
-To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
-of the last faulty char (B) and compares it with the current time:
-If the time elapsed time is less then 2*char_time_usec we will assume
-it's a faked F char and not a Valid char and set
-info->errorcode = ERRCODE_SET_BREAK.
-
-Flaws in the above solution:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We use the timer to distinguish a F character from a V character,
-if a V character is to close after the break we might make the wrong decision.
-
-TODO: The break will be delayed until an F or V character is received.
-
-*/
-
-static
-struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
-{
-       unsigned long data_read;
-       struct tty_struct *tty = info->port.tty;
-
-       if (!tty) {
-               printk("!NO TTY!\n");
-               return info;
-       }
-
-       /* Read data and status at the same time */
-       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
-more_data:
-       if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-       }
-       DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
-
-       if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
-                         IO_MASK(R_SERIAL0_READ, par_err) |
-                         IO_MASK(R_SERIAL0_READ, overrun) )) {
-               /* An error */
-               info->last_rx_active_usec = GET_JIFFIES_USEC();
-               info->last_rx_active = jiffies;
-               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
-               DLOG_INT_TRIG(
-               if (!log_int_trig1_pos) {
-                       log_int_trig1_pos = log_int_pos;
-                       log_int(rdpc(), 0, 0);
-               }
-               );
-
-
-               if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
-                    (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
-                       /* Most likely a break, but we get interrupts over and
-                        * over again.
-                        */
-
-                       if (!info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "#BRK start\n", 0);
-                       }
-                       if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
-                               /* The RX pin is high now, so the break
-                                * must be over, but....
-                                * we can't really know if we will get another
-                                * last byte ending the break or not.
-                                * And we don't know if the byte (if any) will
-                                * have an error or look valid.
-                                */
-                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       }
-                       info->break_detected_cnt++;
-               } else {
-                       /* The error does not look like a break, but could be
-                        * the end of one
-                        */
-                       if (info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       } else {
-                               unsigned char data = IO_EXTRACT(R_SERIAL0_READ,
-                                       data_in, data_read);
-                               char flag = TTY_NORMAL;
-                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
-                                       struct tty_struct *tty = info->port.tty;
-                                       tty_insert_flip_char(tty, 0, flag);
-                                       info->icount.rx++;
-                               }
-
-                               if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
-                                       info->icount.parity++;
-                                       flag = TTY_PARITY;
-                               } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
-                                       info->icount.overrun++;
-                                       flag = TTY_OVERRUN;
-                               } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
-                                       info->icount.frame++;
-                                       flag = TTY_FRAME;
-                               }
-                               tty_insert_flip_char(tty, data, flag);
-                               info->errorcode = 0;
-                       }
-                       info->break_detected_cnt = 0;
-               }
-       } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-               /* No error */
-               DLOG_INT_TRIG(
-               if (!log_int_trig1_pos) {
-                       if (log_int_pos >= log_int_size) {
-                               log_int_pos = 0;
-                       }
-                       log_int_trig0_pos = log_int_pos;
-                       log_int(rdpc(), 0, 0);
-               }
-               );
-               tty_insert_flip_char(tty,
-                       IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
-                       TTY_NORMAL);
-       } else {
-               DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
-       }
-
-
-       info->icount.rx++;
-       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
-       if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-               DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
-               goto more_data;
-       }
-
-       tty_flip_buffer_push(info->port.tty);
-       return info;
-}
-
-static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
-{
-       unsigned char rstat;
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("Interrupt from serport %d\n", i);
-#endif
-/*     DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
-       if (!info->uses_dma_in) {
-               return handle_ser_rx_interrupt_no_dma(info);
-       }
-       /* DMA is used */
-       rstat = info->ioport[REG_STATUS];
-       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-       }
-
-       if (rstat & SER_ERROR_MASK) {
-               unsigned char data;
-
-               info->last_rx_active_usec = GET_JIFFIES_USEC();
-               info->last_rx_active = jiffies;
-               /* If we got an error, we must reset it by reading the
-                * data_in field
-                */
-               data = info->ioport[REG_DATA];
-               DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
-               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
-               if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
-                       /* Most likely a break, but we get interrupts over and
-                        * over again.
-                        */
-
-                       if (!info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "#BRK start\n", 0);
-                       }
-                       if (rstat & SER_RXD_MASK) {
-                               /* The RX pin is high now, so the break
-                                * must be over, but....
-                                * we can't really know if we will get another
-                                * last byte ending the break or not.
-                                * And we don't know if the byte (if any) will
-                                * have an error or look valid.
-                                */
-                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       }
-                       info->break_detected_cnt++;
-               } else {
-                       /* The error does not look like a break, but could be
-                        * the end of one
-                        */
-                       if (info->break_detected_cnt) {
-                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-                               info->errorcode = ERRCODE_INSERT_BREAK;
-                       } else {
-                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
-                                       info->icount.brk++;
-                                       add_char_and_flag(info, '\0', TTY_BREAK);
-                               }
-
-                               if (rstat & SER_PAR_ERR_MASK) {
-                                       info->icount.parity++;
-                                       add_char_and_flag(info, data, TTY_PARITY);
-                               } else if (rstat & SER_OVERRUN_MASK) {
-                                       info->icount.overrun++;
-                                       add_char_and_flag(info, data, TTY_OVERRUN);
-                               } else if (rstat & SER_FRAMING_ERR_MASK) {
-                                       info->icount.frame++;
-                                       add_char_and_flag(info, data, TTY_FRAME);
-                               }
-
-                               info->errorcode = 0;
-                       }
-                       info->break_detected_cnt = 0;
-                       DEBUG_LOG(info->line, "#iERR s d %04X\n",
-                                 ((rstat & SER_ERROR_MASK) << 8) | data);
-               }
-               PROCSTAT(ser_stat[info->line].early_errors_cnt++);
-       } else { /* It was a valid byte, now let the DMA do the rest */
-               unsigned long curr_time_u = GET_JIFFIES_USEC();
-               unsigned long curr_time = jiffies;
-
-               if (info->break_detected_cnt) {
-                       /* Detect if this character is a new valid char or the
-                        * last char in a break sequence: If LSBits are 0 and
-                        * MSBits are high AND the time is close to the
-                        * previous interrupt we should discard it.
-                        */
-                       long elapsed_usec =
-                         (curr_time - info->last_rx_active) * (1000000/HZ) +
-                         curr_time_u - info->last_rx_active_usec;
-                       if (elapsed_usec < 2*info->char_time_usec) {
-                               DEBUG_LOG(info->line, "FBRK %i\n", info->line);
-                               /* Report as BREAK (error) and let
-                                * receive_chars_dma() handle it
-                                */
-                               info->errorcode = ERRCODE_SET_BREAK;
-                       } else {
-                               DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
-                       }
-                       DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
-               }
-
-#ifdef SERIAL_DEBUG_INTR
-               printk("** OK, disabling ser_interrupts\n");
-#endif
-               e100_disable_serial_data_irq(info);
-               DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
-               info->break_detected_cnt = 0;
-
-               PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
-       }
-       /* Restarting the DMA never hurts */
-       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-       START_FLUSH_FAST_TIMER(info, "ser_int");
-       return info;
-} /* handle_ser_rx_interrupt */
-
-static void handle_ser_tx_interrupt(struct e100_serial *info)
-{
-       unsigned long flags;
-
-       if (info->x_char) {
-               unsigned char rstat;
-               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
-               local_irq_save(flags);
-               rstat = info->ioport[REG_STATUS];
-               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-
-               info->ioport[REG_TR_DATA] = info->x_char;
-               info->icount.tx++;
-               info->x_char = 0;
-               /* We must enable since it is disabled in ser_interrupt */
-               e100_enable_serial_tx_ready_irq(info);
-               local_irq_restore(flags);
-               return;
-       }
-       if (info->uses_dma_out) {
-               unsigned char rstat;
-               int i;
-               /* We only use normal tx interrupt when sending x_char */
-               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
-               local_irq_save(flags);
-               rstat = info->ioport[REG_STATUS];
-               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-               e100_disable_serial_tx_ready_irq(info);
-               if (info->port.tty->stopped)
-                       rs_stop(info->port.tty);
-               /* Enable the DMA channel and tell it to continue */
-               e100_enable_txdma_channel(info);
-               /* Wait 12 cycles before doing the DMA command */
-               for(i = 6;  i > 0; i--)
-                       nop();
-
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
-               local_irq_restore(flags);
-               return;
-       }
-       /* Normal char-by-char interrupt */
-       if (info->xmit.head == info->xmit.tail
-           || info->port.tty->stopped
-           || info->port.tty->hw_stopped) {
-               DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
-                               info->port.tty->stopped));
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-               return;
-       }
-       DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
-       /* Send a byte, rs485 timing is critical so turn of ints */
-       local_irq_save(flags);
-       info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
-       info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
-       info->icount.tx++;
-       if (info->xmit.head == info->xmit.tail) {
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-               if (info->rs485.flags & SER_RS485_ENABLED) {
-                       /* Set a short timer to toggle RTS */
-                       start_one_shot_timer(&fast_timers_rs485[info->line],
-                                            rs485_toggle_rts_timer_function,
-                                            (unsigned long)info,
-                                            info->char_time_usec*2,
-                                            "RS-485");
-               }
-#endif /* RS485 */
-               info->last_tx_active_usec = GET_JIFFIES_USEC();
-               info->last_tx_active = jiffies;
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-               DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
-       } else {
-               /* We must enable since it is disabled in ser_interrupt */
-               e100_enable_serial_tx_ready_irq(info);
-       }
-       local_irq_restore(flags);
-
-       if (CIRC_CNT(info->xmit.head,
-                    info->xmit.tail,
-                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-} /* handle_ser_tx_interrupt */
-
-/* result of time measurements:
- * RX duration 54-60 us when doing something, otherwise 6-9 us
- * ser_int duration: just sending: 8-15 us normally, up to 73 us
- */
-static irqreturn_t
-ser_interrupt(int irq, void *dev_id)
-{
-       static volatile int tx_started = 0;
-       struct e100_serial *info;
-       int i;
-       unsigned long flags;
-       unsigned long irq_mask1_rd;
-       unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
-       int handled = 0;
-       static volatile unsigned long reentered_ready_mask = 0;
-
-       local_irq_save(flags);
-       irq_mask1_rd = *R_IRQ_MASK1_RD;
-       /* First handle all rx interrupts with ints disabled */
-       info = rs_table;
-       irq_mask1_rd &= e100_ser_int_mask;
-       for (i = 0; i < NR_PORTS; i++) {
-               /* Which line caused the data irq? */
-               if (irq_mask1_rd & data_mask) {
-                       handled = 1;
-                       handle_ser_rx_interrupt(info);
-               }
-               info += 1;
-               data_mask <<= 2;
-       }
-       /* Handle tx interrupts with interrupts enabled so we
-        * can take care of new data interrupts while transmitting
-        * We protect the tx part with the tx_started flag.
-        * We disable the tr_ready interrupts we are about to handle and
-        * unblock the serial interrupt so new serial interrupts may come.
-        *
-        * If we get a new interrupt:
-        *  - it migth be due to synchronous serial ports.
-        *  - serial irq will be blocked by general irq handler.
-        *  - async data will be handled above (sync will be ignored).
-        *  - tx_started flag will prevent us from trying to send again and
-        *    we will exit fast - no need to unblock serial irq.
-        *  - Next (sync) serial interrupt handler will be runned with
-        *    disabled interrupt due to restore_flags() at end of function,
-        *    so sync handler will not be preempted or reentered.
-        */
-       if (!tx_started) {
-               unsigned long ready_mask;
-               unsigned long
-               tx_started = 1;
-               /* Only the tr_ready interrupts left */
-               irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-                                IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-               while (irq_mask1_rd) {
-                       /* Disable those we are about to handle */
-                       *R_IRQ_MASK1_CLR = irq_mask1_rd;
-                       /* Unblock the serial interrupt */
-                       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
-
-                       local_irq_enable();
-                       ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
-                       info = rs_table;
-                       for (i = 0; i < NR_PORTS; i++) {
-                               /* Which line caused the ready irq? */
-                               if (irq_mask1_rd & ready_mask) {
-                                       handled = 1;
-                                       handle_ser_tx_interrupt(info);
-                               }
-                               info += 1;
-                               ready_mask <<= 2;
-                       }
-                       /* handle_ser_tx_interrupt enables tr_ready interrupts */
-                       local_irq_disable();
-                       /* Handle reentered TX interrupt */
-                       irq_mask1_rd = reentered_ready_mask;
-               }
-               local_irq_disable();
-               tx_started = 0;
-       } else {
-               unsigned long ready_mask;
-               ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-                                            IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-               if (ready_mask) {
-                       reentered_ready_mask |= ready_mask;
-                       /* Disable those we are about to handle */
-                       *R_IRQ_MASK1_CLR = ready_mask;
-                       DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
-               }
-       }
-
-       local_irq_restore(flags);
-       return IRQ_RETVAL(handled);
-} /* ser_interrupt */
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-static void
-do_softint(struct work_struct *work)
-{
-       struct e100_serial      *info;
-       struct tty_struct       *tty;
-
-       info = container_of(work, struct e100_serial, work);
-
-       tty = info->port.tty;
-       if (!tty)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
-               tty_wakeup(tty);
-}
-
-static int
-startup(struct e100_serial * info)
-{
-       unsigned long flags;
-       unsigned long xmit_page;
-       int i;
-
-       xmit_page = get_zeroed_page(GFP_KERNEL);
-       if (!xmit_page)
-               return -ENOMEM;
-
-       local_irq_save(flags);
-
-       /* if it was already initialized, skip this */
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               local_irq_restore(flags);
-               free_page(xmit_page);
-               return 0;
-       }
-
-       if (info->xmit.buf)
-               free_page(xmit_page);
-       else
-               info->xmit.buf = (unsigned char *) xmit_page;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-       /* Bits and pieces collected from below.  Better to have them
-          in one ifdef:ed clause than to mix in a lot of ifdefs,
-          right? */
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->xmit.head = info->xmit.tail = 0;
-       info->first_recv_buffer = info->last_recv_buffer = NULL;
-       info->recv_cnt = info->max_recv_cnt = 0;
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               info->rec_descr[i].buf = NULL;
-
-       /* No real action in the simulator, but may set info important
-          to ioctl. */
-       change_speed(info);
-#else
-
-       /*
-        * Clear the FIFO buffers and disable them
-        * (they will be reenabled in change_speed())
-        */
-
-       /*
-        * Reset the DMA channels and make sure their interrupts are cleared
-        */
-
-       if (info->dma_in_enabled) {
-               info->uses_dma_in = 1;
-               e100_enable_rxdma_channel(info);
-
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-               /* Wait until reset cycle is complete */
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               /* Make sure the irqs are cleared */
-               *info->iclrintradr =
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-       } else {
-               e100_disable_rxdma_channel(info);
-       }
-
-       if (info->dma_out_enabled) {
-               info->uses_dma_out = 1;
-               e100_enable_txdma_channel(info);
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-               /* Make sure the irqs are cleared */
-               *info->oclrintradr =
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-       } else {
-               e100_disable_txdma_channel(info);
-       }
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->xmit.head = info->xmit.tail = 0;
-       info->first_recv_buffer = info->last_recv_buffer = NULL;
-       info->recv_cnt = info->max_recv_cnt = 0;
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               info->rec_descr[i].buf = 0;
-
-       /*
-        * and set the speed and other flags of the serial port
-        * this will start the rx/tx as well
-        */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       e100_enable_serial_data_irq(info);
-#endif
-       change_speed(info);
-
-       /* dummy read to reset any serial errors */
-
-       (void)info->ioport[REG_DATA];
-
-       /* enable the interrupts */
-       if (info->uses_dma_out)
-               e100_enable_txdma_irq(info);
-
-       e100_enable_rx_irq(info);
-
-       info->tr_running = 0; /* to be sure we don't lock up the transmitter */
-
-       /* setup the dma input descriptor and start dma */
-
-       start_receive(info);
-
-       /* for safety, make sure the descriptors last result is 0 bytes written */
-
-       info->tr_descr.sw_len = 0;
-       info->tr_descr.hw_len = 0;
-       info->tr_descr.status = 0;
-
-       /* enable RTS/DTR last */
-
-       e100_rts(info, 1);
-       e100_dtr(info, 1);
-
-#endif /* CONFIG_SVINTO_SIM */
-
-       info->flags |= ASYNC_INITIALIZED;
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-shutdown(struct e100_serial * info)
-{
-       unsigned long flags;
-       struct etrax_dma_descr *descr = info->rec_descr;
-       struct etrax_recv_buffer *buffer;
-       int i;
-
-#ifndef CONFIG_SVINTO_SIM
-       /* shut down the transmitter and receiver */
-       DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
-       e100_disable_rx(info);
-       info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
-
-       /* disable interrupts, reset dma channels */
-       if (info->uses_dma_in) {
-               e100_disable_rxdma_irq(info);
-               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               info->uses_dma_in = 0;
-       } else {
-               e100_disable_serial_data_irq(info);
-       }
-
-       if (info->uses_dma_out) {
-               e100_disable_txdma_irq(info);
-               info->tr_running = 0;
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-               info->uses_dma_out = 0;
-       } else {
-               e100_disable_serial_tx_ready_irq(info);
-               info->tr_running = 0;
-       }
-
-#endif /* CONFIG_SVINTO_SIM */
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....\n", info->line,
-              info->irq);
-#endif
-
-       local_irq_save(flags);
-
-       if (info->xmit.buf) {
-               free_page((unsigned long)info->xmit.buf);
-               info->xmit.buf = NULL;
-       }
-
-       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-               if (descr[i].buf) {
-                       buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
-                       kfree(buffer);
-                       descr[i].buf = 0;
-               }
-
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
-               /* hang up DTR and RTS if HUPCL is enabled */
-               e100_dtr(info, 0);
-               e100_rts(info, 0); /* could check CRTSCTS before doing this */
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-
-/* change baud rate and other assorted parameters */
-
-static void
-change_speed(struct e100_serial *info)
-{
-       unsigned int cflag;
-       unsigned long xoff;
-       unsigned long flags;
-       /* first some safety checks */
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       if (!info->ioport)
-               return;
-
-       cflag = info->port.tty->termios->c_cflag;
-
-       /* possibly, the tx/rx should be disabled first to do this safely */
-
-       /* change baud-rate and write it to the hardware */
-       if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
-               /* Special baudrate */
-               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-               unsigned long alt_source =
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-               /* R_ALT_SER_BAUDRATE selects the source */
-               DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
-                      (unsigned long)info->baud_base, info->custom_divisor));
-               if (info->baud_base == SERIAL_PRESCALE_BASE) {
-                       /* 0, 2-65535 (0=65536) */
-                       u16 divisor = info->custom_divisor;
-                       /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
-                       /* baudrate is 3.125MHz/custom_divisor */
-                       alt_source =
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
-                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
-                       alt_source = 0x11;
-                       DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
-                       *R_SERIAL_PRESCALE = divisor;
-                       info->baud = SERIAL_PRESCALE_BASE/divisor;
-               }
-#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
-               else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
-                         info->custom_divisor == 1) ||
-                        (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
-                         info->custom_divisor == 8)) {
-                               /* ext_clk selected */
-                               alt_source =
-                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
-                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
-                               DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
-                               info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
-                       }
-#endif
-               else
-               {
-                       /* Bad baudbase, we don't support using timer0
-                        * for baudrate.
-                        */
-                       printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
-                              (unsigned long)info->baud_base, info->custom_divisor);
-               }
-               r_alt_ser_baudrate_shadow &= ~mask;
-               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-       } else {
-               /* Normal baudrate */
-               /* Make sure we use normal baudrate */
-               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-               unsigned long alt_source =
-                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-               r_alt_ser_baudrate_shadow &= ~mask;
-               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-#ifndef CONFIG_SVINTO_SIM
-               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-#endif /* CONFIG_SVINTO_SIM */
-
-               info->baud = cflag_to_baud(cflag);
-#ifndef CONFIG_SVINTO_SIM
-               info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
-#endif /* CONFIG_SVINTO_SIM */
-       }
-
-#ifndef CONFIG_SVINTO_SIM
-       /* start with default settings and then fill in changes */
-       local_irq_save(flags);
-       /* 8 bit, no/even parity */
-       info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
-                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
-                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
-
-       /* 8 bit, no/even parity, 1 stop bit, no cts */
-       info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
-                          IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
-
-       if ((cflag & CSIZE) == CS7) {
-               /* set 7 bit mode */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
-       }
-
-       if (cflag & CSTOPB) {
-               /* set 2 stop bit mode */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
-       }
-
-       if (cflag & PARENB) {
-               /* enable parity */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
-       }
-
-       if (cflag & CMSPAR) {
-               /* enable stick parity, PARODD mean Mark which matches ETRAX */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
-       }
-       if (cflag & PARODD) {
-               /* set odd parity (or Mark if CMSPAR) */
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
-               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
-       }
-
-       if (cflag & CRTSCTS) {
-               /* enable automatic CTS handling */
-               DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
-               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
-       }
-
-       /* make sure the tx and rx are enabled */
-
-       info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
-       info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
-
-       /* actually write the control regs to the hardware */
-
-       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
-       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
-       xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
-       xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-       if (info->port.tty->termios->c_iflag & IXON ) {
-               DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
-                               STOP_CHAR(info->port.tty)));
-               xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-       }
-
-       *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
-       local_irq_restore(flags);
-#endif /* !CONFIG_SVINTO_SIM */
-
-       update_char_time(info);
-
-} /* change_speed */
-
-/* start transmitting chars NOW */
-
-static void
-rs_flush_chars(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (info->tr_running ||
-           info->xmit.head == info->xmit.tail ||
-           tty->stopped ||
-           tty->hw_stopped ||
-           !info->xmit.buf)
-               return;
-
-#ifdef SERIAL_DEBUG_FLOW
-       printk("rs_flush_chars\n");
-#endif
-
-       /* this protection might not exactly be necessary here */
-
-       local_irq_save(flags);
-       start_transmit(info);
-       local_irq_restore(flags);
-}
-
-static int rs_raw_write(struct tty_struct *tty,
-                       const unsigned char *buf, int count)
-{
-       int     c, ret = 0;
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       /* first some sanity checks */
-
-       if (!tty || !info->xmit.buf || !tmp_buf)
-               return 0;
-
-#ifdef SERIAL_DEBUG_DATA
-       if (info->line == SERIAL_DEBUG_LINE)
-               printk("rs_raw_write (%d), status %d\n",
-                      count, info->ioport[REG_STATUS]);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-       /* Really simple.  The output is here and now. */
-       SIMCOUT(buf, count);
-       return count;
-#endif
-       local_save_flags(flags);
-       DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
-       DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
-
-
-       /* The local_irq_disable/restore_flags pairs below are needed
-        * because the DMA interrupt handler moves the info->xmit values.
-        * the memcpy needs to be in the critical region unfortunately,
-        * because we need to read xmit values, memcpy, write xmit values
-        * in one atomic operation... this could perhaps be avoided by
-        * more clever design.
-        */
-       local_irq_disable();
-               while (count) {
-                       c = CIRC_SPACE_TO_END(info->xmit.head,
-                                             info->xmit.tail,
-                                             SERIAL_XMIT_SIZE);
-
-                       if (count < c)
-                               c = count;
-                       if (c <= 0)
-                               break;
-
-                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
-                       info->xmit.head = (info->xmit.head + c) &
-                               (SERIAL_XMIT_SIZE-1);
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-       local_irq_restore(flags);
-
-       /* enable transmitter if not running, unless the tty is stopped
-        * this does not need IRQ protection since if tr_running == 0
-        * the IRQ's are not running anyway for this port.
-        */
-       DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
-
-       if (info->xmit.head != info->xmit.tail &&
-           !tty->stopped &&
-           !tty->hw_stopped &&
-           !info->tr_running) {
-               start_transmit(info);
-       }
-
-       return ret;
-} /* raw_raw_write() */
-
-static int
-rs_write(struct tty_struct *tty,
-        const unsigned char *buf, int count)
-{
-#if defined(CONFIG_ETRAX_RS485)
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       if (info->rs485.flags & SER_RS485_ENABLED)
-       {
-               /* If we are in RS-485 mode, we need to toggle RTS and disable
-                * the receiver before initiating a DMA transfer
-                */
-#ifdef CONFIG_ETRAX_FAST_TIMER
-               /* Abort any started timer */
-               fast_timers_rs485[info->line].function = NULL;
-               del_fast_timer(&fast_timers_rs485[info->line]);
-#endif
-               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND));
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-               e100_disable_rx(info);
-               e100_enable_rx_irq(info);
-#endif
-               if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
-                       (info->rs485.delay_rts_before_send > 0))
-                               msleep(info->rs485.delay_rts_before_send);
-       }
-#endif /* CONFIG_ETRAX_RS485 */
-
-       count = rs_raw_write(tty, buf, count);
-
-#if defined(CONFIG_ETRAX_RS485)
-       if (info->rs485.flags & SER_RS485_ENABLED)
-       {
-               unsigned int val;
-               /* If we are in RS-485 mode the following has to be done:
-                * wait until DMA is ready
-                * wait on transmit shift register
-                * toggle RTS
-                * enable the receiver
-                */
-
-               /* Sleep until all sent */
-               tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_FAST_TIMER
-               /* Now sleep a little more so that shift register is empty */
-               schedule_usleep(info->char_time_usec * 2);
-#endif
-               /* wait on transmit shift register */
-               do{
-                       get_lsr_info(info, &val);
-               }while (!(val & TIOCSER_TEMT));
-
-               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
-
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-               e100_enable_rx(info);
-               e100_enable_rxdma_irq(info);
-#endif
-       }
-#endif /* CONFIG_ETRAX_RS485 */
-
-       return count;
-} /* rs_write */
-
-
-/* how much space is available in the xmit buffer? */
-
-static int
-rs_write_room(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* How many chars are in the xmit buffer?
- * This does not include any chars in the transmitter FIFO.
- * Use wait_until_sent for waiting for FIFO drain.
- */
-
-static int
-rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* discard everything in the xmit buffer */
-
-static void
-rs_flush_buffer(struct tty_struct *tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       info->xmit.head = info->xmit.tail = 0;
-       local_irq_restore(flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- *
- * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
- * but we do it in handle_ser_tx_interrupt().
- * We disable DMA channel and enable tx ready interrupt and write the
- * character when possible.
- */
-static void rs_send_xchar(struct tty_struct *tty, char ch)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-       local_irq_save(flags);
-       if (info->uses_dma_out) {
-               /* Put the DMA on hold and disable the channel */
-               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
-               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
-                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
-               e100_disable_txdma_channel(info);
-       }
-
-       /* Must make sure transmitter is not stopped before we can transmit */
-       if (tty->stopped)
-               rs_start(tty);
-
-       /* Enable manual transmit interrupt and send from there */
-       DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
-       info->x_char = ch;
-       e100_enable_serial_tx_ready_irq(info);
-       local_irq_restore(flags);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-rs_throttle(struct tty_struct * tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("throttle %s: %lu....\n", tty_name(tty, buf),
-              (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-       DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
-
-       /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               /* Turn off RTS line */
-               e100_rts(info, 0);
-       }
-       if (I_IXOFF(tty))
-               rs_send_xchar(tty, STOP_CHAR(tty));
-
-}
-
-static void
-rs_unthrottle(struct tty_struct * tty)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-
-       printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
-              (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
-       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
-       /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               /* Assert RTS line  */
-               e100_rts(info, 1);
-       }
-
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       rs_send_xchar(tty, START_CHAR(tty));
-       }
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int
-get_serial_info(struct e100_serial * info,
-               struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-
-       /* this is all probably wrong, there are a lot of fields
-        * here that we don't have in e100_serial and maybe we
-        * should set them to something else than 0.
-        */
-
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = (int)info->ioport;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int
-set_serial_info(struct e100_serial *info,
-               struct serial_struct *new_info)
-{
-       struct serial_struct new_serial;
-       struct e100_serial old_info;
-       int retval = 0;
-
-       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-               return -EFAULT;
-
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                      (new_serial.flags & ASYNC_FLAGS));
-       info->custom_divisor = new_serial.custom_divisor;
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-       if (info->flags & ASYNC_INITIALIZED) {
-               change_speed(info);
-       } else
-               retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static int
-get_lsr_info(struct e100_serial * info, unsigned int *value)
-{
-       unsigned int result = TIOCSER_TEMT;
-#ifndef CONFIG_SVINTO_SIM
-       unsigned long curr_time = jiffies;
-       unsigned long curr_time_usec = GET_JIFFIES_USEC();
-       unsigned long elapsed_usec =
-               (curr_time - info->last_tx_active) * 1000000/HZ +
-               curr_time_usec - info->last_tx_active_usec;
-
-       if (info->xmit.head != info->xmit.tail ||
-           elapsed_usec < 2*info->char_time_usec) {
-               result = 0;
-       }
-#endif
-
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-       return 0;
-}
-
-#ifdef SERIAL_DEBUG_IO
-struct state_str
-{
-       int state;
-       const char *str;
-};
-
-const struct state_str control_state_str[] = {
-       {TIOCM_DTR, "DTR" },
-       {TIOCM_RTS, "RTS"},
-       {TIOCM_ST, "ST?" },
-       {TIOCM_SR, "SR?" },
-       {TIOCM_CTS, "CTS" },
-       {TIOCM_CD, "CD" },
-       {TIOCM_RI, "RI" },
-       {TIOCM_DSR, "DSR" },
-       {0, NULL }
-};
-
-char *get_control_state_str(int MLines, char *s)
-{
-       int i = 0;
-
-       s[0]='\0';
-       while (control_state_str[i].str != NULL) {
-               if (MLines & control_state_str[i].state) {
-                       if (s[0] != '\0') {
-                               strcat(s, ", ");
-                       }
-                       strcat(s, control_state_str[i].str);
-               }
-               i++;
-       }
-       return s;
-}
-#endif
-
-static int
-rs_break(struct tty_struct *tty, int break_state)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info->ioport)
-               return -EIO;
-
-       local_irq_save(flags);
-       if (break_state == -1) {
-               /* Go to manual mode and set the txd pin to 0 */
-               /* Clear bit 7 (txd) and 6 (tr_enable) */
-               info->tx_ctrl &= 0x3F;
-       } else {
-               /* Set bit 7 (txd) and 6 (tr_enable) */
-               info->tx_ctrl |= (0x80 | 0x40);
-       }
-       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int
-rs_tiocmset(struct tty_struct *tty, struct file *file,
-               unsigned int set, unsigned int clear)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (clear & TIOCM_RTS)
-               e100_rts(info, 0);
-       if (clear & TIOCM_DTR)
-               e100_dtr(info, 0);
-       /* Handle FEMALE behaviour */
-       if (clear & TIOCM_RI)
-               e100_ri_out(info, 0);
-       if (clear & TIOCM_CD)
-               e100_cd_out(info, 0);
-
-       if (set & TIOCM_RTS)
-               e100_rts(info, 1);
-       if (set & TIOCM_DTR)
-               e100_dtr(info, 1);
-       /* Handle FEMALE behaviour */
-       if (set & TIOCM_RI)
-               e100_ri_out(info, 1);
-       if (set & TIOCM_CD)
-               e100_cd_out(info, 1);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int
-rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned int result;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       result =
-               (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
-               | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-               | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
-               | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
-               | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
-               | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-
-       local_irq_restore(flags);
-
-#ifdef SERIAL_DEBUG_IO
-       printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
-               info->line, result, result);
-       {
-               char s[100];
-
-               get_control_state_str(result, s);
-               printk(KERN_DEBUG "state: %s\n", s);
-       }
-#endif
-       return result;
-
-}
-
-
-static int
-rs_ioctl(struct tty_struct *tty, struct file * file,
-        unsigned int cmd, unsigned long arg)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                       return -EIO;
-       }
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return get_serial_info(info,
-                                      (struct serial_struct *) arg);
-       case TIOCSSERIAL:
-               return set_serial_info(info,
-                                      (struct serial_struct *) arg);
-       case TIOCSERGETLSR: /* Get line status register */
-               return get_lsr_info(info, (unsigned int *) arg);
-
-       case TIOCSERGSTRUCT:
-               if (copy_to_user((struct e100_serial *) arg,
-                                info, sizeof(struct e100_serial)))
-                       return -EFAULT;
-               return 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-       case TIOCSERSETRS485:
-       {
-               /* In this ioctl we still use the old structure
-                * rs485_control for backward compatibility
-                * (if we use serial_rs485, then old user-level code
-                * wouldn't work anymore...).
-                * The use of this ioctl is deprecated: use TIOCSRS485
-                * instead.*/
-               struct rs485_control rs485ctrl;
-               struct serial_rs485 rs485data;
-               printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n");
-               if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg,
-                               sizeof(rs485ctrl)))
-                       return -EFAULT;
-
-               rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
-               rs485data.flags = 0;
-               if (rs485data.delay_rts_before_send != 0)
-                       rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
-
-               if (rs485ctrl.enabled)
-                       rs485data.flags |= SER_RS485_ENABLED;
-               else
-                       rs485data.flags &= ~(SER_RS485_ENABLED);
-
-               if (rs485ctrl.rts_on_send)
-                       rs485data.flags |= SER_RS485_RTS_ON_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_ON_SEND);
-
-               if (rs485ctrl.rts_after_sent)
-                       rs485data.flags |= SER_RS485_RTS_AFTER_SEND;
-               else
-                       rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND);
-
-               return e100_enable_rs485(tty, &rs485data);
-       }
-
-       case TIOCSRS485:
-       {
-               /* This is the new version of TIOCSRS485, with new
-                * data structure serial_rs485 */
-               struct serial_rs485 rs485data;
-               if (copy_from_user(&rs485data, (struct rs485_control *)arg,
-                               sizeof(rs485data)))
-                       return -EFAULT;
-
-               return e100_enable_rs485(tty, &rs485data);
-       }
-
-       case TIOCGRS485:
-       {
-               struct serial_rs485 *rs485data =
-                       &(((struct e100_serial *)tty->driver_data)->rs485);
-               /* This is the ioctl to get RS485 data from user-space */
-               if (copy_to_user((struct serial_rs485 *) arg,
-                                       rs485data,
-                                       sizeof(struct serial_rs485)))
-                       return -EFAULT;
-               break;
-       }
-
-       case TIOCSERWRRS485:
-       {
-               struct rs485_write rs485wr;
-               if (copy_from_user(&rs485wr, (struct rs485_write *)arg,
-                               sizeof(rs485wr)))
-                       return -EFAULT;
-
-               return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
-       }
-#endif
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static void
-rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-       change_speed(info);
-
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               rs_start(tty);
-       }
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void
-rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-       unsigned long flags;
-
-       if (!info)
-               return;
-
-       /* interrupts are disabled for this entire function */
-
-       local_irq_save(flags);
-
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
-              info->line, info->count);
-#endif
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_CRIT
-                      "rs_close: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-       /*
-        * Save the termios structure, since this port may have
-        * separate termios for callout and dialin.
-        */
-       if (info->flags & ASYNC_NORMAL_ACTIVE)
-               info->normal_termios = *tty->termios;
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the serial receiver and the DMA receive interrupt.
-        */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-       e100_disable_serial_data_irq(info);
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-       e100_disable_rx(info);
-       e100_disable_rx_irq(info);
-
-       if (info->flags & ASYNC_INITIALIZED) {
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important as we have a transmit FIFO!
-                */
-               rs_wait_until_sent(tty, HZ);
-       }
-#endif
-
-       shutdown(info);
-       rs_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-       if (info->blocked_open) {
-               if (info->close_delay)
-                       schedule_timeout_interruptible(info->close_delay);
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-
-       /* port closed */
-
-#if defined(CONFIG_ETRAX_RS485)
-       if (info->rs485.flags & SER_RS485_ENABLED) {
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-               *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              rs485_port_g_bit, 0);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
-               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-                              CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
-#endif
-       }
-#endif
-
-       /*
-        * Release any allocated DMA irq's.
-        */
-       if (info->dma_in_enabled) {
-               free_irq(info->dma_in_irq_nbr, info);
-               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
-               info->uses_dma_in = 0;
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "DMA irq '%s' freed\n",
-                       info->dma_in_irq_description);
-#endif
-       }
-       if (info->dma_out_enabled) {
-               free_irq(info->dma_out_irq_nbr, info);
-               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
-               info->uses_dma_out = 0;
-#ifdef SERIAL_DEBUG_OPEN
-               printk(KERN_DEBUG "DMA irq '%s' freed\n",
-                       info->dma_out_irq_description);
-#endif
-       }
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       unsigned long orig_jiffies;
-       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-       unsigned long curr_time = jiffies;
-       unsigned long curr_time_usec = GET_JIFFIES_USEC();
-       long elapsed_usec =
-               (curr_time - info->last_tx_active) * (1000000/HZ) +
-               curr_time_usec - info->last_tx_active_usec;
-
-       /*
-        * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
-        * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
-        */
-       orig_jiffies = jiffies;
-       while (info->xmit.head != info->xmit.tail || /* More in send queue */
-              (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
-              (elapsed_usec < 2*info->char_time_usec)) {
-               schedule_timeout_interruptible(1);
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-               curr_time = jiffies;
-               curr_time_usec = GET_JIFFIES_USEC();
-               elapsed_usec =
-                       (curr_time - info->last_tx_active) * (1000000/HZ) +
-                       curr_time_usec - info->last_tx_active_usec;
-       }
-       set_current_state(TASK_RUNNING);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void
-rs_hangup(struct tty_struct *tty)
-{
-       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-       rs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
-               struct e100_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long   flags;
-       int             retval;
-       int             do_clocal = 0, extra_count = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
-                       !(info->flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL) {
-                       do_clocal = 1;
-       }
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       local_irq_save(flags);
-       if (!tty_hung_up_p(filp)) {
-               extra_count++;
-               info->count--;
-       }
-       local_irq_restore(flags);
-       info->blocked_open++;
-       while (1) {
-               local_irq_save(flags);
-               /* assert RTS and DTR */
-               e100_rts(info, 1);
-               e100_dtr(info, 1);
-               local_irq_restore(flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) && do_clocal)
-                       /* && (do_clocal || DCD_IS_ASSERTED) */
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-#endif
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&info->open_wait, &wait);
-       if (extra_count)
-               info->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}
-
-static void
-deinit_port(struct e100_serial *info)
-{
-       if (info->dma_out_enabled) {
-               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
-               free_irq(info->dma_out_irq_nbr, info);
-       }
-       if (info->dma_in_enabled) {
-               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
-               free_irq(info->dma_in_irq_nbr, info);
-       }
-}
-
-/*
- * This routine is called whenever a serial port is opened.
- * It performs the serial-specific initialization for the tty structure.
- */
-static int
-rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct e100_serial      *info;
-       int                     retval, line;
-       unsigned long           page;
-       int                     allocated_resources = 0;
-
-       /* find which port we want to open */
-       line = tty->index;
-
-       if (line < 0 || line >= NR_PORTS)
-               return -ENODEV;
-
-       /* find the corresponding e100_serial struct in the table */
-       info = rs_table + line;
-
-       /* don't allow the opening of ports that are not enabled in the HW config */
-       if (!info->enabled)
-               return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
-        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
-              info->count);
-#endif
-
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-       if (!tmp_buf) {
-               page = get_zeroed_page(GFP_KERNEL);
-               if (!page) {
-                       return -ENOMEM;
-               }
-               if (tmp_buf)
-                       free_page(page);
-               else
-                       tmp_buf = (unsigned char *) page;
-       }
-
-       /*
-        * If the port is in the middle of closing, bail out now
-        */
-       if (tty_hung_up_p(filp) ||
-           (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
-                       !(info->flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               return ((info->flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-#else
-               return -EAGAIN;
-#endif
-       }
-
-       /*
-        * If DMA is enabled try to allocate the irq's.
-        */
-       if (info->count == 1) {
-               allocated_resources = 1;
-               if (info->dma_in_enabled) {
-                       if (request_irq(info->dma_in_irq_nbr,
-                                       rec_interrupt,
-                                       info->dma_in_irq_flags,
-                                       info->dma_in_irq_description,
-                                       info)) {
-                               printk(KERN_WARNING "DMA irq '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_in_irq_description);
-                               /* Make sure we never try to use DMA in */
-                               /* for the port again. */
-                               info->dma_in_enabled = 0;
-                       } else if (cris_request_dma(info->dma_in_nbr,
-                                       info->dma_in_irq_description,
-                                       DMA_VERBOSE_ON_ERROR,
-                                       info->dma_owner)) {
-                               free_irq(info->dma_in_irq_nbr, info);
-                               printk(KERN_WARNING "DMA '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_in_irq_description);
-                               /* Make sure we never try to use DMA in */
-                               /* for the port again. */
-                               info->dma_in_enabled = 0;
-                       }
-#ifdef SERIAL_DEBUG_OPEN
-                       else
-                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
-                                       info->dma_in_irq_description);
-#endif
-               }
-               if (info->dma_out_enabled) {
-                       if (request_irq(info->dma_out_irq_nbr,
-                                              tr_interrupt,
-                                              info->dma_out_irq_flags,
-                                              info->dma_out_irq_description,
-                                              info)) {
-                               printk(KERN_WARNING "DMA irq '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_out_irq_description);
-                               /* Make sure we never try to use DMA out */
-                               /* for the port again. */
-                               info->dma_out_enabled = 0;
-                       } else if (cris_request_dma(info->dma_out_nbr,
-                                            info->dma_out_irq_description,
-                                            DMA_VERBOSE_ON_ERROR,
-                                            info->dma_owner)) {
-                               free_irq(info->dma_out_irq_nbr, info);
-                               printk(KERN_WARNING "DMA '%s' busy; "
-                                       "falling back to non-DMA mode\n",
-                                       info->dma_out_irq_description);
-                               /* Make sure we never try to use DMA out */
-                               /* for the port again. */
-                               info->dma_out_enabled = 0;
-                       }
-#ifdef SERIAL_DEBUG_OPEN
-                       else
-                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
-                                       info->dma_out_irq_description);
-#endif
-               }
-       }
-
-       /*
-        * Start up the serial port
-        */
-
-       retval = startup(info);
-       if (retval) {
-               if (allocated_resources)
-                       deinit_port(info);
-
-               /* FIXME Decrease count info->count here too? */
-               return retval;
-       }
-
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               if (allocated_resources)
-                       deinit_port(info);
-
-               return retval;
-       }
-
-       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-               *tty->termios = info->normal_termios;
-               change_speed(info);
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open ttyS%d successful...\n", info->line);
-#endif
-       DLOG_INT_TRIG( log_int_pos = 0);
-
-       DFLIP(  if (info->line == SERIAL_DEBUG_LINE) {
-                       info->icount.rx = 0;
-               } );
-
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- * /proc fs routines....
- */
-
-static void seq_line_info(struct seq_file *m, struct e100_serial *info)
-{
-       unsigned long tmp;
-
-       seq_printf(m, "%d: uart:E100 port:%lX irq:%d",
-                  info->line, (unsigned long)info->ioport, info->irq);
-
-       if (!info->ioport || (info->type == PORT_UNKNOWN)) {
-               seq_printf(m, "\n");
-               return;
-       }
-
-       seq_printf(m, " baud:%d", info->baud);
-       seq_printf(m, " tx:%lu rx:%lu",
-                      (unsigned long)info->icount.tx,
-                      (unsigned long)info->icount.rx);
-       tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-       if (tmp)
-               seq_printf(m, " tx_pend:%lu/%lu",
-                          (unsigned long)tmp,
-                          (unsigned long)SERIAL_XMIT_SIZE);
-
-       seq_printf(m, " rx_pend:%lu/%lu",
-                  (unsigned long)info->recv_cnt,
-                  (unsigned long)info->max_recv_cnt);
-
-#if 1
-       if (info->port.tty) {
-               if (info->port.tty->stopped)
-                       seq_printf(m, " stopped:%i",
-                                  (int)info->port.tty->stopped);
-               if (info->port.tty->hw_stopped)
-                       seq_printf(m, " hw_stopped:%i",
-                                  (int)info->port.tty->hw_stopped);
-       }
-
-       {
-               unsigned char rstat = info->ioport[REG_STATUS];
-               if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect))
-                       seq_printf(m, " xoff_detect:1");
-       }
-
-#endif
-
-       if (info->icount.frame)
-               seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame);
-
-       if (info->icount.parity)
-               seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity);
-
-       if (info->icount.brk)
-               seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk);
-
-       if (info->icount.overrun)
-               seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun);
-
-       /*
-        * Last thing is the RS-232 status lines
-        */
-       if (!E100_RTS_GET(info))
-               seq_puts(m, "|RTS");
-       if (!E100_CTS_GET(info))
-               seq_puts(m, "|CTS");
-       if (!E100_DTR_GET(info))
-               seq_puts(m, "|DTR");
-       if (!E100_DSR_GET(info))
-               seq_puts(m, "|DSR");
-       if (!E100_CD_GET(info))
-               seq_puts(m, "|CD");
-       if (!E100_RI_GET(info))
-               seq_puts(m, "|RI");
-       seq_puts(m, "\n");
-}
-
-
-static int crisv10_proc_show(struct seq_file *m, void *v)
-{
-       int i;
-
-       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
-
-       for (i = 0; i < NR_PORTS; i++) {
-               if (!rs_table[i].enabled)
-                       continue;
-               seq_line_info(m, &rs_table[i]);
-       }
-#ifdef DEBUG_LOG_INCLUDED
-       for (i = 0; i < debug_log_pos; i++) {
-               seq_printf(m, "%-4i %lu.%lu ",
-                        i, debug_log[i].time,
-                        timer_data_to_ns(debug_log[i].timer_data));
-               seq_printf(m, debug_log[i].string, debug_log[i].value);
-       }
-       seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE);
-       debug_log_pos = 0;
-#endif
-       return 0;
-}
-
-static int crisv10_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, crisv10_proc_show, NULL);
-}
-
-static const struct file_operations crisv10_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = crisv10_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk(KERN_INFO
-              "ETRAX 100LX serial-driver %s, "
-              "(c) 2000-2004 Axis Communications AB\r\n",
-              &serial_version[11]); /* "$Revision: x.yy" */
-}
-
-/* rs_init inits the driver at boot (using the module_init chain) */
-
-static const struct tty_operations rs_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-        .unthrottle = rs_unthrottle,
-       .set_termios = rs_set_termios,
-       .stop = rs_stop,
-       .start = rs_start,
-       .hangup = rs_hangup,
-       .break_ctl = rs_break,
-       .send_xchar = rs_send_xchar,
-       .wait_until_sent = rs_wait_until_sent,
-       .tiocmget = rs_tiocmget,
-       .tiocmset = rs_tiocmset,
-#ifdef CONFIG_PROC_FS
-       .proc_fops = &crisv10_proc_fops,
-#endif
-};
-
-static int __init rs_init(void)
-{
-       int i;
-       struct e100_serial *info;
-       struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
-
-       if (!driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Setup the timed flush handler system */
-
-#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
-       setup_timer(&flush_timer, timed_flush_handler, 0);
-       mod_timer(&flush_timer, jiffies + 5);
-#endif
-
-#if defined(CONFIG_ETRAX_RS485)
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-       if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
-                       rs485_pa_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
-                       "RS485 pin\n");
-               put_tty_driver(driver);
-               return -EBUSY;
-       }
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-       if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
-                       rs485_port_g_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
-                       "RS485 pin\n");
-               put_tty_driver(driver);
-               return -EBUSY;
-       }
-#endif
-#endif
-
-       /* Initialize the tty_driver structure */
-
-       driver->driver_name = "serial";
-       driver->name = "ttyS";
-       driver->major = TTY_MAJOR;
-       driver->minor_start = 64;
-       driver->type = TTY_DRIVER_TYPE_SERIAL;
-       driver->subtype = SERIAL_TYPE_NORMAL;
-       driver->init_termios = tty_std_termios;
-       driver->init_termios.c_cflag =
-               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-       driver->init_termios.c_ispeed = 115200;
-       driver->init_termios.c_ospeed = 115200;
-       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-
-       tty_set_operations(driver, &rs_ops);
-        serial_driver = driver;
-       if (tty_register_driver(driver))
-               panic("Couldn't register serial driver\n");
-       /* do some initializing for the separate ports */
-
-       for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
-               if (info->enabled) {
-                       if (cris_request_io_interface(info->io_if,
-                                       info->io_if_description)) {
-                               printk(KERN_CRIT "ETRAX100LX async serial: "
-                                       "Could not allocate IO pins for "
-                                       "%s, port %d\n",
-                                       info->io_if_description, i);
-                               info->enabled = 0;
-                       }
-               }
-               info->uses_dma_in = 0;
-               info->uses_dma_out = 0;
-               info->line = i;
-               info->port.tty = NULL;
-               info->type = PORT_ETRAX;
-               info->tr_running = 0;
-               info->forced_eop = 0;
-               info->baud_base = DEF_BAUD_BASE;
-               info->custom_divisor = 0;
-               info->flags = 0;
-               info->close_delay = 5*HZ/10;
-               info->closing_wait = 30*HZ;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               info->normal_termios = driver->init_termios;
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-               info->xmit.buf = NULL;
-               info->xmit.tail = info->xmit.head = 0;
-               info->first_recv_buffer = info->last_recv_buffer = NULL;
-               info->recv_cnt = info->max_recv_cnt = 0;
-               info->last_tx_active_usec = 0;
-               info->last_tx_active = 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-               /* Set sane defaults */
-               info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
-               info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
-               info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
-               info->rs485.delay_rts_before_send = 0;
-               info->rs485.flags &= ~(SER_RS485_ENABLED);
-#endif
-               INIT_WORK(&info->work, do_softint);
-
-               if (info->enabled) {
-                       printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
-                              serial_driver->name, info->line, info->ioport);
-               }
-       }
-#ifdef CONFIG_ETRAX_FAST_TIMER
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-       memset(fast_timers, 0, sizeof(fast_timers));
-#endif
-#ifdef CONFIG_ETRAX_RS485
-       memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
-#endif
-       fast_timer_init();
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-#ifndef CONFIG_ETRAX_KGDB
-       /* Not needed in simulator.  May only complicate stuff. */
-       /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
-
-       if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
-               panic("%s: Failed to request irq8", __func__);
-
-#endif
-#endif /* CONFIG_SVINTO_SIM */
-
-       return 0;
-}
-
-/* this makes sure that rs_init is called during kernel boot */
-
-module_init(rs_init);
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
deleted file mode 100644 (file)
index ea0beb4..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * serial.h: Arch-dep definitions for the Etrax100 serial driver.
- *
- * Copyright (C) 1998-2007 Axis Communications AB
- */
-
-#ifndef _ETRAX_SERIAL_H
-#define _ETRAX_SERIAL_H
-
-#include <linux/circ_buf.h>
-#include <asm/termios.h>
-#include <asm/dma.h>
-#include <arch/io_interface_mux.h>
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#define SERIAL_RECV_DESCRIPTORS 8
-
-struct etrax_recv_buffer {
-       struct etrax_recv_buffer *next;
-       unsigned short length;
-       unsigned char error;
-       unsigned char pad;
-
-       unsigned char buffer[0];
-};
-
-struct e100_serial {
-       struct tty_port port;
-       int baud;
-       volatile u8     *ioport;        /* R_SERIALx_CTRL */
-       u32             irq;    /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
-       /* Output registers */
-       volatile u8 *oclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
-       volatile u32 *ofirstadr;        /* adr to R_DMA_CHx_FIRST */
-       volatile u8 *ocmdadr;           /* adr to R_DMA_CHx_CMD */
-       const volatile u8 *ostatusadr;  /* adr to R_DMA_CHx_STATUS */
-
-       /* Input registers */
-       volatile u8 *iclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
-       volatile u32 *ifirstadr;        /* adr to R_DMA_CHx_FIRST */
-       volatile u8 *icmdadr;           /* adr to R_DMA_CHx_CMD */
-       volatile u32 *idescradr;        /* adr to R_DMA_CHx_DESCR */
-
-       int flags;      /* defined in tty.h */
-
-       u8 rx_ctrl;     /* shadow for R_SERIALx_REC_CTRL */
-       u8 tx_ctrl;     /* shadow for R_SERIALx_TR_CTRL */
-       u8 iseteop;     /* bit number for R_SET_EOP for the input dma */
-       int enabled;    /* Set to 1 if the port is enabled in HW config */
-
-       u8 dma_out_enabled;     /* Set to 1 if DMA should be used */
-       u8 dma_in_enabled;      /* Set to 1 if DMA should be used */
-
-       /* end of fields defined in rs_table[] in .c-file */
-       int             dma_owner;
-       unsigned int    dma_in_nbr;
-       unsigned int    dma_out_nbr;
-       unsigned int    dma_in_irq_nbr;
-       unsigned int    dma_out_irq_nbr;
-       unsigned long   dma_in_irq_flags;
-       unsigned long   dma_out_irq_flags;
-       char            *dma_in_irq_description;
-       char            *dma_out_irq_description;
-
-       enum cris_io_interface io_if;
-       char            *io_if_description;
-
-       u8              uses_dma_in;  /* Set to 1 if DMA is used */
-       u8              uses_dma_out; /* Set to 1 if DMA is used */
-       u8              forced_eop;   /* a fifo eop has been forced */
-       int                     baud_base;     /* For special baudrates */
-       int                     custom_divisor; /* For special baudrates */
-       struct etrax_dma_descr  tr_descr;
-       struct etrax_dma_descr  rec_descr[SERIAL_RECV_DESCRIPTORS];
-       int                     cur_rec_descr;
-
-       volatile int            tr_running; /* 1 if output is running */
-
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     type;  /* PORT_ETRAX */
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       struct circ_buf         xmit;
-       struct etrax_recv_buffer *first_recv_buffer;
-       struct etrax_recv_buffer *last_recv_buffer;
-       unsigned int            recv_cnt;
-       unsigned int            max_recv_cnt;
-
-       struct work_struct      work;
-       struct async_icount     icount;   /* error-statistics etc.*/
-       struct ktermios         normal_termios;
-       struct ktermios         callout_termios;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
-       unsigned long char_time_usec;       /* The time for 1 char, in usecs */
-       unsigned long flush_time_usec;      /* How often we should flush */
-       unsigned long last_tx_active_usec;  /* Last tx usec in the jiffies */
-       unsigned long last_tx_active;       /* Last tx time in jiffies */
-       unsigned long last_rx_active_usec;  /* Last rx usec in the jiffies */
-       unsigned long last_rx_active;       /* Last rx time in jiffies */
-
-       int break_detected_cnt;
-       int errorcode;
-
-#ifdef CONFIG_ETRAX_RS485
-       struct serial_rs485     rs485;  /* RS-485 support */
-#endif
-};
-
-/* this PORT is not in the standard serial.h. it's not actually used for
- * anything since we only have one type of async serial-port anyway in this
- * system.
- */
-
-#define PORT_ETRAX 1
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-#endif /* __KERNEL__ */
-
-#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
deleted file mode 100644 (file)
index 57421d7..0000000
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * dz.c: Serial port driver for DECstations equipped
- *       with the DZ chipset.
- *
- * Copyright (C) 1998 Olivier A. D. Lebaillif
- *
- * Email: olivier.lebaillif@ifrsys.com
- *
- * Copyright (C) 2004, 2006, 2007  Maciej W. Rozycki
- *
- * [31-AUG-98] triemer
- * Changed IRQ to use Harald's dec internals interrupts.h
- * removed base_addr code - moving address assignment to setup.c
- * Changed name of dz_init to rs_init to be consistent with tc code
- * [13-NOV-98] triemer fixed code to receive characters
- *    after patches by harald to irq code.
- * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
- *            field from "current" - somewhere between 2.1.121 and 2.1.131
- Qua Jun 27 15:02:26 BRT 2001
- * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
- *
- * Parts (C) 1999 David Airlie, airlied@linux.ie
- * [07-SEP-99] Bugfixes
- *
- * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
- * Converted to new serial core
- */
-
-#undef DEBUG_DZ
-
-#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-
-#include <asm/atomic.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/kn01.h>
-#include <asm/dec/kn02.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/system.h>
-
-#include "dz.h"
-
-
-MODULE_DESCRIPTION("DECstation DZ serial driver");
-MODULE_LICENSE("GPL");
-
-
-static char dz_name[] __initdata = "DECstation DZ serial driver version ";
-static char dz_version[] __initdata = "1.04";
-
-struct dz_port {
-       struct dz_mux           *mux;
-       struct uart_port        port;
-       unsigned int            cflag;
-};
-
-struct dz_mux {
-       struct dz_port          dport[DZ_NB_PORT];
-       atomic_t                map_guard;
-       atomic_t                irq_guard;
-       int                     initialised;
-};
-
-static struct dz_mux dz_mux;
-
-static inline struct dz_port *to_dport(struct uart_port *uport)
-{
-       return container_of(uport, struct dz_port, port);
-}
-
-/*
- * ------------------------------------------------------------
- * dz_in () and dz_out ()
- *
- * These routines are used to access the registers of the DZ
- * chip, hiding relocation differences between implementation.
- * ------------------------------------------------------------
- */
-
-static u16 dz_in(struct dz_port *dport, unsigned offset)
-{
-       void __iomem *addr = dport->port.membase + offset;
-
-       return readw(addr);
-}
-
-static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
-{
-       void __iomem *addr = dport->port.membase + offset;
-
-       writew(value, addr);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop () and rs_start ()
- *
- * These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
- * as necessary.
- * ------------------------------------------------------------
- */
-
-static void dz_stop_tx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
-       tmp &= ~mask;                   /* clear the TX flag */
-       dz_out(dport, DZ_TCR, tmp);
-}
-
-static void dz_start_tx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
-       tmp |= mask;                    /* set the TX flag */
-       dz_out(dport, DZ_TCR, tmp);
-}
-
-static void dz_stop_rx(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-
-       dport->cflag &= ~DZ_RXENAB;
-       dz_out(dport, DZ_LPR, dport->cflag);
-}
-
-static void dz_enable_ms(struct uart_port *uport)
-{
-       /* nothing to do */
-}
-
-/*
- * ------------------------------------------------------------
- *
- * Here start the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * dz_interrupt.  They were separated out for readability's sake.
- *
- * Note: dz_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * dz_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- *
- *     make drivers/serial/dz.s
- *
- * and look at the resulting assemble code in dz.s.
- *
- * ------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * receive_char ()
- *
- * This routine deals with inputs from any lines.
- * ------------------------------------------------------------
- */
-static inline void dz_receive_chars(struct dz_mux *mux)
-{
-       struct uart_port *uport;
-       struct dz_port *dport = &mux->dport[0];
-       struct tty_struct *tty = NULL;
-       struct uart_icount *icount;
-       int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
-       unsigned char ch, flag;
-       u16 status;
-       int i;
-
-       while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
-               dport = &mux->dport[LINE(status)];
-               uport = &dport->port;
-               tty = uport->state->port.tty;   /* point to the proper dev */
-
-               ch = UCHAR(status);             /* grab the char */
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
-
-                       /*
-                        * There is no separate BREAK status bit, so treat
-                        * null characters with framing errors as BREAKs;
-                        * normally, otherwise.  For this move the Framing
-                        * Error bit to a simulated BREAK bit.
-                        */
-                       if (!ch) {
-                               status |= (status & DZ_FERR) >>
-                                         (ffs(DZ_FERR) - ffs(DZ_BREAK));
-                               status &= ~DZ_FERR;
-                       }
-
-                       /* Handle SysRq/SAK & keep track of the statistics. */
-                       if (status & DZ_BREAK) {
-                               icount->brk++;
-                               if (uart_handle_break(uport))
-                                       continue;
-                       } else if (status & DZ_FERR)
-                               icount->frame++;
-                       else if (status & DZ_PERR)
-                               icount->parity++;
-                       if (status & DZ_OERR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & DZ_BREAK)
-                               flag = TTY_BREAK;
-                       else if (status & DZ_FERR)
-                               flag = TTY_FRAME;
-                       else if (status & DZ_PERR)
-                               flag = TTY_PARITY;
-
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, DZ_OERR, ch, flag);
-               lines_rx[LINE(status)] = 1;
-       }
-       for (i = 0; i < DZ_NB_PORT; i++)
-               if (lines_rx[i])
-                       tty_flip_buffer_push(mux->dport[i].port.state->port.tty);
-}
-
-/*
- * ------------------------------------------------------------
- * transmit_char ()
- *
- * This routine deals with outputs to any lines.
- * ------------------------------------------------------------
- */
-static inline void dz_transmit_chars(struct dz_mux *mux)
-{
-       struct dz_port *dport = &mux->dport[0];
-       struct circ_buf *xmit;
-       unsigned char tmp;
-       u16 status;
-
-       status = dz_in(dport, DZ_CSR);
-       dport = &mux->dport[LINE(status)];
-       xmit = &dport->port.state->xmit;
-
-       if (dport->port.x_char) {               /* XON/XOFF chars */
-               dz_out(dport, DZ_TDR, dport->port.x_char);
-               dport->port.icount.tx++;
-               dport->port.x_char = 0;
-               return;
-       }
-       /* If nothing to do or stopped or hardware stopped. */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
-               spin_lock(&dport->port.lock);
-               dz_stop_tx(&dport->port);
-               spin_unlock(&dport->port.lock);
-               return;
-       }
-
-       /*
-        * If something to do... (remember the dz has no output fifo,
-        * so we go one char at a time) :-<
-        */
-       tmp = xmit->buf[xmit->tail];
-       xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
-       dz_out(dport, DZ_TDR, tmp);
-       dport->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
-               uart_write_wakeup(&dport->port);
-
-       /* Are we are done. */
-       if (uart_circ_empty(xmit)) {
-               spin_lock(&dport->port.lock);
-               dz_stop_tx(&dport->port);
-               spin_unlock(&dport->port.lock);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * check_modem_status()
- *
- * DS 3100 & 5100: Only valid for the MODEM line, duh!
- * DS 5000/200: Valid for the MODEM and PRINTER line.
- * ------------------------------------------------------------
- */
-static inline void check_modem_status(struct dz_port *dport)
-{
-       /*
-        * FIXME:
-        * 1. No status change interrupt; use a timer.
-        * 2. Handle the 3100/5000 as appropriate. --macro
-        */
-       u16 status;
-
-       /* If not the modem line just return.  */
-       if (dport->port.line != DZ_MODEM)
-               return;
-
-       status = dz_in(dport, DZ_MSR);
-
-       /* it's easy, since DSR2 is the only bit in the register */
-       if (status)
-               dport->port.icount.dsr++;
-}
-
-/*
- * ------------------------------------------------------------
- * dz_interrupt ()
- *
- * this is the main interrupt routine for the DZ chip.
- * It deals with the multiple ports.
- * ------------------------------------------------------------
- */
-static irqreturn_t dz_interrupt(int irq, void *dev_id)
-{
-       struct dz_mux *mux = dev_id;
-       struct dz_port *dport = &mux->dport[0];
-       u16 status;
-
-       /* get the reason why we just got an irq */
-       status = dz_in(dport, DZ_CSR);
-
-       if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
-               dz_receive_chars(mux);
-
-       if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
-               dz_transmit_chars(mux);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the DZ interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static unsigned int dz_get_mctrl(struct uart_port *uport)
-{
-       /*
-        * FIXME: Handle the 3100/5000 as appropriate. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-
-       if (dport->port.line == DZ_MODEM) {
-               if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
-                       mctrl &= ~TIOCM_DSR;
-       }
-
-       return mctrl;
-}
-
-static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       /*
-        * FIXME: Handle the 3100/5000 as appropriate. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       u16 tmp;
-
-       if (dport->port.line == DZ_MODEM) {
-               tmp = dz_in(dport, DZ_TCR);
-               if (mctrl & TIOCM_DTR)
-                       tmp &= ~DZ_MODEM_DTR;
-               else
-                       tmp |= DZ_MODEM_DTR;
-               dz_out(dport, DZ_TCR, tmp);
-       }
-}
-
-/*
- * -------------------------------------------------------------------
- * startup ()
- *
- * various initialization tasks
- * -------------------------------------------------------------------
- */
-static int dz_startup(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       struct dz_mux *mux = dport->mux;
-       unsigned long flags;
-       int irq_guard;
-       int ret;
-       u16 tmp;
-
-       irq_guard = atomic_add_return(1, &mux->irq_guard);
-       if (irq_guard != 1)
-               return 0;
-
-       ret = request_irq(dport->port.irq, dz_interrupt,
-                         IRQF_SHARED, "dz", mux);
-       if (ret) {
-               atomic_add(-1, &mux->irq_guard);
-               printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
-               return ret;
-       }
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-
-       /* Enable interrupts.  */
-       tmp = dz_in(dport, DZ_CSR);
-       tmp |= DZ_RIE | DZ_TIE;
-       dz_out(dport, DZ_CSR, tmp);
-
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       return 0;
-}
-
-/*
- * -------------------------------------------------------------------
- * shutdown ()
- *
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- * -------------------------------------------------------------------
- */
-static void dz_shutdown(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       struct dz_mux *mux = dport->mux;
-       unsigned long flags;
-       int irq_guard;
-       u16 tmp;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       dz_stop_tx(&dport->port);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       irq_guard = atomic_add_return(-1, &mux->irq_guard);
-       if (!irq_guard) {
-               /* Disable interrupts.  */
-               tmp = dz_in(dport, DZ_CSR);
-               tmp &= ~(DZ_RIE | DZ_TIE);
-               dz_out(dport, DZ_CSR, tmp);
-
-               free_irq(dport->port.irq, mux);
-       }
-}
-
-/*
- * -------------------------------------------------------------------
- * dz_tx_empty() -- get the transmitter empty status
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *          is emptied.  On bus types like RS485, the transmitter must
- *          release the bus after transmitting. This must be done when
- *          the transmit shift register is empty, not be done when the
- *          transmit holding register is empty.  This functionality
- *          allows an RS485 driver to be written in user space.
- * -------------------------------------------------------------------
- */
-static unsigned int dz_tx_empty(struct uart_port *uport)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned short tmp, mask = 1 << dport->port.line;
-
-       tmp = dz_in(dport, DZ_TCR);
-       tmp &= mask;
-
-       return tmp ? 0 : TIOCSER_TEMT;
-}
-
-static void dz_break_ctl(struct uart_port *uport, int break_state)
-{
-       /*
-        * FIXME: Can't access BREAK bits in TDR easily;
-        * reuse the code for polled TX. --macro
-        */
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned short tmp, mask = 1 << dport->port.line;
-
-       spin_lock_irqsave(&uport->lock, flags);
-       tmp = dz_in(dport, DZ_TCR);
-       if (break_state)
-               tmp |= mask;
-       else
-               tmp &= ~mask;
-       dz_out(dport, DZ_TCR, tmp);
-       spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-static int dz_encode_baud_rate(unsigned int baud)
-{
-       switch (baud) {
-       case 50:
-               return DZ_B50;
-       case 75:
-               return DZ_B75;
-       case 110:
-               return DZ_B110;
-       case 134:
-               return DZ_B134;
-       case 150:
-               return DZ_B150;
-       case 300:
-               return DZ_B300;
-       case 600:
-               return DZ_B600;
-       case 1200:
-               return DZ_B1200;
-       case 1800:
-               return DZ_B1800;
-       case 2000:
-               return DZ_B2000;
-       case 2400:
-               return DZ_B2400;
-       case 3600:
-               return DZ_B3600;
-       case 4800:
-               return DZ_B4800;
-       case 7200:
-               return DZ_B7200;
-       case 9600:
-               return DZ_B9600;
-       default:
-               return -1;
-       }
-}
-
-
-static void dz_reset(struct dz_port *dport)
-{
-       struct dz_mux *mux = dport->mux;
-
-       if (mux->initialised)
-               return;
-
-       dz_out(dport, DZ_CSR, DZ_CLR);
-       while (dz_in(dport, DZ_CSR) & DZ_CLR);
-       iob();
-
-       /* Enable scanning.  */
-       dz_out(dport, DZ_CSR, DZ_MSE);
-
-       mux->initialised = 1;
-}
-
-static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
-                          struct ktermios *old_termios)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned int cflag, baud;
-       int bflag;
-
-       cflag = dport->port.line;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cflag |= DZ_CS5;
-               break;
-       case CS6:
-               cflag |= DZ_CS6;
-               break;
-       case CS7:
-               cflag |= DZ_CS7;
-               break;
-       case CS8:
-       default:
-               cflag |= DZ_CS8;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cflag |= DZ_CSTOPB;
-       if (termios->c_cflag & PARENB)
-               cflag |= DZ_PARENB;
-       if (termios->c_cflag & PARODD)
-               cflag |= DZ_PARODD;
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
-       bflag = dz_encode_baud_rate(baud);
-       if (bflag < 0)  {                       /* Try to keep unchanged.  */
-               baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600);
-               bflag = dz_encode_baud_rate(baud);
-               if (bflag < 0)  {               /* Resort to 9600.  */
-                       baud = 9600;
-                       bflag = DZ_B9600;
-               }
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-       cflag |= bflag;
-
-       if (termios->c_cflag & CREAD)
-               cflag |= DZ_RXENAB;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       dz_out(dport, DZ_LPR, cflag);
-       dport->cflag = cflag;
-
-       /* setup accept flag */
-       dport->port.read_status_mask = DZ_OERR;
-       if (termios->c_iflag & INPCK)
-               dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               dport->port.read_status_mask |= DZ_BREAK;
-
-       /* characters to ignore */
-       uport->ignore_status_mask = 0;
-       if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
-               dport->port.ignore_status_mask |= DZ_OERR;
-       if (termios->c_iflag & IGNPAR)
-               dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
-       if (termios->c_iflag & IGNBRK)
-               dport->port.ignore_status_mask |= DZ_BREAK;
-
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-}
-
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void dz_pm(struct uart_port *uport, unsigned int state,
-                 unsigned int oldstate)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       if (state < 3)
-               dz_start_tx(&dport->port);
-       else
-               dz_stop_tx(&dport->port);
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-}
-
-
-static const char *dz_type(struct uart_port *uport)
-{
-       return "DZ";
-}
-
-static void dz_release_port(struct uart_port *uport)
-{
-       struct dz_mux *mux = to_dport(uport)->mux;
-       int map_guard;
-
-       iounmap(uport->membase);
-       uport->membase = NULL;
-
-       map_guard = atomic_add_return(-1, &mux->map_guard);
-       if (!map_guard)
-               release_mem_region(uport->mapbase, dec_kn_slot_size);
-}
-
-static int dz_map_port(struct uart_port *uport)
-{
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                dec_kn_slot_size);
-       if (!uport->membase) {
-               printk(KERN_ERR "dz: Cannot map MMIO\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static int dz_request_port(struct uart_port *uport)
-{
-       struct dz_mux *mux = to_dport(uport)->mux;
-       int map_guard;
-       int ret;
-
-       map_guard = atomic_add_return(1, &mux->map_guard);
-       if (map_guard == 1) {
-               if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
-                                       "dz")) {
-                       atomic_add(-1, &mux->map_guard);
-                       printk(KERN_ERR
-                              "dz: Unable to reserve MMIO resource\n");
-                       return -EBUSY;
-               }
-       }
-       ret = dz_map_port(uport);
-       if (ret) {
-               map_guard = atomic_add_return(-1, &mux->map_guard);
-               if (!map_guard)
-                       release_mem_region(uport->mapbase, dec_kn_slot_size);
-               return ret;
-       }
-       return 0;
-}
-
-static void dz_config_port(struct uart_port *uport, int flags)
-{
-       struct dz_port *dport = to_dport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (dz_request_port(uport))
-                       return;
-
-               uport->type = PORT_DZ;
-
-               dz_reset(dport);
-       }
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops dz_ops = {
-       .tx_empty       = dz_tx_empty,
-       .get_mctrl      = dz_get_mctrl,
-       .set_mctrl      = dz_set_mctrl,
-       .stop_tx        = dz_stop_tx,
-       .start_tx       = dz_start_tx,
-       .stop_rx        = dz_stop_rx,
-       .enable_ms      = dz_enable_ms,
-       .break_ctl      = dz_break_ctl,
-       .startup        = dz_startup,
-       .shutdown       = dz_shutdown,
-       .set_termios    = dz_set_termios,
-       .pm             = dz_pm,
-       .type           = dz_type,
-       .release_port   = dz_release_port,
-       .request_port   = dz_request_port,
-       .config_port    = dz_config_port,
-       .verify_port    = dz_verify_port,
-};
-
-static void __init dz_init_ports(void)
-{
-       static int first = 1;
-       unsigned long base;
-       int line;
-
-       if (!first)
-               return;
-       first = 0;
-
-       if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
-               base = dec_kn_slot_base + KN01_DZ11;
-       else
-               base = dec_kn_slot_base + KN02_DZ11;
-
-       for (line = 0; line < DZ_NB_PORT; line++) {
-               struct dz_port *dport = &dz_mux.dport[line];
-               struct uart_port *uport = &dport->port;
-
-               dport->mux      = &dz_mux;
-
-               uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
-               uport->fifosize = 1;
-               uport->iotype   = UPIO_MEM;
-               uport->flags    = UPF_BOOT_AUTOCONF;
-               uport->ops      = &dz_ops;
-               uport->line     = line;
-               uport->mapbase  = base;
-       }
-}
-
-#ifdef CONFIG_SERIAL_DZ_CONSOLE
-/*
- * -------------------------------------------------------------------
- * dz_console_putchar() -- transmit a character
- *
- * Polled transmission.  This is tricky.  We need to mask transmit
- * interrupts so that they do not interfere, enable the transmitter
- * for the line requested and then wait till the transmit scanner
- * requests data for this line.  But it may request data for another
- * line first, in which case we have to disable its transmitter and
- * repeat waiting till our line pops up.  Only then the character may
- * be transmitted.  Finally, the state of the transmitter mask is
- * restored.  Welcome to the world of PDP-11!
- * -------------------------------------------------------------------
- */
-static void dz_console_putchar(struct uart_port *uport, int ch)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-       unsigned short csr, tcr, trdy, mask;
-       int loops = 10000;
-
-       spin_lock_irqsave(&dport->port.lock, flags);
-       csr = dz_in(dport, DZ_CSR);
-       dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
-       tcr = dz_in(dport, DZ_TCR);
-       tcr |= 1 << dport->port.line;
-       mask = tcr;
-       dz_out(dport, DZ_TCR, mask);
-       iob();
-       spin_unlock_irqrestore(&dport->port.lock, flags);
-
-       do {
-               trdy = dz_in(dport, DZ_CSR);
-               if (!(trdy & DZ_TRDY))
-                       continue;
-               trdy = (trdy & DZ_TLINE) >> 8;
-               if (trdy == dport->port.line)
-                       break;
-               mask &= ~(1 << trdy);
-               dz_out(dport, DZ_TCR, mask);
-               iob();
-               udelay(2);
-       } while (--loops);
-
-       if (loops)                              /* Cannot send otherwise. */
-               dz_out(dport, DZ_TDR, ch);
-
-       dz_out(dport, DZ_TCR, tcr);
-       dz_out(dport, DZ_CSR, csr);
-}
-
-/*
- * -------------------------------------------------------------------
- * dz_console_print ()
- *
- * dz_console_print is registered for printk.
- * The console must be locked when we get here.
- * -------------------------------------------------------------------
- */
-static void dz_console_print(struct console *co,
-                            const char *str,
-                            unsigned int count)
-{
-       struct dz_port *dport = &dz_mux.dport[co->index];
-#ifdef DEBUG_DZ
-       prom_printf((char *) str);
-#endif
-       uart_console_write(&dport->port, str, count, dz_console_putchar);
-}
-
-static int __init dz_console_setup(struct console *co, char *options)
-{
-       struct dz_port *dport = &dz_mux.dport[co->index];
-       struct uart_port *uport = &dport->port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       ret = dz_map_port(uport);
-       if (ret)
-               return ret;
-
-       spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
-
-       dz_reset(dport);
-       dz_pm(uport, 0, -1);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&dport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver dz_reg;
-static struct console dz_console = {
-       .name   = "ttyS",
-       .write  = dz_console_print,
-       .device = uart_console_device,
-       .setup  = dz_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &dz_reg,
-};
-
-static int __init dz_serial_console_init(void)
-{
-       if (!IOASIC) {
-               dz_init_ports();
-               register_console(&dz_console);
-               return 0;
-       } else
-               return -ENXIO;
-}
-
-console_initcall(dz_serial_console_init);
-
-#define SERIAL_DZ_CONSOLE      &dz_console
-#else
-#define SERIAL_DZ_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_DZ_CONSOLE */
-
-static struct uart_driver dz_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = DZ_NB_PORT,
-       .cons                   = SERIAL_DZ_CONSOLE,
-};
-
-static int __init dz_init(void)
-{
-       int ret, i;
-
-       if (IOASIC)
-               return -ENXIO;
-
-       printk("%s%s\n", dz_name, dz_version);
-
-       dz_init_ports();
-
-       ret = uart_register_driver(&dz_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < DZ_NB_PORT; i++)
-               uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
-
-       return 0;
-}
-
-module_init(dz_init);
diff --git a/drivers/serial/dz.h b/drivers/serial/dz.h
deleted file mode 100644 (file)
index faf169e..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * dz.h: Serial port driver for DECstations equipped
- *       with the DZ chipset.
- *
- * Copyright (C) 1998 Olivier A. D. Lebaillif 
- *             
- * Email: olivier.lebaillif@ifrsys.com
- *
- * Copyright (C) 2004, 2006  Maciej W. Rozycki
- */
-#ifndef DZ_SERIAL_H
-#define DZ_SERIAL_H
-
-/*
- * Definitions for the Control and Status Register.
- */
-#define DZ_TRDY        0x8000                 /* Transmitter empty */
-#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enbl */
-#define DZ_TLINE       0x0300                 /* Transmitter Line Number */
-#define DZ_RDONE       0x0080                 /* Receiver data ready */
-#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
-#define DZ_MSE         0x0020                 /* Master Scan Enable */
-#define DZ_CLR         0x0010                 /* Master reset */
-#define DZ_MAINT       0x0008                 /* Loop Back Mode */
-
-/*
- * Definitions for the Receiver Buffer Register.
- */
-#define DZ_RBUF_MASK   0x00FF                 /* Data Mask */
-#define DZ_LINE_MASK   0x0300                 /* Line Mask */
-#define DZ_DVAL        0x8000                 /* Valid Data indicator */
-#define DZ_OERR        0x4000                 /* Overrun error indicator */
-#define DZ_FERR        0x2000                 /* Frame error indicator */
-#define DZ_PERR        0x1000                 /* Parity error indicator */
-
-#define DZ_BREAK       0x0800                 /* BREAK event software flag */
-
-#define LINE(x) ((x & DZ_LINE_MASK) >> 8)     /* Get the line number
-                                                 from the input buffer */
-#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
-
-/*
- * Definitions for the Transmit Control Register.
- */
-#define DZ_LINE_KEYBOARD 0x0001
-#define DZ_LINE_MOUSE    0x0002
-#define DZ_LINE_MODEM    0x0004
-#define DZ_LINE_PRINTER  0x0008
-
-#define DZ_MODEM_RTS     0x0800               /* RTS for the modem line (2) */
-#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
-#define DZ_PRINT_RTS     0x0200               /* RTS for the prntr line (3) */
-#define DZ_PRINT_DTR     0x0100               /* DTR for the prntr line (3) */
-#define DZ_LNENB         0x000f               /* Transmitter Line Enable */
-
-/*
- * Definitions for the Modem Status Register.
- */
-#define DZ_MODEM_RI      0x0800               /* RI for the modem line (2) */
-#define DZ_MODEM_CD      0x0400               /* CD for the modem line (2) */
-#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
-#define DZ_MODEM_CTS     0x0100               /* CTS for the modem line (2) */
-#define DZ_PRINT_RI      0x0008               /* RI for the printer line (3) */
-#define DZ_PRINT_CD      0x0004               /* CD for the printer line (3) */
-#define DZ_PRINT_DSR     0x0002               /* DSR for the prntr line (3) */
-#define DZ_PRINT_CTS     0x0001               /* CTS for the prntr line (3) */
-
-/*
- * Definitions for the Transmit Data Register.
- */
-#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
-#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
-#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
-#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
-
-/*
- * Definitions for the Line Parameter Register.
- */
-#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
-#define DZ_MOUSE         0x0001               /* line 1 = mouse */
-#define DZ_MODEM         0x0002               /* line 2 = modem */
-#define DZ_PRINTER       0x0003               /* line 3 = printer */
-
-#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
-#define DZ_CS5           0x0000               /* 5 bits per byte */
-#define DZ_CS6           0x0008               /* 6 bits per byte */
-#define DZ_CS7           0x0010               /* 7 bits per byte */
-#define DZ_CS8           0x0018               /* 8 bits per byte */
-
-#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
-
-#define DZ_PARENB        0x0040               /* Parity enable */
-#define DZ_PARODD        0x0080               /* Odd parity instead of even */
-
-#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
-#define DZ_B50           0x0000
-#define DZ_B75           0x0100
-#define DZ_B110          0x0200
-#define DZ_B134          0x0300
-#define DZ_B150          0x0400
-#define DZ_B300          0x0500
-#define DZ_B600          0x0600
-#define DZ_B1200         0x0700 
-#define DZ_B1800         0x0800
-#define DZ_B2000         0x0900
-#define DZ_B2400         0x0A00
-#define DZ_B3600         0x0B00
-#define DZ_B4800         0x0C00
-#define DZ_B7200         0x0D00
-#define DZ_B9600         0x0E00
-
-#define DZ_RXENAB        0x1000               /* Receiver Enable */
-
-/*
- * Addresses for the DZ registers
- */
-#define DZ_CSR       0x00            /* Control and Status Register */
-#define DZ_RBUF      0x08            /* Receive Buffer */
-#define DZ_LPR       0x08            /* Line Parameters Register */
-#define DZ_TCR       0x10            /* Transmitter Control Register */
-#define DZ_MSR       0x18            /* Modem Status Register */
-#define DZ_TDR       0x18            /* Transmit Data Register */
-
-#define DZ_NB_PORT 4
-
-#define DZ_XMIT_SIZE   4096                 /* buffer size */
-#define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
-
-#endif /* DZ_SERIAL_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
deleted file mode 100644 (file)
index 53a4682..0000000
+++ /dev/null
@@ -1,1658 +0,0 @@
-/*
-  * icom.c
-  *
-  * Copyright (C) 2001 IBM Corporation. All rights reserved.
-  *
-  * Serial device driver.
-  *
-  * Based on code from serial.c
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-  * the Free Software Foundation; either version 2 of the License, or
-  * (at your option) any later version.
-  *
-  * This program is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  * GNU General Public License for more details.
-  *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-  *
-  */
-#define SERIAL_DO_RESTART
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/termios.h>
-#include <linux/fs.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/kref.h>
-#include <linux/firmware.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "icom.h"
-
-/*#define ICOM_TRACE            enable port trace capabilities */
-
-#define ICOM_DRIVER_NAME "icom"
-#define ICOM_VERSION_STR "1.3.1"
-#define NR_PORTS              128
-#define ICOM_PORT ((struct icom_port *)port)
-#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
-
-static const struct pci_device_id icom_pci_table[] = {
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = ADAPTER_V1,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
-               .driver_data = ADAPTER_V2,
-       },
-       {
-               .vendor = PCI_VENDOR_ID_IBM,
-               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
-               .subvendor = PCI_VENDOR_ID_IBM,
-               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
-               .driver_data = ADAPTER_V2,
-       },
-       {}
-};
-
-struct lookup_proc_table start_proc[4] = {
-       {NULL, ICOM_CONTROL_START_A},
-       {NULL, ICOM_CONTROL_START_B},
-       {NULL, ICOM_CONTROL_START_C},
-       {NULL, ICOM_CONTROL_START_D}
-};
-
-
-struct lookup_proc_table stop_proc[4] = {
-       {NULL, ICOM_CONTROL_STOP_A},
-       {NULL, ICOM_CONTROL_STOP_B},
-       {NULL, ICOM_CONTROL_STOP_C},
-       {NULL, ICOM_CONTROL_STOP_D}
-};
-
-struct lookup_int_table int_mask_tbl[4] = {
-       {NULL, ICOM_INT_MASK_PRC_A},
-       {NULL, ICOM_INT_MASK_PRC_B},
-       {NULL, ICOM_INT_MASK_PRC_C},
-       {NULL, ICOM_INT_MASK_PRC_D},
-};
-
-
-MODULE_DEVICE_TABLE(pci, icom_pci_table);
-
-static LIST_HEAD(icom_adapter_head);
-
-/* spinlock for adapter initialization and changing adapter operations */
-static spinlock_t icom_lock;
-
-#ifdef ICOM_TRACE
-static inline void trace(struct icom_port *icom_port, char *trace_pt,
-                       unsigned long trace_data)
-{
-       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
-       icom_port->port, trace_pt, trace_data);
-}
-#else
-static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
-#endif
-static void icom_kref_release(struct kref *kref);
-
-static void free_port_memory(struct icom_port *icom_port)
-{
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       trace(icom_port, "RET_PORT_MEM", 0);
-       if (icom_port->recv_buf) {
-               pci_free_consistent(dev, 4096, icom_port->recv_buf,
-                                   icom_port->recv_buf_pci);
-               icom_port->recv_buf = NULL;
-       }
-       if (icom_port->xmit_buf) {
-               pci_free_consistent(dev, 4096, icom_port->xmit_buf,
-                                   icom_port->xmit_buf_pci);
-               icom_port->xmit_buf = NULL;
-       }
-       if (icom_port->statStg) {
-               pci_free_consistent(dev, 4096, icom_port->statStg,
-                                   icom_port->statStg_pci);
-               icom_port->statStg = NULL;
-       }
-
-       if (icom_port->xmitRestart) {
-               pci_free_consistent(dev, 4096, icom_port->xmitRestart,
-                                   icom_port->xmitRestart_pci);
-               icom_port->xmitRestart = NULL;
-       }
-}
-
-static int __devinit get_port_memory(struct icom_port *icom_port)
-{
-       int index;
-       unsigned long stgAddr;
-       unsigned long startStgAddr;
-       unsigned long offset;
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       icom_port->xmit_buf =
-           pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
-       if (!icom_port->xmit_buf) {
-               dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
-               return -ENOMEM;
-       }
-
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->xmit_buf);
-
-       icom_port->recv_buf =
-           pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
-       if (!icom_port->recv_buf) {
-               dev_err(&dev->dev, "Can not allocate Receive buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->recv_buf);
-
-       icom_port->statStg =
-           pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
-       if (!icom_port->statStg) {
-               dev_err(&dev->dev, "Can not allocate Status buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-       trace(icom_port, "GET_PORT_MEM",
-             (unsigned long) icom_port->statStg);
-
-       icom_port->xmitRestart =
-           pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
-       if (!icom_port->xmitRestart) {
-               dev_err(&dev->dev,
-                       "Can not allocate xmit Restart buffer\n");
-               free_port_memory(icom_port);
-               return -ENOMEM;
-       }
-
-       memset(icom_port->statStg, 0, 4096);
-
-       /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
-           indicates that frames are to be transmitted
-       */
-
-       stgAddr = (unsigned long) icom_port->statStg;
-       for (index = 0; index < NUM_XBUFFS; index++) {
-               trace(icom_port, "FOD_ADDR", stgAddr);
-               stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
-               if (index < (NUM_XBUFFS - 1)) {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-                       icom_port->statStg->xmit[index].leLengthASD =
-                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
-                       trace(icom_port, "FOD_ADDR", stgAddr);
-                       trace(icom_port, "FOD_XBUFF",
-                             (unsigned long) icom_port->xmit_buf);
-                       icom_port->statStg->xmit[index].leBuffer =
-                           cpu_to_le32(icom_port->xmit_buf_pci);
-               } else if (index == (NUM_XBUFFS - 1)) {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-                       icom_port->statStg->xmit[index].leLengthASD =
-                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
-                       trace(icom_port, "FOD_XBUFF",
-                             (unsigned long) icom_port->xmit_buf);
-                       icom_port->statStg->xmit[index].leBuffer =
-                           cpu_to_le32(icom_port->xmit_buf_pci);
-               } else {
-                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
-               }
-       }
-       /* FIDs */
-       startStgAddr = stgAddr;
-
-       /* fill in every entry, even if no buffer */
-       for (index = 0; index <  NUM_RBUFFS; index++) {
-               trace(icom_port, "FID_ADDR", stgAddr);
-               stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
-               icom_port->statStg->rcv[index].leLength = 0;
-               icom_port->statStg->rcv[index].WorkingLength =
-                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-               if (index < (NUM_RBUFFS - 1) ) {
-                       offset = stgAddr - (unsigned long) icom_port->statStg;
-                       icom_port->statStg->rcv[index].leNext =
-                             cpu_to_le32(icom_port-> statStg_pci + offset);
-                       trace(icom_port, "FID_RBUFF",
-                             (unsigned long) icom_port->recv_buf);
-                       icom_port->statStg->rcv[index].leBuffer =
-                           cpu_to_le32(icom_port->recv_buf_pci);
-               } else if (index == (NUM_RBUFFS -1) ) {
-                       offset = startStgAddr - (unsigned long) icom_port->statStg;
-                       icom_port->statStg->rcv[index].leNext =
-                           cpu_to_le32(icom_port-> statStg_pci + offset);
-                       trace(icom_port, "FID_RBUFF",
-                             (unsigned long) icom_port->recv_buf + 2048);
-                       icom_port->statStg->rcv[index].leBuffer =
-                           cpu_to_le32(icom_port->recv_buf_pci + 2048);
-               } else {
-                       icom_port->statStg->rcv[index].leNext = 0;
-                       icom_port->statStg->rcv[index].leBuffer = 0;
-               }
-       }
-
-       return 0;
-}
-
-static void stop_processor(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               stop_proc[port].global_control_reg = &icom_port->global_reg->control;
-       else
-               stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
-
-
-       if (port < 4) {
-               temp = readl(stop_proc[port].global_control_reg);
-               temp =
-                       (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
-               writel(temp, stop_proc[port].global_control_reg);
-
-               /* write flush */
-               readl(stop_proc[port].global_control_reg);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-}
-
-static void start_processor(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               start_proc[port].global_control_reg = &icom_port->global_reg->control;
-       else
-               start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
-       if (port < 4) {
-               temp = readl(start_proc[port].global_control_reg);
-               temp =
-                       (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
-               writel(temp, start_proc[port].global_control_reg);
-
-               /* write flush */
-               readl(start_proc[port].global_control_reg);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-}
-
-static void load_code(struct icom_port *icom_port)
-{
-       const struct firmware *fw;
-       char __iomem *iram_ptr;
-       int index;
-       int status = 0;
-       void __iomem *dram_ptr = icom_port->dram;
-       dma_addr_t temp_pci;
-       unsigned char *new_page = NULL;
-       unsigned char cable_id = NO_CABLE;
-       struct pci_dev *dev = icom_port->adapter->pci_dev;
-
-       /* Clear out any pending interrupts */
-       writew(0x3FFF, icom_port->int_reg);
-
-       trace(icom_port, "CLEAR_INTERRUPTS", 0);
-
-       /* Stop processor */
-       stop_processor(icom_port);
-
-       /* Zero out DRAM */
-       memset_io(dram_ptr, 0, 512);
-
-       /* Load Call Setup into Adapter */
-       if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
-       for (index = 0; index < fw->size; index++)
-               writeb(fw->data[index], &iram_ptr[index]);
-
-       release_firmware(fw);
-
-       /* Load Resident DCE portion of Adapter */
-       if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_IRAM_SIZE) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
-       for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
-               writeb(fw->data[index], &iram_ptr[index]);
-
-       release_firmware(fw);
-
-       /* Set Hardware level */
-       if (icom_port->adapter->version == ADAPTER_V2)
-               writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
-
-       /* Start the processor in Adapter */
-       start_processor(icom_port);
-
-       writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
-              &(icom_port->dram->HDLCConfigReg));
-       writeb(0x04, &(icom_port->dram->FlagFillIdleTimer));    /* 0.5 seconds */
-       writeb(0x00, &(icom_port->dram->CmdReg));
-       writeb(0x10, &(icom_port->dram->async_config3));
-       writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
-               ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
-
-       /*Set up data in icom DRAM to indicate where personality
-        *code is located and its length.
-        */
-       new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
-
-       if (!new_page) {
-               dev_err(&dev->dev, "Can not allocate DMA buffer\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
-               dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
-               status = -1;
-               goto load_code_exit;
-       }
-
-       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
-               dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
-               release_firmware(fw);
-               status = -1;
-               goto load_code_exit;
-       }
-
-       for (index = 0; index < fw->size; index++)
-               new_page[index] = fw->data[index];
-
-       release_firmware(fw);
-
-       writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
-       writel(temp_pci, &icom_port->dram->mac_load_addr);
-
-       /*Setting the syncReg to 0x80 causes adapter to start downloading
-          the personality code into adapter instruction RAM.
-          Once code is loaded, it will begin executing and, based on
-          information provided above, will start DMAing data from
-          shared memory to adapter DRAM.
-        */
-       /* the wait loop below verifies this write operation has been done
-          and processed
-       */
-       writeb(START_DOWNLOAD, &icom_port->dram->sync);
-
-       /* Wait max 1 Sec for data download and processor to start */
-       for (index = 0; index < 10; index++) {
-               msleep(100);
-               if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
-                       break;
-       }
-
-       if (index == 10)
-               status = -1;
-
-       /*
-        * check Cable ID
-        */
-       cable_id = readb(&icom_port->dram->cable_id);
-
-       if (cable_id & ICOM_CABLE_ID_VALID) {
-               /* Get cable ID into the lower 4 bits (standard form) */
-               cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
-               icom_port->cable_id = cable_id;
-       } else {
-               dev_err(&dev->dev,"Invalid or no cable attached\n");
-               icom_port->cable_id = NO_CABLE;
-       }
-
-      load_code_exit:
-
-       if (status != 0) {
-               /* Clear out any pending interrupts */
-               writew(0x3FFF, icom_port->int_reg);
-
-               /* Turn off port */
-               writeb(ICOM_DISABLE, &(icom_port->dram->disable));
-
-               /* Stop processor */
-               stop_processor(icom_port);
-
-               dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
-       }
-
-       if (new_page != NULL)
-               pci_free_consistent(dev, 4096, new_page, temp_pci);
-}
-
-static int startup(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned char cable_id, raw_cable_id;
-       unsigned long flags;
-       int port;
-
-       trace(icom_port, "STARTUP", 0);
-
-       if (!icom_port->dram) {
-               /* should NEVER be NULL */
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                       "Unusable Port, port configuration missing\n");
-               return -ENODEV;
-       }
-
-       /*
-        * check Cable ID
-        */
-       raw_cable_id = readb(&icom_port->dram->cable_id);
-       trace(icom_port, "CABLE_ID", raw_cable_id);
-
-       /* Get cable ID into the lower 4 bits (standard form) */
-       cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
-
-       /* Check for valid Cable ID */
-       if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
-           (cable_id != icom_port->cable_id)) {
-
-               /* reload adapter code, pick up any potential changes in cable id */
-               load_code(icom_port);
-
-               /* still no sign of cable, error out */
-               raw_cable_id = readb(&icom_port->dram->cable_id);
-               cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
-               if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
-                   (icom_port->cable_id == NO_CABLE))
-                       return -EIO;
-       }
-
-       /*
-        * Finally, clear and  enable interrupts
-        */
-       spin_lock_irqsave(&icom_lock, flags);
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
-       else
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
-
-       if (port == 0 || port == 2)
-               writew(0x00FF, icom_port->int_reg);
-       else
-               writew(0x3F00, icom_port->int_reg);
-       if (port < 4) {
-               temp = readl(int_mask_tbl[port].global_int_mask);
-               writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
-
-               /* write flush */
-               readl(int_mask_tbl[port].global_int_mask);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-
-       spin_unlock_irqrestore(&icom_lock, flags);
-       return 0;
-}
-
-static void shutdown(struct icom_port *icom_port)
-{
-       unsigned long temp;
-       unsigned char cmdReg;
-       unsigned long flags;
-       int port;
-
-       spin_lock_irqsave(&icom_lock, flags);
-       trace(icom_port, "SHUTDOWN", 0);
-
-       /*
-        * disable all interrupts
-        */
-       port = icom_port->port;
-       if (port == 0 || port == 1)
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
-       else
-               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
-
-       if (port < 4) {
-               temp = readl(int_mask_tbl[port].global_int_mask);
-               writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
-
-               /* write flush */
-               readl(int_mask_tbl[port].global_int_mask);
-       } else {
-               dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-       }
-       spin_unlock_irqrestore(&icom_lock, flags);
-
-       /*
-        * disable break condition
-        */
-       cmdReg = readb(&icom_port->dram->CmdReg);
-       if (cmdReg & CMD_SND_BREAK) {
-               writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
-       }
-}
-
-static int icom_write(struct uart_port *port)
-{
-       unsigned long data_count;
-       unsigned char cmdReg;
-       unsigned long offset;
-       int temp_tail = port->state->xmit.tail;
-
-       trace(ICOM_PORT, "WRITE", 0);
-
-       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
-           SA_FLAGS_READY_TO_XMIT) {
-               trace(ICOM_PORT, "WRITE_FULL", 0);
-               return 0;
-       }
-
-       data_count = 0;
-       while ((port->state->xmit.head != temp_tail) &&
-              (data_count <= XMIT_BUFF_SZ)) {
-
-               ICOM_PORT->xmit_buf[data_count++] =
-                   port->state->xmit.buf[temp_tail];
-
-               temp_tail++;
-               temp_tail &= (UART_XMIT_SIZE - 1);
-       }
-
-       if (data_count) {
-               ICOM_PORT->statStg->xmit[0].flags =
-                   cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
-               ICOM_PORT->statStg->xmit[0].leLength =
-                   cpu_to_le16(data_count);
-               offset =
-                   (unsigned long) &ICOM_PORT->statStg->xmit[0] -
-                   (unsigned long) ICOM_PORT->statStg;
-               *ICOM_PORT->xmitRestart =
-                   cpu_to_le32(ICOM_PORT->statStg_pci + offset);
-               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-               writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
-                      &ICOM_PORT->dram->CmdReg);
-               writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
-               trace(ICOM_PORT, "WRITE_START", data_count);
-               /* write flush */
-               readb(&ICOM_PORT->dram->StartXmitCmd);
-       }
-
-       return data_count;
-}
-
-static inline void check_modem_status(struct icom_port *icom_port)
-{
-       static char old_status = 0;
-       char delta_status;
-       unsigned char status;
-
-       spin_lock(&icom_port->uart_port.lock);
-
-       /*modem input register */
-       status = readb(&icom_port->dram->isr);
-       trace(icom_port, "CHECK_MODEM", status);
-       delta_status = status ^ old_status;
-       if (delta_status) {
-               if (delta_status & ICOM_RI)
-                       icom_port->uart_port.icount.rng++;
-               if (delta_status & ICOM_DSR)
-                       icom_port->uart_port.icount.dsr++;
-               if (delta_status & ICOM_DCD)
-                       uart_handle_dcd_change(&icom_port->uart_port,
-                                              delta_status & ICOM_DCD);
-               if (delta_status & ICOM_CTS)
-                       uart_handle_cts_change(&icom_port->uart_port,
-                                              delta_status & ICOM_CTS);
-
-               wake_up_interruptible(&icom_port->uart_port.state->
-                                     port.delta_msr_wait);
-               old_status = status;
-       }
-       spin_unlock(&icom_port->uart_port.lock);
-}
-
-static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
-{
-       unsigned short int count;
-       int i;
-
-       if (port_int_reg & (INT_XMIT_COMPLETED)) {
-               trace(icom_port, "XMIT_COMPLETE", 0);
-
-               /* clear buffer in use bit */
-               icom_port->statStg->xmit[0].flags &=
-                       cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
-
-               count = (unsigned short int)
-                       cpu_to_le16(icom_port->statStg->xmit[0].leLength);
-               icom_port->uart_port.icount.tx += count;
-
-               for (i=0; i<count &&
-                       !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
-
-                       icom_port->uart_port.state->xmit.tail++;
-                       icom_port->uart_port.state->xmit.tail &=
-                               (UART_XMIT_SIZE - 1);
-               }
-
-               if (!icom_write(&icom_port->uart_port))
-                       /* activate write queue */
-                       uart_write_wakeup(&icom_port->uart_port);
-       } else
-               trace(icom_port, "XMIT_DISABLED", 0);
-}
-
-static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
-{
-       short int count, rcv_buff;
-       struct tty_struct *tty = icom_port->uart_port.state->port.tty;
-       unsigned short int status;
-       struct uart_icount *icount;
-       unsigned long offset;
-       unsigned char flag;
-
-       trace(icom_port, "RCV_COMPLETE", 0);
-       rcv_buff = icom_port->next_rcv;
-
-       status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
-       while (status & SA_FL_RCV_DONE) {
-               int first = -1;
-
-               trace(icom_port, "FID_STATUS", status);
-               count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
-
-               trace(icom_port, "RCV_COUNT", count);
-
-               trace(icom_port, "REAL_COUNT", count);
-
-               offset =
-                       cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
-                       icom_port->recv_buf_pci;
-
-               /* Block copy all but the last byte as this may have status */
-               if (count > 0) {
-                       first = icom_port->recv_buf[offset];
-                       tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
-               }
-
-               icount = &icom_port->uart_port.icount;
-               icount->rx += count;
-
-               /* Break detect logic */
-               if ((status & SA_FLAGS_FRAME_ERROR)
-                   && first == 0) {
-                       status &= ~SA_FLAGS_FRAME_ERROR;
-                       status |= SA_FLAGS_BREAK_DET;
-                       trace(icom_port, "BREAK_DET", 0);
-               }
-
-               flag = TTY_NORMAL;
-
-               if (status &
-                   (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
-                    SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
-
-                       if (status & SA_FLAGS_BREAK_DET)
-                               icount->brk++;
-                       if (status & SA_FLAGS_PARITY_ERROR)
-                               icount->parity++;
-                       if (status & SA_FLAGS_FRAME_ERROR)
-                               icount->frame++;
-                       if (status & SA_FLAGS_OVERRUN)
-                               icount->overrun++;
-
-                       /*
-                        * Now check to see if character should be
-                        * ignored, and mask off conditions which
-                        * should be ignored.
-                        */
-                       if (status & icom_port->ignore_status_mask) {
-                               trace(icom_port, "IGNORE_CHAR", 0);
-                               goto ignore_char;
-                       }
-
-                       status &= icom_port->read_status_mask;
-
-                       if (status & SA_FLAGS_BREAK_DET) {
-                               flag = TTY_BREAK;
-                       } else if (status & SA_FLAGS_PARITY_ERROR) {
-                               trace(icom_port, "PARITY_ERROR", 0);
-                               flag = TTY_PARITY;
-                       } else if (status & SA_FLAGS_FRAME_ERROR)
-                               flag = TTY_FRAME;
-
-               }
-
-               tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
-
-               if (status & SA_FLAGS_OVERRUN)
-                       /*
-                        * Overrun is special, since it's
-                        * reported immediately, and doesn't
-                        * affect the current character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-ignore_char:
-               icom_port->statStg->rcv[rcv_buff].flags = 0;
-               icom_port->statStg->rcv[rcv_buff].leLength = 0;
-               icom_port->statStg->rcv[rcv_buff].WorkingLength =
-                       (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-
-               rcv_buff++;
-               if (rcv_buff == NUM_RBUFFS)
-                       rcv_buff = 0;
-
-               status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
-       }
-       icom_port->next_rcv = rcv_buff;
-       tty_flip_buffer_push(tty);
-}
-
-static void process_interrupt(u16 port_int_reg,
-                             struct icom_port *icom_port)
-{
-
-       spin_lock(&icom_port->uart_port.lock);
-       trace(icom_port, "INTERRUPT", port_int_reg);
-
-       if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
-               xmit_interrupt(port_int_reg, icom_port);
-
-       if (port_int_reg & INT_RCV_COMPLETED)
-               recv_interrupt(port_int_reg, icom_port);
-
-       spin_unlock(&icom_port->uart_port.lock);
-}
-
-static irqreturn_t icom_interrupt(int irq, void *dev_id)
-{
-       void __iomem * int_reg;
-       u32 adapter_interrupts;
-       u16 port_int_reg;
-       struct icom_adapter *icom_adapter;
-       struct icom_port *icom_port;
-
-       /* find icom_port for this interrupt */
-       icom_adapter = (struct icom_adapter *) dev_id;
-
-       if (icom_adapter->version == ADAPTER_V2) {
-               int_reg = icom_adapter->base_addr + 0x8024;
-
-               adapter_interrupts = readl(int_reg);
-
-               if (adapter_interrupts & 0x00003FFF) {
-                       /* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */
-                       icom_port = &icom_adapter->port_info[2];
-                       port_int_reg = (u16) adapter_interrupts;
-                       process_interrupt(port_int_reg, icom_port);
-                       check_modem_status(icom_port);
-               }
-               if (adapter_interrupts & 0x3FFF0000) {
-                       /* port 3 interrupt */
-                       icom_port = &icom_adapter->port_info[3];
-                       if (icom_port->status == ICOM_PORT_ACTIVE) {
-                               port_int_reg =
-                                   (u16) (adapter_interrupts >> 16);
-                               process_interrupt(port_int_reg, icom_port);
-                               check_modem_status(icom_port);
-                       }
-               }
-
-               /* Clear out any pending interrupts */
-               writel(adapter_interrupts, int_reg);
-
-               int_reg = icom_adapter->base_addr + 0x8004;
-       } else {
-               int_reg = icom_adapter->base_addr + 0x4004;
-       }
-
-       adapter_interrupts = readl(int_reg);
-
-       if (adapter_interrupts & 0x00003FFF) {
-               /* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */
-               icom_port = &icom_adapter->port_info[0];
-               port_int_reg = (u16) adapter_interrupts;
-               process_interrupt(port_int_reg, icom_port);
-               check_modem_status(icom_port);
-       }
-       if (adapter_interrupts & 0x3FFF0000) {
-               /* port 1 interrupt */
-               icom_port = &icom_adapter->port_info[1];
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       port_int_reg = (u16) (adapter_interrupts >> 16);
-                       process_interrupt(port_int_reg, icom_port);
-                       check_modem_status(icom_port);
-               }
-       }
-
-       /* Clear out any pending interrupts */
-       writel(adapter_interrupts, int_reg);
-
-       /* flush the write */
-       adapter_interrupts = readl(int_reg);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * ------------------------------------------------------------------
- * Begin serial-core API
- * ------------------------------------------------------------------
- */
-static unsigned int icom_tx_empty(struct uart_port *port)
-{
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
-           SA_FLAGS_READY_TO_XMIT)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-       return ret;
-}
-
-static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned char local_osr;
-
-       trace(ICOM_PORT, "SET_MODEM", 0);
-       local_osr = readb(&ICOM_PORT->dram->osr);
-
-       if (mctrl & TIOCM_RTS) {
-               trace(ICOM_PORT, "RAISE_RTS", 0);
-               local_osr |= ICOM_RTS;
-       } else {
-               trace(ICOM_PORT, "LOWER_RTS", 0);
-               local_osr &= ~ICOM_RTS;
-       }
-
-       if (mctrl & TIOCM_DTR) {
-               trace(ICOM_PORT, "RAISE_DTR", 0);
-               local_osr |= ICOM_DTR;
-       } else {
-               trace(ICOM_PORT, "LOWER_DTR", 0);
-               local_osr &= ~ICOM_DTR;
-       }
-
-       writeb(local_osr, &ICOM_PORT->dram->osr);
-}
-
-static unsigned int icom_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int result;
-
-       trace(ICOM_PORT, "GET_MODEM", 0);
-
-       status = readb(&ICOM_PORT->dram->isr);
-
-       result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
-           | ((status & ICOM_RI) ? TIOCM_RNG : 0)
-           | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
-           | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
-       return result;
-}
-
-static void icom_stop_tx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "STOP", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
-}
-
-static void icom_start_tx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "START", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
-               writeb(cmdReg & ~CMD_HOLD_XMIT,
-                      &ICOM_PORT->dram->CmdReg);
-
-       icom_write(port);
-}
-
-static void icom_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned char xdata;
-       int index;
-       unsigned long flags;
-
-       trace(ICOM_PORT, "SEND_XCHAR", ch);
-
-       /* wait .1 sec to send char */
-       for (index = 0; index < 10; index++) {
-               spin_lock_irqsave(&port->lock, flags);
-               xdata = readb(&ICOM_PORT->dram->xchar);
-               if (xdata == 0x00) {
-                       trace(ICOM_PORT, "QUICK_WRITE", 0);
-                       writeb(ch, &ICOM_PORT->dram->xchar);
-
-                       /* flush write operation */
-                       xdata = readb(&ICOM_PORT->dram->xchar);
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(&port->lock, flags);
-               msleep(10);
-       }
-}
-
-static void icom_stop_rx(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
-}
-
-static void icom_enable_ms(struct uart_port *port)
-{
-       /* no-op */
-}
-
-static void icom_break(struct uart_port *port, int break_state)
-{
-       unsigned char cmdReg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       trace(ICOM_PORT, "BREAK", 0);
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       if (break_state == -1) {
-               writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
-       } else {
-               writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int icom_open(struct uart_port *port)
-{
-       int retval;
-
-       kref_get(&ICOM_PORT->adapter->kref);
-       retval = startup(ICOM_PORT);
-
-       if (retval) {
-               kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
-               trace(ICOM_PORT, "STARTUP_ERROR", 0);
-               return retval;
-       }
-
-       return 0;
-}
-
-static void icom_close(struct uart_port *port)
-{
-       unsigned char cmdReg;
-
-       trace(ICOM_PORT, "CLOSE", 0);
-
-       /* stop receiver */
-       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-       writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
-              &ICOM_PORT->dram->CmdReg);
-
-       shutdown(ICOM_PORT);
-
-       kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
-}
-
-static void icom_set_termios(struct uart_port *port,
-                            struct ktermios *termios,
-                            struct ktermios *old_termios)
-{
-       int baud;
-       unsigned cflag, iflag;
-       char new_config2;
-       char new_config3 = 0;
-       char tmp_byte;
-       int index;
-       int rcv_buff, xmit_buff;
-       unsigned long offset;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       trace(ICOM_PORT, "CHANGE_SPEED", 0);
-
-       cflag = termios->c_cflag;
-       iflag = termios->c_iflag;
-
-       new_config2 = ICOM_ACFG_DRIVE1;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:               /* 5 bits/char */
-               new_config2 |= ICOM_ACFG_5BPC;
-               break;
-       case CS6:               /* 6 bits/char */
-               new_config2 |= ICOM_ACFG_6BPC;
-               break;
-       case CS7:               /* 7 bits/char */
-               new_config2 |= ICOM_ACFG_7BPC;
-               break;
-       case CS8:               /* 8 bits/char */
-               new_config2 |= ICOM_ACFG_8BPC;
-               break;
-       default:
-               break;
-       }
-       if (cflag & CSTOPB) {
-               /* 2 stop bits */
-               new_config2 |= ICOM_ACFG_2STOP_BIT;
-       }
-       if (cflag & PARENB) {
-               /* parity bit enabled */
-               new_config2 |= ICOM_ACFG_PARITY_ENAB;
-               trace(ICOM_PORT, "PARENB", 0);
-       }
-       if (cflag & PARODD) {
-               /* odd parity */
-               new_config2 |= ICOM_ACFG_PARITY_ODD;
-               trace(ICOM_PORT, "PARODD", 0);
-       }
-
-       /* Determine divisor based on baud rate */
-       baud = uart_get_baud_rate(port, termios, old_termios,
-                                 icom_acfg_baud[0],
-                                 icom_acfg_baud[BAUD_TABLE_LIMIT]);
-       if (!baud)
-               baud = 9600;    /* B0 transition handled in rs_set_termios */
-
-       for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
-               if (icom_acfg_baud[index] == baud) {
-                       new_config3 = index;
-                       break;
-               }
-       }
-
-       uart_update_timeout(port, cflag, baud);
-
-       /* CTS flow control flag and modem status interrupts */
-       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
-       if (cflag & CRTSCTS)
-               tmp_byte |= HDLC_HDW_FLOW;
-       else
-               tmp_byte &= ~HDLC_HDW_FLOW;
-       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
-
-       /*
-        * Set up parity check flag
-        */
-       ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
-       if (iflag & INPCK)
-               ICOM_PORT->read_status_mask |=
-                   SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
-
-       if ((iflag & BRKINT) || (iflag & PARMRK))
-               ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
-
-       /*
-        * Characters to ignore
-        */
-       ICOM_PORT->ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               ICOM_PORT->ignore_status_mask |=
-                   SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
-       if (iflag & IGNBRK) {
-               ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (iflag & IGNPAR)
-                       ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
-       }
-
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
-
-       /* Turn off Receiver to prepare for reset */
-       writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
-
-       for (index = 0; index < 10; index++) {
-               if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
-                       break;
-               }
-       }
-
-       /* clear all current buffers of data */
-       for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
-               ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
-               ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
-               ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
-                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
-       }
-
-       for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
-               ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
-       }
-
-       /* activate changes and start xmit and receiver here */
-       /* Enable the receiver */
-       writeb(new_config3, &(ICOM_PORT->dram->async_config3));
-       writeb(new_config2, &(ICOM_PORT->dram->async_config2));
-       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
-       tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
-       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
-       writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));    /* 0.5 seconds */
-       writeb(0xFF, &(ICOM_PORT->dram->ier));  /* enable modem signal interrupts */
-
-       /* reset processor */
-       writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
-
-       for (index = 0; index < 10; index++) {
-               if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
-                       break;
-               }
-       }
-
-       /* Enable Transmitter and Reciever */
-       offset =
-           (unsigned long) &ICOM_PORT->statStg->rcv[0] -
-           (unsigned long) ICOM_PORT->statStg;
-       writel(ICOM_PORT->statStg_pci + offset,
-              &ICOM_PORT->dram->RcvStatusAddr);
-       ICOM_PORT->next_rcv = 0;
-       ICOM_PORT->put_length = 0;
-       *ICOM_PORT->xmitRestart = 0;
-       writel(ICOM_PORT->xmitRestart_pci,
-              &ICOM_PORT->dram->XmitStatusAddr);
-       trace(ICOM_PORT, "XR_ENAB", 0);
-       writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *icom_type(struct uart_port *port)
-{
-       return "icom";
-}
-
-static void icom_release_port(struct uart_port *port)
-{
-}
-
-static int icom_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void icom_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_ICOM;
-}
-
-static struct uart_ops icom_ops = {
-       .tx_empty = icom_tx_empty,
-       .set_mctrl = icom_set_mctrl,
-       .get_mctrl = icom_get_mctrl,
-       .stop_tx = icom_stop_tx,
-       .start_tx = icom_start_tx,
-       .send_xchar = icom_send_xchar,
-       .stop_rx = icom_stop_rx,
-       .enable_ms = icom_enable_ms,
-       .break_ctl = icom_break,
-       .startup = icom_open,
-       .shutdown = icom_close,
-       .set_termios = icom_set_termios,
-       .type = icom_type,
-       .release_port = icom_release_port,
-       .request_port = icom_request_port,
-       .config_port = icom_config_port,
-};
-
-#define ICOM_CONSOLE NULL
-
-static struct uart_driver icom_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = ICOM_DRIVER_NAME,
-       .dev_name = "ttyA",
-       .major = ICOM_MAJOR,
-       .minor = ICOM_MINOR_START,
-       .nr = NR_PORTS,
-       .cons = ICOM_CONSOLE,
-};
-
-static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
-{
-       u32 subsystem_id = icom_adapter->subsystem_id;
-       int i;
-       struct icom_port *icom_port;
-
-       if (icom_adapter->version == ADAPTER_V1) {
-               icom_adapter->numb_ports = 2;
-
-               for (i = 0; i < 2; i++) {
-                       icom_port = &icom_adapter->port_info[i];
-                       icom_port->port = i;
-                       icom_port->status = ICOM_PORT_ACTIVE;
-                       icom_port->imbed_modem = ICOM_UNKNOWN;
-               }
-       } else {
-               if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
-                       icom_adapter->numb_ports = 4;
-
-                       for (i = 0; i < 4; i++) {
-                               icom_port = &icom_adapter->port_info[i];
-
-                               icom_port->port = i;
-                               icom_port->status = ICOM_PORT_ACTIVE;
-                               icom_port->imbed_modem = ICOM_IMBED_MODEM;
-                       }
-               } else {
-                       icom_adapter->numb_ports = 4;
-
-                       icom_adapter->port_info[0].port = 0;
-                       icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
-
-                       if (subsystem_id ==
-                           PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
-                               icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
-                       } else {
-                               icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
-                       }
-
-                       icom_adapter->port_info[1].status = ICOM_PORT_OFF;
-
-                       icom_adapter->port_info[2].port = 2;
-                       icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
-                       icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
-                       icom_adapter->port_info[3].status = ICOM_PORT_OFF;
-               }
-       }
-
-       return 0;
-}
-
-static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
-{
-       if (icom_adapter->version == ADAPTER_V1) {
-               icom_port->global_reg = icom_adapter->base_addr + 0x4000;
-               icom_port->int_reg = icom_adapter->base_addr +
-                   0x4004 + 2 - 2 * port_num;
-       } else {
-               icom_port->global_reg = icom_adapter->base_addr + 0x8000;
-               if (icom_port->port < 2)
-                       icom_port->int_reg = icom_adapter->base_addr +
-                           0x8004 + 2 - 2 * icom_port->port;
-               else
-                       icom_port->int_reg = icom_adapter->base_addr +
-                           0x8024 + 2 - 2 * (icom_port->port - 2);
-       }
-}
-static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
-{
-       struct icom_port *icom_port;
-       int port_num;
-
-       for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
-
-               icom_port = &icom_adapter->port_info[port_num];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       icom_port_active(icom_port, icom_adapter, port_num);
-                       icom_port->dram = icom_adapter->base_addr +
-                                       0x2000 * icom_port->port;
-
-                       icom_port->adapter = icom_adapter;
-
-                       /* get port memory */
-                       if (get_port_memory(icom_port) != 0) {
-                               dev_err(&icom_port->adapter->pci_dev->dev,
-                                       "Memory allocation for port FAILED\n");
-                       }
-               }
-       }
-       return 0;
-}
-
-static int __devinit icom_alloc_adapter(struct icom_adapter
-                                       **icom_adapter_ref)
-{
-       int adapter_count = 0;
-       struct icom_adapter *icom_adapter;
-       struct icom_adapter *cur_adapter_entry;
-       struct list_head *tmp;
-
-       icom_adapter = (struct icom_adapter *)
-           kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
-
-       if (!icom_adapter) {
-               return -ENOMEM;
-       }
-
-       list_for_each(tmp, &icom_adapter_head) {
-               cur_adapter_entry =
-                   list_entry(tmp, struct icom_adapter,
-                              icom_adapter_entry);
-               if (cur_adapter_entry->index != adapter_count) {
-                       break;
-               }
-               adapter_count++;
-       }
-
-       icom_adapter->index = adapter_count;
-       list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
-
-       *icom_adapter_ref = icom_adapter;
-       return 0;
-}
-
-static void icom_free_adapter(struct icom_adapter *icom_adapter)
-{
-       list_del(&icom_adapter->icom_adapter_entry);
-       kfree(icom_adapter);
-}
-
-static void icom_remove_adapter(struct icom_adapter *icom_adapter)
-{
-       struct icom_port *icom_port;
-       int index;
-
-       for (index = 0; index < icom_adapter->numb_ports; index++) {
-               icom_port = &icom_adapter->port_info[index];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       dev_info(&icom_adapter->pci_dev->dev,
-                                "Device removed\n");
-
-                       uart_remove_one_port(&icom_uart_driver,
-                                            &icom_port->uart_port);
-
-                       /* be sure that DTR and RTS are dropped */
-                       writeb(0x00, &icom_port->dram->osr);
-
-                       /* Wait 0.1 Sec for simple Init to complete */
-                       msleep(100);
-
-                       /* Stop proccessor */
-                       stop_processor(icom_port);
-
-                       free_port_memory(icom_port);
-               }
-       }
-
-       free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
-       iounmap(icom_adapter->base_addr);
-       pci_release_regions(icom_adapter->pci_dev);
-       icom_free_adapter(icom_adapter);
-}
-
-static void icom_kref_release(struct kref *kref)
-{
-       struct icom_adapter *icom_adapter;
-
-       icom_adapter = to_icom_adapter(kref);
-       icom_remove_adapter(icom_adapter);
-}
-
-static int __devinit icom_probe(struct pci_dev *dev,
-                               const struct pci_device_id *ent)
-{
-       int index;
-       unsigned int command_reg;
-       int retval;
-       struct icom_adapter *icom_adapter;
-       struct icom_port *icom_port;
-
-       retval = pci_enable_device(dev);
-       if (retval) {
-               dev_err(&dev->dev, "Device enable FAILED\n");
-               return retval;
-       }
-
-       if ( (retval = pci_request_regions(dev, "icom"))) {
-                dev_err(&dev->dev, "pci_request_regions FAILED\n");
-                pci_disable_device(dev);
-                return retval;
-        }
-
-       pci_set_master(dev);
-
-       if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
-               dev_err(&dev->dev, "PCI Config read FAILED\n");
-               return retval;
-       }
-
-       pci_write_config_dword(dev, PCI_COMMAND,
-               command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
-               | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
-
-       if (ent->driver_data == ADAPTER_V1) {
-               pci_write_config_dword(dev, 0x44, 0x8300830A);
-       } else {
-               pci_write_config_dword(dev, 0x44, 0x42004200);
-               pci_write_config_dword(dev, 0x48, 0x42004200);
-       }
-
-
-       retval = icom_alloc_adapter(&icom_adapter);
-       if (retval) {
-                dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
-                retval = -EIO;
-                goto probe_exit0;
-       }
-
-       icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
-       icom_adapter->pci_dev = dev;
-       icom_adapter->version = ent->driver_data;
-       icom_adapter->subsystem_id = ent->subdevice;
-
-
-       retval = icom_init_ports(icom_adapter);
-       if (retval) {
-               dev_err(&dev->dev, "Port configuration failed\n");
-               goto probe_exit1;
-       }
-
-       icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
-
-       if (!icom_adapter->base_addr)
-               goto probe_exit1;
-
-        /* save off irq and request irq line */
-        if ( (retval = request_irq(dev->irq, icom_interrupt,
-                                  IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
-                                  (void *) icom_adapter))) {
-                 goto probe_exit2;
-        }
-
-       retval = icom_load_ports(icom_adapter);
-
-       for (index = 0; index < icom_adapter->numb_ports; index++) {
-               icom_port = &icom_adapter->port_info[index];
-
-               if (icom_port->status == ICOM_PORT_ACTIVE) {
-                       icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
-                       icom_port->uart_port.type = PORT_ICOM;
-                       icom_port->uart_port.iotype = UPIO_MEM;
-                       icom_port->uart_port.membase =
-                                              (char *) icom_adapter->base_addr_pci;
-                       icom_port->uart_port.fifosize = 16;
-                       icom_port->uart_port.ops = &icom_ops;
-                       icom_port->uart_port.line =
-                       icom_port->port + icom_adapter->index * 4;
-                       if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
-                               icom_port->status = ICOM_PORT_OFF;
-                               dev_err(&dev->dev, "Device add failed\n");
-                        } else
-                               dev_info(&dev->dev, "Device added\n");
-               }
-       }
-
-       kref_init(&icom_adapter->kref);
-       return 0;
-
-probe_exit2:
-       iounmap(icom_adapter->base_addr);
-probe_exit1:
-       icom_free_adapter(icom_adapter);
-
-probe_exit0:
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-
-       return retval;
-}
-
-static void __devexit icom_remove(struct pci_dev *dev)
-{
-       struct icom_adapter *icom_adapter;
-       struct list_head *tmp;
-
-       list_for_each(tmp, &icom_adapter_head) {
-               icom_adapter = list_entry(tmp, struct icom_adapter,
-                                         icom_adapter_entry);
-               if (icom_adapter->pci_dev == dev) {
-                       kref_put(&icom_adapter->kref, icom_kref_release);
-                       return;
-               }
-       }
-
-       dev_err(&dev->dev, "Unable to find device to remove\n");
-}
-
-static struct pci_driver icom_pci_driver = {
-       .name = ICOM_DRIVER_NAME,
-       .id_table = icom_pci_table,
-       .probe = icom_probe,
-       .remove = __devexit_p(icom_remove),
-};
-
-static int __init icom_init(void)
-{
-       int ret;
-
-       spin_lock_init(&icom_lock);
-
-       ret = uart_register_driver(&icom_uart_driver);
-       if (ret)
-               return ret;
-
-       ret = pci_register_driver(&icom_pci_driver);
-
-       if (ret < 0)
-               uart_unregister_driver(&icom_uart_driver);
-
-       return ret;
-}
-
-static void __exit icom_exit(void)
-{
-       pci_unregister_driver(&icom_pci_driver);
-       uart_unregister_driver(&icom_uart_driver);
-}
-
-module_init(icom_init);
-module_exit(icom_exit);
-
-MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
-MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
-MODULE_SUPPORTED_DEVICE
-    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("icom_call_setup.bin");
-MODULE_FIRMWARE("icom_res_dce.bin");
-MODULE_FIRMWARE("icom_asc.bin");
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
deleted file mode 100644 (file)
index c8029e0..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * icom.h
- *
- * Copyright (C) 2001 Michael Anderson, IBM Corporation
- *
- * Serial device driver include file.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/serial_core.h>
-
-#define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
-static int icom_acfg_baud[] = {
-       300,
-       600,
-       900,
-       1200,
-       1800,
-       2400,
-       3600,
-       4800,
-       7200,
-       9600,
-       14400,
-       19200,
-       28800,
-       38400,
-       57600,
-       76800,
-       115200,
-       153600,
-       230400,
-       307200,
-       460800,
-};
-
-struct icom_regs {
-       u32 control;            /* Adapter Control Register     */
-       u32 interrupt;          /* Adapter Interrupt Register   */
-       u32 int_mask;           /* Adapter Interrupt Mask Reg   */
-       u32 int_pri;            /* Adapter Interrupt Priority r */
-       u32 int_reg_b;          /* Adapter non-masked Interrupt */
-       u32 resvd01;
-       u32 resvd02;
-       u32 resvd03;
-       u32 control_2;          /* Adapter Control Register 2   */
-       u32 interrupt_2;        /* Adapter Interrupt Register 2 */
-       u32 int_mask_2;         /* Adapter Interrupt Mask 2     */
-       u32 int_pri_2;          /* Adapter Interrupt Prior 2    */
-       u32 int_reg_2b;         /* Adapter non-masked 2         */
-};
-
-struct func_dram {
-       u32 reserved[108];      /* 0-1B0   reserved by personality code */
-       u32 RcvStatusAddr;      /* 1B0-1B3 Status Address for Next rcv */
-       u8 RcvStnAddr;          /* 1B4     Receive Station Addr */
-       u8 IdleState;           /* 1B5     Idle State */
-       u8 IdleMonitor;         /* 1B6     Idle Monitor */
-       u8 FlagFillIdleTimer;   /* 1B7     Flag Fill Idle Timer */
-       u32 XmitStatusAddr;     /* 1B8-1BB Transmit Status Address */
-       u8 StartXmitCmd;        /* 1BC     Start Xmit Command */
-       u8 HDLCConfigReg;       /* 1BD     Reserved */
-       u8 CauseCode;           /* 1BE     Cause code for fatal error */
-       u8 xchar;               /* 1BF     High priority send */
-       u32 reserved3;          /* 1C0-1C3 Reserved */
-       u8 PrevCmdReg;          /* 1C4     Reserved */
-       u8 CmdReg;              /* 1C5     Command Register */
-       u8 async_config2;       /* 1C6     Async Config Byte 2 */
-       u8 async_config3;       /* 1C7     Async Config Byte 3 */
-       u8 dce_resvd[20];       /* 1C8-1DB DCE Rsvd           */
-       u8 dce_resvd21;         /* 1DC     DCE Rsvd (21st byte */
-       u8 misc_flags;          /* 1DD     misc flags         */
-#define V2_HARDWARE     0x40
-#define ICOM_HDW_ACTIVE 0x01
-       u8 call_length;         /* 1DE     Phone #/CFI buff ln */
-       u8 call_length2;        /* 1DF     Upper byte (unused) */
-       u32 call_addr;          /* 1E0-1E3 Phn #/CFI buff addr */
-       u16 timer_value;        /* 1E4-1E5 general timer value */
-       u8 timer_command;       /* 1E6     general timer cmd  */
-       u8 dce_command;         /* 1E7     dce command reg    */
-       u8 dce_cmd_status;      /* 1E8     dce command stat   */
-       u8 x21_r1_ioff;         /* 1E9     dce ready counter  */
-       u8 x21_r0_ioff;         /* 1EA     dce not ready ctr  */
-       u8 x21_ralt_ioff;       /* 1EB     dce CNR counter    */
-       u8 x21_r1_ion;          /* 1EC     dce ready I on ctr */
-       u8 rsvd_ier;            /* 1ED     Rsvd for IER (if ne */
-       u8 ier;                 /* 1EE     Interrupt Enable   */
-       u8 isr;                 /* 1EF     Input Signal Reg   */
-       u8 osr;                 /* 1F0     Output Signal Reg  */
-       u8 reset;               /* 1F1     Reset/Reload Reg   */
-       u8 disable;             /* 1F2     Disable Reg        */
-       u8 sync;                /* 1F3     Sync Reg           */
-       u8 error_stat;          /* 1F4     Error Status       */
-       u8 cable_id;            /* 1F5     Cable ID           */
-       u8 cs_length;           /* 1F6     CS Load Length     */
-       u8 mac_length;          /* 1F7     Mac Load Length    */
-       u32 cs_load_addr;       /* 1F8-1FB Call Load PCI Addr */
-       u32 mac_load_addr;      /* 1FC-1FF Mac Load PCI Addr  */
-};
-
-/*
- * adapter defines and structures
- */
-#define ICOM_CONTROL_START_A         0x00000008
-#define ICOM_CONTROL_STOP_A          0x00000004
-#define ICOM_CONTROL_START_B         0x00000002
-#define ICOM_CONTROL_STOP_B          0x00000001
-#define ICOM_CONTROL_START_C         0x00000008
-#define ICOM_CONTROL_STOP_C          0x00000004
-#define ICOM_CONTROL_START_D         0x00000002
-#define ICOM_CONTROL_STOP_D          0x00000001
-#define ICOM_IRAM_OFFSET             0x1000
-#define ICOM_IRAM_SIZE               0x0C00
-#define ICOM_DCE_IRAM_OFFSET         0x0A00
-#define ICOM_CABLE_ID_VALID          0x01
-#define ICOM_CABLE_ID_MASK           0xF0
-#define ICOM_DISABLE                 0x80
-#define CMD_XMIT_RCV_ENABLE          0xC0
-#define CMD_XMIT_ENABLE              0x40
-#define CMD_RCV_DISABLE              0x00
-#define CMD_RCV_ENABLE               0x80
-#define CMD_RESTART                  0x01
-#define CMD_HOLD_XMIT                0x02
-#define CMD_SND_BREAK                0x04
-#define RS232_CABLE                  0x06
-#define V24_CABLE                    0x0E
-#define V35_CABLE                    0x0C
-#define V36_CABLE                    0x02
-#define NO_CABLE                     0x00
-#define START_DOWNLOAD               0x80
-#define ICOM_INT_MASK_PRC_A          0x00003FFF
-#define ICOM_INT_MASK_PRC_B          0x3FFF0000
-#define ICOM_INT_MASK_PRC_C          0x00003FFF
-#define ICOM_INT_MASK_PRC_D          0x3FFF0000
-#define INT_RCV_COMPLETED            0x1000
-#define INT_XMIT_COMPLETED           0x2000
-#define INT_IDLE_DETECT              0x0800
-#define INT_RCV_DISABLED             0x0400
-#define INT_XMIT_DISABLED            0x0200
-#define INT_RCV_XMIT_SHUTDOWN        0x0100
-#define INT_FATAL_ERROR              0x0080
-#define INT_CABLE_PULL               0x0020
-#define INT_SIGNAL_CHANGE            0x0010
-#define HDLC_PPP_PURE_ASYNC          0x02
-#define HDLC_FF_FILL                 0x00
-#define HDLC_HDW_FLOW                0x01
-#define START_XMIT                   0x80
-#define ICOM_ACFG_DRIVE1             0x20
-#define ICOM_ACFG_NO_PARITY          0x00
-#define ICOM_ACFG_PARITY_ENAB        0x02
-#define ICOM_ACFG_PARITY_ODD         0x01
-#define ICOM_ACFG_8BPC               0x00
-#define ICOM_ACFG_7BPC               0x04
-#define ICOM_ACFG_6BPC               0x08
-#define ICOM_ACFG_5BPC               0x0C
-#define ICOM_ACFG_1STOP_BIT          0x00
-#define ICOM_ACFG_2STOP_BIT          0x10
-#define ICOM_DTR                     0x80
-#define ICOM_RTS                     0x40
-#define ICOM_RI                      0x08
-#define ICOM_DSR                     0x80
-#define ICOM_DCD                     0x20
-#define ICOM_CTS                     0x40
-
-#define NUM_XBUFFS 1
-#define NUM_RBUFFS 2
-#define RCV_BUFF_SZ 0x0200
-#define XMIT_BUFF_SZ 0x1000
-struct statusArea {
-    /**********************************************/
-       /* Transmit Status Area                       */
-    /**********************************************/
-       struct xmit_status_area{
-               u32 leNext;     /* Next entry in Little Endian on Adapter */
-               u32 leNextASD;
-               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
-               u16 leLengthASD;
-               u16 leOffsetASD;
-               u16 leLength;   /* Length of data in segment */
-               u16 flags;
-#define SA_FLAGS_DONE           0x0080 /* Done with Segment */
-#define SA_FLAGS_CONTINUED      0x8000 /* More Segments */
-#define SA_FLAGS_IDLE           0x4000 /* Mark IDLE after frm */
-#define SA_FLAGS_READY_TO_XMIT  0x0800
-#define SA_FLAGS_STAT_MASK      0x007F
-       } xmit[NUM_XBUFFS];
-
-    /**********************************************/
-       /* Receive Status Area                        */
-    /**********************************************/
-       struct {
-               u32 leNext;     /* Next entry in Little Endian on Adapter */
-               u32 leNextASD;
-               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
-               u16 WorkingLength;      /* size of segment */
-               u16 reserv01;
-               u16 leLength;   /* Length of data in segment */
-               u16 flags;
-#define SA_FL_RCV_DONE           0x0010        /* Data ready */
-#define SA_FLAGS_OVERRUN         0x0040
-#define SA_FLAGS_PARITY_ERROR    0x0080
-#define SA_FLAGS_FRAME_ERROR     0x0001
-#define SA_FLAGS_FRAME_TRUNC     0x0002
-#define SA_FLAGS_BREAK_DET       0x0004        /* set conditionally by device driver, not hardware */
-#define SA_FLAGS_RCV_MASK        0xFFE6
-       } rcv[NUM_RBUFFS];
-};
-
-struct icom_adapter;
-
-
-#define ICOM_MAJOR       243
-#define ICOM_MINOR_START 0
-
-struct icom_port {
-       struct uart_port uart_port;
-       u8 imbed_modem;
-#define ICOM_UNKNOWN           1
-#define ICOM_RVX               2
-#define ICOM_IMBED_MODEM       3
-       unsigned char cable_id;
-       unsigned char read_status_mask;
-       unsigned char ignore_status_mask;
-       void __iomem * int_reg;
-       struct icom_regs __iomem *global_reg;
-       struct func_dram __iomem *dram;
-       int port;
-       struct statusArea *statStg;
-       dma_addr_t statStg_pci;
-       u32 *xmitRestart;
-       dma_addr_t xmitRestart_pci;
-       unsigned char *xmit_buf;
-       dma_addr_t xmit_buf_pci;
-       unsigned char *recv_buf;
-       dma_addr_t recv_buf_pci;
-       int next_rcv;
-       int put_length;
-       int status;
-#define ICOM_PORT_ACTIVE       1       /* Port exists. */
-#define ICOM_PORT_OFF          0       /* Port does not exist. */
-       int load_in_progress;
-       struct icom_adapter *adapter;
-};
-
-struct icom_adapter {
-       void __iomem * base_addr;
-       unsigned long base_addr_pci;
-       struct pci_dev *pci_dev;
-       struct icom_port port_info[4];
-       int index;
-       int version;
-#define ADAPTER_V1     0x0001
-#define ADAPTER_V2     0x0002
-       u32 subsystem_id;
-#define FOUR_PORT_MODEL                                0x0252
-#define V2_TWO_PORTS_RVX                       0x021A
-#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
-       int numb_ports;
-       struct list_head icom_adapter_entry;
-       struct kref kref;
-};
-
-/* prototype */
-extern void iCom_sercons_init(void);
-
-struct lookup_proc_table {
-       u32     __iomem *global_control_reg;
-       unsigned long   processor_id;
-};
-
-struct lookup_int_table {
-       u32     __iomem *global_int_mask;
-       unsigned long   processor_id;
-};
diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
deleted file mode 100644 (file)
index ab93763..0000000
+++ /dev/null
@@ -1,1406 +0,0 @@
-/****************************************************************************
- *
- * Driver for the IFX 6x60 spi modem.
- *
- * Copyright (C) 2008 Option International
- * Copyright (C) 2008 Filip Aben <f.aben@option.com>
- *                   Denis Joseph Barrow <d.barow@option.com>
- *                   Jan Dumon <j.dumon@option.com>
- *
- * Copyright (C) 2009, 2010 Intel Corp
- * Russ Gorby <richardx.r.gorby@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA
- *
- * Driver modified by Intel from Option gtm501l_spi.c
- *
- * Notes
- * o   The driver currently assumes a single device only. If you need to
- *     change this then look for saved_ifx_dev and add a device lookup
- * o   The driver is intended to be big-endian safe but has never been
- *     tested that way (no suitable hardware). There are a couple of FIXME
- *     notes by areas that may need addressing
- * o   Some of the GPIO naming/setup assumptions may need revisiting if
- *     you need to use this driver for another platform.
- *
- *****************************************************************************/
-#include <linux/module.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/tty.h>
-#include <linux/kfifo.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/serial.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/rfkill.h>
-#include <linux/fs.h>
-#include <linux/ip.h>
-#include <linux/dmapool.h>
-#include <linux/gpio.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/tty.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-#include <linux/spi/ifx_modem.h>
-#include <linux/delay.h>
-
-#include "ifx6x60.h"
-
-#define IFX_SPI_MORE_MASK              0x10
-#define IFX_SPI_MORE_BIT               12      /* bit position in u16 */
-#define IFX_SPI_CTS_BIT                        13      /* bit position in u16 */
-#define IFX_SPI_TTY_ID                 0
-#define IFX_SPI_TIMEOUT_SEC            2
-#define IFX_SPI_HEADER_0               (-1)
-#define IFX_SPI_HEADER_F               (-2)
-
-/* forward reference */
-static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
-
-/* local variables */
-static int spi_b16 = 1;                        /* 8 or 16 bit word length */
-static struct tty_driver *tty_drv;
-static struct ifx_spi_device *saved_ifx_dev;
-static struct lock_class_key ifx_spi_key;
-
-/* GPIO/GPE settings */
-
-/**
- *     mrdy_set_high           -       set MRDY GPIO
- *     @ifx: device we are controlling
- *
- */
-static inline void mrdy_set_high(struct ifx_spi_device *ifx)
-{
-       gpio_set_value(ifx->gpio.mrdy, 1);
-}
-
-/**
- *     mrdy_set_low            -       clear MRDY GPIO
- *     @ifx: device we are controlling
- *
- */
-static inline void mrdy_set_low(struct ifx_spi_device *ifx)
-{
-       gpio_set_value(ifx->gpio.mrdy, 0);
-}
-
-/**
- *     ifx_spi_power_state_set
- *     @ifx_dev: our SPI device
- *     @val: bits to set
- *
- *     Set bit in power status and signal power system if status becomes non-0
- */
-static void
-ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ifx_dev->power_lock, flags);
-
-       /*
-        * if power status is already non-0, just update, else
-        * tell power system
-        */
-       if (!ifx_dev->power_status)
-               pm_runtime_get(&ifx_dev->spi_dev->dev);
-       ifx_dev->power_status |= val;
-
-       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
-}
-
-/**
- *     ifx_spi_power_state_clear       -       clear power bit
- *     @ifx_dev: our SPI device
- *     @val: bits to clear
- *
- *     clear bit in power status and signal power system if status becomes 0
- */
-static void
-ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ifx_dev->power_lock, flags);
-
-       if (ifx_dev->power_status) {
-               ifx_dev->power_status &= ~val;
-               if (!ifx_dev->power_status)
-                       pm_runtime_put(&ifx_dev->spi_dev->dev);
-       }
-
-       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
-}
-
-/**
- *     swap_buf
- *     @buf: our buffer
- *     @len : number of bytes (not words) in the buffer
- *     @end: end of buffer
- *
- *     Swap the contents of a buffer into big endian format
- */
-static inline void swap_buf(u16 *buf, int len, void *end)
-{
-       int n;
-
-       len = ((len + 1) >> 1);
-       if ((void *)&buf[len] > end) {
-               pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
-                      &buf[len], end);
-               return;
-       }
-       for (n = 0; n < len; n++) {
-               *buf = cpu_to_be16(*buf);
-               buf++;
-       }
-}
-
-/**
- *     mrdy_assert             -       assert MRDY line
- *     @ifx_dev: our SPI device
- *
- *     Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
- *     now.
- *
- *     FIXME: Can SRDY even go high as we are running this code ?
- */
-static void mrdy_assert(struct ifx_spi_device *ifx_dev)
-{
-       int val = gpio_get_value(ifx_dev->gpio.srdy);
-       if (!val) {
-               if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
-                                     &ifx_dev->flags)) {
-                       ifx_dev->spi_timer.expires =
-                               jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
-                       add_timer(&ifx_dev->spi_timer);
-
-               }
-       }
-       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
-       mrdy_set_high(ifx_dev);
-}
-
-/**
- *     ifx_spi_hangup          -       hang up an IFX device
- *     @ifx_dev: our SPI device
- *
- *     Hang up the tty attached to the IFX device if one is currently
- *     open. If not take no action
- */
-static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
-{
-       struct tty_port *pport = &ifx_dev->tty_port;
-       struct tty_struct *tty = tty_port_tty_get(pport);
-       if (tty) {
-               tty_hangup(tty);
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     ifx_spi_timeout         -       SPI timeout
- *     @arg: our SPI device
- *
- *     The SPI has timed out: hang up the tty. Users will then see a hangup
- *     and error events.
- */
-static void ifx_spi_timeout(unsigned long arg)
-{
-       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
-
-       dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
-       ifx_spi_ttyhangup(ifx_dev);
-       mrdy_set_low(ifx_dev);
-       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-}
-
-/* char/tty operations */
-
-/**
- *     ifx_spi_tiocmget        -       get modem lines
- *     @tty: our tty device
- *     @filp: file handle issuing the request
- *
- *     Map the signal state into Linux modem flags and report the value
- *     in Linux terms
- */
-static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-       unsigned int value;
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-
-       value =
-       (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
-       (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
-       (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
-       (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
-       (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
-       (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
-       return value;
-}
-
-/**
- *     ifx_spi_tiocmset        -       set modem bits
- *     @tty: the tty structure
- *     @filp: file handle issuing the request
- *     @set: bits to set
- *     @clear: bits to clear
- *
- *     The IFX6x60 only supports DTR and RTS. Set them accordingly
- *     and flag that an update to the modem is needed.
- *
- *     FIXME: do we need to kick the tranfers when we do this ?
- */
-static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
-                           unsigned int set, unsigned int clear)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-
-       if (set & TIOCM_RTS)
-               set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
-       if (set & TIOCM_DTR)
-               set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
-       if (clear & TIOCM_RTS)
-               clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
-       if (clear & TIOCM_DTR)
-               clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
-
-       set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
-       return 0;
-}
-
-/**
- *     ifx_spi_open    -       called on tty open
- *     @tty: our tty device
- *     @filp: file handle being associated with the tty
- *
- *     Open the tty interface. We let the tty_port layer do all the work
- *     for us.
- *
- *     FIXME: Remove single device assumption and saved_ifx_dev
- */
-static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
-{
-       return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
-}
-
-/**
- *     ifx_spi_close   -       called when our tty closes
- *     @tty: the tty being closed
- *     @filp: the file handle being closed
- *
- *     Perform the close of the tty. We use the tty_port layer to do all
- *     our hard work.
- */
-static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       tty_port_close(&ifx_dev->tty_port, tty, filp);
-       /* FIXME: should we do an ifx_spi_reset here ? */
-}
-
-/**
- *     ifx_decode_spi_header   -       decode received header
- *     @buffer: the received data
- *     @length: decoded length
- *     @more: decoded more flag
- *     @received_cts: status of cts we received
- *
- *     Note how received_cts is handled -- if header is all F it is left
- *     the same as it was, if header is all 0 it is set to 0 otherwise it is
- *     taken from the incoming header.
- *
- *     FIXME: endianness
- */
-static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
-                       unsigned char *more, unsigned char *received_cts)
-{
-       u16 h1;
-       u16 h2;
-       u16 *in_buffer = (u16 *)buffer;
-
-       h1 = *in_buffer;
-       h2 = *(in_buffer+1);
-
-       if (h1 == 0 && h2 == 0) {
-               *received_cts = 0;
-               return IFX_SPI_HEADER_0;
-       } else if (h1 == 0xffff && h2 == 0xffff) {
-               /* spi_slave_cts remains as it was */
-               return IFX_SPI_HEADER_F;
-       }
-
-       *length = h1 & 0xfff;   /* upper bits of byte are flags */
-       *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
-       *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
-       return 0;
-}
-
-/**
- *     ifx_setup_spi_header    -       set header fields
- *     @txbuffer: pointer to start of SPI buffer
- *     @tx_count: bytes
- *     @more: indicate if more to follow
- *
- *     Format up an SPI header for a transfer
- *
- *     FIXME: endianness?
- */
-static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
-                                       unsigned char more)
-{
-       *(u16 *)(txbuffer) = tx_count;
-       *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
-       txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
-}
-
-/**
- *     ifx_spi_wakeup_serial   -       SPI space made
- *     @port_data: our SPI device
- *
- *     We have emptied the FIFO enough that we want to get more data
- *     queued into it. Poke the line discipline via tty_wakeup so that
- *     it will feed us more bits
- */
-static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
-{
-       struct tty_struct *tty;
-
-       tty = tty_port_tty_get(&ifx_dev->tty_port);
-       if (!tty)
-               return;
-       tty_wakeup(tty);
-       tty_kref_put(tty);
-}
-
-/**
- *     ifx_spi_prepare_tx_buffer       -       prepare transmit frame
- *     @ifx_dev: our SPI device
- *
- *     The transmit buffr needs a header and various other bits of
- *     information followed by as much data as we can pull from the FIFO
- *     and transfer. This function formats up a suitable buffer in the
- *     ifx_dev->tx_buffer
- *
- *     FIXME: performance - should we wake the tty when the queue is half
- *                          empty ?
- */
-static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
-{
-       int temp_count;
-       int queue_length;
-       int tx_count;
-       unsigned char *tx_buffer;
-
-       tx_buffer = ifx_dev->tx_buffer;
-       memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
-
-       /* make room for required SPI header */
-       tx_buffer += IFX_SPI_HEADER_OVERHEAD;
-       tx_count = IFX_SPI_HEADER_OVERHEAD;
-
-       /* clear to signal no more data if this turns out to be the
-        * last buffer sent in a sequence */
-       ifx_dev->spi_more = 0;
-
-       /* if modem cts is set, just send empty buffer */
-       if (!ifx_dev->spi_slave_cts) {
-               /* see if there's tx data */
-               queue_length = kfifo_len(&ifx_dev->tx_fifo);
-               if (queue_length != 0) {
-                       /* data to mux -- see if there's room for it */
-                       temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
-                       temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
-                                       tx_buffer, temp_count,
-                                       &ifx_dev->fifo_lock);
-
-                       /* update buffer pointer and data count in message */
-                       tx_buffer += temp_count;
-                       tx_count += temp_count;
-                       if (temp_count == queue_length)
-                               /* poke port to get more data */
-                               ifx_spi_wakeup_serial(ifx_dev);
-                       else /* more data in port, use next SPI message */
-                               ifx_dev->spi_more = 1;
-               }
-       }
-       /* have data and info for header -- set up SPI header in buffer */
-       /* spi header needs payload size, not entire buffer size */
-       ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
-                                       tx_count-IFX_SPI_HEADER_OVERHEAD,
-                                       ifx_dev->spi_more);
-       /* swap actual data in the buffer */
-       swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
-               &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
-       return tx_count;
-}
-
-/**
- *     ifx_spi_write           -       line discipline write
- *     @tty: our tty device
- *     @buf: pointer to buffer to write (kernel space)
- *     @count: size of buffer
- *
- *     Write the characters we have been given into the FIFO. If the device
- *     is not active then activate it, when the SRDY line is asserted back
- *     this will commence I/O
- */
-static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
-                        int count)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       unsigned char *tmp_buf = (unsigned char *)buf;
-       int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
-                                  &ifx_dev->fifo_lock);
-       mrdy_assert(ifx_dev);
-       return tx_count;
-}
-
-/**
- *     ifx_spi_chars_in_buffer -       line discipline helper
- *     @tty: our tty device
- *
- *     Report how much data we can accept before we drop bytes. As we use
- *     a simple FIFO this is nice and easy.
- */
-static int ifx_spi_write_room(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_spi_chars_in_buffer -       line discipline helper
- *     @tty: our tty device
- *
- *     Report how many characters we have buffered. In our case this is the
- *     number of bytes sitting in our transmit FIFO.
- */
-static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       return kfifo_len(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_port_hangup
- *     @port: our tty port
- *
- *     tty port hang up. Called when tty_hangup processing is invoked either
- *     by loss of carrier, or by software (eg vhangup). Serialized against
- *     activate/shutdown by the tty layer.
- */
-static void ifx_spi_hangup(struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev = tty->driver_data;
-       tty_port_hangup(&ifx_dev->tty_port);
-}
-
-/**
- *     ifx_port_activate
- *     @port: our tty port
- *
- *     tty port activate method - called for first open. Serialized
- *     with hangup and shutdown by the tty layer.
- */
-static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
-{
-       struct ifx_spi_device *ifx_dev =
-               container_of(port, struct ifx_spi_device, tty_port);
-
-       /* clear any old data; can't do this in 'close' */
-       kfifo_reset(&ifx_dev->tx_fifo);
-
-       /* put port data into this tty */
-       tty->driver_data = ifx_dev;
-
-       /* allows flip string push from int context */
-       tty->low_latency = 1;
-
-       return 0;
-}
-
-/**
- *     ifx_port_shutdown
- *     @port: our tty port
- *
- *     tty port shutdown method - called for last port close. Serialized
- *     with hangup and activate by the tty layer.
- */
-static void ifx_port_shutdown(struct tty_port *port)
-{
-       struct ifx_spi_device *ifx_dev =
-               container_of(port, struct ifx_spi_device, tty_port);
-
-       mrdy_set_low(ifx_dev);
-       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-       tasklet_kill(&ifx_dev->io_work_tasklet);
-}
-
-static const struct tty_port_operations ifx_tty_port_ops = {
-       .activate = ifx_port_activate,
-       .shutdown = ifx_port_shutdown,
-};
-
-static const struct tty_operations ifx_spi_serial_ops = {
-       .open = ifx_spi_open,
-       .close = ifx_spi_close,
-       .write = ifx_spi_write,
-       .hangup = ifx_spi_hangup,
-       .write_room = ifx_spi_write_room,
-       .chars_in_buffer = ifx_spi_chars_in_buffer,
-       .tiocmget = ifx_spi_tiocmget,
-       .tiocmset = ifx_spi_tiocmset,
-};
-
-/**
- *     ifx_spi_insert_fip_string       -       queue received data
- *     @ifx_ser: our SPI device
- *     @chars: buffer we have received
- *     @size: number of chars reeived
- *
- *     Queue bytes to the tty assuming the tty side is currently open. If
- *     not the discard the data.
- */
-static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
-                                   unsigned char *chars, size_t size)
-{
-       struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
-       if (!tty)
-               return;
-       tty_insert_flip_string(tty, chars, size);
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-}
-
-/**
- *     ifx_spi_complete        -       SPI transfer completed
- *     @ctx: our SPI device
- *
- *     An SPI transfer has completed. Process any received data and kick off
- *     any further transmits we can commence.
- */
-static void ifx_spi_complete(void *ctx)
-{
-       struct ifx_spi_device *ifx_dev = ctx;
-       struct tty_struct *tty;
-       struct tty_ldisc *ldisc = NULL;
-       int length;
-       int actual_length;
-       unsigned char more;
-       unsigned char cts;
-       int local_write_pending = 0;
-       int queue_length;
-       int srdy;
-       int decode_result;
-
-       mrdy_set_low(ifx_dev);
-
-       if (!ifx_dev->spi_msg.status) {
-               /* check header validity, get comm flags */
-               swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
-                       &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
-               decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
-                               &length, &more, &cts);
-               if (decode_result == IFX_SPI_HEADER_0) {
-                       dev_dbg(&ifx_dev->spi_dev->dev,
-                               "ignore input: invalid header 0");
-                       ifx_dev->spi_slave_cts = 0;
-                       goto complete_exit;
-               } else if (decode_result == IFX_SPI_HEADER_F) {
-                       dev_dbg(&ifx_dev->spi_dev->dev,
-                               "ignore input: invalid header F");
-                       goto complete_exit;
-               }
-
-               ifx_dev->spi_slave_cts = cts;
-
-               actual_length = min((unsigned int)length,
-                                       ifx_dev->spi_msg.actual_length);
-               swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
-                        actual_length,
-                        &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
-               ifx_spi_insert_flip_string(
-                       ifx_dev,
-                       ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
-                       (size_t)actual_length);
-       } else {
-               dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
-                      ifx_dev->spi_msg.status);
-       }
-
-complete_exit:
-       if (ifx_dev->write_pending) {
-               ifx_dev->write_pending = 0;
-               local_write_pending = 1;
-       }
-
-       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
-
-       queue_length = kfifo_len(&ifx_dev->tx_fifo);
-       srdy = gpio_get_value(ifx_dev->gpio.srdy);
-       if (!srdy)
-               ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
-
-       /* schedule output if there is more to do */
-       if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
-               tasklet_schedule(&ifx_dev->io_work_tasklet);
-       else {
-               if (more || ifx_dev->spi_more || queue_length > 0 ||
-                       local_write_pending) {
-                       if (ifx_dev->spi_slave_cts) {
-                               if (more)
-                                       mrdy_assert(ifx_dev);
-                       } else
-                               mrdy_assert(ifx_dev);
-               } else {
-                       /*
-                        * poke line discipline driver if any for more data
-                        * may or may not get more data to write
-                        * for now, say not busy
-                        */
-                       ifx_spi_power_state_clear(ifx_dev,
-                                                 IFX_SPI_POWER_DATA_PENDING);
-                       tty = tty_port_tty_get(&ifx_dev->tty_port);
-                       if (tty) {
-                               ldisc = tty_ldisc_ref(tty);
-                               if (ldisc) {
-                                       ldisc->ops->write_wakeup(tty);
-                                       tty_ldisc_deref(ldisc);
-                               }
-                               tty_kref_put(tty);
-                       }
-               }
-       }
-}
-
-/**
- *     ifx_spio_io             -       I/O tasklet
- *     @data: our SPI device
- *
- *     Queue data for transmission if possible and then kick off the
- *     transfer.
- */
-static void ifx_spi_io(unsigned long data)
-{
-       int retval;
-       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
-
-       if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
-               if (ifx_dev->gpio.unack_srdy_int_nb > 0)
-                       ifx_dev->gpio.unack_srdy_int_nb--;
-
-               ifx_spi_prepare_tx_buffer(ifx_dev);
-
-               spi_message_init(&ifx_dev->spi_msg);
-               INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
-
-               ifx_dev->spi_msg.context = ifx_dev;
-               ifx_dev->spi_msg.complete = ifx_spi_complete;
-
-               /* set up our spi transfer */
-               /* note len is BYTES, not transfers */
-               ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
-               ifx_dev->spi_xfer.cs_change = 0;
-               ifx_dev->spi_xfer.speed_hz = 12500000;
-               /* ifx_dev->spi_xfer.speed_hz = 390625; */
-               ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
-
-               ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
-               ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
-
-               /*
-                * setup dma pointers
-                */
-               if (ifx_dev->is_6160) {
-                       ifx_dev->spi_msg.is_dma_mapped = 1;
-                       ifx_dev->tx_dma = ifx_dev->tx_bus;
-                       ifx_dev->rx_dma = ifx_dev->rx_bus;
-                       ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
-                       ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
-               } else {
-                       ifx_dev->spi_msg.is_dma_mapped = 0;
-                       ifx_dev->tx_dma = (dma_addr_t)0;
-                       ifx_dev->rx_dma = (dma_addr_t)0;
-                       ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
-                       ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
-               }
-
-               spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
-
-               /* Assert MRDY. This may have already been done by the write
-                * routine.
-                */
-               mrdy_assert(ifx_dev);
-
-               retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
-               if (retval) {
-                       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
-                                 &ifx_dev->flags);
-                       tasklet_schedule(&ifx_dev->io_work_tasklet);
-                       return;
-               }
-       } else
-               ifx_dev->write_pending = 1;
-}
-
-/**
- *     ifx_spi_free_port       -       free up the tty side
- *     @ifx_dev: IFX device going away
- *
- *     Unregister and free up a port when the device goes away
- */
-static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
-{
-       if (ifx_dev->tty_dev)
-               tty_unregister_device(tty_drv, ifx_dev->minor);
-       kfifo_free(&ifx_dev->tx_fifo);
-}
-
-/**
- *     ifx_spi_create_port     -       create a new port
- *     @ifx_dev: our spi device
- *
- *     Allocate and initialise the tty port that goes with this interface
- *     and add it to the tty layer so that it can be opened.
- */
-static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
-{
-       int ret = 0;
-       struct tty_port *pport = &ifx_dev->tty_port;
-
-       spin_lock_init(&ifx_dev->fifo_lock);
-       lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
-               &ifx_spi_key, 0);
-
-       if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       pport->ops = &ifx_tty_port_ops;
-       tty_port_init(pport);
-       ifx_dev->minor = IFX_SPI_TTY_ID;
-       ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
-                                              &ifx_dev->spi_dev->dev);
-       if (IS_ERR(ifx_dev->tty_dev)) {
-               dev_dbg(&ifx_dev->spi_dev->dev,
-                       "%s: registering tty device failed", __func__);
-               ret = PTR_ERR(ifx_dev->tty_dev);
-               goto error_ret;
-       }
-       return 0;
-
-error_ret:
-       ifx_spi_free_port(ifx_dev);
-       return ret;
-}
-
-/**
- *     ifx_spi_handle_srdy             -       handle SRDY
- *     @ifx_dev: device asserting SRDY
- *
- *     Check our device state and see what we need to kick off when SRDY
- *     is asserted. This usually means killing the timer and firing off the
- *     I/O processing.
- */
-static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
-{
-       if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
-               del_timer_sync(&ifx_dev->spi_timer);
-               clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
-       }
-
-       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
-
-       if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
-               tasklet_schedule(&ifx_dev->io_work_tasklet);
-       else
-               set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
-}
-
-/**
- *     ifx_spi_srdy_interrupt  -       SRDY asserted
- *     @irq: our IRQ number
- *     @dev: our ifx device
- *
- *     The modem asserted SRDY. Handle the srdy event
- */
-static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
-{
-       struct ifx_spi_device *ifx_dev = dev;
-       ifx_dev->gpio.unack_srdy_int_nb++;
-       ifx_spi_handle_srdy(ifx_dev);
-       return IRQ_HANDLED;
-}
-
-/**
- *     ifx_spi_reset_interrupt -       Modem has changed reset state
- *     @irq: interrupt number
- *     @dev: our device pointer
- *
- *     The modem has either entered or left reset state. Check the GPIO
- *     line to see which.
- *
- *     FIXME: review locking on MR_INPROGRESS versus
- *     parallel unsolicited reset/solicited reset
- */
-static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
-{
-       struct ifx_spi_device *ifx_dev = dev;
-       int val = gpio_get_value(ifx_dev->gpio.reset_out);
-       int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
-
-       if (val == 0) {
-               /* entered reset */
-               set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
-               if (!solreset) {
-                       /* unsolicited reset  */
-                       ifx_spi_ttyhangup(ifx_dev);
-               }
-       } else {
-               /* exited reset */
-               clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
-               if (solreset) {
-                       set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
-                       wake_up(&ifx_dev->mdm_reset_wait);
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-/**
- *     ifx_spi_free_device - free device
- *     @ifx_dev: device to free
- *
- *     Free the IFX device
- */
-static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
-{
-       ifx_spi_free_port(ifx_dev);
-       dma_free_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               ifx_dev->tx_buffer,
-                               ifx_dev->tx_bus);
-       dma_free_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               ifx_dev->rx_buffer,
-                               ifx_dev->rx_bus);
-}
-
-/**
- *     ifx_spi_reset   -       reset modem
- *     @ifx_dev: modem to reset
- *
- *     Perform a reset on the modem
- */
-static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
-{
-       int ret;
-       /*
-        * set up modem power, reset
-        *
-        * delays are required on some platforms for the modem
-        * to reset properly
-        */
-       set_bit(MR_START, &ifx_dev->mdm_reset_state);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       gpio_set_value(ifx_dev->gpio.reset, 0);
-       msleep(25);
-       gpio_set_value(ifx_dev->gpio.reset, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 1);
-       msleep(1);
-       gpio_set_value(ifx_dev->gpio.po, 0);
-       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
-                                test_bit(MR_COMPLETE,
-                                         &ifx_dev->mdm_reset_state),
-                                IFX_RESET_TIMEOUT);
-       if (!ret)
-               dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
-                        ifx_dev->mdm_reset_state);
-
-       ifx_dev->mdm_reset_state = 0;
-       return ret;
-}
-
-/**
- *     ifx_spi_spi_probe       -       probe callback
- *     @spi: our possible matching SPI device
- *
- *     Probe for a 6x60 modem on SPI bus. Perform any needed device and
- *     GPIO setup.
- *
- *     FIXME:
- *     -       Support for multiple devices
- *     -       Split out MID specific GPIO handling eventually
- */
-
-static int ifx_spi_spi_probe(struct spi_device *spi)
-{
-       int ret;
-       int srdy;
-       struct ifx_modem_platform_data *pl_data = NULL;
-       struct ifx_spi_device *ifx_dev;
-
-       if (saved_ifx_dev) {
-               dev_dbg(&spi->dev, "ignoring subsequent detection");
-               return -ENODEV;
-       }
-
-       /* initialize structure to hold our device variables */
-       ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
-       if (!ifx_dev) {
-               dev_err(&spi->dev, "spi device allocation failed");
-               return -ENOMEM;
-       }
-       saved_ifx_dev = ifx_dev;
-       ifx_dev->spi_dev = spi;
-       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
-       spin_lock_init(&ifx_dev->write_lock);
-       spin_lock_init(&ifx_dev->power_lock);
-       ifx_dev->power_status = 0;
-       init_timer(&ifx_dev->spi_timer);
-       ifx_dev->spi_timer.function = ifx_spi_timeout;
-       ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
-       ifx_dev->is_6160 = pl_data->is_6160;
-
-       /* ensure SPI protocol flags are initialized to enable transfer */
-       ifx_dev->spi_more = 0;
-       ifx_dev->spi_slave_cts = 0;
-
-       /*initialize transfer and dma buffers */
-       ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               &ifx_dev->tx_bus,
-                               GFP_KERNEL);
-       if (!ifx_dev->tx_buffer) {
-               dev_err(&spi->dev, "DMA-TX buffer allocation failed");
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-       ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
-                               IFX_SPI_TRANSFER_SIZE,
-                               &ifx_dev->rx_bus,
-                               GFP_KERNEL);
-       if (!ifx_dev->rx_buffer) {
-               dev_err(&spi->dev, "DMA-RX buffer allocation failed");
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       /* initialize waitq for modem reset */
-       init_waitqueue_head(&ifx_dev->mdm_reset_wait);
-
-       spi_set_drvdata(spi, ifx_dev);
-       tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
-                                               (unsigned long)ifx_dev);
-
-       set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
-
-       /* create our tty port */
-       ret = ifx_spi_create_port(ifx_dev);
-       if (ret != 0) {
-               dev_err(&spi->dev, "create default tty port failed");
-               goto error_ret;
-       }
-
-       pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
-       if (pl_data) {
-               ifx_dev->gpio.reset = pl_data->rst_pmu;
-               ifx_dev->gpio.po = pl_data->pwr_on;
-               ifx_dev->gpio.mrdy = pl_data->mrdy;
-               ifx_dev->gpio.srdy = pl_data->srdy;
-               ifx_dev->gpio.reset_out = pl_data->rst_out;
-       } else {
-               dev_err(&spi->dev, "missing platform data!");
-               ret = -ENODEV;
-               goto error_ret;
-       }
-
-       dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
-                ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
-                ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
-
-       /* Configure gpios */
-       ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
-                       ifx_dev->gpio.reset);
-               goto error_ret;
-       }
-       ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
-       ret += gpio_export(ifx_dev->gpio.reset, 1);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
-                       ifx_dev->gpio.reset);
-               ret = -EBUSY;
-               goto error_ret2;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
-       ret += gpio_direction_output(ifx_dev->gpio.po, 0);
-       ret += gpio_export(ifx_dev->gpio.po, 1);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
-                       ifx_dev->gpio.po);
-               ret = -EBUSY;
-               goto error_ret3;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
-                       ifx_dev->gpio.mrdy);
-               goto error_ret3;
-       }
-       ret += gpio_export(ifx_dev->gpio.mrdy, 1);
-       ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
-                       ifx_dev->gpio.mrdy);
-               ret = -EBUSY;
-               goto error_ret4;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
-                       ifx_dev->gpio.srdy);
-               ret = -EBUSY;
-               goto error_ret4;
-       }
-       ret += gpio_export(ifx_dev->gpio.srdy, 1);
-       ret += gpio_direction_input(ifx_dev->gpio.srdy);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
-                       ifx_dev->gpio.srdy);
-               ret = -EBUSY;
-               goto error_ret5;
-       }
-
-       ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
-                       ifx_dev->gpio.reset_out);
-               goto error_ret5;
-       }
-       ret += gpio_export(ifx_dev->gpio.reset_out, 1);
-       ret += gpio_direction_input(ifx_dev->gpio.reset_out);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
-                       ifx_dev->gpio.reset_out);
-               ret = -EBUSY;
-               goto error_ret6;
-       }
-
-       ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
-                         ifx_spi_reset_interrupt,
-                         IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
-               (void *)ifx_dev);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to get irq %x\n",
-                       gpio_to_irq(ifx_dev->gpio.reset_out));
-               goto error_ret6;
-       }
-
-       ret = ifx_spi_reset(ifx_dev);
-
-       ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
-                         ifx_spi_srdy_interrupt,
-                         IRQF_TRIGGER_RISING, DRVNAME,
-                         (void *)ifx_dev);
-       if (ret) {
-               dev_err(&spi->dev, "Unable to get irq %x",
-                       gpio_to_irq(ifx_dev->gpio.srdy));
-               goto error_ret7;
-       }
-
-       /* set pm runtime power state and register with power system */
-       pm_runtime_set_active(&spi->dev);
-       pm_runtime_enable(&spi->dev);
-
-       /* handle case that modem is already signaling SRDY */
-       /* no outgoing tty open at this point, this just satisfies the
-        * modem's read and should reset communication properly
-        */
-       srdy = gpio_get_value(ifx_dev->gpio.srdy);
-
-       if (srdy) {
-               mrdy_assert(ifx_dev);
-               ifx_spi_handle_srdy(ifx_dev);
-       } else
-               mrdy_set_low(ifx_dev);
-       return 0;
-
-error_ret7:
-       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
-error_ret6:
-       gpio_free(ifx_dev->gpio.srdy);
-error_ret5:
-       gpio_free(ifx_dev->gpio.mrdy);
-error_ret4:
-       gpio_free(ifx_dev->gpio.reset);
-error_ret3:
-       gpio_free(ifx_dev->gpio.po);
-error_ret2:
-       gpio_free(ifx_dev->gpio.reset_out);
-error_ret:
-       ifx_spi_free_device(ifx_dev);
-       saved_ifx_dev = NULL;
-       return ret;
-}
-
-/**
- *     ifx_spi_spi_remove      -       SPI device was removed
- *     @spi: SPI device
- *
- *     FIXME: We should be shutting the device down here not in
- *     the module unload path.
- */
-
-static int ifx_spi_spi_remove(struct spi_device *spi)
-{
-       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
-       /* stop activity */
-       tasklet_kill(&ifx_dev->io_work_tasklet);
-       /* free irq */
-       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
-       free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
-
-       gpio_free(ifx_dev->gpio.srdy);
-       gpio_free(ifx_dev->gpio.mrdy);
-       gpio_free(ifx_dev->gpio.reset);
-       gpio_free(ifx_dev->gpio.po);
-       gpio_free(ifx_dev->gpio.reset_out);
-
-       /* free allocations */
-       ifx_spi_free_device(ifx_dev);
-
-       saved_ifx_dev = NULL;
-       return 0;
-}
-
-/**
- *     ifx_spi_spi_shutdown    -       called on SPI shutdown
- *     @spi: SPI device
- *
- *     No action needs to be taken here
- */
-
-static void ifx_spi_spi_shutdown(struct spi_device *spi)
-{
-}
-
-/*
- * various suspends and resumes have nothing to do
- * no hardware to save state for
- */
-
-/**
- *     ifx_spi_spi_suspend     -       suspend SPI on system suspend
- *     @dev: device being suspended
- *
- *     Suspend the SPI side. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_spi_resume      -       resume SPI side on system resume
- *     @dev: device being suspended
- *
- *     Suspend the SPI side. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_spi_resume(struct spi_device *spi)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_suspend      -       suspend modem on system suspend
- *     @dev: device being suspended
- *
- *     Suspend the modem. No action needed on Intel MID platforms, may
- *     need extending for other systems.
- */
-static int ifx_spi_pm_suspend(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_resume       -       resume modem on system resume
- *     @dev: device being suspended
- *
- *     Allow the modem to resume. No action needed.
- *
- *     FIXME: do we need to reset anything here ?
- */
-static int ifx_spi_pm_resume(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_resume       -       suspend modem
- *     @dev: device being suspended
- *
- *     Allow the modem to resume. No action needed.
- */
-static int ifx_spi_pm_runtime_resume(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_suspend      -       suspend modem
- *     @dev: device being suspended
- *
- *     Allow the modem to suspend and thus suspend to continue up the
- *     device tree.
- */
-static int ifx_spi_pm_runtime_suspend(struct device *dev)
-{
-       return 0;
-}
-
-/**
- *     ifx_spi_pm_runtime_idle         -       check if modem idle
- *     @dev: our device
- *
- *     Check conditions and queue runtime suspend if idle.
- */
-static int ifx_spi_pm_runtime_idle(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
-
-       if (!ifx_dev->power_status)
-               pm_runtime_suspend(dev);
-
-       return 0;
-}
-
-static const struct dev_pm_ops ifx_spi_pm = {
-       .resume = ifx_spi_pm_resume,
-       .suspend = ifx_spi_pm_suspend,
-       .runtime_resume = ifx_spi_pm_runtime_resume,
-       .runtime_suspend = ifx_spi_pm_runtime_suspend,
-       .runtime_idle = ifx_spi_pm_runtime_idle
-};
-
-static const struct spi_device_id ifx_id_table[] = {
-       {"ifx6160", 0},
-       {"ifx6260", 0},
-       { }
-};
-MODULE_DEVICE_TABLE(spi, ifx_id_table);
-
-/* spi operations */
-static const struct spi_driver ifx_spi_driver_6160 = {
-       .driver = {
-               .name = "ifx6160",
-               .bus = &spi_bus_type,
-               .pm = &ifx_spi_pm,
-               .owner = THIS_MODULE},
-       .probe = ifx_spi_spi_probe,
-       .shutdown = ifx_spi_spi_shutdown,
-       .remove = __devexit_p(ifx_spi_spi_remove),
-       .suspend = ifx_spi_spi_suspend,
-       .resume = ifx_spi_spi_resume,
-       .id_table = ifx_id_table
-};
-
-/**
- *     ifx_spi_exit    -       module exit
- *
- *     Unload the module.
- */
-
-static void __exit ifx_spi_exit(void)
-{
-       /* unregister */
-       tty_unregister_driver(tty_drv);
-       spi_unregister_driver((void *)&ifx_spi_driver_6160);
-}
-
-/**
- *     ifx_spi_init            -       module entry point
- *
- *     Initialise the SPI and tty interfaces for the IFX SPI driver
- *     We need to initialize upper-edge spi driver after the tty
- *     driver because otherwise the spi probe will race
- */
-
-static int __init ifx_spi_init(void)
-{
-       int result;
-
-       tty_drv = alloc_tty_driver(1);
-       if (!tty_drv) {
-               pr_err("%s: alloc_tty_driver failed", DRVNAME);
-               return -ENOMEM;
-       }
-
-       tty_drv->magic = TTY_DRIVER_MAGIC;
-       tty_drv->owner = THIS_MODULE;
-       tty_drv->driver_name = DRVNAME;
-       tty_drv->name = TTYNAME;
-       tty_drv->minor_start = IFX_SPI_TTY_ID;
-       tty_drv->num = 1;
-       tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-       tty_drv->subtype = SERIAL_TYPE_NORMAL;
-       tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       tty_drv->init_termios = tty_std_termios;
-
-       tty_set_operations(tty_drv, &ifx_spi_serial_ops);
-
-       result = tty_register_driver(tty_drv);
-       if (result) {
-               pr_err("%s: tty_register_driver failed(%d)",
-                       DRVNAME, result);
-               put_tty_driver(tty_drv);
-               return result;
-       }
-
-       result = spi_register_driver((void *)&ifx_spi_driver_6160);
-       if (result) {
-               pr_err("%s: spi_register_driver failed(%d)",
-                       DRVNAME, result);
-               tty_unregister_driver(tty_drv);
-       }
-       return result;
-}
-
-module_init(ifx_spi_init);
-module_exit(ifx_spi_exit);
-
-MODULE_AUTHOR("Intel");
-MODULE_DESCRIPTION("IFX6x60 spi driver");
-MODULE_LICENSE("GPL");
-MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
deleted file mode 100644 (file)
index deb7b8d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
- *
- * Driver for the IFX spi modem.
- *
- * Copyright (C) 2009, 2010 Intel Corp
- * Jim Stanley <jim.stanley@intel.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA
- *
- *
- *
- *****************************************************************************/
-#ifndef _IFX6X60_H
-#define _IFX6X60_H
-
-#define DRVNAME                                "ifx6x60"
-#define TTYNAME                                "ttyIFX"
-
-/* #define IFX_THROTTLE_CODE */
-
-#define IFX_SPI_MAX_MINORS             1
-#define IFX_SPI_TRANSFER_SIZE          2048
-#define IFX_SPI_FIFO_SIZE              4096
-
-#define IFX_SPI_HEADER_OVERHEAD                4
-#define IFX_RESET_TIMEOUT              msecs_to_jiffies(50)
-
-/* device flags bitfield definitions */
-#define IFX_SPI_STATE_PRESENT          0
-#define IFX_SPI_STATE_IO_IN_PROGRESS   1
-#define IFX_SPI_STATE_IO_READY         2
-#define IFX_SPI_STATE_TIMER_PENDING    3
-
-/* flow control bitfields */
-#define IFX_SPI_DCD                    0
-#define IFX_SPI_CTS                    1
-#define IFX_SPI_DSR                    2
-#define IFX_SPI_RI                     3
-#define IFX_SPI_DTR                    4
-#define IFX_SPI_RTS                    5
-#define IFX_SPI_TX_FC                  6
-#define IFX_SPI_RX_FC                  7
-#define IFX_SPI_UPDATE                 8
-
-#define IFX_SPI_PAYLOAD_SIZE           (IFX_SPI_TRANSFER_SIZE - \
-                                               IFX_SPI_HEADER_OVERHEAD)
-
-#define IFX_SPI_IRQ_TYPE               DETECT_EDGE_RISING
-#define IFX_SPI_GPIO_TARGET            0
-#define IFX_SPI_GPIO0                  0x105
-
-#define IFX_SPI_STATUS_TIMEOUT         (2000*HZ)
-
-/* values for bits in power status byte */
-#define IFX_SPI_POWER_DATA_PENDING     1
-#define IFX_SPI_POWER_SRDY             2
-
-struct ifx_spi_device {
-       /* Our SPI device */
-       struct spi_device *spi_dev;
-
-       /* Port specific data */
-       struct kfifo tx_fifo;
-       spinlock_t fifo_lock;
-       unsigned long signal_state;
-
-       /* TTY Layer logic */
-       struct tty_port tty_port;
-       struct device *tty_dev;
-       int minor;
-
-       /* Low level I/O work */
-       struct tasklet_struct io_work_tasklet;
-       unsigned long flags;
-       dma_addr_t rx_dma;
-       dma_addr_t tx_dma;
-
-       int is_6160;                            /* Modem type */
-
-       spinlock_t write_lock;
-       int write_pending;
-       spinlock_t power_lock;
-       unsigned char power_status;
-
-       unsigned char *rx_buffer;
-       unsigned char *tx_buffer;
-       dma_addr_t rx_bus;
-       dma_addr_t tx_bus;
-       unsigned char spi_more;
-       unsigned char spi_slave_cts;
-
-       struct timer_list spi_timer;
-
-       struct spi_message spi_msg;
-       struct spi_transfer spi_xfer;
-
-       struct {
-               /* gpio lines */
-               unsigned short srdy;            /* slave-ready gpio */
-               unsigned short mrdy;            /* master-ready gpio */
-               unsigned short reset;           /* modem-reset gpio */
-               unsigned short po;              /* modem-on gpio */
-               unsigned short reset_out;       /* modem-in-reset gpio */
-               /* state/stats */
-               int unack_srdy_int_nb;
-       } gpio;
-
-       /* modem reset */
-       unsigned long mdm_reset_state;
-#define MR_START       0
-#define MR_INPROGRESS  1
-#define MR_COMPLETE    2
-       wait_queue_head_t mdm_reset_wait;
-};
-
-#endif /* _IFX6X60_H */
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
deleted file mode 100644 (file)
index dfcf4b1..0000000
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- *  linux/drivers/serial/imx.c
- *
- *  Driver for Motorola IMX serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Author: Sascha Hauer <sascha@saschahauer.de>
- *  Copyright (C) 2004 Pengutronix
- *
- *  Copyright (C) 2009 emlix GmbH
- *  Author: Fabian Godehardt (added IrDA support for iMX)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * [29-Mar-2005] Mike Lee
- * Added hardware handshake
- */
-
-#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/rational.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/imx-uart.h>
-
-/* Register definitions */
-#define URXD0 0x0  /* Receiver Register */
-#define URTX0 0x40 /* Transmitter Register */
-#define UCR1  0x80 /* Control Register 1 */
-#define UCR2  0x84 /* Control Register 2 */
-#define UCR3  0x88 /* Control Register 3 */
-#define UCR4  0x8c /* Control Register 4 */
-#define UFCR  0x90 /* FIFO Control Register */
-#define USR1  0x94 /* Status Register 1 */
-#define USR2  0x98 /* Status Register 2 */
-#define UESC  0x9c /* Escape Character Register */
-#define UTIM  0xa0 /* Escape Timer Register */
-#define UBIR  0xa4 /* BRM Incremental Register */
-#define UBMR  0xa8 /* BRM Modulator Register */
-#define UBRC  0xac /* Baud Rate Count Register */
-#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
-
-/* UART Control Register Bit Fields.*/
-#define  URXD_CHARRDY    (1<<15)
-#define  URXD_ERR        (1<<14)
-#define  URXD_OVRRUN     (1<<13)
-#define  URXD_FRMERR     (1<<12)
-#define  URXD_BRK        (1<<11)
-#define  URXD_PRERR      (1<<10)
-#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
-#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
-#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
-#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
-#define  UCR1_RRDYEN     (1<<9)         /* Recv ready interrupt enable */
-#define  UCR1_RDMAEN     (1<<8)         /* Recv ready DMA enable */
-#define  UCR1_IREN       (1<<7)         /* Infrared interface enable */
-#define  UCR1_TXMPTYEN   (1<<6)         /* Transimitter empty interrupt enable */
-#define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
-#define  UCR1_SNDBRK     (1<<4)         /* Send break */
-#define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
-#define  UCR1_DOZE       (1<<1)         /* Doze */
-#define  UCR1_UARTEN     (1<<0)         /* UART enabled */
-#define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
-#define  UCR2_IRTS      (1<<14) /* Ignore RTS pin */
-#define  UCR2_CTSC      (1<<13) /* CTS pin control */
-#define  UCR2_CTS        (1<<12) /* Clear to send */
-#define  UCR2_ESCEN      (1<<11) /* Escape enable */
-#define  UCR2_PREN       (1<<8)  /* Parity enable */
-#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
-#define  UCR2_STPB       (1<<6)         /* Stop */
-#define  UCR2_WS         (1<<5)         /* Word size */
-#define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
-#define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
-#define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
-#define  UCR2_SRST      (1<<0)  /* SW reset */
-#define  UCR3_DTREN     (1<<13) /* DTR interrupt enable */
-#define  UCR3_PARERREN   (1<<12) /* Parity enable */
-#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
-#define  UCR3_DSR        (1<<10) /* Data set ready */
-#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
-#define  UCR3_RI         (1<<8)  /* Ring indicator */
-#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
-#define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
-#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
-#define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
-#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
-#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
-#define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
-#define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
-#define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
-#define  UCR4_CTSTL_MASK 0x3F    /* CTS trigger is 6 bits wide */
-#define  UCR4_INVR      (1<<9)  /* Inverted infrared reception */
-#define  UCR4_ENIRI     (1<<8)  /* Serial infrared interrupt enable */
-#define  UCR4_WKEN      (1<<7)  /* Wake interrupt enable */
-#define  UCR4_REF16     (1<<6)  /* Ref freq 16 MHz */
-#define  UCR4_IRSC      (1<<5)  /* IR special case */
-#define  UCR4_TCEN      (1<<3)  /* Transmit complete interrupt enable */
-#define  UCR4_BKEN      (1<<2)  /* Break condition interrupt enable */
-#define  UCR4_OREN      (1<<1)  /* Receiver overrun interrupt enable */
-#define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
-#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
-#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
-#define  UFCR_RFDIV_REG(x)     (((x) < 7 ? 6 - (x) : 6) << 7)
-#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
-#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
-#define  USR1_RTSS      (1<<14) /* RTS pin status */
-#define  USR1_TRDY      (1<<13) /* Transmitter ready interrupt/dma flag */
-#define  USR1_RTSD      (1<<12) /* RTS delta */
-#define  USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
-#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
-#define  USR1_RRDY       (1<<9)         /* Receiver ready interrupt/dma flag */
-#define  USR1_TIMEOUT    (1<<7)         /* Receive timeout interrupt status */
-#define  USR1_RXDS      (1<<6)  /* Receiver idle interrupt flag */
-#define  USR1_AIRINT    (1<<5)  /* Async IR wake interrupt flag */
-#define  USR1_AWAKE     (1<<4)  /* Aysnc wake interrupt flag */
-#define  USR2_ADET      (1<<15) /* Auto baud rate detect complete */
-#define  USR2_TXFE      (1<<14) /* Transmit buffer FIFO empty */
-#define  USR2_DTRF      (1<<13) /* DTR edge interrupt flag */
-#define  USR2_IDLE      (1<<12) /* Idle condition */
-#define  USR2_IRINT     (1<<8)  /* Serial infrared interrupt flag */
-#define  USR2_WAKE      (1<<7)  /* Wake */
-#define  USR2_RTSF      (1<<4)  /* RTS edge interrupt flag */
-#define  USR2_TXDC      (1<<3)  /* Transmitter complete */
-#define  USR2_BRCD      (1<<2)  /* Break condition */
-#define  USR2_ORE        (1<<1)         /* Overrun error */
-#define  USR2_RDR        (1<<0)         /* Recv data ready */
-#define  UTS_FRCPERR    (1<<13) /* Force parity error */
-#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
-#define  UTS_TXEMPTY    (1<<6)  /* TxFIFO empty */
-#define  UTS_RXEMPTY    (1<<5)  /* RxFIFO empty */
-#define  UTS_TXFULL     (1<<4)  /* TxFIFO full */
-#define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
-#define  UTS_SOFTRST    (1<<0)  /* Software reset */
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_IMX_MAJOR        207
-#define MINOR_START            16
-#define DEV_NAME               "ttymxc"
-#define MAX_INTERNAL_IRQ       MXC_INTERNAL_IRQS
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-#define DRIVER_NAME "IMX-uart"
-
-#define UART_NR 8
-
-struct imx_port {
-       struct uart_port        port;
-       struct timer_list       timer;
-       unsigned int            old_status;
-       int                     txirq,rxirq,rtsirq;
-       unsigned int            have_rtscts:1;
-       unsigned int            use_irda:1;
-       unsigned int            irda_inv_rx:1;
-       unsigned int            irda_inv_tx:1;
-       unsigned short          trcv_delay; /* transceiver delay */
-       struct clk              *clk;
-};
-
-#ifdef CONFIG_IRDA
-#define USE_IRDA(sport)        ((sport)->use_irda)
-#else
-#define USE_IRDA(sport)        (0)
-#endif
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void imx_mctrl_check(struct imx_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void imx_timeout(unsigned long data)
-{
-       struct imx_port *sport = (struct imx_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               imx_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_tx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       if (USE_IRDA(sport)) {
-               /* half duplex - wait for end of transmission */
-               int n = 256;
-               while ((--n > 0) &&
-                     !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
-                       udelay(5);
-                       barrier();
-               }
-               /*
-                * irda transceiver - wait a bit more to avoid
-                * cutoff, hardware dependent
-                */
-               udelay(sport->trcv_delay);
-
-               /*
-                * half duplex - reactivate receive mode,
-                * flush receive pipe echo crap
-                */
-               if (readl(sport->port.membase + USR2) & USR2_TXDC) {
-                       temp = readl(sport->port.membase + UCR1);
-                       temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
-                       writel(temp, sport->port.membase + UCR1);
-
-                       temp = readl(sport->port.membase + UCR4);
-                       temp &= ~(UCR4_TCEN);
-                       writel(temp, sport->port.membase + UCR4);
-
-                       while (readl(sport->port.membase + URXD0) &
-                              URXD_CHARRDY)
-                               barrier();
-
-                       temp = readl(sport->port.membase + UCR1);
-                       temp |= UCR1_RRDYEN;
-                       writel(temp, sport->port.membase + UCR1);
-
-                       temp = readl(sport->port.membase + UCR4);
-                       temp |= UCR4_DREN;
-                       writel(temp, sport->port.membase + UCR4);
-               }
-               return;
-       }
-
-       temp = readl(sport->port.membase + UCR1);
-       writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_rx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2);
-       writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void imx_enable_ms(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static inline void imx_transmit_buffer(struct imx_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
-               /* send xmit->buf[xmit->tail]
-                * out the port here */
-               writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               imx_stop_tx(&sport->port);
-}
-
-/*
- * interrupts disabled on entry
- */
-static void imx_start_tx(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       if (USE_IRDA(sport)) {
-               /* half duplex in IrDA mode; have to disable receive mode */
-               temp = readl(sport->port.membase + UCR4);
-               temp &= ~(UCR4_DREN);
-               writel(temp, sport->port.membase + UCR4);
-
-               temp = readl(sport->port.membase + UCR1);
-               temp &= ~(UCR1_RRDYEN);
-               writel(temp, sport->port.membase + UCR1);
-       }
-
-       temp = readl(sport->port.membase + UCR1);
-       writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
-
-       if (USE_IRDA(sport)) {
-               temp = readl(sport->port.membase + UCR1);
-               temp |= UCR1_TRDYEN;
-               writel(temp, sport->port.membase + UCR1);
-
-               temp = readl(sport->port.membase + UCR4);
-               temp |= UCR4_TCEN;
-               writel(temp, sport->port.membase + UCR4);
-       }
-
-       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
-               imx_transmit_buffer(sport);
-}
-
-static irqreturn_t imx_rtsint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       writel(USR1_RTSD, sport->port.membase + USR1);
-       uart_handle_cts_change(&sport->port, !!val);
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_txint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->port.lock,flags);
-       if (sport->port.x_char)
-       {
-               /* Send next char */
-               writel(sport->port.x_char, sport->port.membase + URTX0);
-               goto out;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               imx_stop_tx(&sport->port);
-               goto out;
-       }
-
-       imx_transmit_buffer(sport);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-out:
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_rxint(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int rx,flg,ignored = 0;
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned long flags, temp;
-
-       spin_lock_irqsave(&sport->port.lock,flags);
-
-       while (readl(sport->port.membase + USR2) & USR2_RDR) {
-               flg = TTY_NORMAL;
-               sport->port.icount.rx++;
-
-               rx = readl(sport->port.membase + URXD0);
-
-               temp = readl(sport->port.membase + USR2);
-               if (temp & USR2_BRCD) {
-                       writel(USR2_BRCD, sport->port.membase + USR2);
-                       if (uart_handle_break(&sport->port))
-                               continue;
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
-                       continue;
-
-               if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
-                       if (rx & URXD_PRERR)
-                               sport->port.icount.parity++;
-                       else if (rx & URXD_FRMERR)
-                               sport->port.icount.frame++;
-                       if (rx & URXD_OVRRUN)
-                               sport->port.icount.overrun++;
-
-                       if (rx & sport->port.ignore_status_mask) {
-                               if (++ignored > 100)
-                                       goto out;
-                               continue;
-                       }
-
-                       rx &= sport->port.read_status_mask;
-
-                       if (rx & URXD_PRERR)
-                               flg = TTY_PARITY;
-                       else if (rx & URXD_FRMERR)
-                               flg = TTY_FRAME;
-                       if (rx & URXD_OVRRUN)
-                               flg = TTY_OVERRUN;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               tty_insert_flip_char(tty, rx, flg);
-       }
-
-out:
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-       tty_flip_buffer_push(tty);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_int(int irq, void *dev_id)
-{
-       struct imx_port *sport = dev_id;
-       unsigned int sts;
-
-       sts = readl(sport->port.membase + USR1);
-
-       if (sts & USR1_RRDY)
-               imx_rxint(irq, dev_id);
-
-       if (sts & USR1_TRDY &&
-                       readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
-               imx_txint(irq, dev_id);
-
-       if (sts & USR1_RTSD)
-               imx_rtsint(irq, dev_id);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int imx_tx_empty(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
-}
-
-/*
- * We have a modem side uart, so the meanings of RTS and CTS are inverted.
- */
-static unsigned int imx_get_mctrl(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
-
-       if (readl(sport->port.membase + USR1) & USR1_RTSS)
-               tmp |= TIOCM_CTS;
-
-       if (readl(sport->port.membase + UCR2) & UCR2_CTS)
-               tmp |= TIOCM_RTS;
-
-       return tmp;
-}
-
-static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
-
-       if (mctrl & TIOCM_RTS)
-               temp |= UCR2_CTS;
-
-       writel(temp, sport->port.membase + UCR2);
-}
-
-/*
- * Interrupts always disabled.
- */
-static void imx_break_ctl(struct uart_port *port, int break_state)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long flags, temp;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
-
-       if ( break_state != 0 )
-               temp |= UCR1_SNDBRK;
-
-       writel(temp, sport->port.membase + UCR1);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-#define TXTL 2 /* reset default */
-#define RXTL 1 /* reset default */
-
-static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
-{
-       unsigned int val;
-       unsigned int ufcr_rfdiv;
-
-       /* set receiver / transmitter trigger level.
-        * RFDIV is set such way to satisfy requested uartclk value
-        */
-       val = TXTL << 10 | RXTL;
-       ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
-                       / sport->port.uartclk;
-
-       if(!ufcr_rfdiv)
-               ufcr_rfdiv = 1;
-
-       val |= UFCR_RFDIV_REG(ufcr_rfdiv);
-
-       writel(val, sport->port.membase + UFCR);
-
-       return 0;
-}
-
-/* half the RX buffer size */
-#define CTSTL 16
-
-static int imx_startup(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       int retval;
-       unsigned long flags, temp;
-
-       imx_setup_ufcr(sport, 0);
-
-       /* disable the DREN bit (Data Ready interrupt enable) before
-        * requesting IRQs
-        */
-       temp = readl(sport->port.membase + UCR4);
-
-       if (USE_IRDA(sport))
-               temp |= UCR4_IRSC;
-
-       /* set the trigger level for CTS */
-       temp &= ~(UCR4_CTSTL_MASK<<  UCR4_CTSTL_SHF);
-       temp |= CTSTL<<  UCR4_CTSTL_SHF;
-
-       writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
-
-       if (USE_IRDA(sport)) {
-               /* reset fifo's and state machines */
-               int i = 100;
-               temp = readl(sport->port.membase + UCR2);
-               temp &= ~UCR2_SRST;
-               writel(temp, sport->port.membase + UCR2);
-               while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
-                   (--i > 0)) {
-                       udelay(1);
-               }
-       }
-
-       /*
-        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
-        * chips only have one interrupt.
-        */
-       if (sport->txirq > 0) {
-               retval = request_irq(sport->rxirq, imx_rxint, 0,
-                               DRIVER_NAME, sport);
-               if (retval)
-                       goto error_out1;
-
-               retval = request_irq(sport->txirq, imx_txint, 0,
-                               DRIVER_NAME, sport);
-               if (retval)
-                       goto error_out2;
-
-               /* do not use RTS IRQ on IrDA */
-               if (!USE_IRDA(sport)) {
-                       retval = request_irq(sport->rtsirq, imx_rtsint,
-                                    (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
-                                      IRQF_TRIGGER_FALLING |
-                                      IRQF_TRIGGER_RISING,
-                                       DRIVER_NAME, sport);
-                       if (retval)
-                               goto error_out3;
-               }
-       } else {
-               retval = request_irq(sport->port.irq, imx_int, 0,
-                               DRIVER_NAME, sport);
-               if (retval) {
-                       free_irq(sport->port.irq, sport);
-                       goto error_out1;
-               }
-       }
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-       writel(USR1_RTSD, sport->port.membase + USR1);
-
-       temp = readl(sport->port.membase + UCR1);
-       temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
-
-       if (USE_IRDA(sport)) {
-               temp |= UCR1_IREN;
-               temp &= ~(UCR1_RTSDEN);
-       }
-
-       writel(temp, sport->port.membase + UCR1);
-
-       temp = readl(sport->port.membase + UCR2);
-       temp |= (UCR2_RXEN | UCR2_TXEN);
-       writel(temp, sport->port.membase + UCR2);
-
-       if (USE_IRDA(sport)) {
-               /* clear RX-FIFO */
-               int i = 64;
-               while ((--i > 0) &&
-                       (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
-                       barrier();
-               }
-       }
-
-       if (!cpu_is_mx1()) {
-               temp = readl(sport->port.membase + UCR3);
-               temp |= MX2_UCR3_RXDMUXSEL;
-               writel(temp, sport->port.membase + UCR3);
-       }
-
-       if (USE_IRDA(sport)) {
-               temp = readl(sport->port.membase + UCR4);
-               if (sport->irda_inv_rx)
-                       temp |= UCR4_INVR;
-               else
-                       temp &= ~(UCR4_INVR);
-               writel(temp | UCR4_DREN, sport->port.membase + UCR4);
-
-               temp = readl(sport->port.membase + UCR3);
-               if (sport->irda_inv_tx)
-                       temp |= UCR3_INVT;
-               else
-                       temp &= ~(UCR3_INVT);
-               writel(temp, sport->port.membase + UCR3);
-       }
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irqsave(&sport->port.lock,flags);
-       imx_enable_ms(&sport->port);
-       spin_unlock_irqrestore(&sport->port.lock,flags);
-
-       if (USE_IRDA(sport)) {
-               struct imxuart_platform_data *pdata;
-               pdata = sport->port.dev->platform_data;
-               sport->irda_inv_rx = pdata->irda_inv_rx;
-               sport->irda_inv_tx = pdata->irda_inv_tx;
-               sport->trcv_delay = pdata->transceiver_delay;
-               if (pdata->irda_enable)
-                       pdata->irda_enable(1);
-       }
-
-       return 0;
-
-error_out3:
-       if (sport->txirq)
-               free_irq(sport->txirq, sport);
-error_out2:
-       if (sport->rxirq)
-               free_irq(sport->rxirq, sport);
-error_out1:
-       return retval;
-}
-
-static void imx_shutdown(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long temp;
-
-       temp = readl(sport->port.membase + UCR2);
-       temp &= ~(UCR2_TXEN);
-       writel(temp, sport->port.membase + UCR2);
-
-       if (USE_IRDA(sport)) {
-               struct imxuart_platform_data *pdata;
-               pdata = sport->port.dev->platform_data;
-               if (pdata->irda_enable)
-                       pdata->irda_enable(0);
-       }
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Free the interrupts
-        */
-       if (sport->txirq > 0) {
-               if (!USE_IRDA(sport))
-                       free_irq(sport->rtsirq, sport);
-               free_irq(sport->txirq, sport);
-               free_irq(sport->rxirq, sport);
-       } else
-               free_irq(sport->port.irq, sport);
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-
-       temp = readl(sport->port.membase + UCR1);
-       temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
-       if (USE_IRDA(sport))
-               temp &= ~(UCR1_IREN);
-
-       writel(temp, sport->port.membase + UCR1);
-}
-
-static void
-imx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       unsigned long flags;
-       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-       unsigned int div, ufcr;
-       unsigned long num, denom;
-       uint64_t tdiv64;
-
-       /*
-        * If we don't support modem control lines, don't allow
-        * these to be set.
-        */
-       if (0) {
-               termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
-               termios->c_cflag |= CLOCAL;
-       }
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
-       else
-               ucr2 = UCR2_SRST | UCR2_IRTS;
-
-       if (termios->c_cflag & CRTSCTS) {
-               if( sport->have_rtscts ) {
-                       ucr2 &= ~UCR2_IRTS;
-                       ucr2 |= UCR2_CTSC;
-               } else {
-                       termios->c_cflag &= ~CRTSCTS;
-               }
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               ucr2 |= UCR2_STPB;
-       if (termios->c_cflag & PARENB) {
-               ucr2 |= UCR2_PREN;
-               if (termios->c_cflag & PARODD)
-                       ucr2 |= UCR2_PROE;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask = 0;
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |= URXD_BRK;
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |= URXD_PRERR;
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |= URXD_BRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |= URXD_OVRRUN;
-       }
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_ucr1 = readl(sport->port.membase + UCR1);
-       writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
-                       sport->port.membase + UCR1);
-
-       while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
-               barrier();
-
-       /* then, disable everything */
-       old_txrxen = readl(sport->port.membase + UCR2);
-       writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
-                       sport->port.membase + UCR2);
-       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
-
-       if (USE_IRDA(sport)) {
-               /*
-                * use maximum available submodule frequency to
-                * avoid missing short pulses due to low sampling rate
-                */
-               div = 1;
-       } else {
-               div = sport->port.uartclk / (baud * 16);
-               if (div > 7)
-                       div = 7;
-               if (!div)
-                       div = 1;
-       }
-
-       rational_best_approximation(16 * div * baud, sport->port.uartclk,
-               1 << 16, 1 << 16, &num, &denom);
-
-       tdiv64 = sport->port.uartclk;
-       tdiv64 *= num;
-       do_div(tdiv64, denom * 16 * div);
-       tty_termios_encode_baud_rate(termios,
-                               (speed_t)tdiv64, (speed_t)tdiv64);
-
-       num -= 1;
-       denom -= 1;
-
-       ufcr = readl(sport->port.membase + UFCR);
-       ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
-       writel(ufcr, sport->port.membase + UFCR);
-
-       writel(num, sport->port.membase + UBIR);
-       writel(denom, sport->port.membase + UBMR);
-
-       if (!cpu_is_mx1())
-               writel(sport->port.uartclk / div / 1000,
-                               sport->port.membase + MX2_ONEMS);
-
-       writel(old_ucr1, sport->port.membase + UCR1);
-
-       /* set the parity, stop bits and data size */
-       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               imx_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *imx_type(struct uart_port *port)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       return sport->port.type == PORT_IMX ? "IMX" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void imx_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *mmres;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mmres->start, mmres->end - mmres->start + 1);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int imx_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *mmres;
-       void *ret;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mmres)
-               return -ENODEV;
-
-       ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
-                       "imx-uart");
-
-       return  ret ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void imx_config_port(struct uart_port *port, int flags)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           imx_request_port(&sport->port) == 0)
-               sport->port.type = PORT_IMX;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_IMX and PORT_UNKNOWN
- */
-static int
-imx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != UPIO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops imx_pops = {
-       .tx_empty       = imx_tx_empty,
-       .set_mctrl      = imx_set_mctrl,
-       .get_mctrl      = imx_get_mctrl,
-       .stop_tx        = imx_stop_tx,
-       .start_tx       = imx_start_tx,
-       .stop_rx        = imx_stop_rx,
-       .enable_ms      = imx_enable_ms,
-       .break_ctl      = imx_break_ctl,
-       .startup        = imx_startup,
-       .shutdown       = imx_shutdown,
-       .set_termios    = imx_set_termios,
-       .type           = imx_type,
-       .release_port   = imx_release_port,
-       .request_port   = imx_request_port,
-       .config_port    = imx_config_port,
-       .verify_port    = imx_verify_port,
-};
-
-static struct imx_port *imx_ports[UART_NR];
-
-#ifdef CONFIG_SERIAL_IMX_CONSOLE
-static void imx_console_putchar(struct uart_port *port, int ch)
-{
-       struct imx_port *sport = (struct imx_port *)port;
-
-       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
-               barrier();
-
-       writel(ch, sport->port.membase + URTX0);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-imx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct imx_port *sport = imx_ports[co->index];
-       unsigned int old_ucr1, old_ucr2, ucr1;
-
-       /*
-        *      First, save UCR1/2 and then disable interrupts
-        */
-       ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
-       old_ucr2 = readl(sport->port.membase + UCR2);
-
-       if (cpu_is_mx1())
-               ucr1 |= MX1_UCR1_UARTCLKEN;
-       ucr1 |= UCR1_UARTEN;
-       ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
-
-       writel(ucr1, sport->port.membase + UCR1);
-
-       writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
-
-       uart_console_write(&sport->port, s, count, imx_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore UCR1/2
-        */
-       while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
-
-       writel(old_ucr1, sport->port.membase + UCR1);
-       writel(old_ucr2, sport->port.membase + UCR2);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-imx_console_get_options(struct imx_port *sport, int *baud,
-                          int *parity, int *bits)
-{
-
-       if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
-               /* ok, the port was enabled */
-               unsigned int ucr2, ubir,ubmr, uartclk;
-               unsigned int baud_raw;
-               unsigned int ucfr_rfdiv;
-
-               ucr2 = readl(sport->port.membase + UCR2);
-
-               *parity = 'n';
-               if (ucr2 & UCR2_PREN) {
-                       if (ucr2 & UCR2_PROE)
-                               *parity = 'o';
-                       else
-                               *parity = 'e';
-               }
-
-               if (ucr2 & UCR2_WS)
-                       *bits = 8;
-               else
-                       *bits = 7;
-
-               ubir = readl(sport->port.membase + UBIR) & 0xffff;
-               ubmr = readl(sport->port.membase + UBMR) & 0xffff;
-
-               ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
-               if (ucfr_rfdiv == 6)
-                       ucfr_rfdiv = 7;
-               else
-                       ucfr_rfdiv = 6 - ucfr_rfdiv;
-
-               uartclk = clk_get_rate(sport->clk);
-               uartclk /= ucfr_rfdiv;
-
-               {       /*
-                        * The next code provides exact computation of
-                        *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
-                        * without need of float support or long long division,
-                        * which would be required to prevent 32bit arithmetic overflow
-                        */
-                       unsigned int mul = ubir + 1;
-                       unsigned int div = 16 * (ubmr + 1);
-                       unsigned int rem = uartclk % div;
-
-                       baud_raw = (uartclk / div) * mul;
-                       baud_raw += (rem * mul + div / 2) / div;
-                       *baud = (baud_raw + 50) / 100 * 100;
-               }
-
-               if(*baud != baud_raw)
-                       printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
-                               baud_raw, *baud);
-       }
-}
-
-static int __init
-imx_console_setup(struct console *co, char *options)
-{
-       struct imx_port *sport;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
-               co->index = 0;
-       sport = imx_ports[co->index];
-       if(sport == NULL)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               imx_console_get_options(sport, &baud, &parity, &bits);
-
-       imx_setup_ufcr(sport, 0);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver imx_reg;
-static struct console imx_console = {
-       .name           = DEV_NAME,
-       .write          = imx_console_write,
-       .device         = uart_console_device,
-       .setup          = imx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &imx_reg,
-};
-
-#define IMX_CONSOLE    &imx_console
-#else
-#define IMX_CONSOLE    NULL
-#endif
-
-static struct uart_driver imx_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRIVER_NAME,
-       .dev_name       = DEV_NAME,
-       .major          = SERIAL_IMX_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ARRAY_SIZE(imx_ports),
-       .cons           = IMX_CONSOLE,
-};
-
-static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct imx_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_suspend_port(&imx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_imx_resume(struct platform_device *dev)
-{
-       struct imx_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_resume_port(&imx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_imx_probe(struct platform_device *pdev)
-{
-       struct imx_port *sport;
-       struct imxuart_platform_data *pdata;
-       void __iomem *base;
-       int ret = 0;
-       struct resource *res;
-
-       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
-       if (!sport)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto free;
-       }
-
-       base = ioremap(res->start, PAGE_SIZE);
-       if (!base) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       sport->port.dev = &pdev->dev;
-       sport->port.mapbase = res->start;
-       sport->port.membase = base;
-       sport->port.type = PORT_IMX,
-       sport->port.iotype = UPIO_MEM;
-       sport->port.irq = platform_get_irq(pdev, 0);
-       sport->rxirq = platform_get_irq(pdev, 0);
-       sport->txirq = platform_get_irq(pdev, 1);
-       sport->rtsirq = platform_get_irq(pdev, 2);
-       sport->port.fifosize = 32;
-       sport->port.ops = &imx_pops;
-       sport->port.flags = UPF_BOOT_AUTOCONF;
-       sport->port.line = pdev->id;
-       init_timer(&sport->timer);
-       sport->timer.function = imx_timeout;
-       sport->timer.data     = (unsigned long)sport;
-
-       sport->clk = clk_get(&pdev->dev, "uart");
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               goto unmap;
-       }
-       clk_enable(sport->clk);
-
-       sport->port.uartclk = clk_get_rate(sport->clk);
-
-       imx_ports[pdev->id] = sport;
-
-       pdata = pdev->dev.platform_data;
-       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-               sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
-       if (pdata && (pdata->flags & IMXUART_IRDA))
-               sport->use_irda = 1;
-#endif
-
-       if (pdata && pdata->init) {
-               ret = pdata->init(pdev);
-               if (ret)
-                       goto clkput;
-       }
-
-       ret = uart_add_one_port(&imx_reg, &sport->port);
-       if (ret)
-               goto deinit;
-       platform_set_drvdata(pdev, &sport->port);
-
-       return 0;
-deinit:
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-clkput:
-       clk_put(sport->clk);
-       clk_disable(sport->clk);
-unmap:
-       iounmap(sport->port.membase);
-free:
-       kfree(sport);
-
-       return ret;
-}
-
-static int serial_imx_remove(struct platform_device *pdev)
-{
-       struct imxuart_platform_data *pdata;
-       struct imx_port *sport = platform_get_drvdata(pdev);
-
-       pdata = pdev->dev.platform_data;
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport) {
-               uart_remove_one_port(&imx_reg, &sport->port);
-               clk_put(sport->clk);
-       }
-
-       clk_disable(sport->clk);
-
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-
-       iounmap(sport->port.membase);
-       kfree(sport);
-
-       return 0;
-}
-
-static struct platform_driver serial_imx_driver = {
-       .probe          = serial_imx_probe,
-       .remove         = serial_imx_remove,
-
-       .suspend        = serial_imx_suspend,
-       .resume         = serial_imx_resume,
-       .driver         = {
-               .name   = "imx-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init imx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: IMX driver\n");
-
-       ret = uart_register_driver(&imx_reg);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&serial_imx_driver);
-       if (ret != 0)
-               uart_unregister_driver(&imx_reg);
-
-       return 0;
-}
-
-static void __exit imx_serial_exit(void)
-{
-       platform_driver_unregister(&serial_imx_driver);
-       uart_unregister_driver(&imx_reg);
-}
-
-module_init(imx_serial_init);
-module_exit(imx_serial_exit);
-
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_DESCRIPTION("IMX generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-uart");
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
deleted file mode 100644 (file)
index ee43efc..0000000
+++ /dev/null
@@ -1,2199 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * This file contains a module version of the ioc3 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/ioc3.h>
-#include <linux/slab.h>
-
-/*
- * Interesting things about the ioc3
- */
-
-#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
-#define PORTS_PER_CARD         2
-#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
-#define MAX_CARDS              8
-#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
-
-/* determine given the sio_ir what port it applies to */
-#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
-
-
-/*
- * we have 2 logical ports (rs232, rs422) for each physical port
- * evens are rs232, odds are rs422
- */
-#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
-#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
-#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
-#define IS_RS232(_x)           !((_x) & 1)
-
-static unsigned int Num_of_ioc3_cards;
-static unsigned int Submodule_slot;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...)  printk _x
-#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS()       printk("%s : fails %d\n", __func__, __LINE__)
-
-/* number of characters we want to transmit to the lower level at a time */
-#define MAX_CHARS              256
-#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
-
-/* Device name we're using */
-#define DEVICE_NAME            "ttySIOC"
-#define DEVICE_MAJOR           204
-#define DEVICE_MINOR           116
-
-/* flags for next_char_state */
-#define NCS_BREAK              0x1
-#define NCS_PARITY             0x2
-#define NCS_FRAMING            0x4
-#define NCS_OVERRUN            0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232            0
-#define PROTO_RS422            1
-
-/* Notification types */
-#define N_DATA_READY           0x01
-#define N_OUTPUT_LOWAT         0x02
-#define N_BREAK                        0x04
-#define N_PARITY_ERROR         0x08
-#define N_FRAMING_ERROR                0x10
-#define N_OVERRUN_ERROR                0x20
-#define N_DDCD                 0x40
-#define N_DCTS                 0x80
-
-#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
-                                               | N_OVERRUN_ERROR)
-
-#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
-#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
-#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
-
-#define RING_BUF_SIZE          4096
-#define BUF_SIZE_BIT           SBBR_L_SIZE
-#define PROD_CONS_MASK         PROD_CONS_PTR_4K
-
-#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
-
-/* driver specific - one per card */
-struct ioc3_card {
-       struct {
-               /* uart ports are allocated here */
-               struct uart_port icp_uart_port[LOGICAL_PORTS];
-               /* the ioc3_port used for this port */
-               struct ioc3_port *icp_port;
-       } ic_port[PORTS_PER_CARD];
-       /* currently enabled interrupts */
-       uint32_t ic_enable;
-};
-
-/* Local port info for each IOC3 serial port */
-struct ioc3_port {
-       /* handy reference material */
-       struct uart_port *ip_port;
-       struct ioc3_card *ip_card;
-       struct ioc3_driver_data *ip_idd;
-       struct ioc3_submodule *ip_is;
-
-       /* pci mem addresses for this port */
-       struct ioc3_serialregs __iomem *ip_serial_regs;
-       struct ioc3_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct port_hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH             0x01
-       /* used to signify that we have turned off the rx_high
-        * temporarily - we need to drain the fifo and don't
-        * want to get blasted with interrupts.
-        */
-#define DCD_ON                 0x02
-       /* DCD state is on */
-#define LOWAT_WRITTEN          0x04
-#define READ_ABORTED           0x08
-       /* the read was aborted - used to avaoid infinate looping
-        * in the interrupt handler
-        */
-#define INPUT_ENABLE           0x10
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct port_hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       char rs422_select_pin;
-};
-
-static struct port_hooks hooks_array[PORTS_PER_CARD] = {
-       /* values for port A */
-       {
-       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SA_TX_MT,
-       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
-       .intr_rx_high = SIO_IR_SA_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
-                               | SIO_IR_SA_RX_HIGH
-                               | SIO_IR_SA_RX_TIMER
-                               | SIO_IR_SA_DELTA_DCD
-                               | SIO_IR_SA_DELTA_CTS
-                               | SIO_IR_SA_INT
-                               | SIO_IR_SA_TX_EXPLICIT
-                               | SIO_IR_SA_MEMERR),
-       .intr_all =  SIO_IR_SA,
-       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
-        },
-
-       /* values for port B */
-       {
-       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SB_TX_MT,
-       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
-       .intr_rx_high = SIO_IR_SB_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
-                               | SIO_IR_SB_RX_HIGH
-                               | SIO_IR_SB_RX_TIMER
-                               | SIO_IR_SB_DELTA_DCD
-                               | SIO_IR_SB_DELTA_CTS
-                               | SIO_IR_SB_INT
-                               | SIO_IR_SB_TX_EXPLICIT
-                               | SIO_IR_SB_MEMERR),
-       .intr_all = SIO_IR_SB,
-       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
-        }
-};
-
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc                u.s.sc
-#define ring_data      u.s.data
-#define ring_allsc     u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_A;
-       struct ring RX_A;
-       struct ring TX_B;
-       struct ring RX_B;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* for Infinite loop detection  */
-#define MAXITER                10000000
-
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc3_port *port, int baud)
-{
-       int divisor;
-       int actual_baud;
-       int diff;
-       int lcr, prediv;
-       struct ioc3_uartregs __iomem *uart;
-
-       for (prediv = 6; prediv < 64; prediv++) {
-               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
-               if (!divisor)
-                       continue;       /* invalid divisor */
-               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
-
-               diff = actual_baud - baud;
-               if (diff < 0)
-                       diff = -diff;
-
-               /* if we're within 1% we've found a match */
-               if (diff * 100 <= actual_baud)
-                       break;
-       }
-
-       /* if the above loop completed, we didn't match
-        * the baud rate.  give up.
-        */
-       if (prediv == 64) {
-               NOT_PROGRESS();
-               return 1;
-       }
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->iu_lcr);
-
-       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
-       writeb((unsigned char)divisor, &uart->iu_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
-       writeb((unsigned char)prediv, &uart->iu_scr);
-       writeb((unsigned char)lcr, &uart->iu_lcr);
-
-       return 0;
-}
-
-/**
- * get_ioc3_port - given a uart port, return the control structure
- * @the_port: uart port to find
- */
-static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
-{
-       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
-       int ii, jj;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return NULL;
-       }
-       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
-               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
-                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
-                               return card_ptr->ic_port[ii].icp_port;
-               }
-       }
-       NOT_PROGRESS();
-       return NULL;
-}
-
-/**
- * port_init - Initialize the sio and ioc3 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static int inline port_init(struct ioc3_port *port)
-{
-       uint32_t sio_cr;
-       struct port_hooks *hooks = port->ip_hooks;
-       struct ioc3_uartregs __iomem *uart;
-       int reset_loop_counter = 0xfffff;
-       struct ioc3_driver_data *idd = port->ip_idd;
-
-       /* Idle the IOC3 serial interface */
-       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do {
-               sio_cr = readl(&idd->vma->sio_cr);
-               if (reset_loop_counter-- <= 0) {
-                       printk(KERN_WARNING
-                              "IOC3 unable to come out of reset"
-                               " scr 0x%x\n", sio_cr);
-                       return -1;
-               }
-       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
-              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
-               || sio_cr == SIO_CR_ARB_DIAG_TXB
-               || sio_cr == SIO_CR_ARB_DIAG_RXA
-               || sio_cr == SIO_CR_ARB_DIAG_RXB));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->iu_lcr);
-       writeb(0, &uart->iu_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-              &uart->iu_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->iu_mcr);
-
-       /* Clear deltas in modem status register */
-       writel(0, &port->ip_serial_regs->shadow);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l, *sbbr_h;
-
-               sbbr_l = &idd->vma->sbbr_l;
-               sbbr_h = &idd->vma->sbbr_h;
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
-                              __func__, (void *)ring_pci_addr));
-
-               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-
-       /* uart experiences pauses at high baud rate reducing actual
-        * throughput by 10% or so unless we enable high speed polling
-        * XXX when this hardware bug is resolved we should revert to
-        * normal polling speed
-        */
-       port->ip_sscr |= SSCR_HIGH_SPD;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       port->ip_card->ic_enable &= ~hooks->intr_clear;
-       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
-       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
-       return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if ((port->ip_card->ic_enable & mask) != mask) {
-               port->ip_card->ic_enable |= mask;
-               ioc3_enable(port->ip_is, port->ip_idd, mask);
-       }
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc3_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = INPUT_ENABLE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               NOT_PROGRESS();
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-              &port->ip_uart_regs->iu_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * SRTR_HZ / HZ
-        */
-       timeout = timeout * SRTR_HZ / 100;
-       if (timeout > SRTR_CNT)
-               timeout = SRTR_CNT;
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc3_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
-                       "parodd %d\n",
-                      __func__, ((struct uart_port *)port->ip_port)->line,
-                       baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->iu_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->iu_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc3_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
-               port->ip_sscr |= SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if (port->ip_card->ic_enable & mask) {
-               ioc3_disable(port->ip_is, port->ip_idd, mask);
-               port->ip_card->ic_enable &= ~mask;
-       }
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc3_port *port, int mask, int set_on)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= SSCR_DMA_EN;
-       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
-               port->ip_sscr &= ~SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-                         int mask1, int mask2)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-       writeb(mcr, &port->ip_uart_regs->iu_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc3_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc3_set_proto(struct ioc3_port *port, int proto)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       default:
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs232\n", __func__));
-               writel(0, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs422\n", __func__));
-               writel(1, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with the_port->lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc3_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc3_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned int cflag, iflag;
-       int baud;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               break;
-       case CS6:
-               new_data = 6;
-               break;
-       case CS7:
-               new_data = 7;
-               break;
-       case CS8:
-               new_data = 8;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
-                               the_port->line));
-
-       if (!the_port->fifosize)
-               the_port->fifosize = FIFO_SIZE;
-       uart_update_timeout(the_port, cflag, baud);
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.tty->low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                                 | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               /* enable hardware flow control */
-               port->ip_sscr |= SSCR_HFC_EN;
-       }
-       else {
-               /* disable hardware flow control */
-               port->ip_sscr &= ~SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
-                      "config_port(baud %d data %d stop %d penable %d "
-                       " parity %d), notification 0x%x\n",
-                      __func__, (void *)port, the_port->line, cflag, baud,
-                      new_data, new_stop, new_parity_enable, new_parity,
-                      the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,    /* baud */
-                        new_data,      /* byte size */
-                        new_stop,      /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic3_startup_local(struct uart_port *the_port)
-{
-       struct ioc3_port *port;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       local_open(port);
-
-       /* set the protocol */
-       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
-                                                       PROTO_RS422);
-       return 0;
-}
-
-/*
- * ioc3_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
- */
-static void ioc3_cb_output_lowat(struct ioc3_port *port)
-{
-       unsigned long pflags;
-
-       /* the_port->lock is set on the call here */
-       if (port->ip_port) {
-               spin_lock_irqsave(&port->ip_port->lock, pflags);
-               transmit_chars(port->ip_port);
-               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
-       }
-}
-
-/*
- * ioc3_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks = port->ip_hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-
-       /* There is a nasty timing issue in the IOC3. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & SSCR_DMA_EN)) {
-                       port->ip_sscr |= SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | SSCR_RX_DRAIN,
-                      &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                              SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                           & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on read (line %d).\n",
-                               the_port->line);
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & RXSB_MODEM_VALID)
-                           && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-                               if ((port->ip_flags & DCD_ON)
-                                   && !(*sc & RXSB_DCD)) {
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                           == 0) {
-                                               cons_ptr += (int)sizeof
-                                                   (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                              &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                           && port->ip_port) {
-                                               uart_handle_dcd_change
-                                                       (port->ip_port, 0);
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                    port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & RXSB_DATA_VALID) &&
-                           ((*sc & (RXSB_PAR_ERR
-                                    | RXSB_FRAME_ERR | RXSB_BREAK))
-                            && (port->ip_notify & (N_PARITY_ERROR
-                                                   | N_FRAMING_ERROR
-                                                   | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & RXSB_PAR_ERR) &&
-                                           (port->
-                                            ip_notify & N_PARITY_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_PARITY);
-                                       }
-                                       if ((*sc & RXSB_FRAME_ERR) &&
-                                           (port->
-                                            ip_notify & N_FRAMING_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_FRAMING);
-                                       }
-                                       if ((*sc & RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                               ioc3_cb_post_ncs
-                                                   (the_port, NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & RXSB_DATA_VALID) {
-                               *sc &= ~RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                                              & PROD_CONS_MASK) <
-                                             ((port->
-                                               ip_sscr &
-                                               SSCR_RX_THRESHOLD)
-                                              << PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read.
- * @the_port: port to read from
- */
-static int receive_chars(struct uart_port *the_port)
-{
-       struct tty_struct *tty;
-       unsigned char ch[MAX_CHARS];
-       int read_count = 0, read_room, flip = 0;
-       struct uart_state *state = the_port->state;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return 0;
-       if (!state->port.tty)
-               return 0;
-
-       if (!(port->ip_flags & INPUT_ENABLE))
-               return 0;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-       tty = state->port.tty;
-
-       read_count = do_read(the_port, ch, MAX_CHARS);
-       if (read_count > 0) {
-               flip = 1;
-               read_room = tty_insert_flip_string(tty, ch, read_count);
-               the_port->icount.rx += read_count;
-       }
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       if (flip)
-               tty_flip_buffer_push(tty);
-
-       return read_count;
-}
-
-/**
- * ioc3uart_intr_one - lowest level (per port) interrupt handler.
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- */
-
-static int inline
-ioc3uart_intr_one(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int port_num = GET_PORT_FROM_SIO_IR(pending);
-       struct port_hooks *hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int loop_counter;
-       struct ioc3_card *card_ptr;
-       unsigned int sio_ir;
-
-       card_ptr = idd->data[is->id];
-       port = card_ptr->ic_port[port_num].icp_port;
-       hooks = port->ip_hooks;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-
-       sio_ir = pending & ~(hooks->intr_tx_mt);
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on interrupt (line %d).\n",
-                               ((struct uart_port *)port->ip_port)->line);
-                       break;
-               }
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                           && (shadow & SHADOW_DCD)
-                           && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_dcd_change(the_port,
-                                               shadow & SHADOW_DCD);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                  && !(shadow & SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               uart_handle_dcd_change(port->ip_port,
-                                               shadow & SHADOW_DCD);
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       ioc3_ack(is, idd, hooks->intr_delta_cts);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_cts_change(the_port, shadow
-                                               & SHADOW_CTS);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       ioc3_ack(is, idd, hooks->intr_rx_timer);
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && (port->ip_port)) {
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(card_ptr, idd))
-                                       & hooks->intr_rx_high) {
-                               if (port->ip_flags & READ_ABORTED) {
-                                       rx_high_rd_aborted++;
-                               }
-                               else {
-                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc3_cb_output_lowat(port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc3_cb_output_lowat(port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(card_ptr, idd);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                     & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                & SSCR_DMA_EN));
-                                       port->ip_sscr &= ~SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                              &port->ip_serial_regs->sscr);
-                               }
-                               /* Prevent infinite tx_mt interrupt */
-                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(card_ptr, idd);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-       ioc3_enable(is, idd, card_ptr->ic_enable);
-       return 0;
-}
-
-/**
- * ioc3uart_intr - field all serial interrupts
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- *
- */
-
-static int ioc3uart_intr(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int ret = 0;
-
-       /*
-        * The upper level interrupt handler sends interrupts for both ports
-        * here. So we need to call for each port with its interrupts.
-        */
-
-       if (pending & SIO_IR_SA)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
-       if (pending & SIO_IR_SB)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
-
-       return ret;
-}
-
-/**
- * ic3_type
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic3_type(struct uart_port *the_port)
-{
-       if (IS_RS232(the_port->line))
-               return "SGI IOC3 Serial [rs232]";
-       else
-               return "SGI IOC3 Serial [rs422]";
-}
-
-/**
- * ic3_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic3_tx_empty(struct uart_port *the_port)
-{
-       unsigned int ret = 0;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
-               ret = TIOCSER_TEMT;
-       return ret;
-}
-
-/**
- * ic3_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic3_stop_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * ic3_stop_rx - stop the receiver
- * @port: Port to operate on
- *
- */
-static void ic3_stop_rx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               port->ip_flags &= ~INPUT_ENABLE;
-}
-
-/**
- * null_void_function
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic3_shutdown - shut down the port - free irq and disable
- * @port: port to shut down
- *
- */
-static void ic3_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc3_port *port;
-       struct uart_state *state;
-
-       port = get_ioc3_port(the_port);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, SHADOW_DTR);
-}
-
-/**
- * ic3_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic3_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port)
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & SHADOW_DCD)
-               ret |= TIOCM_CD;
-       if (shadow & SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic3_start_tx - Start transmitter. Called with the_port->lock
- * @port: Port to operate on
- *
- */
-static void ic3_start_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic3_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic3_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic3_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int ic3_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc3_port *port;
-       struct ioc3_card *card_ptr;
-       unsigned long port_flags;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       card_ptr = port->ip_card;
-       port->ip_port = the_port;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic3_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic3_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic3_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc3_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic3_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-static struct uart_ops ioc3_ops = {
-       .tx_empty = ic3_tx_empty,
-       .set_mctrl = ic3_set_mctrl,
-       .get_mctrl = ic3_get_mctrl,
-       .stop_tx = ic3_stop_tx,
-       .start_tx = ic3_start_tx,
-       .stop_rx = ic3_stop_rx,
-       .enable_ms = null_void_function,
-       .break_ctl = ic3_break_ctl,
-       .startup = ic3_startup,
-       .shutdown = ic3_shutdown,
-       .set_termios = ic3_set_termios,
-       .type = ic3_type,
-       .release_port = null_void_function,
-       .request_port = ic3_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc3_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "ioc3_serial",
-       .dev_name = DEVICE_NAME,
-       .major = DEVICE_MAJOR,
-       .minor = DEVICE_MINOR,
-       .nr = MAX_LOGICAL_PORTS
-};
-
-/**
- * ioc3_serial_core_attach - register with serial core
- *             This is done during pci probing
- * @is: submodule struct for this
- * @idd: handle for this card
- */
-static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
-                               struct ioc3_driver_data *idd)
-{
-       struct ioc3_port *port;
-       struct uart_port *the_port;
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       int ii, phys_port;
-       struct pci_dev *pdev = idd->pdev;
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
-                      __func__, pdev, (void *)card_ptr));
-
-       if (!card_ptr)
-               return -ENODEV;
-
-       /* once around for each logical port on this card */
-       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-               phys_port = GET_PHYSICAL_PORT(ii);
-               the_port = &card_ptr->ic_port[phys_port].
-                               icp_uart_port[GET_LOGICAL_PORT(ii)];
-               port = card_ptr->ic_port[phys_port].icp_port;
-               port->ip_port = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
-                       __func__, (void *)the_port, (void *)port,
-                               phys_port, ii));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  ii;
-               the_port->line = (Num_of_ioc3_cards << 2) | ii;
-               the_port->mapbase = 1;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = FIFO_SIZE;
-               the_port->ops = &ioc3_ops;
-               the_port->irq = idd->irq_io;
-               the_port->dev = &pdev->dev;
-
-               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
-                       printk(KERN_WARNING
-                         "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
-                         the_port->line, the_port->irq, pdev->bus->number));
-               }
-
-               /* all ports are rs232 for now */
-               if (IS_PHYSICAL_PORT(ii))
-                       ioc3_set_proto(port, PROTO_RS232);
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_remove - register detach function
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this submodule
- */
-
-static int ioc3uart_remove(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd)
-{
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int ii;
-
-       if (card_ptr) {
-               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
-                       if (the_port)
-                               uart_remove_one_port(&ioc3_uart, the_port);
-                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
-                       if (port && IS_PHYSICAL_PORT(ii)
-                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
-                               pci_free_consistent(port->ip_idd->pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                               kfree(port);
-                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                                       icp_port = NULL;
-                       }
-               }
-               kfree(card_ptr);
-               idd->data[is->id] = NULL;
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_probe - card probe function called from shim driver
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this card
- */
-
-static int __devinit
-ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
-{
-       struct pci_dev *pdev = idd->pdev;
-       struct ioc3_card *card_ptr;
-       int ret = 0;
-       struct ioc3_port *port;
-       struct ioc3_port *ports[PORTS_PER_CARD];
-       int phys_port;
-       int cnt;
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
-
-       card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
-       if (!card_ptr) {
-               printk(KERN_WARNING "ioc3_attach_one"
-                      ": unable to get memory for the IOC3\n");
-               return -ENOMEM;
-       }
-       idd->data[is->id] = card_ptr;
-       Submodule_slot = is->id;
-
-       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
-               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
-               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
-
-       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
-
-       /* Create port structures for each port */
-       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
-               port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                              "IOC3 serial memory not available for port\n");
-                       ret = -ENOMEM;
-                       goto out4;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[phys_port] = port;
-
-               /* init to something useful */
-               card_ptr->ic_port[phys_port].icp_port = port;
-               port->ip_is = is;
-               port->ip_idd = idd;
-               port->ip_baud = 9600;
-               port->ip_card = card_ptr;
-               port->ip_hooks = &hooks_array[phys_port];
-
-               /* Setup each port */
-               if (phys_port == 0) {
-                       port->ip_serial_regs = &idd->vma->port_a;
-                       port->ip_uart_regs = &idd->vma->sregs.uarta;
-
-                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* setup ring buffers */
-                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
-                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
-
-                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
-                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       port->ip_inring = RING(port, RX_A);
-                       port->ip_outring = RING(port, TX_A);
-                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-               else {
-                       port->ip_serial_regs = &idd->vma->port_b;
-                       port->ip_uart_regs = &idd->vma->sregs.uartb;
-
-                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* share the ring buffers */
-                       port->ip_dma_ringbuf =
-                           ports[phys_port - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                           ports[phys_port - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_B);
-                       port->ip_outring = RING(port, TX_B);
-                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
-                              __func__,
-                              phys_port, (void *)port, (void *)card_ptr));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                              (void *)port->ip_serial_regs,
-                              (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC3 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
-                              "outring 0x%p\n",
-                              __func__,
-                              phys_port, (void *)port,
-                              (void *)port->ip_inring,
-                              (void *)port->ip_outring));
-
-       }
-
-       /* register port with the serial core */
-
-       if ((ret = ioc3_serial_core_attach(is, idd)))
-               goto out4;
-
-       Num_of_ioc3_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out4:
-       for (cnt = 0; cnt < phys_port; cnt++)
-               kfree(ports[cnt]);
-
-       kfree(card_ptr);
-       return ret;
-}
-
-static struct ioc3_submodule ioc3uart_ops = {
-       .name = "IOC3uart",
-       .probe = ioc3uart_probe,
-       .remove = ioc3uart_remove,
-       /* call .intr for both ports initially */
-       .irq_mask = SIO_IR_SA | SIO_IR_SB,
-       .intr = ioc3uart_intr,
-       .owner = THIS_MODULE,
-};
-
-/**
- * ioc3_detect - module init called,
- */
-static int __init ioc3uart_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
-               printk(KERN_WARNING
-                      "%s: Couldn't register IOC3 uart serial driver\n",
-                      __func__);
-               return ret;
-       }
-       ret = ioc3_register_submodule(&ioc3uart_ops);
-       if (ret)
-               uart_unregister_driver(&ioc3_uart);
-       return ret;
-}
-
-static void __exit ioc3uart_exit(void)
-{
-       ioc3_unregister_submodule(&ioc3uart_ops);
-       uart_unregister_driver(&ioc3_uart);
-}
-
-module_init(ioc3uart_init);
-module_exit(ioc3uart_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
deleted file mode 100644 (file)
index fcfe826..0000000
+++ /dev/null
@@ -1,2953 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-
-/*
- * This file contains a module version of the ioc4 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-/*
- * interesting things about the ioc4
- */
-
-#define IOC4_NUM_SERIAL_PORTS  4       /* max ports per card */
-#define IOC4_NUM_CARDS         8       /* max cards per partition */
-
-#define        GET_SIO_IR(_n)  (_n == 0) ? (IOC4_SIO_IR_S0) : \
-                               (_n == 1) ? (IOC4_SIO_IR_S1) : \
-                               (_n == 2) ? (IOC4_SIO_IR_S2) : \
-                               (IOC4_SIO_IR_S3)
-
-#define        GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
-                               (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
-                               (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
-                               (IOC4_OTHER_IR_S3_MEMERR)
-
-
-/*
- * All IOC4 registers are 32 bits wide.
- */
-
-/*
- * PCI Memory Space Map
- */
-#define IOC4_PCI_ERR_ADDR_L     0x000  /* Low Error Address */
-#define IOC4_PCI_ERR_ADDR_VLD          (0x1 << 0)
-#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
-#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
-#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
-#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
-#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
-
-/* Interrupt types */
-#define        IOC4_SIO_INTR_TYPE      0
-#define        IOC4_OTHER_INTR_TYPE    1
-#define        IOC4_NUM_INTR_TYPES     2
-
-/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
-#define IOC4_SIO_IR_S0_TX_MT      0x00000001   /* Serial port 0 TX empty */
-#define IOC4_SIO_IR_S0_RX_FULL    0x00000002   /* Port 0 RX buf full */
-#define IOC4_SIO_IR_S0_RX_HIGH    0x00000004   /* Port 0 RX hiwat */
-#define IOC4_SIO_IR_S0_RX_TIMER           0x00000008   /* Port 0 RX timeout */
-#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010  /* Port 0 delta DCD */
-#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020  /* Port 0 delta CTS */
-#define IOC4_SIO_IR_S0_INT        0x00000040   /* Port 0 pass-thru intr */
-#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080  /* Port 0 explicit TX thru */
-#define IOC4_SIO_IR_S1_TX_MT      0x00000100   /* Serial port 1 */
-#define IOC4_SIO_IR_S1_RX_FULL    0x00000200   /* */
-#define IOC4_SIO_IR_S1_RX_HIGH    0x00000400   /* */
-#define IOC4_SIO_IR_S1_RX_TIMER           0x00000800   /* */
-#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000  /* */
-#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000  /* */
-#define IOC4_SIO_IR_S1_INT        0x00004000   /* */
-#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000  /* */
-#define IOC4_SIO_IR_S2_TX_MT      0x00010000   /* Serial port 2 */
-#define IOC4_SIO_IR_S2_RX_FULL    0x00020000   /* */
-#define IOC4_SIO_IR_S2_RX_HIGH    0x00040000   /* */
-#define IOC4_SIO_IR_S2_RX_TIMER           0x00080000   /* */
-#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000  /* */
-#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000  /* */
-#define IOC4_SIO_IR_S2_INT        0x00400000   /* */
-#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000  /* */
-#define IOC4_SIO_IR_S3_TX_MT      0x01000000   /* Serial port 3 */
-#define IOC4_SIO_IR_S3_RX_FULL    0x02000000   /* */
-#define IOC4_SIO_IR_S3_RX_HIGH    0x04000000   /* */
-#define IOC4_SIO_IR_S3_RX_TIMER           0x08000000   /* */
-#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000  /* */
-#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000  /* */
-#define IOC4_SIO_IR_S3_INT        0x40000000   /* */
-#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000  /* */
-
-/* Per device interrupt masks */
-#define IOC4_SIO_IR_S0         (IOC4_SIO_IR_S0_TX_MT | \
-                                IOC4_SIO_IR_S0_RX_FULL | \
-                                IOC4_SIO_IR_S0_RX_HIGH | \
-                                IOC4_SIO_IR_S0_RX_TIMER | \
-                                IOC4_SIO_IR_S0_DELTA_DCD | \
-                                IOC4_SIO_IR_S0_DELTA_CTS | \
-                                IOC4_SIO_IR_S0_INT | \
-                                IOC4_SIO_IR_S0_TX_EXPLICIT)
-#define IOC4_SIO_IR_S1         (IOC4_SIO_IR_S1_TX_MT | \
-                                IOC4_SIO_IR_S1_RX_FULL | \
-                                IOC4_SIO_IR_S1_RX_HIGH | \
-                                IOC4_SIO_IR_S1_RX_TIMER | \
-                                IOC4_SIO_IR_S1_DELTA_DCD | \
-                                IOC4_SIO_IR_S1_DELTA_CTS | \
-                                IOC4_SIO_IR_S1_INT | \
-                                IOC4_SIO_IR_S1_TX_EXPLICIT)
-#define IOC4_SIO_IR_S2         (IOC4_SIO_IR_S2_TX_MT | \
-                                IOC4_SIO_IR_S2_RX_FULL | \
-                                IOC4_SIO_IR_S2_RX_HIGH | \
-                                IOC4_SIO_IR_S2_RX_TIMER | \
-                                IOC4_SIO_IR_S2_DELTA_DCD | \
-                                IOC4_SIO_IR_S2_DELTA_CTS | \
-                                IOC4_SIO_IR_S2_INT | \
-                                IOC4_SIO_IR_S2_TX_EXPLICIT)
-#define IOC4_SIO_IR_S3         (IOC4_SIO_IR_S3_TX_MT | \
-                                IOC4_SIO_IR_S3_RX_FULL | \
-                                IOC4_SIO_IR_S3_RX_HIGH | \
-                                IOC4_SIO_IR_S3_RX_TIMER | \
-                                IOC4_SIO_IR_S3_DELTA_DCD | \
-                                IOC4_SIO_IR_S3_DELTA_CTS | \
-                                IOC4_SIO_IR_S3_INT | \
-                                IOC4_SIO_IR_S3_TX_EXPLICIT)
-
-/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
-#define IOC4_OTHER_IR_ATA_INT          0x00000001  /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR       0x00000002  /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR                0x00000004  /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR                0x00000008  /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR                0x00000010  /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR                0x00000020  /* Port 3 PCI error */
-#define IOC4_OTHER_IR_KBD_INT          0x00000040  /* Keyboard/mouse */
-#define IOC4_OTHER_IR_RESERVED         0x007fff80  /* Reserved */
-#define IOC4_OTHER_IR_RT_INT           0x00800000  /* INT_OUT section output */
-#define IOC4_OTHER_IR_GEN_INT          0xff000000  /* Generic pins */
-
-#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
-                                 IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
-
-/* Bitmasks for IOC4_SIO_CR */
-#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
-#define IOC4_SIO_CR_ARB_DIAG_TX0       0x00000000
-#define IOC4_SIO_CR_ARB_DIAG_RX0       0x00000010
-#define IOC4_SIO_CR_ARB_DIAG_TX1       0x00000020
-#define IOC4_SIO_CR_ARB_DIAG_RX1       0x00000030
-#define IOC4_SIO_CR_ARB_DIAG_TX2       0x00000040
-#define IOC4_SIO_CR_ARB_DIAG_RX2       0x00000050
-#define IOC4_SIO_CR_ARB_DIAG_TX3       0x00000060
-#define IOC4_SIO_CR_ARB_DIAG_RX3       0x00000070
-#define IOC4_SIO_CR_SIO_DIAG_IDLE      0x00000080  /* 0 -> active request among
-                                                          serial ports (ro) */
-/* Defs for some of the generic I/O pins */
-#define IOC4_GPCR_UART0_MODESEL           0x10 /* Pin is output to port 0
-                                                  mode sel */
-#define IOC4_GPCR_UART1_MODESEL           0x20 /* Pin is output to port 1
-                                                  mode sel */
-#define IOC4_GPCR_UART2_MODESEL           0x40 /* Pin is output to port 2
-                                                  mode sel */
-#define IOC4_GPCR_UART3_MODESEL           0x80 /* Pin is output to port 3
-                                                  mode sel */
-
-#define IOC4_GPPR_UART0_MODESEL_PIN   4        /* GIO pin controlling
-                                          uart 0 mode select */
-#define IOC4_GPPR_UART1_MODESEL_PIN   5        /* GIO pin controlling
-                                          uart 1 mode select */
-#define IOC4_GPPR_UART2_MODESEL_PIN   6        /* GIO pin controlling
-                                          uart 2 mode select */
-#define IOC4_GPPR_UART3_MODESEL_PIN   7        /* GIO pin controlling
-                                          uart 3 mode select */
-
-/* Bitmasks for serial RX status byte */
-#define IOC4_RXSB_OVERRUN       0x01   /* Char(s) lost */
-#define IOC4_RXSB_PAR_ERR      0x02    /* Parity error */
-#define IOC4_RXSB_FRAME_ERR    0x04    /* Framing error */
-#define IOC4_RXSB_BREAK                0x08    /* Break character */
-#define IOC4_RXSB_CTS          0x10    /* State of CTS */
-#define IOC4_RXSB_DCD          0x20    /* State of DCD */
-#define IOC4_RXSB_MODEM_VALID   0x40   /* DCD, CTS, and OVERRUN are valid */
-#define IOC4_RXSB_DATA_VALID    0x80   /* Data byte, FRAME_ERR PAR_ERR
-                                        * & BREAK valid */
-
-/* Bitmasks for serial TX control byte */
-#define IOC4_TXCB_INT_WHEN_DONE 0x20   /* Interrupt after this byte is sent */
-#define IOC4_TXCB_INVALID      0x00    /* Byte is invalid */
-#define IOC4_TXCB_VALID                0x40    /* Byte is valid */
-#define IOC4_TXCB_MCR          0x80    /* Data<7:0> to modem control reg */
-#define IOC4_TXCB_DELAY                0xc0    /* Delay data<7:0> mSec */
-
-/* Bitmasks for IOC4_SBBR_L */
-#define IOC4_SBBR_L_SIZE       0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
-
-/* Bitmasks for IOC4_SSCR_<3:0> */
-#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
-#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
-#define IOC4_SSCR_HFC_EN       0x00020000  /* Hardware flow control enabled */
-#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
-#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
-#define IOC4_SSCR_DIAG         0x00200000  /* Bypass clock divider for sim */
-#define IOC4_SSCR_RX_DRAIN     0x08000000  /* Drain RX buffer to memory */
-#define IOC4_SSCR_DMA_EN       0x10000000  /* Enable ring buffer DMA */
-#define IOC4_SSCR_DMA_PAUSE    0x20000000  /* Pause DMA */
-#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
-#define IOC4_SSCR_RESET                0x80000000  /* Reset DMA channels */
-
-/* All producer/comsumer pointers are the same bitfield */
-#define IOC4_PROD_CONS_PTR_4K   0x00000ff8     /* For 4K buffers */
-#define IOC4_PROD_CONS_PTR_1K   0x000003f8     /* For 1K buffers */
-#define IOC4_PROD_CONS_PTR_OFF           3
-
-/* Bitmasks for IOC4_SRCIR_<3:0> */
-#define IOC4_SRCIR_ARM         0x80000000      /* Arm RX timer */
-
-/* Bitmasks for IOC4_SHADOW_<3:0> */
-#define IOC4_SHADOW_DR  0x00000001     /* Data ready */
-#define IOC4_SHADOW_OE  0x00000002     /* Overrun error */
-#define IOC4_SHADOW_PE  0x00000004     /* Parity error */
-#define IOC4_SHADOW_FE  0x00000008     /* Framing error */
-#define IOC4_SHADOW_BI  0x00000010     /* Break interrupt */
-#define IOC4_SHADOW_THRE 0x00000020    /* Xmit holding register empty */
-#define IOC4_SHADOW_TEMT 0x00000040    /* Xmit shift register empty */
-#define IOC4_SHADOW_RFCE 0x00000080    /* Char in RX fifo has an error */
-#define IOC4_SHADOW_DCTS 0x00010000    /* Delta clear to send */
-#define IOC4_SHADOW_DDCD 0x00080000    /* Delta data carrier detect */
-#define IOC4_SHADOW_CTS         0x00100000     /* Clear to send */
-#define IOC4_SHADOW_DCD         0x00800000     /* Data carrier detect */
-#define IOC4_SHADOW_DTR         0x01000000     /* Data terminal ready */
-#define IOC4_SHADOW_RTS         0x02000000     /* Request to send */
-#define IOC4_SHADOW_OUT1 0x04000000    /* 16550 OUT1 bit */
-#define IOC4_SHADOW_OUT2 0x08000000    /* 16550 OUT2 bit */
-#define IOC4_SHADOW_LOOP 0x10000000    /* Loopback enabled */
-
-/* Bitmasks for IOC4_SRTR_<3:0> */
-#define IOC4_SRTR_CNT          0x00000fff      /* Reload value for RX timer */
-#define IOC4_SRTR_CNT_VAL      0x0fff0000      /* Current value of RX timer */
-#define IOC4_SRTR_CNT_VAL_SHIFT         16
-#define IOC4_SRTR_HZ                 16000     /* SRTR clock frequency */
-
-/* Serial port register map used for DMA and PIO serial I/O */
-struct ioc4_serialregs {
-       uint32_t sscr;
-       uint32_t stpir;
-       uint32_t stcir;
-       uint32_t srpir;
-       uint32_t srcir;
-       uint32_t srtr;
-       uint32_t shadow;
-};
-
-/* IOC4 UART register map */
-struct ioc4_uartregs {
-       char i4u_lcr;
-       union {
-               char iir;       /* read only */
-               char fcr;       /* write only */
-       } u3;
-       union {
-               char ier;       /* DLAB == 0 */
-               char dlm;       /* DLAB == 1 */
-       } u2;
-       union {
-               char rbr;       /* read only, DLAB == 0 */
-               char thr;       /* write only, DLAB == 0 */
-               char dll;       /* DLAB == 1 */
-       } u1;
-       char i4u_scr;
-       char i4u_msr;
-       char i4u_lsr;
-       char i4u_mcr;
-};
-
-/* short names */
-#define i4u_dll u1.dll
-#define i4u_ier u2.ier
-#define i4u_dlm u2.dlm
-#define i4u_fcr u3.fcr
-
-/* Serial port registers used for DMA serial I/O */
-struct ioc4_serial {
-       uint32_t sbbr01_l;
-       uint32_t sbbr01_h;
-       uint32_t sbbr23_l;
-       uint32_t sbbr23_h;
-
-       struct ioc4_serialregs port_0;
-       struct ioc4_serialregs port_1;
-       struct ioc4_serialregs port_2;
-       struct ioc4_serialregs port_3;
-       struct ioc4_uartregs uart_0;
-       struct ioc4_uartregs uart_1;
-       struct ioc4_uartregs uart_2;
-       struct ioc4_uartregs uart_3;
-} ioc4_serial;
-
-/* UART clock speed */
-#define IOC4_SER_XIN_CLK_66     66666667
-#define IOC4_SER_XIN_CLK_33     33333333
-
-#define IOC4_W_IES             0
-#define IOC4_W_IEC             1
-
-typedef void ioc4_intr_func_f(void *, uint32_t);
-typedef ioc4_intr_func_f *ioc4_intr_func_t;
-
-static unsigned int Num_of_ioc4_cards;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...) printk _x
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS   256
-
-/* number of characters we want to transmit to the lower level at a time */
-#define IOC4_MAX_CHARS 256
-#define IOC4_FIFO_CHARS        255
-
-/* Device name we're using */
-#define DEVICE_NAME_RS232  "ttyIOC"
-#define DEVICE_NAME_RS422  "ttyAIOC"
-#define DEVICE_MAJOR      204
-#define DEVICE_MINOR_RS232 50
-#define DEVICE_MINOR_RS422 84
-
-
-/* register offsets */
-#define IOC4_SERIAL_OFFSET     0x300
-
-/* flags for next_char_state */
-#define NCS_BREAK      0x1
-#define NCS_PARITY     0x2
-#define NCS_FRAMING    0x4
-#define NCS_OVERRUN    0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232    3
-#define PROTO_RS422    7
-
-/* Notification types */
-#define N_DATA_READY   0x01
-#define N_OUTPUT_LOWAT 0x02
-#define N_BREAK                0x04
-#define N_PARITY_ERROR 0x08
-#define N_FRAMING_ERROR        0x10
-#define N_OVERRUN_ERROR        0x20
-#define N_DDCD         0x40
-#define N_DCTS         0x80
-
-#define N_ALL_INPUT    (N_DATA_READY | N_BREAK |                       \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT   N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS   (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
-
-#define N_ALL          (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |      \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_DIVISOR(_x, clk)           (((clk) + (_x) * 8) / ((_x) * 16))
-#define DIVISOR_TO_BAUD(div, clk)      ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_p)    (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
-#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
-
-/* Default to 4k buffers */
-#ifdef IOC4_1K_BUFFERS
-#define RING_BUF_SIZE 1024
-#define IOC4_BUF_SIZE_BIT 0
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
-#else
-#define RING_BUF_SIZE 4096
-#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
-#endif
-
-#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
-
-/*
- * This is the entry saved by the driver - one per card
- */
-
-#define UART_PORT_MIN          0
-#define UART_PORT_RS232                UART_PORT_MIN
-#define UART_PORT_RS422                1
-#define UART_PORT_COUNT                2       /* one for each mode */
-
-struct ioc4_control {
-       int ic_irq;
-       struct {
-               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
-               struct uart_port icp_uart_port[UART_PORT_COUNT];
-               /* Handy reference material */
-               struct ioc4_port *icp_port;
-       } ic_port[IOC4_NUM_SERIAL_PORTS];
-       struct ioc4_soft *ic_soft;
-};
-
-/*
- * per-IOC4 data structure
- */
-#define MAX_IOC4_INTR_ENTS     (8 * sizeof(uint32_t))
-struct ioc4_soft {
-       struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
-       struct ioc4_serial __iomem *is_ioc4_serial_addr;
-
-       /* Each interrupt type has an entry in the array */
-       struct ioc4_intr_type {
-
-               /*
-                * Each in-use entry in this array contains at least
-                * one nonzero bit in sd_bits; no two entries in this
-                * array have overlapping sd_bits values.
-                */
-               struct ioc4_intr_info {
-                       uint32_t sd_bits;
-                       ioc4_intr_func_f *sd_intr;
-                       void *sd_info;
-               } is_intr_info[MAX_IOC4_INTR_ENTS];
-
-               /* Number of entries active in the above array */
-               atomic_t is_num_intrs;
-       } is_intr_type[IOC4_NUM_INTR_TYPES];
-
-       /* is_ir_lock must be held while
-        * modifying sio_ie values, so
-        * we can be sure that sio_ie is
-        * not changing when we read it
-        * along with sio_ir.
-        */
-       spinlock_t is_ir_lock;  /* SIO_IE[SC] mod lock */
-};
-
-/* Local port info for each IOC4 serial ports */
-struct ioc4_port {
-       struct uart_port *ip_port;      /* current active port ptr */
-       /* Ptrs for all ports */
-       struct uart_port *ip_all_ports[UART_PORT_COUNT];
-       /* Back ptrs for this port */
-       struct ioc4_control *ip_control;
-       struct pci_dev *ip_pdev;
-       struct ioc4_soft *ip_ioc4_soft;
-
-       /* pci mem addresses */
-       struct ioc4_misc_regs __iomem *ip_mem;
-       struct ioc4_serial __iomem *ip_serial;
-       struct ioc4_serialregs __iomem *ip_serial_regs;
-       struct ioc4_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_ienb;       /* Enabled interrupts */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       int ip_pci_bus_speed;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH     0x01
-#define DCD_ON         0x02
-#define LOWAT_WRITTEN  0x04
-#define READ_ABORTED   0x08
-#define PORT_ACTIVE    0x10
-#define PORT_INACTIVE  0       /* This is the value when "off" */
-
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_dma_error;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       int rs422_select_pin;
-};
-
-static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
-       /* Values for port 0 */
-       {
-        IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
-        IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
-        IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
-        IOC4_OTHER_IR_S0_MEMERR,
-        (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
-         IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
-         IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
-         IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
-        IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
-        },
-
-       /* Values for port 1 */
-       {
-        IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
-        IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
-        IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
-        IOC4_OTHER_IR_S1_MEMERR,
-        (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
-         IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
-         IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
-         IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
-        IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
-        },
-
-       /* Values for port 2 */
-       {
-        IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
-        IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
-        IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
-        IOC4_OTHER_IR_S2_MEMERR,
-        (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
-         IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
-         IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
-         IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
-        IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
-        },
-
-       /* Values for port 3 */
-       {
-        IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
-        IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
-        IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
-        IOC4_OTHER_IR_S3_MEMERR,
-        (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
-         IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
-         IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
-         IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
-        IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
-        }
-};
-
-/* A ring buffer entry */
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc     u.s.sc
-#define ring_data   u.s.data
-#define ring_allsc  u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_0_OR_2;
-       struct ring RX_0_OR_2;
-       struct ring TX_1_OR_3;
-       struct ring RX_1_OR_3;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* Infinite loop detection.
- */
-#define MAXITER 10000000
-
-/* Prototypes */
-static void receive_chars(struct uart_port *);
-static void handle_intr(void *arg, uint32_t sio_ir);
-
-/*
- * port_is_active - determines if this port is currently active
- * @port: ptr to soft struct for this port
- * @uart_port: uart port to test for
- */
-static inline int port_is_active(struct ioc4_port *port,
-               struct uart_port *uart_port)
-{
-       if (port) {
-               if ((port->ip_flags & PORT_ACTIVE)
-                                       && (port->ip_port == uart_port))
-                       return 1;
-       }
-       return 0;
-}
-
-
-/**
- * write_ireg - write the interrupt regs
- * @ioc4_soft: ptr to soft struct for this port
- * @val: value to write
- * @which: which register
- * @type: which ireg set
- */
-static inline void
-write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->sio_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->sio_iec.raw);
-                       break;
-               }
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->other_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->other_iec.raw);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
-}
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc4_port *port, int baud)
-{
-       int actual_baud;
-       int diff;
-       int lcr;
-       unsigned short divisor;
-       struct ioc4_uartregs __iomem *uart;
-
-       divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
-       if (!divisor)
-               return 1;
-       actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
-
-       diff = actual_baud - baud;
-       if (diff < 0)
-               diff = -diff;
-
-       /* If we're within 1%, we've found a match */
-       if (diff * 100 > actual_baud)
-               return 1;
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->i4u_lcr);
-       writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
-       writeb((unsigned char)divisor, &uart->i4u_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
-       writeb(lcr, &uart->i4u_lcr);
-       return 0;
-}
-
-
-/**
- * get_ioc4_port - given a uart port, return the control structure
- * @port: uart port
- * @set: set this port as current
- */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
-{
-       struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       struct ioc4_port *port;
-       int port_num, port_type;
-
-       if (control) {
-               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
-                                                       port_num++ ) {
-                       port = control->ic_port[port_num].icp_port;
-                       if (!port)
-                               continue;
-                       for (port_type = UART_PORT_MIN;
-                                               port_type < UART_PORT_COUNT;
-                                               port_type++) {
-                               if (the_port == port->ip_all_ports
-                                                       [port_type]) {
-                                       /* set local copy */
-                                       if (set) {
-                                               port->ip_port = the_port;
-                                       }
-                                       return port;
-                               }
-                       }
-               }
-       }
-       return NULL;
-}
-
-/* The IOC4 hardware provides no atomic way to determine if interrupts
- * are pending since two reads are required to do so.  The handler must
- * read the SIO_IR and the SIO_IES, and take the logical and of the
- * two.  When this value is zero, all interrupts have been serviced and
- * the handler may return.
- *
- * This has the unfortunate "hole" that, if some other CPU or
- * some other thread or some higher level interrupt manages to
- * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
- * think we have observed SIO_IR&SIO_IE==0 when in fact this
- * condition never really occurred.
- *
- * To solve this, we use a simple spinlock that must be held
- * whenever modifying SIO_IE; holding this lock while observing
- * both SIO_IR and SIO_IE guarantees that we do not falsely
- * conclude that no enabled interrupts are pending.
- */
-
-static inline uint32_t
-pending_intrs(struct ioc4_soft *soft, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-       unsigned long flag;
-       uint32_t intrs = 0;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       spin_lock_irqsave(&soft->is_ir_lock, flag);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
-
-               /* Don't process any ATA interrupte */
-               intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       return intrs;
-}
-
-/**
- * port_init - Initialize the sio and ioc4 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static int inline port_init(struct ioc4_port *port)
-{
-       uint32_t sio_cr;
-       struct hooks *hooks = port->ip_hooks;
-       struct ioc4_uartregs __iomem *uart;
-
-       /* Idle the IOC4 serial interface */
-       writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do
-               sio_cr = readl(&port->ip_mem->sio_cr.raw);
-       while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->i4u_lcr);
-       writeb(0, &uart->i4u_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-                       &uart->i4u_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->i4u_mcr);
-
-       /* Clear deltas in modem status register */
-       readb(&uart->i4u_msr);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]
-                           || port->ip_hooks == &hooks_array[2]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l;
-               uint32_t __iomem *sbbr_h;
-
-               if (port->ip_hooks == &hooks_array[0]) {
-                       sbbr_l = &port->ip_serial->sbbr01_l;
-                       sbbr_h = &port->ip_serial->sbbr01_h;
-               } else {
-                       sbbr_l = &port->ip_serial->sbbr23_l;
-                       sbbr_h = &port->ip_serial->sbbr23_h;
-               }
-
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
-                                       __func__, ring_pci_addr));
-
-               writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
-                      IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       port->ip_ienb &= ~hooks->intr_clear;
-       writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
-       return 0;
-}
-
-/**
- * handle_dma_error_intr - service any pending DMA error interrupts for the
- *                     given port - 2nd level called via sd_intr
- * @arg: handler arg
- * @other_ir: ioc4regs
- */
-static void handle_dma_error_intr(void *arg, uint32_t other_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       /* ACK the interrupt */
-       writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
-
-       if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
-               printk(KERN_ERR
-                       "PCI error address is 0x%llx, "
-                               "master is serial port %c %s\n",
-                    (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
-                                                        << 32)
-                               | readl(&port->ip_mem->pci_err_addr_l.raw))
-                                       & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
-                    ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
-                            IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
-                    (readl(&port->ip_mem->pci_err_addr_l.raw)
-                               & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
-                               ? "RX" : "TX");
-
-               if (readl(&port->ip_mem->pci_err_addr_l.raw)
-                                               & IOC4_PCI_ERR_ADDR_MUL_ERR) {
-                       printk(KERN_ERR
-                               "Multiple errors occurred\n");
-               }
-       }
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable DMA error interrupts */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
-                                               IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * intr_connect - interrupt connect function
- * @soft: soft struct for this card
- * @type: interrupt type
- * @intrbits: bit pattern to set
- * @intr: handler function
- * @info: handler arg
- */
-static void
-intr_connect(struct ioc4_soft *soft, int type,
-                 uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
-{
-       int i;
-       struct ioc4_intr_info *intr_ptr;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
-       BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
-
-       /* Save off the lower level interrupt handler */
-       intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
-       intr_ptr->sd_bits = intrbits;
-       intr_ptr->sd_intr = intr;
-       intr_ptr->sd_info = info;
-}
-
-/**
- * ioc4_intr - Top level IOC4 interrupt handler.
- * @irq: irq value
- * @arg: handler arg
- */
-
-static irqreturn_t ioc4_intr(int irq, void *arg)
-{
-       struct ioc4_soft *soft;
-       uint32_t this_ir, this_mir;
-       int xx, num_intrs = 0;
-       int intr_type;
-       int handled = 0;
-       struct ioc4_intr_info *intr_info;
-
-       soft = arg;
-       for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
-               num_intrs = (int)atomic_read(
-                               &soft->is_intr_type[intr_type].is_num_intrs);
-
-               this_mir = this_ir = pending_intrs(soft, intr_type);
-
-               /* Farm out the interrupt to the various drivers depending on
-                * which interrupt bits are set.
-                */
-               for (xx = 0; xx < num_intrs; xx++) {
-                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
-                       if ((this_mir = this_ir & intr_info->sd_bits)) {
-                               /* Disable owned interrupts, call handler */
-                               handled++;
-                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
-                                                               intr_type);
-                               intr_info->sd_intr(intr_info->sd_info, this_mir);
-                               this_ir &= ~this_mir;
-                       }
-               }
-       }
-#ifdef DEBUG_INTERRUPTS
-       {
-               struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-               unsigned long flag;
-
-               spin_lock_irqsave(&soft->is_ir_lock, flag);
-               printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
-                               "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
-                    __func__, __LINE__,
-                    (void *)mem, readl(&mem->sio_ir.raw),
-                    readl(&mem->sio_ies.raw),
-                    readl(&mem->other_ir.raw),
-                    readl(&mem->other_ies.raw),
-                    IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       }
-#endif
-       return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/**
- * ioc4_attach_local - Device initialization.
- *                     Called at *_attach() time for each
- *                     IOC4 with serial ports in the system.
- * @idd: Master module data for this IOC4
- */
-static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
-{
-       struct ioc4_port *port;
-       struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
-       int port_number;
-       uint16_t ioc4_revid_min = 62;
-       uint16_t ioc4_revid;
-       struct pci_dev *pdev = idd->idd_pdev;
-       struct ioc4_control* control = idd->idd_serial_data;
-       struct ioc4_soft *soft = control->ic_soft;
-       void __iomem *ioc4_misc = idd->idd_misc_regs;
-       void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
-
-       /* IOC4 firmware must be at least rev 62 */
-       pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
-
-       printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
-       if (ioc4_revid < ioc4_revid_min) {
-               printk(KERN_WARNING
-                   "IOC4 serial not supported on firmware rev %d, "
-                               "please upgrade to rev %d or higher\n",
-                               ioc4_revid, ioc4_revid_min);
-               return -EPERM;
-       }
-       BUG_ON(ioc4_misc == NULL);
-       BUG_ON(ioc4_serial == NULL);
-
-       /* Create port structures for each port */
-       for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
-                                                       port_number++) {
-               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                               "IOC4 serial memory not available for port\n");
-                       return -ENOMEM;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[port_number] = port;
-
-               /* Allocate buffers and jumpstart the hardware.  */
-               control->ic_port[port_number].icp_port = port;
-               port->ip_ioc4_soft = soft;
-               port->ip_pdev = pdev;
-               port->ip_ienb = 0;
-               /* Use baud rate calculations based on detected PCI
-                * bus speed.  Simply test whether the PCI clock is
-                * running closer to 66MHz or 33MHz.
-                */
-               if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
-               } else {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
-               }
-               port->ip_baud = 9600;
-               port->ip_control = control;
-               port->ip_mem = ioc4_misc;
-               port->ip_serial = ioc4_serial;
-
-               /* point to the right hook */
-               port->ip_hooks = &hooks_array[port_number];
-
-               /* Get direct hooks to the serial regs and uart regs
-                * for this port
-                */
-               switch (port_number) {
-               case 0:
-                       port->ip_serial_regs = &(port->ip_serial->port_0);
-                       port->ip_uart_regs = &(port->ip_serial->uart_0);
-                       break;
-               case 1:
-                       port->ip_serial_regs = &(port->ip_serial->port_1);
-                       port->ip_uart_regs = &(port->ip_serial->uart_1);
-                       break;
-               case 2:
-                       port->ip_serial_regs = &(port->ip_serial->port_2);
-                       port->ip_uart_regs = &(port->ip_serial->uart_2);
-                       break;
-               default:
-               case 3:
-                       port->ip_serial_regs = &(port->ip_serial->port_3);
-                       port->ip_uart_regs = &(port->ip_serial->uart_3);
-                       break;
-               }
-
-               /* ring buffers are 1 to a pair of ports */
-               if (port_number && (port_number & 1)) {
-                       /* odd use the evens buffer */
-                       port->ip_dma_ringbuf =
-                                       ports[port_number - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                                       ports[port_number - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_1_OR_3);
-                       port->ip_outring = RING(port, TX_1_OR_3);
-
-               } else {
-                       if (port->ip_dma_ringbuf == 0) {
-                               port->ip_cpu_ringbuf = pci_alloc_consistent
-                                       (pdev, TOTAL_RING_BUF_SIZE,
-                                       &port->ip_dma_ringbuf);
-
-                       }
-                       BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
-                               (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
-                                               "ip_dma_ringbuf 0x%p\n",
-                                       __func__,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       (void *)port->ip_dma_ringbuf));
-                       port->ip_inring = RING(port, RX_0_OR_2);
-                       port->ip_outring = RING(port, TX_0_OR_2);
-               }
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
-                               __func__,
-                               port_number, (void *)port, (void *)control));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                               (void *)port->ip_serial_regs,
-                               (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC4 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
-                                               "outring 0x%p\n",
-                               __func__,
-                               port_number, (void *)port,
-                               (void *)port->ip_inring,
-                               (void *)port->ip_outring));
-
-               /* Attach interrupt handlers */
-               intr_connect(soft, IOC4_SIO_INTR_TYPE,
-                               GET_SIO_IR(port_number),
-                               handle_intr, port);
-
-               intr_connect(soft, IOC4_OTHER_INTR_TYPE,
-                               GET_OTHER_IR(port_number),
-                               handle_dma_error_intr, port);
-       }
-       return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if ((port->ip_ienb & mask) != mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
-                                               IOC4_SIO_INTR_TYPE);
-               port->ip_ienb |= mask;
-       }
-
-       if (port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc4_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = PORT_ACTIVE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs-> sscr)
-                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               port->ip_flags = PORT_INACTIVE;
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-                               &port->ip_uart_regs->i4u_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * IOC4_SRTR_HZ / HZ
-        */
-       timeout = timeout * IOC4_SRTR_HZ / 100;
-       if (timeout > IOC4_SRTR_CNT)
-               timeout = IOC4_SRTR_CNT;
-
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc4_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
-               __func__, baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs->sscr)
-                                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->i4u_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->i4u_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc4_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = IOC4_TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                       ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                               <= port->ip_tx_lowat
-                                       * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void disable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if (port->ip_ienb & mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
-                                       IOC4_SIO_INTR_TYPE);
-               port->ip_ienb &= ~mask;
-       }
-
-       if (!port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc4_port *port, int mask, int set_on)
-{
-       struct hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= IOC4_SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-       else if (!(port->ip_ienb & hooks->intr_tx_mt))
-               port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-               int mask1, int mask2)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                                       & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-
-       writeb(mcr, &port->ip_uart_regs->i4u_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc4_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc4_set_proto(struct ioc4_port *port, int proto)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       default:
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with ip_lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc4_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc4_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       int baud, bits;
-       unsigned cflag, iflag;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               bits = 7;
-               break;
-       case CS6:
-               new_data = 6;
-               bits = 8;
-               break;
-       case CS7:
-               new_data = 7;
-               bits = 9;
-               break;
-       case CS8:
-               new_data = 8;
-               bits = 10;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               bits = 7;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               bits++;
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               bits++;
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                               MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
-
-       /* default is 9600 */
-       if (!baud)
-               baud = 9600;
-
-       if (!the_port->fifosize)
-               the_port->fifosize = IOC4_FIFO_CHARS;
-       the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
-       the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.tty->low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                               | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               port->ip_sscr |= IOC4_SSCR_HFC_EN;
-       }
-       else {
-               port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
-               "config_port(baud %d data %d stop %d p enable %d parity %d),"
-               " notification 0x%x\n",
-            __func__, (void *)port, cflag, baud, new_data, new_stop,
-            new_parity_enable, new_parity, the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,            /* baud */
-                        new_data,              /* byte size */
-                        new_stop,              /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic4_startup_local(struct uart_port *the_port)
-{
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       if (!the_port)
-               return -1;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return -1;
-
-       state = the_port->state;
-
-       local_open(port);
-
-       /* set the protocol - mapbase has the port type */
-       ioc4_set_proto(port, the_port->mapbase);
-
-       /* set the speed of the serial port */
-       ioc4_change_speed(the_port, state->port.tty->termios,
-                         (struct ktermios *)0);
-
-       return 0;
-}
-
-/*
- * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @the_port: port to output
- */
-static void ioc4_cb_output_lowat(struct uart_port *the_port)
-{
-       unsigned long pflags;
-
-       /* ip_lock is set on the call here */
-       if (the_port) {
-               spin_lock_irqsave(&the_port->lock, pflags);
-               transmit_chars(the_port);
-               spin_unlock_irqrestore(&the_port->lock, pflags);
-       }
-}
-
-/**
- * handle_intr - service any interrupts for the given port - 2nd level
- *                     called via sd_intr
- * @arg: handler arg
- * @sio_ir: ioc4regs
- */
-static void handle_intr(void *arg, uint32_t sio_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       int loop_counter;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-       sio_ir &= ~(hooks->intr_tx_mt);
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on interrupt.\n");
-                       break;
-               }
-
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_dcd,
-                               &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                                       && (shadow & IOC4_SHADOW_DCD)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.dcd = 1;
-                               wake_up_interruptible
-                                           (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                       && !(shadow & IOC4_SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_cts,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.cts =
-                                       (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
-                               wake_up_interruptible
-                                       (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_rx_timer,
-                               &port->ip_mem->sio_ir.raw);
-
-                       if ((port->ip_notify & N_DATA_READY)
-                                       && (port->ip_port)) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && port->ip_port) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
-                               if ((port->ip_flags & READ_ABORTED) == 0) {
-                                       port->ip_ienb &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               } else {
-                                       rx_high_rd_aborted++;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-
-                       /* ACK the interrupt */
-                       writel(hooks->intr_tx_explicit,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc4_cb_output_lowat(port->ip_port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc4_cb_output_lowat(port->ip_port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(port);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                               & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                       & IOC4_SSCR_DMA_EN));
-                                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                          &port->ip_serial_regs->sscr);
-                               }
-
-                               /* Prevent infinite tx_mt interrupt */
-                               port->ip_ienb &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(port);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable interrupts before returning from interrupt handler.
-        * Getting interrupted here is okay.  It'll just v() our semaphore, and
-        * we'll come through the loop again.
-        */
-
-       write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
-                                                       IOC4_SIO_INTR_TYPE);
-}
-
-/*
- * ioc4_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, unsigned char *buf,
-                               int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct hooks *hooks = port->ip_hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-
-       /* There is a nasty timing issue in the IOC4. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-                       port->ip_sscr |= IOC4_SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
-                               &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir)
-                               & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                                               IOC4_SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                                                       & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on read.\n");
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & IOC4_RXSB_MODEM_VALID)
-                                               && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-
-                               if ((port->ip_flags & DCD_ON)
-                                               && !(*sc & IOC4_RXSB_DCD)) {
-
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~IOC4_RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                                                       == 0) {
-                                               cons_ptr += (int)sizeof
-                                                       (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                               &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                                  && port->ip_port) {
-                                               the_port->icount.dcd = 0;
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                       port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & IOC4_RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~IOC4_RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & IOC4_RXSB_DATA_VALID) &&
-                                       ((*sc & (IOC4_RXSB_PAR_ERR
-                                                       | IOC4_RXSB_FRAME_ERR
-                                                       | IOC4_RXSB_BREAK))
-                                       && (port->ip_notify & (N_PARITY_ERROR
-                                                       | N_FRAMING_ERROR
-                                                       | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & IOC4_RXSB_PAR_ERR) &&
-                                          (port->ip_notify & N_PARITY_ERROR)) {
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_PARITY);
-                                       }
-                                       if ((*sc & IOC4_RXSB_FRAME_ERR) &&
-                                          (port->ip_notify & N_FRAMING_ERROR)){
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_FRAMING);
-                                       }
-                                       if ((*sc & IOC4_RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                                       ioc4_cb_post_ncs
-                                                                   (the_port,
-                                                                    NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_DATA_VALID) {
-                               *sc &= ~IOC4_RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                       & PROD_CONS_MASK) < ((port->ip_sscr &
-                               IOC4_SSCR_RX_THRESHOLD)
-                                       << IOC4_PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read. Called with ip_lock.
- * @the_port: port to read from
- */
-static void receive_chars(struct uart_port *the_port)
-{
-       struct tty_struct *tty;
-       unsigned char ch[IOC4_MAX_CHARS];
-       int read_count, request_count = IOC4_MAX_CHARS;
-       struct uart_icount *icount;
-       struct uart_state *state = the_port->state;
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return;
-       if (!state->port.tty)
-               return;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-       tty = state->port.tty;
-
-       request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
-
-       if (request_count > 0) {
-               icount = &the_port->icount;
-               read_count = do_read(the_port, ch, request_count);
-               if (read_count > 0) {
-                       tty_insert_flip_string(tty, ch, read_count);
-                       icount->rx += read_count;
-               }
-       }
-
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       tty_flip_buffer_push(tty);
-}
-
-/**
- * ic4_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic4_type(struct uart_port *the_port)
-{
-       if (the_port->mapbase == PROTO_RS232)
-               return "SGI IOC4 Serial [rs232]";
-       else
-               return "SGI IOC4 Serial [rs422]";
-}
-
-/**
- * ic4_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic4_tx_empty(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       unsigned int ret = 0;
-
-       if (port_is_active(port, the_port)) {
-               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
-                       ret = TIOCSER_TEMT;
-       }
-       return ret;
-}
-
-/**
- * ic4_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic4_stop_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port))
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * null_void_function -
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic4_shutdown - shut down the port - free irq and disable
- * @port: Port to shut down
- *
- */
-static void ic4_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       port->ip_port = NULL;
-
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       if (state->port.tty)
-               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       port->ip_flags = PORT_INACTIVE;
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-       struct ioc4_port *port;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port_is_active(port, the_port))
-               return;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
-}
-
-/**
- * ic4_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic4_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port_is_active(port, the_port))
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & IOC4_SHADOW_DCD)
-               ret |= TIOCM_CAR;
-       if (shadow & IOC4_SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & IOC4_SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic4_start_tx - Start transmitter, flush any output
- * @port: Port to operate on
- *
- */
-static void ic4_start_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port)) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic4_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic4_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic4_startup - Start up the serial port
- * @port: Port to operate on
- *
- */
-static int ic4_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc4_port *port;
-       struct ioc4_control *control;
-       struct uart_state *state;
-       unsigned long port_flags;
-
-       if (!the_port)
-               return -ENODEV;
-       port = get_ioc4_port(the_port, 1);
-       if (!port)
-               return -ENODEV;
-       state = the_port->state;
-
-       control = port->ip_control;
-       if (!control) {
-               port->ip_port = NULL;
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic4_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic4_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic4_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc4_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic4_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static struct uart_ops ioc4_ops = {
-       .tx_empty       = ic4_tx_empty,
-       .set_mctrl      = ic4_set_mctrl,
-       .get_mctrl      = ic4_get_mctrl,
-       .stop_tx        = ic4_stop_tx,
-       .start_tx       = ic4_start_tx,
-       .stop_rx        = null_void_function,
-       .enable_ms      = null_void_function,
-       .break_ctl      = ic4_break_ctl,
-       .startup        = ic4_startup,
-       .shutdown       = ic4_shutdown,
-       .set_termios    = ic4_set_termios,
-       .type           = ic4_type,
-       .release_port   = null_void_function,
-       .request_port   = ic4_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc4_uart_rs232 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs232",
-       .dev_name       = DEVICE_NAME_RS232,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS232,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-static struct uart_driver ioc4_uart_rs422 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs422",
-       .dev_name       = DEVICE_NAME_RS422,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS422,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
-       int port_num, port_type;
-       struct ioc4_control *control;
-       struct uart_port *the_port;
-       struct ioc4_port *port;
-       struct ioc4_soft *soft;
-
-       /* If serial driver did not attach, don't try to detach */
-       control = idd->idd_serial_data;
-       if (!control)
-               return 0;
-
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               for (port_type = UART_PORT_MIN;
-                                       port_type < UART_PORT_COUNT;
-                                       port_type++) {
-                       the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type];
-                       if (the_port) {
-                               switch (port_type) {
-                               case UART_PORT_RS422:
-                                       uart_remove_one_port(&ioc4_uart_rs422,
-                                                       the_port);
-                                       break;
-                               default:
-                               case UART_PORT_RS232:
-                                       uart_remove_one_port(&ioc4_uart_rs232,
-                                                       the_port);
-                                       break;
-                               }
-                       }
-               }
-               port = control->ic_port[port_num].icp_port;
-               /* we allocate in pairs */
-               if (!(port_num & 1) && port) {
-                       pci_free_consistent(port->ip_pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                       kfree(port);
-               }
-       }
-       soft = control->ic_soft;
-       if (soft) {
-               free_irq(control->ic_irq, soft);
-               if (soft->is_ioc4_serial_addr) {
-                       iounmap(soft->is_ioc4_serial_addr);
-                       release_mem_region((unsigned long)
-                            soft->is_ioc4_serial_addr,
-                               sizeof(struct ioc4_serial));
-               }
-               kfree(soft);
-       }
-       kfree(control);
-       idd->idd_serial_data = NULL;
-
-       return 0;
-}
-
-
-/**
- * ioc4_serial_core_attach_rs232 - register with serial core
- *             This is done during pci probing
- * @pdev: handle for this card
- */
-static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
-{
-       struct ioc4_port *port;
-       struct uart_port *the_port;
-       struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       int port_num;
-       int port_type_idx;
-       struct uart_driver *u_driver;
-
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
-                       __func__, pdev, (void *)control));
-
-       if (!control)
-               return -ENODEV;
-
-       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
-                                               : UART_PORT_RS422;
-
-       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
-                                               : &ioc4_uart_rs422;
-
-       /* once around for each port on this card */
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type_idx];
-               port = control->ic_port[port_num].icp_port;
-               port->ip_all_ports[port_type_idx] = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
-                               __func__, (void *)the_port,
-                               (void *)port,
-                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  port_num;
-               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
-               the_port->mapbase = port_type;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = IOC4_FIFO_CHARS;
-               the_port->ops = &ioc4_ops;
-               the_port->irq = control->ic_irq;
-               the_port->dev = &pdev->dev;
-               spin_lock_init(&the_port->lock);
-               if (uart_add_one_port(u_driver, the_port) < 0) {
-                       printk(KERN_WARNING
-                          "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(
-                           ("IOC4 serial port %d irq = %d, bus %d\n",
-                              the_port->line, the_port->irq, pdev->bus->number));
-               }
-       }
-       return 0;
-}
-
-/**
- * ioc4_serial_attach_one - register attach function
- *             called per card found from IOC4 master module.
- * @idd: Master module data for this IOC4
- */
-int
-ioc4_serial_attach_one(struct ioc4_driver_data *idd)
-{
-       unsigned long tmp_addr1;
-       struct ioc4_serial __iomem *serial;
-       struct ioc4_soft *soft;
-       struct ioc4_control *control;
-       int ret = 0;
-
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
-                                                       idd->idd_pci_id));
-
-       /* PCI-RT does not bring out serial connections.
-        * Do not attach to this particular IOC4.
-        */
-       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
-               return 0;
-
-       /* request serial registers */
-       tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
-
-       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
-                                       "sioc4_uart")) {
-               printk(KERN_WARNING
-                       "ioc4 (%p): unable to get request region for "
-                               "uart space\n", (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out1;
-       }
-       serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
-       if (!serial) {
-               printk(KERN_WARNING
-                        "ioc4 (%p) : unable to remap ioc4 serial register\n",
-                               (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out2;
-       }
-       DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
-                               __func__, (void *)idd->idd_misc_regs,
-                               (void *)serial));
-
-       /* Get memory for the new card */
-       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
-
-       if (!control) {
-               printk(KERN_WARNING "ioc4_attach_one"
-                      ": unable to get memory for the IOC4\n");
-               ret = -ENOMEM;
-               goto out2;
-       }
-       idd->idd_serial_data = control;
-
-       /* Allocate the soft structure */
-       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
-       if (!soft) {
-               printk(KERN_WARNING
-                      "ioc4 (%p): unable to get memory for the soft struct\n",
-                      (void *)idd->idd_pdev);
-               ret = -ENOMEM;
-               goto out3;
-       }
-
-       spin_lock_init(&soft->is_ir_lock);
-       soft->is_ioc4_misc_addr = idd->idd_misc_regs;
-       soft->is_ioc4_serial_addr = serial;
-
-       /* Init the IOC4 */
-       writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
-              &idd->idd_misc_regs->sio_cr.raw);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
-               | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
-               &idd->idd_misc_regs->gpcr_s.raw);
-
-       /* Clear and disable all serial interrupts */
-       write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       writel(~0, &idd->idd_misc_regs->sio_ir.raw);
-       write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
-                  IOC4_OTHER_INTR_TYPE);
-       writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
-       control->ic_soft = soft;
-
-       /* Hook up interrupt handler */
-       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
-                               "sgi-ioc4serial", soft)) {
-               control->ic_irq = idd->idd_pdev->irq;
-       } else {
-               printk(KERN_WARNING
-                   "%s : request_irq fails for IRQ 0x%x\n ",
-                       __func__, idd->idd_pdev->irq);
-       }
-       ret = ioc4_attach_local(idd);
-       if (ret)
-               goto out4;
-
-       /* register port with the serial core - 1 rs232, 1 rs422 */
-
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
-               goto out4;
-
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
-               goto out5;
-
-       Num_of_ioc4_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out5:
-       ioc4_serial_remove_one(idd);
-out4:
-       kfree(soft);
-out3:
-       kfree(control);
-out2:
-       if (serial)
-               iounmap(serial);
-       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
-out1:
-
-       return ret;
-}
-
-
-static struct ioc4_submodule ioc4_serial_submodule = {
-       .is_name = "IOC4_serial",
-       .is_owner = THIS_MODULE,
-       .is_probe = ioc4_serial_attach_one,
-       .is_remove = ioc4_serial_remove_one,
-};
-
-/**
- * ioc4_serial_init - module init
- */
-static int __init ioc4_serial_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs232 IOC4 serial driver\n",
-                       __func__);
-               goto out;
-       }
-       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs422 IOC4 serial driver\n",
-                       __func__);
-               goto out_uart_rs232;
-       }
-
-       /* register with IOC4 main module */
-       ret = ioc4_register_submodule(&ioc4_serial_submodule);
-       if (ret)
-               goto out_uart_rs422;
-       return 0;
-
-out_uart_rs422:
-       uart_unregister_driver(&ioc4_uart_rs422);
-out_uart_rs232:
-       uart_unregister_driver(&ioc4_uart_rs232);
-out:
-       return ret;
-}
-
-static void __exit ioc4_serial_exit(void)
-{
-       ioc4_unregister_submodule(&ioc4_serial_submodule);
-       uart_unregister_driver(&ioc4_uart_rs232);
-       uart_unregister_driver(&ioc4_uart_rs422);
-}
-
-late_initcall(ioc4_serial_init); /* Call only after tty init is done */
-module_exit(ioc4_serial_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
deleted file mode 100644 (file)
index ebff4a1..0000000
+++ /dev/null
@@ -1,1221 +0,0 @@
-/*
- * Driver for Zilog serial chips found on SGI workstations and
- * servers.  This driver could actually be made more generic.
- *
- * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the
- * old drivers/sgi/char/sgiserial.c code which itself is based of the original
- * drivers/sbus/char/zs.c code.  A lot of code has been simply moved over
- * directly from there but much has been rewritten.  Credits therefore go out
- * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell
- * for their work there.
- *
- *  Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
- *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/sgialib.h>
-#include <asm/sgi/ioc.h>
-#include <asm/sgi/hpc3.h>
-#include <asm/sgi/ip22.h>
-
-#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "ip22zilog.h"
-
-/*
- * On IP22 we need to delay after register accesses but we do not need to
- * flush writes.
- */
-#define ZSDELAY()              udelay(5)
-#define ZSDELAY_LONG()         udelay(20)
-#define ZS_WSYNC(channel)      do { } while (0)
-
-#define NUM_IP22ZILOG          1
-#define NUM_CHANNELS           (NUM_IP22ZILOG * 2)
-
-#define ZS_CLOCK               3672000 /* Zilog input clock rate. */
-#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_ip22zilog_port {
-       struct uart_port                port;
-
-       /* IRQ servicing chain.  */
-       struct uart_ip22zilog_port      *next;
-
-       /* Current values of Zilog write registers.  */
-       unsigned char                   curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define IP22ZILOG_FLAG_IS_CONS         0x00000004
-#define IP22ZILOG_FLAG_IS_KGDB         0x00000008
-#define IP22ZILOG_FLAG_MODEM_STATUS    0x00000010
-#define IP22ZILOG_FLAG_IS_CHANNEL_A    0x00000020
-#define IP22ZILOG_FLAG_REGS_HELD       0x00000040
-#define IP22ZILOG_FLAG_TX_STOPPED      0x00000080
-#define IP22ZILOG_FLAG_TX_ACTIVE       0x00000100
-#define IP22ZILOG_FLAG_RESET_DONE      0x00000200
-
-       unsigned int                    tty_break;
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-};
-
-#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel *)((PORT)->membase))
-#define UART_ZILOG(PORT)               ((struct uart_ip22zilog_port *)(PORT))
-#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM)           \
-       (UART_ZILOG(PORT)->curregs[REGNUM])
-#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL)   \
-       ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL))
-#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)       ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)      ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)       ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
-
-/* Reading and writing Zilog8530 registers.  The delays are to make this
- * driver work on the IP22 which needs a settling delay after each chip
- * register access, other machines handle this in hardware via auxiliary
- * flip-flops which implement the settle time we do in software.
- *
- * The port lock must be held and local IRQs must be disabled
- * when {read,write}_zsreg is invoked.
- */
-static unsigned char read_zsreg(struct zilog_channel *channel,
-                               unsigned char reg)
-{
-       unsigned char retval;
-
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       retval = readb(&channel->control);
-       ZSDELAY();
-
-       return retval;
-}
-
-static void write_zsreg(struct zilog_channel *channel,
-                       unsigned char reg, unsigned char value)
-{
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       writeb(value, &channel->control);
-       ZSDELAY();
-}
-
-static void ip22zilog_clear_fifo(struct zilog_channel *channel)
-{
-       int i;
-
-       for (i = 0; i < 32; i++) {
-               unsigned char regval;
-
-               regval = readb(&channel->control);
-               ZSDELAY();
-               if (regval & Rx_CH_AV)
-                       break;
-
-               regval = read_zsreg(channel, R1);
-               readb(&channel->data);
-               ZSDELAY();
-
-               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-       }
-}
-
-/* This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
-{
-       int i;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       writeb(ERR_RES, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       ip22zilog_clear_fifo(channel);
-
-       /* Disable all interrupts.  */
-       write_zsreg(channel, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(channel, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(channel, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-
-       /* Synchronous mode config.  */
-       write_zsreg(channel, R6, regs[R6]);
-       write_zsreg(channel, R7, regs[R7]);
-
-       /* Don't mess with the interrupt vector (R2, unused by us) and
-        * master interrupt control (R9).  We make sure this is setup
-        * properly at probe time then never touch it again.
-        */
-
-       /* Disable baud generator.  */
-       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(channel, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(channel, R14, regs[R14]);
-
-       /* External status interrupt control.  */
-       write_zsreg(channel, R15, regs[R15]);
-
-       /* Reset external status interrupts.  */
-       write_zsreg(channel, R0, RES_EXT_INT);
-       write_zsreg(channel, R0, RES_EXT_INT);
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(channel, R1, regs[R1]);
-}
-
-/* Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
-                                      struct zilog_channel *channel)
-{
-       if (!ZS_REGS_HELD(up)) {
-               if (ZS_TX_ACTIVE(up)) {
-                       up->flags |= IP22ZILOG_FLAG_REGS_HELD;
-               } else {
-                       __load_zsregs(channel, up->curregs);
-               }
-       }
-}
-
-#define Rx_BRK 0x0100                   /* BREAK event software flag.  */
-#define Rx_SYS 0x0200                   /* SysRq event software flag.  */
-
-static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
-                                                 struct zilog_channel *channel)
-{
-       struct tty_struct *tty;
-       unsigned char ch, flag;
-       unsigned int r1;
-
-       tty = NULL;
-       if (up->port.state != NULL &&
-           up->port.state->port.tty != NULL)
-               tty = up->port.state->port.tty;
-
-       for (;;) {
-               ch = readb(&channel->control);
-               ZSDELAY();
-               if (!(ch & Rx_CH_AV))
-                       break;
-
-               r1 = read_zsreg(channel, R1);
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-
-               ch = readb(&channel->data);
-               ZSDELAY();
-
-               ch &= up->parity_mask;
-
-               /* Handle the null char got when BREAK is removed.  */
-               if (!ch)
-                       r1 |= up->tty_break;
-
-               /* A real serial line, record the character and status.  */
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
-                       up->tty_break = 0;
-
-                       if (r1 & (Rx_SYS | Rx_BRK)) {
-                               up->port.icount.brk++;
-                               if (r1 & Rx_SYS)
-                                       continue;
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                       }
-                       else if (r1 & PAR_ERR)
-                               up->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               up->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               up->port.icount.overrun++;
-                       r1 &= up->port.read_status_mask;
-                       if (r1 & Rx_BRK)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if (tty)
-                       uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
-       }
-       return tty;
-}
-
-static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
-                                  struct zilog_channel *channel)
-{
-       unsigned char status;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       writeb(RES_EXT_INT, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       if (up->curregs[R15] & BRKIE) {
-               if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
-                       if (uart_handle_break(&up->port))
-                               up->tty_break = Rx_SYS;
-                       else
-                               up->tty_break = Rx_BRK;
-               }
-       }
-
-       if (ZS_WANTS_MODEM_STATUS(up)) {
-               if (status & SYNC)
-                       up->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                */
-               if ((status ^ up->prev_status) ^ DCD)
-                       uart_handle_dcd_change(&up->port,
-                                              (status & DCD));
-               if ((status ^ up->prev_status) ^ CTS)
-                       uart_handle_cts_change(&up->port,
-                                              (status & CTS));
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       up->prev_status = status;
-}
-
-static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
-                                   struct zilog_channel *channel)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_CONS(up)) {
-               unsigned char status = readb(&channel->control);
-               ZSDELAY();
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(up)) {
-               __load_zsregs(channel, up->curregs);
-               up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(up)) {
-               up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       if (up->port.x_char) {
-               up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-               writeb(up->port.x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-
-       if (up->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &up->port.state->xmit;
-       if (uart_circ_empty(xmit))
-               goto ack_tx_int;
-       if (uart_tx_stopped(&up->port))
-               goto ack_tx_int;
-
-       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-       writeb(xmit->buf[xmit->tail], &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       up->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return;
-
-ack_tx_int:
-       writeb(RES_Tx_P, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
-{
-       struct uart_ip22zilog_port *up = dev_id;
-
-       while (up) {
-               struct zilog_channel *channel
-                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
-               struct tty_struct *tty;
-               unsigned char r3;
-
-               spin_lock(&up->port.lock);
-               r3 = read_zsreg(channel, R3);
-
-               /* Channel A */
-               tty = NULL;
-               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHARxIP)
-                               tty = ip22zilog_receive_chars(up, channel);
-                       if (r3 & CHAEXT)
-                               ip22zilog_status_handle(up, channel);
-                       if (r3 & CHATxIP)
-                               ip22zilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               /* Channel B */
-               up = up->next;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-               spin_lock(&up->port.lock);
-               tty = NULL;
-               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHBRxIP)
-                               tty = ip22zilog_receive_chars(up, channel);
-                       if (r3 & CHBEXT)
-                               ip22zilog_status_handle(up, channel);
-                       if (r3 & CHBTxIP)
-                               ip22zilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               up = up->next;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
- * port lock, it is acquired here.
- */
-static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
-{
-       struct zilog_channel *channel;
-       unsigned char status;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       return status;
-}
-
-/* The port lock is not held.  */
-static unsigned int ip22zilog_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned char status;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       status = ip22zilog_read_channel_status(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (status & Tx_BUF_EMP)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int ret;
-
-       status = ip22zilog_read_channel_status(port);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC)
-               ret |= TIOCM_DSR;
-       if (status & CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits;
-
-       set_bits = clear_bits = 0;
-
-       if (mctrl & TIOCM_RTS)
-               set_bits |= RTS;
-       else
-               clear_bits |= RTS;
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */
-       up->curregs[R5] |= set_bits;
-       up->curregs[R5] &= ~clear_bits;
-       write_zsreg(channel, R5, up->curregs[R5]);
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_tx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-
-       up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_start_tx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char status;
-
-       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
-       up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               writeb(port->x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               writeb(xmit->buf[xmit->tail], &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&up->port);
-       }
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void ip22zilog_stop_rx(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable all RX interrupts.  */
-       up->curregs[R1] &= ~RxINT_MASK;
-       ip22zilog_maybe_update_regs(up, channel);
-}
-
-/* The port lock is held.  */
-static void ip22zilog_enable_ms(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char new_reg;
-
-       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != up->curregs[R15]) {
-               up->curregs[R15] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */
-               write_zsreg(channel, R15, up->curregs[R15]);
-       }
-}
-
-/* The port lock is not held.  */
-static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != up->curregs[R5]) {
-               up->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */
-               write_zsreg(channel, R5, up->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
-{
-       struct zilog_channel *channel;
-       int i;
-
-       if (up->flags & IP22ZILOG_FLAG_RESET_DONE)
-               return;
-
-       /* Let pending transmits finish.  */
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       if (!ZS_IS_CHANNEL_A(up)) {
-               up++;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       }
-       write_zsreg(channel, R9, FHWRES);
-       ZSDELAY_LONG();
-       (void) read_zsreg(channel, R0);
-
-       up->flags |= IP22ZILOG_FLAG_RESET_DONE;
-       up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
-}
-
-static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
-{
-       struct zilog_channel *channel;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-       __ip22zilog_reset(up);
-
-       __load_zsregs(channel, up->curregs);
-       /* set master interrupt enable */
-       write_zsreg(channel, R9, up->curregs[R9]);
-       up->prev_status = readb(&channel->control);
-
-       /* Enable receiver and transmitter.  */
-       up->curregs[R3] |= RxENAB;
-       up->curregs[R5] |= TxENAB;
-
-       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-       ip22zilog_maybe_update_regs(up, channel);
-}
-
-static int ip22zilog_startup(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __ip22zilog_startup(up);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
-}
-
-/*
- * The test for ZS_IS_CONS is explained by the following e-mail:
- *****
- * From: Russell King <rmk@arm.linux.org.uk>
- * Date: Sun, 8 Dec 2002 10:18:38 +0000
- *
- * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
- * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
- * > and I noticed that something is not right with reference
- * > counting in this case. It seems that when the console
- * > is open by kernel initially, this is not accounted
- * > as an open, and uart_startup is not called.
- *
- * That is correct.  We are unable to call uart_startup when the serial
- * console is initialised because it may need to allocate memory (as
- * request_irq does) and the memory allocators may not have been
- * initialised.
- *
- * 1. initialise the port into a state where it can send characters in the
- *    console write method.
- *
- * 2. don't do the actual hardware shutdown in your shutdown() method (but
- *    do the normal software shutdown - ie, free irqs etc)
- *****
- */
-static void ip22zilog_shutdown(struct uart_port *port)
-{
-       struct uart_ip22zilog_port *up = UART_ZILOG(port);
-       struct zilog_channel *channel;
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable receiver and transmitter.  */
-       up->curregs[R3] &= ~RxENAB;
-       up->curregs[R5] &= ~TxENAB;
-
-       /* Disable all interrupts and BRK assertion.  */
-       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       up->curregs[R5] &= ~SND_BRK;
-       ip22zilog_maybe_update_regs(up, channel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void
-ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
-                      unsigned int iflag, int brg)
-{
-
-       up->curregs[R10] = NRZ;
-       up->curregs[R11] = TCBR | RCBR;
-
-       /* Program BAUD and clock source. */
-       up->curregs[R4] &= ~XCLK_MASK;
-       up->curregs[R4] |= X16CLK;
-       up->curregs[R12] = brg & 0xff;
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       up->curregs[R14] = BRENAB;
-
-       /* Character size, stop bits, and parity. */
-       up->curregs[3] &= ~RxN_MASK;
-       up->curregs[5] &= ~TxN_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               up->curregs[3] |= Rx5;
-               up->curregs[5] |= Tx5;
-               up->parity_mask = 0x1f;
-               break;
-       case CS6:
-               up->curregs[3] |= Rx6;
-               up->curregs[5] |= Tx6;
-               up->parity_mask = 0x3f;
-               break;
-       case CS7:
-               up->curregs[3] |= Rx7;
-               up->curregs[5] |= Tx7;
-               up->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               up->curregs[3] |= Rx8;
-               up->curregs[5] |= Tx8;
-               up->parity_mask = 0xff;
-               break;
-       };
-       up->curregs[4] &= ~0x0c;
-       if (cflag & CSTOPB)
-               up->curregs[4] |= SB2;
-       else
-               up->curregs[4] |= SB1;
-       if (cflag & PARENB)
-               up->curregs[4] |= PAR_ENAB;
-       else
-               up->curregs[4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               up->curregs[4] |= PAR_EVEN;
-       else
-               up->curregs[4] &= ~PAR_EVEN;
-
-       up->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= BRK_ABRT;
-
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask = 0xff;
-}
-
-/* The port lock is not held.  */
-static void
-ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
-                     struct ktermios *old)
-{
-       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
-       unsigned long flags;
-       int baud, brg;
-
-       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
-
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->flags |= IP22ZILOG_FLAG_MODEM_STATUS;
-       else
-               up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
-
-       ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *ip22zilog_type(struct uart_port *port)
-{
-       return "IP22-Zilog";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void ip22zilog_release_port(struct uart_port *port)
-{
-}
-
-static int ip22zilog_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void ip22zilog_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops ip22zilog_pops = {
-       .tx_empty       =       ip22zilog_tx_empty,
-       .set_mctrl      =       ip22zilog_set_mctrl,
-       .get_mctrl      =       ip22zilog_get_mctrl,
-       .stop_tx        =       ip22zilog_stop_tx,
-       .start_tx       =       ip22zilog_start_tx,
-       .stop_rx        =       ip22zilog_stop_rx,
-       .enable_ms      =       ip22zilog_enable_ms,
-       .break_ctl      =       ip22zilog_break_ctl,
-       .startup        =       ip22zilog_startup,
-       .shutdown       =       ip22zilog_shutdown,
-       .set_termios    =       ip22zilog_set_termios,
-       .type           =       ip22zilog_type,
-       .release_port   =       ip22zilog_release_port,
-       .request_port   =       ip22zilog_request_port,
-       .config_port    =       ip22zilog_config_port,
-       .verify_port    =       ip22zilog_verify_port,
-};
-
-static struct uart_ip22zilog_port *ip22zilog_port_table;
-static struct zilog_layout **ip22zilog_chip_regs;
-
-static struct uart_ip22zilog_port *ip22zilog_irq_chain;
-static int zilog_irq = -1;
-
-static void * __init alloc_one_table(unsigned long size)
-{
-       return kzalloc(size, GFP_KERNEL);
-}
-
-static void __init ip22zilog_alloc_tables(void)
-{
-       ip22zilog_port_table = (struct uart_ip22zilog_port *)
-               alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
-       ip22zilog_chip_regs = (struct zilog_layout **)
-               alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
-
-       if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
-               panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
-       }
-}
-
-/* Get the address of the registers for IP22-Zilog instance CHIP.  */
-static struct zilog_layout * __init get_zs(int chip)
-{
-       unsigned long base;
-
-       if (chip < 0 || chip >= NUM_IP22ZILOG) {
-               panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
-       }
-
-       /* Not probe-able, hard code it. */
-       base = (unsigned long) &sgioc->uart;
-
-       zilog_irq = SGI_SERIAL_IRQ;
-       request_mem_region(base, 8, "IP22-Zilog");
-
-       return (struct zilog_layout *) base;
-}
-
-#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
-
-#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-static void ip22zilog_put_char(struct uart_port *port, int ch)
-{
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       int loops = ZS_PUT_CHAR_MAX_DELAY;
-
-       /* This is a timed polling loop so do not switch the explicit
-        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
-        */
-       do {
-               unsigned char val = readb(&channel->control);
-               if (val & Tx_BUF_EMP) {
-                       ZSDELAY();
-                       break;
-               }
-               udelay(5);
-       } while (--loops);
-
-       writeb(ch, &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static void
-ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       uart_console_write(&up->port, s, count, ip22zilog_put_char);
-       udelay(2);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int __init ip22zilog_console_setup(struct console *con, char *options)
-{
-       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
-       unsigned long flags;
-       int baud = 9600, bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       up->flags |= IP22ZILOG_FLAG_IS_CONS;
-
-       printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->curregs[R15] |= BRKIE;
-
-       __ip22zilog_startup(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(&up->port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver ip22zilog_reg;
-
-static struct console ip22zilog_console = {
-       .name   =       "ttyS",
-       .write  =       ip22zilog_console_write,
-       .device =       uart_console_device,
-       .setup  =       ip22zilog_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &ip22zilog_reg,
-};
-#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
-
-static struct uart_driver ip22zilog_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = NUM_CHANNELS,
-#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-       .cons           = &ip22zilog_console,
-#endif
-};
-
-static void __init ip22zilog_prepare(void)
-{
-       struct uart_ip22zilog_port *up;
-       struct zilog_layout *rp;
-       int channel, chip;
-
-       /*
-        * Temporary fix.
-        */
-       for (channel = 0; channel < NUM_CHANNELS; channel++)
-               spin_lock_init(&ip22zilog_port_table[channel].port.lock);
-
-       ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
-        up = &ip22zilog_port_table[0];
-       for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
-               up[channel].next = &up[channel - 1];
-       up[channel].next = NULL;
-
-       for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
-               if (!ip22zilog_chip_regs[chip]) {
-                       ip22zilog_chip_regs[chip] = rp = get_zs(chip);
-
-                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
-                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
-
-                       /* In theory mapbase is the physical address ...  */
-                       up[(chip * 2) + 0].port.mapbase =
-                               (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
-                       up[(chip * 2) + 1].port.mapbase =
-                               (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
-               }
-
-               /* Channel A */
-               up[(chip * 2) + 0].port.iotype = UPIO_MEM;
-               up[(chip * 2) + 0].port.irq = zilog_irq;
-               up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
-               up[(chip * 2) + 0].port.fifosize = 1;
-               up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
-               up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
-               up[(chip * 2) + 0].port.flags = 0;
-               up[(chip * 2) + 0].port.line = (chip * 2) + 0;
-               up[(chip * 2) + 0].flags = 0;
-
-               /* Channel B */
-               up[(chip * 2) + 1].port.iotype = UPIO_MEM;
-               up[(chip * 2) + 1].port.irq = zilog_irq;
-               up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
-               up[(chip * 2) + 1].port.fifosize = 1;
-               up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
-               up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
-               up[(chip * 2) + 1].port.line = (chip * 2) + 1;
-               up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
-       }
-
-       for (channel = 0; channel < NUM_CHANNELS; channel++) {
-               struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
-               int brg;
-
-               /* Normal serial TTY. */
-               up->parity_mask = 0xff;
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R9] = NV | MIE;
-               up->curregs[R10] = NRZ;
-               up->curregs[R11] = TCBR | RCBR;
-               brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-               up->curregs[R12] = (brg & 0xff);
-               up->curregs[R13] = (brg >> 8) & 0xff;
-               up->curregs[R14] = BRENAB;
-       }
-}
-
-static int __init ip22zilog_ports_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
-
-       ip22zilog_prepare();
-
-       if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
-                       "IP22-Zilog", ip22zilog_irq_chain)) {
-               panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
-       }
-
-       ret = uart_register_driver(&ip22zilog_reg);
-       if (ret == 0) {
-               int i;
-
-               for (i = 0; i < NUM_CHANNELS; i++) {
-                       struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
-
-                       uart_add_one_port(&ip22zilog_reg, &up->port);
-               }
-       }
-
-       return ret;
-}
-
-static int __init ip22zilog_init(void)
-{
-       /* IP22 Zilog setup is hard coded, no probing to do.  */
-       ip22zilog_alloc_tables();
-       ip22zilog_ports_init();
-
-       return 0;
-}
-
-static void __exit ip22zilog_exit(void)
-{
-       int i;
-       struct uart_ip22zilog_port *up;
-
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               up = &ip22zilog_port_table[i];
-
-               uart_remove_one_port(&ip22zilog_reg, &up->port);
-       }
-
-       /* Free IO mem */
-       up = &ip22zilog_port_table[0];
-       for (i = 0; i < NUM_IP22ZILOG; i++) {
-               if (up[(i * 2) + 0].port.mapbase) {
-                  iounmap((void*)up[(i * 2) + 0].port.mapbase);
-                  up[(i * 2) + 0].port.mapbase = 0;
-               }
-               if (up[(i * 2) + 1].port.mapbase) {
-                       iounmap((void*)up[(i * 2) + 1].port.mapbase);
-                       up[(i * 2) + 1].port.mapbase = 0;
-               }
-       }
-
-       uart_unregister_driver(&ip22zilog_reg);
-}
-
-module_init(ip22zilog_init);
-module_exit(ip22zilog_exit);
-
-/* David wrote it but I'm to blame for the bugs ...  */
-MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
-MODULE_DESCRIPTION("SGI Zilog serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ip22zilog.h b/drivers/serial/ip22zilog.h
deleted file mode 100644 (file)
index a59a9a8..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-#ifndef _IP22_ZILOG_H
-#define _IP22_ZILOG_H
-
-#include <asm/byteorder.h>
-
-struct zilog_channel {
-#ifdef __BIG_ENDIAN
-       volatile unsigned char unused0[3];
-       volatile unsigned char control;
-       volatile unsigned char unused1[3];
-       volatile unsigned char data;
-#else /* __LITTLE_ENDIAN */
-       volatile unsigned char control;
-       volatile unsigned char unused0[3];
-       volatile unsigned char data;
-       volatile unsigned char unused1[3];
-#endif
-};
-
-struct zilog_layout {
-       struct zilog_channel channelB;
-       struct zilog_channel channelA;
-};
-
-#define NUM_ZSREGS    16
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENAB          0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        ZCIE    2       /* Zero count IE */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC            0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY   0x00
-#define CHB_EXT_STAT   0x02
-#define CHB_Rx_AVAIL   0x04
-#define CHB_SPECIAL    0x06
-#define CHA_Tx_EMPTY   0x08
-#define CHA_EXT_STAT   0x0a
-#define CHA_Rx_AVAIL   0x0c
-#define CHA_SPECIAL    0x0e
-#define STATUS_MASK    0x0e
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    do { writeb(ERR_RES, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARSTAT(channel)   do { writeb(RES_EXT_INT, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARFIFO(channel)   do { readb(&channel->data); \
-                                    udelay(2); \
-                                    readb(&channel->data); \
-                                    udelay(2); \
-                                    readb(&channel->data); \
-                                    udelay(2); } while(0)
-
-#endif /* _IP22_ZILOG_H */
diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile
deleted file mode 100644 (file)
index e46b6e0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for Jasmine adapter
-#
-
-obj-$(CONFIG_SERIAL_JSM) += jsm.o
-
-jsm-objs :=    jsm_driver.o jsm_neo.o jsm_tty.o
-
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
deleted file mode 100644 (file)
index 38a509c..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
- * MA  02111-1307, USA.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- ***********************************************************************/
-
-#ifndef __JSM_DRIVER_H
-#define __JSM_DRIVER_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>       /* To pick up the varions Linux types */
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-
-/*
- * Debugging levels can be set using debug insmod variable
- * They can also be compiled out completely.
- */
-enum {
-       DBG_INIT        = 0x01,
-       DBG_BASIC       = 0x02,
-       DBG_CORE        = 0x04,
-       DBG_OPEN        = 0x08,
-       DBG_CLOSE       = 0x10,
-       DBG_READ        = 0x20,
-       DBG_WRITE       = 0x40,
-       DBG_IOCTL       = 0x80,
-       DBG_PROC        = 0x100,
-       DBG_PARAM       = 0x200,
-       DBG_PSCAN       = 0x400,
-       DBG_EVENT       = 0x800,
-       DBG_DRAIN       = 0x1000,
-       DBG_MSIGS       = 0x2000,
-       DBG_MGMT        = 0x4000,
-       DBG_INTR        = 0x8000,
-       DBG_CARR        = 0x10000,
-};
-
-#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \
-       if ((DBG_##nlevel & jsm_debug))                 \
-       dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
-
-#define        MAXLINES        256
-#define MAXPORTS       8
-#define MAX_STOPS_SENT 5
-
-/* Board type definitions */
-
-#define T_NEO          0000
-#define T_CLASSIC      0001
-#define T_PCIBUS       0400
-
-/* Board State Definitions */
-
-#define BD_RUNNING     0x0
-#define BD_REASON      0x7f
-#define BD_NOTFOUND    0x1
-#define BD_NOIOPORT    0x2
-#define BD_NOMEM       0x3
-#define BD_NOBIOS      0x4
-#define BD_NOFEP       0x5
-#define BD_FAILED      0x6
-#define BD_ALLOCATED   0x7
-#define BD_TRIBOOT     0x8
-#define BD_BADKME      0x80
-
-
-/* 4 extra for alignment play space */
-#define WRITEBUFLEN    ((4096) + 4)
-#define MYFLIPLEN      N_TTY_BUF_SIZE
-
-#define JSM_VERSION    "jsm: 1.2-1-INKERNEL"
-#define JSM_PARTNUM    "40002438_A-INKERNEL"
-
-struct jsm_board;
-struct jsm_channel;
-
-/************************************************************************
- * Per board operations structure                                      *
- ************************************************************************/
-struct board_ops {
-       irq_handler_t intr;
-       void (*uart_init) (struct jsm_channel *ch);
-       void (*uart_off) (struct jsm_channel *ch);
-       void (*param) (struct jsm_channel *ch);
-       void (*assert_modem_signals) (struct jsm_channel *ch);
-       void (*flush_uart_write) (struct jsm_channel *ch);
-       void (*flush_uart_read) (struct jsm_channel *ch);
-       void (*disable_receiver) (struct jsm_channel *ch);
-       void (*enable_receiver) (struct jsm_channel *ch);
-       void (*send_break) (struct jsm_channel *ch);
-       void (*clear_break) (struct jsm_channel *ch, int);
-       void (*send_start_character) (struct jsm_channel *ch);
-       void (*send_stop_character) (struct jsm_channel *ch);
-       void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
-       u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
-       void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
-};
-
-
-/*
- *     Per-board information
- */
-struct jsm_board
-{
-       int             boardnum;       /* Board number: 0-32 */
-
-       int             type;           /* Type of board */
-       u8              rev;            /* PCI revision ID */
-       struct pci_dev  *pci_dev;
-       u32             maxports;       /* MAX ports this board can handle */
-
-       spinlock_t      bd_intr_lock;   /* Used to protect the poller tasklet and
-                                        * the interrupt routine from each other.
-                                        */
-
-       u32             nasync;         /* Number of ports on card */
-
-       u32             irq;            /* Interrupt request number */
-
-       u64             membase;        /* Start of base memory of the card */
-       u64             membase_end;    /* End of base memory of the card */
-
-       u8      __iomem *re_map_membase;/* Remapped memory of the card */
-
-       u64             iobase;         /* Start of io base of the card */
-       u64             iobase_end;     /* End of io base of the card */
-
-       u32             bd_uart_offset; /* Space between each UART */
-
-       struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
-       char            *flipbuf;       /* Our flip buffer, alloced if board is found */
-
-       u32             bd_dividend;    /* Board/UARTs specific dividend */
-
-       struct board_ops *bd_ops;
-
-       struct list_head jsm_board_entry;
-};
-
-/************************************************************************
- * Device flag definitions for ch_flags.
- ************************************************************************/
-#define CH_PRON                0x0001          /* Printer on string            */
-#define CH_STOP                0x0002          /* Output is stopped            */
-#define CH_STOPI       0x0004          /* Input is stopped             */
-#define CH_CD          0x0008          /* Carrier is present           */
-#define CH_FCAR                0x0010          /* Carrier forced on            */
-#define CH_HANGUP      0x0020          /* Hangup received              */
-
-#define CH_RECEIVER_OFF        0x0040          /* Receiver is off              */
-#define CH_OPENING     0x0080          /* Port in fragile open state   */
-#define CH_CLOSING     0x0100          /* Port in fragile close state  */
-#define CH_FIFO_ENABLED 0x0200         /* Port has FIFOs enabled       */
-#define CH_TX_FIFO_EMPTY 0x0400                /* TX Fifo is completely empty  */
-#define CH_TX_FIFO_LWM 0x0800          /* TX Fifo is below Low Water   */
-#define CH_BREAK_SENDING 0x1000                /* Break is being sent          */
-#define CH_LOOPBACK 0x2000             /* Channel is in lookback mode  */
-#define CH_FLIPBUF_IN_USE 0x4000       /* Channel's flipbuf is in use  */
-#define CH_BAUD0       0x08000         /* Used for checking B0 transitions */
-
-/* Our Read/Error/Write queue sizes */
-#define RQUEUEMASK     0x1FFF          /* 8 K - 1 */
-#define EQUEUEMASK     0x1FFF          /* 8 K - 1 */
-#define WQUEUEMASK     0x0FFF          /* 4 K - 1 */
-#define RQUEUESIZE     (RQUEUEMASK + 1)
-#define EQUEUESIZE     RQUEUESIZE
-#define WQUEUESIZE     (WQUEUEMASK + 1)
-
-
-/************************************************************************
- * Channel information structure.
- ************************************************************************/
-struct jsm_channel {
-       struct uart_port uart_port;
-       struct jsm_board        *ch_bd;         /* Board structure pointer      */
-
-       spinlock_t      ch_lock;        /* provide for serialization */
-       wait_queue_head_t ch_flags_wait;
-
-       u32             ch_portnum;     /* Port number, 0 offset.       */
-       u32             ch_open_count;  /* open count                   */
-       u32             ch_flags;       /* Channel flags                */
-
-       u64             ch_close_delay; /* How long we should drop RTS/DTR for */
-
-       tcflag_t        ch_c_iflag;     /* channel iflags               */
-       tcflag_t        ch_c_cflag;     /* channel cflags               */
-       tcflag_t        ch_c_oflag;     /* channel oflags               */
-       tcflag_t        ch_c_lflag;     /* channel lflags               */
-       u8              ch_stopc;       /* Stop character               */
-       u8              ch_startc;      /* Start character              */
-
-       u8              ch_mostat;      /* FEP output modem status      */
-       u8              ch_mistat;      /* FEP input modem status       */
-
-       struct neo_uart_struct __iomem *ch_neo_uart;    /* Pointer to the "mapped" UART struct */
-       u8              ch_cached_lsr;  /* Cached value of the LSR register */
-
-       u8              *ch_rqueue;     /* Our read queue buffer - malloc'ed */
-       u16             ch_r_head;      /* Head location of the read queue */
-       u16             ch_r_tail;      /* Tail location of the read queue */
-
-       u8              *ch_equeue;     /* Our error queue buffer - malloc'ed */
-       u16             ch_e_head;      /* Head location of the error queue */
-       u16             ch_e_tail;      /* Tail location of the error queue */
-
-       u8              *ch_wqueue;     /* Our write queue buffer - malloc'ed */
-       u16             ch_w_head;      /* Head location of the write queue */
-       u16             ch_w_tail;      /* Tail location of the write queue */
-
-       u64             ch_rxcount;     /* total of data received so far */
-       u64             ch_txcount;     /* total of data transmitted so far */
-
-       u8              ch_r_tlevel;    /* Receive Trigger level */
-       u8              ch_t_tlevel;    /* Transmit Trigger level */
-
-       u8              ch_r_watermark; /* Receive Watermark */
-
-
-       u32             ch_stops_sent;  /* How many times I have sent a stop character
-                                        * to try to stop the other guy sending.
-                                        */
-       u64             ch_err_parity;  /* Count of parity errors on channel */
-       u64             ch_err_frame;   /* Count of framing errors on channel */
-       u64             ch_err_break;   /* Count of breaks on channel */
-       u64             ch_err_overrun; /* Count of overruns on channel */
-
-       u64             ch_xon_sends;   /* Count of xons transmitted */
-       u64             ch_xoff_sends;  /* Count of xoffs transmitted */
-};
-
-
-/************************************************************************
- * Per channel/port NEO UART structure                                 *
- ************************************************************************
- *             Base Structure Entries Usage Meanings to Host           *
- *                                                                     *
- *     W = read write          R = read only                           *
- *                     U = Unused.                                     *
- ************************************************************************/
-
-struct neo_uart_struct {
-        u8 txrx;               /* WR   RHR/THR - Holding Reg */
-        u8 ier;                /* WR   IER - Interrupt Enable Reg */
-        u8 isr_fcr;            /* WR   ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
-        u8 lcr;                /* WR   LCR - Line Control Reg */
-        u8 mcr;                /* WR   MCR - Modem Control Reg */
-        u8 lsr;                /* WR   LSR - Line Status Reg */
-        u8 msr;                /* WR   MSR - Modem Status Reg */
-        u8 spr;                /* WR   SPR - Scratch Pad Reg */
-        u8 fctr;               /* WR   FCTR - Feature Control Reg */
-        u8 efr;                /* WR   EFR - Enhanced Function Reg */
-        u8 tfifo;              /* WR   TXCNT/TXTRG - Transmit FIFO Reg */
-        u8 rfifo;              /* WR   RXCNT/RXTRG - Recieve FIFO Reg */
-        u8 xoffchar1;  /* WR   XOFF 1 - XOff Character 1 Reg */
-        u8 xoffchar2;  /* WR   XOFF 2 - XOff Character 2 Reg */
-        u8 xonchar1;   /* WR   XON 1 - Xon Character 1 Reg */
-        u8 xonchar2;   /* WR   XON 2 - XOn Character 2 Reg */
-
-        u8 reserved1[0x2ff - 0x200]; /* U      Reserved by Exar */
-        u8 txrxburst[64];      /* RW   64 bytes of RX/TX FIFO Data */
-        u8 reserved2[0x37f - 0x340]; /* U      Reserved by Exar */
-        u8 rxburst_with_errors[64];    /* R    64 bytes of RX FIFO Data + LSR */
-};
-
-/* Where to read the extended interrupt register (32bits instead of 8bits) */
-#define        UART_17158_POLL_ADDR_OFFSET     0x80
-
-/*
- * These are the redefinitions for the FCTR on the XR17C158, since
- * Exar made them different than their earlier design. (XR16C854)
- */
-
-/* These are only applicable when table D is selected */
-#define UART_17158_FCTR_RTS_NODELAY    0x00
-#define UART_17158_FCTR_RTS_4DELAY     0x01
-#define UART_17158_FCTR_RTS_6DELAY     0x02
-#define UART_17158_FCTR_RTS_8DELAY     0x03
-#define UART_17158_FCTR_RTS_12DELAY    0x12
-#define UART_17158_FCTR_RTS_16DELAY    0x05
-#define UART_17158_FCTR_RTS_20DELAY    0x13
-#define UART_17158_FCTR_RTS_24DELAY    0x06
-#define UART_17158_FCTR_RTS_28DELAY    0x14
-#define UART_17158_FCTR_RTS_32DELAY    0x07
-#define UART_17158_FCTR_RTS_36DELAY    0x16
-#define UART_17158_FCTR_RTS_40DELAY    0x08
-#define UART_17158_FCTR_RTS_44DELAY    0x09
-#define UART_17158_FCTR_RTS_48DELAY    0x10
-#define UART_17158_FCTR_RTS_52DELAY    0x11
-
-#define UART_17158_FCTR_RTS_IRDA       0x10
-#define UART_17158_FCTR_RS485          0x20
-#define UART_17158_FCTR_TRGA           0x00
-#define UART_17158_FCTR_TRGB           0x40
-#define UART_17158_FCTR_TRGC           0x80
-#define UART_17158_FCTR_TRGD           0xC0
-
-/* 17158 trigger table selects.. */
-#define UART_17158_FCTR_BIT6           0x40
-#define UART_17158_FCTR_BIT7           0x80
-
-/* 17158 TX/RX memmapped buffer offsets */
-#define UART_17158_RX_FIFOSIZE         64
-#define UART_17158_TX_FIFOSIZE         64
-
-/* 17158 Extended IIR's */
-#define UART_17158_IIR_RDI_TIMEOUT     0x0C    /* Receiver data TIMEOUT */
-#define UART_17158_IIR_XONXOFF         0x10    /* Received an XON/XOFF char */
-#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20        /* CTS/DSR or RTS/DTR state change */
-#define UART_17158_IIR_FIFO_ENABLED    0xC0    /* 16550 FIFOs are Enabled */
-
-/*
- * These are the extended interrupts that get sent
- * back to us from the UART's 32bit interrupt register
- */
-#define UART_17158_RX_LINE_STATUS      0x1     /* RX Ready */
-#define UART_17158_RXRDY_TIMEOUT       0x2     /* RX Ready Timeout */
-#define UART_17158_TXRDY               0x3     /* TX Ready */
-#define UART_17158_MSR                 0x4     /* Modem State Change */
-#define UART_17158_TX_AND_FIFO_CLR     0x40    /* Transmitter Holding Reg Empty */
-#define UART_17158_RX_FIFO_DATA_ERROR  0x80    /* UART detected an RX FIFO Data error */
-
-/*
- * These are the EXTENDED definitions for the 17C158's Interrupt
- * Enable Register.
- */
-#define UART_17158_EFR_ECB     0x10    /* Enhanced control bit */
-#define UART_17158_EFR_IXON    0x2     /* Receiver compares Xon1/Xoff1 */
-#define UART_17158_EFR_IXOFF   0x8     /* Transmit Xon1/Xoff1 */
-#define UART_17158_EFR_RTSDTR  0x40    /* Auto RTS/DTR Flow Control Enable */
-#define UART_17158_EFR_CTSDSR  0x80    /* Auto CTS/DSR Flow COntrol Enable */
-
-#define UART_17158_XOFF_DETECT 0x1     /* Indicates whether chip saw an incoming XOFF char */
-#define UART_17158_XON_DETECT  0x2     /* Indicates whether chip saw an incoming XON char */
-
-#define UART_17158_IER_RSVD1   0x10    /* Reserved by Exar */
-#define UART_17158_IER_XOFF    0x20    /* Xoff Interrupt Enable */
-#define UART_17158_IER_RTSDTR  0x40    /* Output Interrupt Enable */
-#define UART_17158_IER_CTSDSR  0x80    /* Input Interrupt Enable */
-
-#define PCI_DEVICE_NEO_2DB9_PCI_NAME           "Neo 2 - DB9 Universal PCI"
-#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME                "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
-#define PCI_DEVICE_NEO_2RJ45_PCI_NAME          "Neo 2 - RJ45 Universal PCI"
-#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME       "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
-#define PCIE_DEVICE_NEO_IBM_PCI_NAME           "Neo 4 - PCI Express - IBM"
-
-/*
- * Our Global Variables.
- */
-extern struct  uart_driver jsm_uart_driver;
-extern struct  board_ops jsm_neo_ops;
-extern int     jsm_debug;
-
-/*************************************************************************
- *
- * Prototypes for non-static functions used in more than one module
- *
- *************************************************************************/
-int jsm_tty_write(struct uart_port *port);
-int jsm_tty_init(struct jsm_board *);
-int jsm_uart_port_init(struct jsm_board *);
-int jsm_remove_uart_port(struct jsm_board *);
-void jsm_input(struct jsm_channel *ch);
-void jsm_check_queue_flow_control(struct jsm_channel *ch);
-
-#endif
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
deleted file mode 100644 (file)
index 18f5484..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
- * MA  02111-1307, USA.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- *
- ***********************************************************************/
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "jsm.h"
-
-MODULE_AUTHOR("Digi International, http://www.digi.com");
-MODULE_DESCRIPTION("Driver for the Digi International "
-                  "Neo PCI based product line");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("jsm");
-
-#define JSM_DRIVER_NAME "jsm"
-#define NR_PORTS       32
-#define JSM_MINOR_START        0
-
-struct uart_driver jsm_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = JSM_DRIVER_NAME,
-       .dev_name       = "ttyn",
-       .major          = 0,
-       .minor          = JSM_MINOR_START,
-       .nr             = NR_PORTS,
-};
-
-static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
-                                       pci_channel_state_t state);
-static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
-static void jsm_io_resume(struct pci_dev *pdev);
-
-static struct pci_error_handlers jsm_err_handler = {
-       .error_detected = jsm_io_error_detected,
-       .slot_reset = jsm_io_slot_reset,
-       .resume = jsm_io_resume,
-};
-
-int jsm_debug;
-module_param(jsm_debug, int, 0);
-MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-
-static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       int rc = 0;
-       struct jsm_board *brd;
-       static int adapter_count = 0;
-
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               dev_err(&pdev->dev, "Device enable FAILED\n");
-               goto out;
-       }
-
-       rc = pci_request_regions(pdev, "jsm");
-       if (rc) {
-               dev_err(&pdev->dev, "pci_request_region FAILED\n");
-               goto out_disable_device;
-       }
-
-       brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
-       if (!brd) {
-               dev_err(&pdev->dev,
-                       "memory allocation for board structure failed\n");
-               rc = -ENOMEM;
-               goto out_release_regions;
-       }
-
-       /* store the info for the board we've found */
-       brd->boardnum = adapter_count++;
-       brd->pci_dev = pdev;
-       if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
-               brd->maxports = 4;
-       else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
-               brd->maxports = 8;
-       else
-               brd->maxports = 2;
-
-       spin_lock_init(&brd->bd_intr_lock);
-
-       /* store which revision we have */
-       brd->rev = pdev->revision;
-
-       brd->irq = pdev->irq;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev,
-               "jsm_found_board - NEO adapter\n");
-
-       /* get the PCI Base Address Registers */
-       brd->membase    = pci_resource_start(pdev, 0);
-       brd->membase_end = pci_resource_end(pdev, 0);
-
-       if (brd->membase & 1)
-               brd->membase &= ~3;
-       else
-               brd->membase &= ~15;
-
-       /* Assign the board_ops struct */
-       brd->bd_ops = &jsm_neo_ops;
-
-       brd->bd_uart_offset = 0x200;
-       brd->bd_dividend = 921600;
-
-       brd->re_map_membase = ioremap(brd->membase, 0x1000);
-       if (!brd->re_map_membase) {
-               dev_err(&pdev->dev,
-                       "card has no PCI Memory resources, "
-                       "failing board.\n");
-               rc = -ENOMEM;
-               goto out_kfree_brd;
-       }
-
-       rc = request_irq(brd->irq, brd->bd_ops->intr,
-                       IRQF_SHARED, "JSM", brd);
-       if (rc) {
-               printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
-               goto out_iounmap;
-       }
-
-       rc = jsm_tty_init(brd);
-       if (rc < 0) {
-               dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
-               rc = -ENXIO;
-               goto out_free_irq;
-       }
-
-       rc = jsm_uart_port_init(brd);
-       if (rc < 0) {
-               /* XXX: leaking all resources from jsm_tty_init here! */
-               dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
-               rc = -ENXIO;
-               goto out_free_irq;
-       }
-
-       /* Log the information about the board */
-       dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
-                       adapter_count, brd->rev, brd->irq);
-
-       /*
-        * allocate flip buffer for board.
-        *
-        * Okay to malloc with GFP_KERNEL, we are not at interrupt
-        * context, and there are no locks held.
-        */
-       brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
-       if (!brd->flipbuf) {
-               /* XXX: leaking all resources from jsm_tty_init and
-                       jsm_uart_port_init here! */
-               dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
-               rc = -ENOMEM;
-               goto out_free_uart;
-       }
-
-       pci_set_drvdata(pdev, brd);
-       pci_save_state(pdev);
-
-       return 0;
- out_free_uart:
-       jsm_remove_uart_port(brd);
- out_free_irq:
-       jsm_remove_uart_port(brd);
-       free_irq(brd->irq, brd);
- out_iounmap:
-       iounmap(brd->re_map_membase);
- out_kfree_brd:
-       kfree(brd);
- out_release_regions:
-       pci_release_regions(pdev);
- out_disable_device:
-       pci_disable_device(pdev);
- out:
-       return rc;
-}
-
-static void __devexit jsm_remove_one(struct pci_dev *pdev)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-       int i = 0;
-
-       jsm_remove_uart_port(brd);
-
-       free_irq(brd->irq, brd);
-       iounmap(brd->re_map_membase);
-
-       /* Free all allocated channels structs */
-       for (i = 0; i < brd->maxports; i++) {
-               if (brd->channels[i]) {
-                       kfree(brd->channels[i]->ch_rqueue);
-                       kfree(brd->channels[i]->ch_equeue);
-                       kfree(brd->channels[i]->ch_wqueue);
-                       kfree(brd->channels[i]);
-               }
-       }
-
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       kfree(brd->flipbuf);
-       kfree(brd);
-}
-
-static struct pci_device_id jsm_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
-       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
-
-static struct pci_driver jsm_driver = {
-       .name           = "jsm",
-       .id_table       = jsm_pci_tbl,
-       .probe          = jsm_probe_one,
-       .remove         = __devexit_p(jsm_remove_one),
-       .err_handler    = &jsm_err_handler,
-};
-
-static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
-                                       pci_channel_state_t state)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-
-       jsm_remove_uart_port(brd);
-
-       return PCI_ERS_RESULT_NEED_RESET;
-}
-
-static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
-{
-       int rc;
-
-       rc = pci_enable_device(pdev);
-
-       if (rc)
-               return PCI_ERS_RESULT_DISCONNECT;
-
-       pci_set_master(pdev);
-
-       return PCI_ERS_RESULT_RECOVERED;
-}
-
-static void jsm_io_resume(struct pci_dev *pdev)
-{
-       struct jsm_board *brd = pci_get_drvdata(pdev);
-
-       pci_restore_state(pdev);
-
-       jsm_uart_port_init(brd);
-}
-
-static int __init jsm_init_module(void)
-{
-       int rc;
-
-       rc = uart_register_driver(&jsm_uart_driver);
-       if (!rc) {
-               rc = pci_register_driver(&jsm_driver);
-               if (rc)
-                       uart_unregister_driver(&jsm_uart_driver);
-       }
-       return rc;
-}
-
-static void __exit jsm_exit_module(void)
-{
-       pci_unregister_driver(&jsm_driver);
-       uart_unregister_driver(&jsm_uart_driver);
-}
-
-module_init(jsm_init_module);
-module_exit(jsm_exit_module);
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
deleted file mode 100644 (file)
index 7960d96..0000000
+++ /dev/null
@@ -1,1412 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
- * MA  02111-1307, USA.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong   <wendyx@us.ibm.com>
- *
- ***********************************************************************/
-#include <linux/delay.h>       /* For udelay */
-#include <linux/serial_reg.h>  /* For the various UART offsets */
-#include <linux/tty.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "jsm.h"               /* Driver main header file */
-
-static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
-
-/*
- * This function allows calls to ensure that all outstanding
- * PCI writes have been completed, by doing a PCI read against
- * a non-destructive, read-only location on the Neo card.
- *
- * In this case, we are reading the DVID (Read-only Device Identification)
- * value of the Neo card.
- */
-static inline void neo_pci_posting_flush(struct jsm_board *bd)
-{
-      readb(bd->re_map_membase + 0x8D);
-}
-
-static void neo_set_cts_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
-
-       /* Turn on auto CTS flow control */
-       ier |= (UART_17158_IER_CTSDSR);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
-
-       /* Turn off auto Xon flow control */
-       efr &= ~(UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
-
-       /* Feed the UART our trigger levels */
-       writeb(8, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 8;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_rts_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
-
-       /* Turn on auto RTS flow control */
-       ier |= (UART_17158_IER_RTSDTR);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
-
-       /* Turn off auto Xoff flow control */
-       ier &= ~(UART_17158_IER_XOFF);
-       efr &= ~(UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
-       ch->ch_r_watermark = 4;
-
-       writeb(56, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 56;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-
-       /*
-        * From the Neo UART spec sheet:
-        * The auto RTS/DTR function must be started by asserting
-        * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
-        * it is enabled.
-        */
-       ch->ch_mostat |= (UART_MCR_RTS);
-}
-
-
-static void neo_set_ixon_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
-
-       /* Turn off auto CTS flow control */
-       ier &= ~(UART_17158_IER_CTSDSR);
-       efr &= ~(UART_17158_EFR_CTSDSR);
-
-       /* Turn on auto Xon flow control */
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-       ch->ch_r_watermark = 4;
-
-       writeb(32, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 32;
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
-
-       /* Turn off auto RTS flow control */
-       ier &= ~(UART_17158_IER_RTSDTR);
-       efr &= ~(UART_17158_EFR_RTSDTR);
-
-       /* Turn on auto Xoff flow control */
-       ier |= (UART_17158_IER_XOFF);
-       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       writeb(8, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 8;
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_no_input_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
-
-       /* Turn off auto RTS flow control */
-       ier &= ~(UART_17158_IER_RTSDTR);
-       efr &= ~(UART_17158_EFR_RTSDTR);
-
-       /* Turn off auto Xoff flow control */
-       ier &= ~(UART_17158_IER_XOFF);
-       if (ch->ch_c_iflag & IXON)
-               efr &= ~(UART_17158_EFR_IXOFF);
-       else
-               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       ch->ch_r_watermark = 0;
-
-       writeb(16, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 16;
-
-       writeb(16, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 16;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static void neo_set_no_output_flow_control(struct jsm_channel *ch)
-{
-       u8 ier, efr;
-       ier = readb(&ch->ch_neo_uart->ier);
-       efr = readb(&ch->ch_neo_uart->efr);
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
-
-       /* Turn off auto CTS flow control */
-       ier &= ~(UART_17158_IER_CTSDSR);
-       efr &= ~(UART_17158_EFR_CTSDSR);
-
-       /* Turn off auto Xon flow control */
-       if (ch->ch_c_iflag & IXOFF)
-               efr &= ~(UART_17158_EFR_IXON);
-       else
-               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
-
-       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Turn on UART enhanced bits */
-       writeb(efr, &ch->ch_neo_uart->efr);
-
-       /* Turn on table D, with 8 char hi/low watermarks */
-       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
-
-       ch->ch_r_watermark = 0;
-
-       writeb(16, &ch->ch_neo_uart->tfifo);
-       ch->ch_t_tlevel = 16;
-
-       writeb(16, &ch->ch_neo_uart->rfifo);
-       ch->ch_r_tlevel = 16;
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-}
-
-static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
-{
-
-       /* if hardware flow control is set, then skip this whole thing */
-       if (ch->ch_c_cflag & CRTSCTS)
-               return;
-
-       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       /* Tell UART what start/stop chars it should be looking for */
-       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
-       writeb(0, &ch->ch_neo_uart->xonchar2);
-
-       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
-       writeb(0, &ch->ch_neo_uart->xoffchar2);
-}
-
-static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
-{
-       int qleft = 0;
-       u8 linestatus = 0;
-       u8 error_mask = 0;
-       int n = 0;
-       int total = 0;
-       u16 head;
-       u16 tail;
-
-       if (!ch)
-               return;
-
-       /* cache head and tail of queue */
-       head = ch->ch_r_head & RQUEUEMASK;
-       tail = ch->ch_r_tail & RQUEUEMASK;
-
-       /* Get our cached LSR */
-       linestatus = ch->ch_cached_lsr;
-       ch->ch_cached_lsr = 0;
-
-       /* Store how much space we have left in the queue */
-       if ((qleft = tail - head - 1) < 0)
-               qleft += RQUEUEMASK + 1;
-
-       /*
-        * If the UART is not in FIFO mode, force the FIFO copy to
-        * NOT be run, by setting total to 0.
-        *
-        * On the other hand, if the UART IS in FIFO mode, then ask
-        * the UART to give us an approximation of data it has RX'ed.
-        */
-       if (!(ch->ch_flags & CH_FIFO_ENABLED))
-               total = 0;
-       else {
-               total = readb(&ch->ch_neo_uart->rfifo);
-
-               /*
-                * EXAR chip bug - RX FIFO COUNT - Fudge factor.
-                *
-                * This resolves a problem/bug with the Exar chip that sometimes
-                * returns a bogus value in the rfifo register.
-                * The count can be any where from 0-3 bytes "off".
-                * Bizarre, but true.
-                */
-               total -= 3;
-       }
-
-       /*
-        * Finally, bound the copy to make sure we don't overflow
-        * our own queue...
-        * The byte by byte copy loop below this loop this will
-        * deal with the queue overflow possibility.
-        */
-       total = min(total, qleft);
-
-       while (total > 0) {
-               /*
-                * Grab the linestatus register, we need to check
-                * to see if there are any errors in the FIFO.
-                */
-               linestatus = readb(&ch->ch_neo_uart->lsr);
-
-               /*
-                * Break out if there is a FIFO error somewhere.
-                * This will allow us to go byte by byte down below,
-                * finding the exact location of the error.
-                */
-               if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
-                       break;
-
-               /* Make sure we don't go over the end of our queue */
-               n = min(((u32) total), (RQUEUESIZE - (u32) head));
-
-               /*
-                * Cut down n even further if needed, this is to fix
-                * a problem with memcpy_fromio() with the Neo on the
-                * IBM pSeries platform.
-                * 15 bytes max appears to be the magic number.
-                */
-               n = min((u32) n, (u32) 12);
-
-               /*
-                * Since we are grabbing the linestatus register, which
-                * will reset some bits after our read, we need to ensure
-                * we don't miss our TX FIFO emptys.
-                */
-               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
-               linestatus = 0;
-
-               /* Copy data from uart to the queue */
-               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
-               /*
-                * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
-                * that all the data currently in the FIFO is free of
-                * breaks and parity/frame/orun errors.
-                */
-               memset(ch->ch_equeue + head, 0, n);
-
-               /* Add to and flip head if needed */
-               head = (head + n) & RQUEUEMASK;
-               total -= n;
-               qleft -= n;
-               ch->ch_rxcount += n;
-       }
-
-       /*
-        * Create a mask to determine whether we should
-        * insert the character (if any) into our queue.
-        */
-       if (ch->ch_c_iflag & IGNBRK)
-               error_mask |= UART_LSR_BI;
-
-       /*
-        * Now cleanup any leftover bytes still in the UART.
-        * Also deal with any possible queue overflow here as well.
-        */
-       while (1) {
-
-               /*
-                * Its possible we have a linestatus from the loop above
-                * this, so we "OR" on any extra bits.
-                */
-               linestatus |= readb(&ch->ch_neo_uart->lsr);
-
-               /*
-                * If the chip tells us there is no more data pending to
-                * be read, we can then leave.
-                * But before we do, cache the linestatus, just in case.
-                */
-               if (!(linestatus & UART_LSR_DR)) {
-                       ch->ch_cached_lsr = linestatus;
-                       break;
-               }
-
-               /* No need to store this bit */
-               linestatus &= ~UART_LSR_DR;
-
-               /*
-                * Since we are grabbing the linestatus register, which
-                * will reset some bits after our read, we need to ensure
-                * we don't miss our TX FIFO emptys.
-                */
-               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
-                       linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               }
-
-               /*
-                * Discard character if we are ignoring the error mask.
-                */
-               if (linestatus & error_mask) {
-                       u8 discard;
-                       linestatus = 0;
-                       memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
-                       continue;
-               }
-
-               /*
-                * If our queue is full, we have no choice but to drop some data.
-                * The assumption is that HWFLOW or SWFLOW should have stopped
-                * things way way before we got to this point.
-                *
-                * I decided that I wanted to ditch the oldest data first,
-                * I hope thats okay with everyone? Yes? Good.
-                */
-               while (qleft < 1) {
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "Queue full, dropping DATA:%x LSR:%x\n",
-                               ch->ch_rqueue[tail], ch->ch_equeue[tail]);
-
-                       ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
-                       ch->ch_err_overrun++;
-                       qleft++;
-               }
-
-               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
-               ch->ch_equeue[head] = (u8) linestatus;
-
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                               "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
-
-               /* Ditch any remaining linestatus value. */
-               linestatus = 0;
-
-               /* Add to and flip head if needed */
-               head = (head + 1) & RQUEUEMASK;
-
-               qleft--;
-               ch->ch_rxcount++;
-       }
-
-       /*
-        * Write new final heads to channel structure.
-        */
-       ch->ch_r_head = head & RQUEUEMASK;
-       ch->ch_e_head = head & EQUEUEMASK;
-       jsm_input(ch);
-}
-
-static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
-{
-       u16 head;
-       u16 tail;
-       int n;
-       int s;
-       int qlen;
-       u32 len_written = 0;
-
-       if (!ch)
-               return;
-
-       /* No data to write to the UART */
-       if (ch->ch_w_tail == ch->ch_w_head)
-               return;
-
-       /* If port is "stopped", don't send any data to the UART */
-       if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
-               return;
-       /*
-        * If FIFOs are disabled. Send data directly to txrx register
-        */
-       if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
-               u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
-
-               ch->ch_cached_lsr |= lsrbits;
-               if (ch->ch_cached_lsr & UART_LSR_THRE) {
-                       ch->ch_cached_lsr &= ~(UART_LSR_THRE);
-
-                       writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
-                       jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
-                                       "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
-                       ch->ch_w_tail++;
-                       ch->ch_w_tail &= WQUEUEMASK;
-                       ch->ch_txcount++;
-               }
-               return;
-       }
-
-       /*
-        * We have to do it this way, because of the EXAR TXFIFO count bug.
-        */
-       if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
-               return;
-
-       n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
-
-       /* cache head and tail of queue */
-       head = ch->ch_w_head & WQUEUEMASK;
-       tail = ch->ch_w_tail & WQUEUEMASK;
-       qlen = (head - tail) & WQUEUEMASK;
-
-       /* Find minimum of the FIFO space, versus queue length */
-       n = min(n, qlen);
-
-       while (n > 0) {
-
-               s = ((head >= tail) ? head : WQUEUESIZE) - tail;
-               s = min(s, n);
-
-               if (s <= 0)
-                       break;
-
-               memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
-               /* Add and flip queue if needed */
-               tail = (tail + s) & WQUEUEMASK;
-               n -= s;
-               ch->ch_txcount += s;
-               len_written += s;
-       }
-
-       /* Update the final tail */
-       ch->ch_w_tail = tail & WQUEUEMASK;
-
-       if (len_written >= ch->ch_t_tlevel)
-               ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
-       if (!jsm_tty_write(&ch->uart_port))
-               uart_write_wakeup(&ch->uart_port);
-}
-
-static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
-{
-       u8 msignals = signals;
-
-       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
-                       "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
-
-       /* Scrub off lower bits. They signify delta's, which I don't care about */
-       /* Keep DDCD and DDSR though */
-       msignals &= 0xf8;
-
-       if (msignals & UART_MSR_DDCD)
-               uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
-       if (msignals & UART_MSR_DDSR)
-               uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
-       if (msignals & UART_MSR_DCD)
-               ch->ch_mistat |= UART_MSR_DCD;
-       else
-               ch->ch_mistat &= ~UART_MSR_DCD;
-
-       if (msignals & UART_MSR_DSR)
-               ch->ch_mistat |= UART_MSR_DSR;
-       else
-               ch->ch_mistat &= ~UART_MSR_DSR;
-
-       if (msignals & UART_MSR_RI)
-               ch->ch_mistat |= UART_MSR_RI;
-       else
-               ch->ch_mistat &= ~UART_MSR_RI;
-
-       if (msignals & UART_MSR_CTS)
-               ch->ch_mistat |= UART_MSR_CTS;
-       else
-               ch->ch_mistat &= ~UART_MSR_CTS;
-
-       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
-                       "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
-               ch->ch_portnum,
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
-               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
-}
-
-/* Make the UART raise any of the output signals we want up */
-static void neo_assert_modem_signals(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-/*
- * Flush the WRITE FIFO on the Neo.
- *
- * NOTE: Channel lock MUST be held before calling this function!
- */
-static void neo_flush_uart_write(struct jsm_channel *ch)
-{
-       u8 tmp = 0;
-       int i = 0;
-
-       if (!ch)
-               return;
-
-       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
-
-       for (i = 0; i < 10; i++) {
-
-               /* Check to see if the UART feels it completely flushed the FIFO. */
-               tmp = readb(&ch->ch_neo_uart->isr_fcr);
-               if (tmp & 4) {
-                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                                       "Still flushing TX UART... i: %d\n", i);
-                       udelay(10);
-               }
-               else
-                       break;
-       }
-
-       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-}
-
-
-/*
- * Flush the READ FIFO on the Neo.
- *
- * NOTE: Channel lock MUST be held before calling this function!
- */
-static void neo_flush_uart_read(struct jsm_channel *ch)
-{
-       u8 tmp = 0;
-       int i = 0;
-
-       if (!ch)
-               return;
-
-       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
-
-       for (i = 0; i < 10; i++) {
-
-               /* Check to see if the UART feels it completely flushed the FIFO. */
-               tmp = readb(&ch->ch_neo_uart->isr_fcr);
-               if (tmp & 2) {
-                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                                       "Still flushing RX UART... i: %d\n", i);
-                       udelay(10);
-               }
-               else
-                       break;
-       }
-}
-
-/*
- * No locks are assumed to be held when calling this function.
- */
-static void neo_clear_break(struct jsm_channel *ch, int force)
-{
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-
-       /* Turn break off, and unset some variables */
-       if (ch->ch_flags & CH_BREAK_SENDING) {
-               u8 temp = readb(&ch->ch_neo_uart->lcr);
-               writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
-
-               ch->ch_flags &= ~(CH_BREAK_SENDING);
-               jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
-                               "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-}
-
-/*
- * Parse the ISR register.
- */
-static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
-{
-       struct jsm_channel *ch;
-       u8 isr;
-       u8 cause;
-       unsigned long lock_flags;
-
-       if (!brd)
-               return;
-
-       if (port > brd->maxports)
-               return;
-
-       ch = brd->channels[port];
-       if (!ch)
-               return;
-
-       /* Here we try to figure out what caused the interrupt to happen */
-       while (1) {
-
-               isr = readb(&ch->ch_neo_uart->isr_fcr);
-
-               /* Bail if no pending interrupt */
-               if (isr & UART_IIR_NO_INT)
-                       break;
-
-               /*
-                * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
-                */
-               isr &= ~(UART_17158_IIR_FIFO_ENABLED);
-
-               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                               "%s:%d isr: %x\n", __FILE__, __LINE__, isr);
-
-               if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
-                       /* Read data from uart -> queue */
-                       neo_copy_data_from_uart_to_queue(ch);
-
-                       /* Call our tty layer to enforce queue flow control if needed. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       jsm_check_queue_flow_control(ch);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               if (isr & UART_IIR_THRI) {
-                       /* Transfer data (if any) from Write Queue -> UART. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-                       neo_copy_data_from_queue_to_uart(ch);
-               }
-
-               if (isr & UART_17158_IIR_XONXOFF) {
-                       cause = readb(&ch->ch_neo_uart->xoffchar1);
-
-                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                       "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
-
-                       /*
-                        * Since the UART detected either an XON or
-                        * XOFF match, we need to figure out which
-                        * one it was, so we can suspend or resume data flow.
-                        */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       if (cause == UART_17158_XON_DETECT) {
-                               /* Is output stopped right now, if so, resume it */
-                               if (brd->channels[port]->ch_flags & CH_STOP) {
-                                       ch->ch_flags &= ~(CH_STOP);
-                               }
-                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                               "Port %d. XON detected in incoming data\n", port);
-                       }
-                       else if (cause == UART_17158_XOFF_DETECT) {
-                               if (!(brd->channels[port]->ch_flags & CH_STOP)) {
-                                       ch->ch_flags |= CH_STOP;
-                                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                                       "Setting CH_STOP\n");
-                               }
-                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                                               "Port: %d. XOFF detected in incoming data\n", port);
-                       }
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
-                       /*
-                        * If we get here, this means the hardware is doing auto flow control.
-                        * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
-                        */
-                       cause = readb(&ch->ch_neo_uart->mcr);
-
-                       /* Which pin is doing auto flow? RTS or DTR? */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-                       if ((cause & 0x4) == 0) {
-                               if (cause & UART_MCR_RTS)
-                                       ch->ch_mostat |= UART_MCR_RTS;
-                               else
-                                       ch->ch_mostat &= ~(UART_MCR_RTS);
-                       } else {
-                               if (cause & UART_MCR_DTR)
-                                       ch->ch_mostat |= UART_MCR_DTR;
-                               else
-                                       ch->ch_mostat &= ~(UART_MCR_DTR);
-                       }
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               }
-
-               /* Parse any modem signal changes */
-               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                               "MOD_STAT: sending to parse_modem_sigs\n");
-               neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
-       }
-}
-
-static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
-{
-       struct jsm_channel *ch;
-       int linestatus;
-       unsigned long lock_flags;
-
-       if (!brd)
-               return;
-
-       if (port > brd->maxports)
-               return;
-
-       ch = brd->channels[port];
-       if (!ch)
-               return;
-
-       linestatus = readb(&ch->ch_neo_uart->lsr);
-
-       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
-                       "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
-
-       ch->ch_cached_lsr |= linestatus;
-
-       if (ch->ch_cached_lsr & UART_LSR_DR) {
-               /* Read data from uart -> queue */
-               neo_copy_data_from_uart_to_queue(ch);
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               jsm_check_queue_flow_control(ch);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-       }
-
-       /*
-        * This is a special flag. It indicates that at least 1
-        * RX error (parity, framing, or break) has happened.
-        * Mark this in our struct, which will tell me that I have
-        *to do the special RX+LSR read for this FIFO load.
-        */
-       if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d Got an RX error, need to parse LSR\n",
-                       __FILE__, __LINE__, port);
-
-       /*
-        * The next 3 tests should *NOT* happen, as the above test
-        * should encapsulate all 3... At least, thats what Exar says.
-        */
-
-       if (linestatus & UART_LSR_PE) {
-               ch->ch_err_parity++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_FE) {
-               ch->ch_err_frame++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_BI) {
-               ch->ch_err_break++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_OE) {
-               /*
-                * Rx Oruns. Exar says that an orun will NOT corrupt
-                * the FIFO. It will just replace the holding register
-                * with this new data byte. So basically just ignore this.
-                * Probably we should eventually have an orun stat in our driver...
-                */
-               ch->ch_err_overrun++;
-               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
-                       "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
-       }
-
-       if (linestatus & UART_LSR_THRE) {
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               /* Transfer data (if any) from Write Queue -> UART. */
-               neo_copy_data_from_queue_to_uart(ch);
-       }
-       else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
-               spin_lock_irqsave(&ch->ch_lock, lock_flags);
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-               /* Transfer data (if any) from Write Queue -> UART. */
-               neo_copy_data_from_queue_to_uart(ch);
-       }
-}
-
-/*
- * neo_param()
- * Send any/all changes to the line to the UART.
- */
-static void neo_param(struct jsm_channel *ch)
-{
-       u8 lcr = 0;
-       u8 uart_lcr, ier;
-       u32 baud;
-       int quot;
-       struct jsm_board *bd;
-
-       bd = ch->ch_bd;
-       if (!bd)
-               return;
-
-       /*
-        * If baud rate is zero, flush queues, and set mval to drop DTR.
-        */
-       if ((ch->ch_c_cflag & (CBAUD)) == 0) {
-               ch->ch_r_head = ch->ch_r_tail = 0;
-               ch->ch_e_head = ch->ch_e_tail = 0;
-               ch->ch_w_head = ch->ch_w_tail = 0;
-
-               neo_flush_uart_write(ch);
-               neo_flush_uart_read(ch);
-
-               ch->ch_flags |= (CH_BAUD0);
-               ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
-               neo_assert_modem_signals(ch);
-               return;
-
-       } else {
-               int i;
-               unsigned int cflag;
-               static struct {
-                       unsigned int rate;
-                       unsigned int cflag;
-               } baud_rates[] = {
-                       { 921600, B921600 },
-                       { 460800, B460800 },
-                       { 230400, B230400 },
-                       { 115200, B115200 },
-                       {  57600, B57600  },
-                       {  38400, B38400  },
-                       {  19200, B19200  },
-                       {   9600, B9600   },
-                       {   4800, B4800   },
-                       {   2400, B2400   },
-                       {   1200, B1200   },
-                       {    600, B600    },
-                       {    300, B300    },
-                       {    200, B200    },
-                       {    150, B150    },
-                       {    134, B134    },
-                       {    110, B110    },
-                       {     75, B75     },
-                       {     50, B50     },
-               };
-
-               cflag = C_BAUD(ch->uart_port.state->port.tty);
-               baud = 9600;
-               for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
-                       if (baud_rates[i].cflag == cflag) {
-                               baud = baud_rates[i].rate;
-                               break;
-                       }
-               }
-
-               if (ch->ch_flags & CH_BAUD0)
-                       ch->ch_flags &= ~(CH_BAUD0);
-       }
-
-       if (ch->ch_c_cflag & PARENB)
-               lcr |= UART_LCR_PARITY;
-
-       if (!(ch->ch_c_cflag & PARODD))
-               lcr |= UART_LCR_EPAR;
-
-       /*
-        * Not all platforms support mark/space parity,
-        * so this will hide behind an ifdef.
-        */
-#ifdef CMSPAR
-       if (ch->ch_c_cflag & CMSPAR)
-               lcr |= UART_LCR_SPAR;
-#endif
-
-       if (ch->ch_c_cflag & CSTOPB)
-               lcr |= UART_LCR_STOP;
-
-       switch (ch->ch_c_cflag & CSIZE) {
-               case CS5:
-                       lcr |= UART_LCR_WLEN5;
-                       break;
-               case CS6:
-                       lcr |= UART_LCR_WLEN6;
-                       break;
-               case CS7:
-                       lcr |= UART_LCR_WLEN7;
-                       break;
-               case CS8:
-               default:
-                       lcr |= UART_LCR_WLEN8;
-               break;
-       }
-
-       ier = readb(&ch->ch_neo_uart->ier);
-       uart_lcr = readb(&ch->ch_neo_uart->lcr);
-
-       if (baud == 0)
-               baud = 9600;
-
-       quot = ch->ch_bd->bd_dividend / baud;
-
-       if (quot != 0) {
-               writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
-               writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
-               writeb((quot >> 8), &ch->ch_neo_uart->ier);
-               writeb(lcr, &ch->ch_neo_uart->lcr);
-       }
-
-       if (uart_lcr != lcr)
-               writeb(lcr, &ch->ch_neo_uart->lcr);
-
-       if (ch->ch_c_cflag & CREAD)
-               ier |= (UART_IER_RDI | UART_IER_RLSI);
-
-       ier |= (UART_IER_THRI | UART_IER_MSI);
-
-       writeb(ier, &ch->ch_neo_uart->ier);
-
-       /* Set new start/stop chars */
-       neo_set_new_start_stop_chars(ch);
-
-       if (ch->ch_c_cflag & CRTSCTS)
-               neo_set_cts_flow_control(ch);
-       else if (ch->ch_c_iflag & IXON) {
-               /* If start/stop is set to disable, then we should disable flow control */
-               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
-                       neo_set_no_output_flow_control(ch);
-               else
-                       neo_set_ixon_flow_control(ch);
-       }
-       else
-               neo_set_no_output_flow_control(ch);
-
-       if (ch->ch_c_cflag & CRTSCTS)
-               neo_set_rts_flow_control(ch);
-       else if (ch->ch_c_iflag & IXOFF) {
-               /* If start/stop is set to disable, then we should disable flow control */
-               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
-                       neo_set_no_input_flow_control(ch);
-               else
-                       neo_set_ixoff_flow_control(ch);
-       }
-       else
-               neo_set_no_input_flow_control(ch);
-       /*
-        * Adjust the RX FIFO Trigger level if baud is less than 9600.
-        * Not exactly elegant, but this is needed because of the Exar chip's
-        * delay on firing off the RX FIFO interrupt on slower baud rates.
-        */
-       if (baud < 9600) {
-               writeb(1, &ch->ch_neo_uart->rfifo);
-               ch->ch_r_tlevel = 1;
-       }
-
-       neo_assert_modem_signals(ch);
-
-       /* Get current status of the modem signals now */
-       neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
-       return;
-}
-
-/*
- * jsm_neo_intr()
- *
- * Neo specific interrupt handler.
- */
-static irqreturn_t neo_intr(int irq, void *voidbrd)
-{
-       struct jsm_board *brd = voidbrd;
-       struct jsm_channel *ch;
-       int port = 0;
-       int type = 0;
-       int current_port;
-       u32 tmp;
-       u32 uart_poll;
-       unsigned long lock_flags;
-       unsigned long lock_flags2;
-       int outofloop_count = 0;
-
-       /* Lock out the slow poller from running on this board. */
-       spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
-
-       /*
-        * Read in "extended" IRQ information from the 32bit Neo register.
-        * Bits 0-7: What port triggered the interrupt.
-        * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
-        */
-       uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
-
-       jsm_printk(INTR, INFO, &brd->pci_dev,
-               "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
-
-       if (!uart_poll) {
-               jsm_printk(INTR, INFO, &brd->pci_dev,
-                       "Kernel interrupted to me, but no pending interrupts...\n");
-               spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
-               return IRQ_NONE;
-       }
-
-       /* At this point, we have at least SOMETHING to service, dig further... */
-
-       current_port = 0;
-
-       /* Loop on each port */
-       while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
-
-               tmp = uart_poll;
-               outofloop_count++;
-
-               /* Check current port to see if it has interrupt pending */
-               if ((tmp & jsm_offset_table[current_port]) != 0) {
-                       port = current_port;
-                       type = tmp >> (8 + (port * 3));
-                       type &= 0x7;
-               } else {
-                       current_port++;
-                       continue;
-               }
-
-               jsm_printk(INTR, INFO, &brd->pci_dev,
-               "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
-
-               /* Remove this port + type from uart_poll */
-               uart_poll &= ~(jsm_offset_table[port]);
-
-               if (!type) {
-                       /* If no type, just ignore it, and move onto next port */
-                       jsm_printk(INTR, ERR, &brd->pci_dev,
-                               "Interrupt with no type! port: %d\n", port);
-                       continue;
-               }
-
-               /* Switch on type of interrupt we have */
-               switch (type) {
-
-               case UART_17158_RXRDY_TIMEOUT:
-                       /*
-                        * RXRDY Time-out is cleared by reading data in the
-                       * RX FIFO until it falls below the trigger level.
-                        */
-
-                       /* Verify the port is in range. */
-                       if (port > brd->nasync)
-                               continue;
-
-                       ch = brd->channels[port];
-                       neo_copy_data_from_uart_to_queue(ch);
-
-                       /* Call our tty layer to enforce queue flow control if needed. */
-                       spin_lock_irqsave(&ch->ch_lock, lock_flags2);
-                       jsm_check_queue_flow_control(ch);
-                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
-
-                       continue;
-
-               case UART_17158_RX_LINE_STATUS:
-                       /*
-                        * RXRDY and RX LINE Status (logic OR of LSR[4:1])
-                        */
-                       neo_parse_lsr(brd, port);
-                       continue;
-
-               case UART_17158_TXRDY:
-                       /*
-                        * TXRDY interrupt clears after reading ISR register for the UART channel.
-                        */
-
-                       /*
-                        * Yes, this is odd...
-                        * Why would I check EVERY possibility of type of
-                        * interrupt, when we know its TXRDY???
-                        * Becuz for some reason, even tho we got triggered for TXRDY,
-                        * it seems to be occassionally wrong. Instead of TX, which
-                        * it should be, I was getting things like RXDY too. Weird.
-                        */
-                       neo_parse_isr(brd, port);
-                       continue;
-
-               case UART_17158_MSR:
-                       /*
-                        * MSR or flow control was seen.
-                        */
-                       neo_parse_isr(brd, port);
-                       continue;
-
-               default:
-                       /*
-                        * The UART triggered us with a bogus interrupt type.
-                        * It appears the Exar chip, when REALLY bogged down, will throw
-                        * these once and awhile.
-                        * Its harmless, just ignore it and move on.
-                        */
-                       jsm_printk(INTR, ERR, &brd->pci_dev,
-                               "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
-                       continue;
-               }
-       }
-
-       spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
-
-       jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
-       return IRQ_HANDLED;
-}
-
-/*
- * Neo specific way of turning off the receiver.
- * Used as a way to enforce queue flow control when in
- * hardware flow control mode.
- */
-static void neo_disable_receiver(struct jsm_channel *ch)
-{
-       u8 tmp = readb(&ch->ch_neo_uart->ier);
-       tmp &= ~(UART_IER_RDI);
-       writeb(tmp, &ch->ch_neo_uart->ier);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-
-/*
- * Neo specific way of turning on the receiver.
- * Used as a way to un-enforce queue flow control when in
- * hardware flow control mode.
- */
-static void neo_enable_receiver(struct jsm_channel *ch)
-{
-       u8 tmp = readb(&ch->ch_neo_uart->ier);
-       tmp |= (UART_IER_RDI);
-       writeb(tmp, &ch->ch_neo_uart->ier);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-static void neo_send_start_character(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       if (ch->ch_startc != __DISABLED_CHAR) {
-               ch->ch_xon_sends++;
-               writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-static void neo_send_stop_character(struct jsm_channel *ch)
-{
-       if (!ch)
-               return;
-
-       if (ch->ch_stopc != __DISABLED_CHAR) {
-               ch->ch_xoff_sends++;
-               writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-/*
- * neo_uart_init
- */
-static void neo_uart_init(struct jsm_channel *ch)
-{
-       writeb(0, &ch->ch_neo_uart->ier);
-       writeb(0, &ch->ch_neo_uart->efr);
-       writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
-
-       /* Clear out UART and FIFO */
-       readb(&ch->ch_neo_uart->txrx);
-       writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
-       readb(&ch->ch_neo_uart->lsr);
-       readb(&ch->ch_neo_uart->msr);
-
-       ch->ch_flags |= CH_FIFO_ENABLED;
-
-       /* Assert any signals we want up */
-       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
-}
-
-/*
- * Make the UART completely turn off.
- */
-static void neo_uart_off(struct jsm_channel *ch)
-{
-       /* Turn off UART enhanced bits */
-       writeb(0, &ch->ch_neo_uart->efr);
-
-       /* Stop all interrupts from occurring. */
-       writeb(0, &ch->ch_neo_uart->ier);
-}
-
-static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
-{
-       u8 left = 0;
-       u8 lsr = readb(&ch->ch_neo_uart->lsr);
-
-       /* We must cache the LSR as some of the bits get reset once read... */
-       ch->ch_cached_lsr |= lsr;
-
-       /* Determine whether the Transmitter is empty or not */
-       if (!(lsr & UART_LSR_TEMT))
-               left = 1;
-       else {
-               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-               left = 0;
-       }
-
-       return left;
-}
-
-/* Channel lock MUST be held by the calling function! */
-static void neo_send_break(struct jsm_channel *ch)
-{
-       /*
-        * Set the time we should stop sending the break.
-        * If we are already sending a break, toss away the existing
-        * time to stop, and use this new value instead.
-        */
-
-       /* Tell the UART to start sending the break */
-       if (!(ch->ch_flags & CH_BREAK_SENDING)) {
-               u8 temp = readb(&ch->ch_neo_uart->lcr);
-               writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
-               ch->ch_flags |= (CH_BREAK_SENDING);
-
-               /* flush write operation */
-               neo_pci_posting_flush(ch->ch_bd);
-       }
-}
-
-/*
- * neo_send_immediate_char.
- *
- * Sends a specific character as soon as possible to the UART,
- * jumping over any bytes that might be in the write queue.
- *
- * The channel lock MUST be held by the calling function.
- */
-static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
-{
-       if (!ch)
-               return;
-
-       writeb(c, &ch->ch_neo_uart->txrx);
-
-       /* flush write operation */
-       neo_pci_posting_flush(ch->ch_bd);
-}
-
-struct board_ops jsm_neo_ops = {
-       .intr                           = neo_intr,
-       .uart_init                      = neo_uart_init,
-       .uart_off                       = neo_uart_off,
-       .param                          = neo_param,
-       .assert_modem_signals           = neo_assert_modem_signals,
-       .flush_uart_write               = neo_flush_uart_write,
-       .flush_uart_read                = neo_flush_uart_read,
-       .disable_receiver               = neo_disable_receiver,
-       .enable_receiver                = neo_enable_receiver,
-       .send_break                     = neo_send_break,
-       .clear_break                    = neo_clear_break,
-       .send_start_character           = neo_send_start_character,
-       .send_stop_character            = neo_send_stop_character,
-       .copy_data_from_queue_to_uart   = neo_copy_data_from_queue_to_uart,
-       .get_uart_bytes_left            = neo_get_uart_bytes_left,
-       .send_immediate_char            = neo_send_immediate_char
-};
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
deleted file mode 100644 (file)
index 7a4a914..0000000
+++ /dev/null
@@ -1,910 +0,0 @@
-/************************************************************************
- * Copyright 2003 Digi International (www.digi.com)
- *
- * Copyright (C) 2004 IBM Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
- * MA  02111-1307, USA.
- *
- * Contact Information:
- * Scott H Kilau <Scott_Kilau@digi.com>
- * Ananda Venkatarman <mansarov@us.ibm.com>
- * Modifications:
- * 01/19/06:   changed jsm_input routine to use the dynamically allocated
- *             tty_buffer changes. Contributors: Scott Kilau and Ananda V.
- ***********************************************************************/
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h>       /* For udelay */
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "jsm.h"
-
-static DECLARE_BITMAP(linemap, MAXLINES);
-
-static void jsm_carrier(struct jsm_channel *ch);
-
-static inline int jsm_get_mstat(struct jsm_channel *ch)
-{
-       unsigned char mstat;
-       unsigned result;
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       mstat = (ch->ch_mostat | ch->ch_mistat);
-
-       result = 0;
-
-       if (mstat & UART_MCR_DTR)
-               result |= TIOCM_DTR;
-       if (mstat & UART_MCR_RTS)
-               result |= TIOCM_RTS;
-       if (mstat & UART_MSR_CTS)
-               result |= TIOCM_CTS;
-       if (mstat & UART_MSR_DSR)
-               result |= TIOCM_DSR;
-       if (mstat & UART_MSR_RI)
-               result |= TIOCM_RI;
-       if (mstat & UART_MSR_DCD)
-               result |= TIOCM_CD;
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
-       return result;
-}
-
-static unsigned int jsm_tty_tx_empty(struct uart_port *port)
-{
-       return TIOCSER_TEMT;
-}
-
-/*
- * Return modem signals to ld.
- */
-static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
-{
-       int result;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       result = jsm_get_mstat(channel);
-
-       if (result < 0)
-               return -ENXIO;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-
-       return result;
-}
-
-/*
- * jsm_set_modem_info()
- *
- * Set modem signals, called by ld.
- */
-static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       if (mctrl & TIOCM_RTS)
-               channel->ch_mostat |= UART_MCR_RTS;
-       else
-               channel->ch_mostat &= ~UART_MCR_RTS;
-
-       if (mctrl & TIOCM_DTR)
-               channel->ch_mostat |= UART_MCR_DTR;
-       else
-               channel->ch_mostat &= ~UART_MCR_DTR;
-
-       channel->ch_bd->bd_ops->assert_modem_signals(channel);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-       udelay(10);
-}
-
-static void jsm_tty_start_tx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       channel->ch_flags &= ~(CH_STOP);
-       jsm_tty_write(port);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_stop_tx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       channel->ch_flags |= (CH_STOP);
-
-       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-       struct ktermios *termios;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       termios = port->state->port.tty->termios;
-       if (ch == termios->c_cc[VSTART])
-               channel->ch_bd->bd_ops->send_start_character(channel);
-
-       if (ch == termios->c_cc[VSTOP])
-               channel->ch_bd->bd_ops->send_stop_character(channel);
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static void jsm_tty_stop_rx(struct uart_port *port)
-{
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       channel->ch_bd->bd_ops->disable_receiver(channel);
-}
-
-static void jsm_tty_enable_ms(struct uart_port *port)
-{
-       /* Nothing needed */
-}
-
-static void jsm_tty_break(struct uart_port *port, int break_state)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       if (break_state == -1)
-               channel->ch_bd->bd_ops->send_break(channel);
-       else
-               channel->ch_bd->bd_ops->clear_break(channel, 0);
-
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static int jsm_tty_open(struct uart_port *port)
-{
-       struct jsm_board *brd;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-       struct ktermios *termios;
-
-       /* Get board pointer from our array of majors we have allocated */
-       brd = channel->ch_bd;
-
-       /*
-        * Allocate channel buffers for read/write/error.
-        * Set flag, so we don't get trounced on.
-        */
-       channel->ch_flags |= (CH_OPENING);
-
-       /* Drop locks, as malloc with GFP_KERNEL can sleep */
-
-       if (!channel->ch_rqueue) {
-               channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_rqueue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate read queue buf");
-                       return -ENOMEM;
-               }
-       }
-       if (!channel->ch_equeue) {
-               channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_equeue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate error queue buf");
-                       return -ENOMEM;
-               }
-       }
-       if (!channel->ch_wqueue) {
-               channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_wqueue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate write queue buf");
-                       return -ENOMEM;
-               }
-       }
-
-       channel->ch_flags &= ~(CH_OPENING);
-       /*
-        * Initialize if neither terminal is open.
-        */
-       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
-               "jsm_open: initializing channel in open...\n");
-
-       /*
-        * Flush input queues.
-        */
-       channel->ch_r_head = channel->ch_r_tail = 0;
-       channel->ch_e_head = channel->ch_e_tail = 0;
-       channel->ch_w_head = channel->ch_w_tail = 0;
-
-       brd->bd_ops->flush_uart_write(channel);
-       brd->bd_ops->flush_uart_read(channel);
-
-       channel->ch_flags = 0;
-       channel->ch_cached_lsr = 0;
-       channel->ch_stops_sent = 0;
-
-       termios = port->state->port.tty->termios;
-       channel->ch_c_cflag     = termios->c_cflag;
-       channel->ch_c_iflag     = termios->c_iflag;
-       channel->ch_c_oflag     = termios->c_oflag;
-       channel->ch_c_lflag     = termios->c_lflag;
-       channel->ch_startc      = termios->c_cc[VSTART];
-       channel->ch_stopc       = termios->c_cc[VSTOP];
-
-       /* Tell UART to init itself */
-       brd->bd_ops->uart_init(channel);
-
-       /*
-        * Run param in case we changed anything
-        */
-       brd->bd_ops->param(channel);
-
-       jsm_carrier(channel);
-
-       channel->ch_open_count++;
-
-       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
-       return 0;
-}
-
-static void jsm_tty_close(struct uart_port *port)
-{
-       struct jsm_board *bd;
-       struct ktermios *ts;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
-
-       bd = channel->ch_bd;
-       ts = port->state->port.tty->termios;
-
-       channel->ch_flags &= ~(CH_STOPI);
-
-       channel->ch_open_count--;
-
-       /*
-        * If we have HUPCL set, lower DTR and RTS
-        */
-       if (channel->ch_c_cflag & HUPCL) {
-               jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
-                       "Close. HUPCL set, dropping DTR/RTS\n");
-
-               /* Drop RTS/DTR */
-               channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
-               bd->bd_ops->assert_modem_signals(channel);
-       }
-
-       /* Turn off UART interrupts for this port */
-       channel->ch_bd->bd_ops->uart_off(channel);
-
-       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_tty_set_termios(struct uart_port *port,
-                                struct ktermios *termios,
-                                struct ktermios *old_termios)
-{
-       unsigned long lock_flags;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       spin_lock_irqsave(&port->lock, lock_flags);
-       channel->ch_c_cflag     = termios->c_cflag;
-       channel->ch_c_iflag     = termios->c_iflag;
-       channel->ch_c_oflag     = termios->c_oflag;
-       channel->ch_c_lflag     = termios->c_lflag;
-       channel->ch_startc      = termios->c_cc[VSTART];
-       channel->ch_stopc       = termios->c_cc[VSTOP];
-
-       channel->ch_bd->bd_ops->param(channel);
-       jsm_carrier(channel);
-       spin_unlock_irqrestore(&port->lock, lock_flags);
-}
-
-static const char *jsm_tty_type(struct uart_port *port)
-{
-       return "jsm";
-}
-
-static void jsm_tty_release_port(struct uart_port *port)
-{
-}
-
-static int jsm_tty_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void jsm_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_JSM;
-}
-
-static struct uart_ops jsm_ops = {
-       .tx_empty       = jsm_tty_tx_empty,
-       .set_mctrl      = jsm_tty_set_mctrl,
-       .get_mctrl      = jsm_tty_get_mctrl,
-       .stop_tx        = jsm_tty_stop_tx,
-       .start_tx       = jsm_tty_start_tx,
-       .send_xchar     = jsm_tty_send_xchar,
-       .stop_rx        = jsm_tty_stop_rx,
-       .enable_ms      = jsm_tty_enable_ms,
-       .break_ctl      = jsm_tty_break,
-       .startup        = jsm_tty_open,
-       .shutdown       = jsm_tty_close,
-       .set_termios    = jsm_tty_set_termios,
-       .type           = jsm_tty_type,
-       .release_port   = jsm_tty_release_port,
-       .request_port   = jsm_tty_request_port,
-       .config_port    = jsm_config_port,
-};
-
-/*
- * jsm_tty_init()
- *
- * Init the tty subsystem.  Called once per board after board has been
- * downloaded and init'ed.
- */
-int __devinit jsm_tty_init(struct jsm_board *brd)
-{
-       int i;
-       void __iomem *vaddr;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /*
-        * Allocate channel memory that might not have been allocated
-        * when the driver was first loaded.
-        */
-       for (i = 0; i < brd->nasync; i++) {
-               if (!brd->channels[i]) {
-
-                       /*
-                        * Okay to malloc with GFP_KERNEL, we are not at
-                        * interrupt context, and there are no locks held.
-                        */
-                       brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
-                       if (!brd->channels[i]) {
-                               jsm_printk(CORE, ERR, &brd->pci_dev,
-                                       "%s:%d Unable to allocate memory for channel struct\n",
-                                                        __FILE__, __LINE__);
-                       }
-               }
-       }
-
-       ch = brd->channels[0];
-       vaddr = brd->re_map_membase;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               spin_lock_init(&ch->ch_lock);
-
-               if (brd->bd_uart_offset == 0x200)
-                       ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
-
-               ch->ch_bd = brd;
-               ch->ch_portnum = i;
-
-               /* .25 second delay */
-               ch->ch_close_delay = 250;
-
-               init_waitqueue_head(&ch->ch_flags_wait);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-int jsm_uart_port_init(struct jsm_board *brd)
-{
-       int i, rc;
-       unsigned int line;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               brd->channels[i]->uart_port.irq = brd->irq;
-               brd->channels[i]->uart_port.uartclk = 14745600;
-               brd->channels[i]->uart_port.type = PORT_JSM;
-               brd->channels[i]->uart_port.iotype = UPIO_MEM;
-               brd->channels[i]->uart_port.membase = brd->re_map_membase;
-               brd->channels[i]->uart_port.fifosize = 16;
-               brd->channels[i]->uart_port.ops = &jsm_ops;
-               line = find_first_zero_bit(linemap, MAXLINES);
-               if (line >= MAXLINES) {
-                       printk(KERN_INFO "jsm: linemap is full, added device failed\n");
-                       continue;
-               } else
-                       set_bit(line, linemap);
-               brd->channels[i]->uart_port.line = line;
-               rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port);
-               if (rc){
-                       printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
-                       return rc;
-               }
-               else
-                       printk(KERN_INFO "jsm: Port %d added\n", i);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-int jsm_remove_uart_port(struct jsm_board *brd)
-{
-       int i;
-       struct jsm_channel *ch;
-
-       if (!brd)
-               return -ENXIO;
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
-
-       /*
-        * Initialize board structure elements.
-        */
-
-       brd->nasync = brd->maxports;
-
-       /* Set up channel variables */
-       for (i = 0; i < brd->nasync; i++) {
-
-               if (!brd->channels[i])
-                       continue;
-
-               ch = brd->channels[i];
-
-               clear_bit(ch->uart_port.line, linemap);
-               uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
-       }
-
-       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
-       return 0;
-}
-
-void jsm_input(struct jsm_channel *ch)
-{
-       struct jsm_board *bd;
-       struct tty_struct *tp;
-       u32 rmask;
-       u16 head;
-       u16 tail;
-       int data_len;
-       unsigned long lock_flags;
-       int len = 0;
-       int n = 0;
-       int s = 0;
-       int i = 0;
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       if (!ch)
-               return;
-
-       tp = ch->uart_port.state->port.tty;
-
-       bd = ch->ch_bd;
-       if(!bd)
-               return;
-
-       spin_lock_irqsave(&ch->ch_lock, lock_flags);
-
-       /*
-        *Figure the number of characters in the buffer.
-        *Exit immediately if none.
-        */
-
-       rmask = RQUEUEMASK;
-
-       head = ch->ch_r_head & rmask;
-       tail = ch->ch_r_tail & rmask;
-
-       data_len = (head - tail) & rmask;
-       if (data_len == 0) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               return;
-       }
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
-
-       /*
-        *If the device is not open, or CREAD is off, flush
-        *input data and return immediately.
-        */
-       if (!tp ||
-               !(tp->termios->c_cflag & CREAD) ) {
-
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                       "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
-               ch->ch_r_head = tail;
-
-               /* Force queue flow control to be released, if needed */
-               jsm_check_queue_flow_control(ch);
-
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               return;
-       }
-
-       /*
-        * If we are throttled, simply don't read any data.
-        */
-       if (ch->ch_flags & CH_STOPI) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                       "Port %d throttled, not reading any data. head: %x tail: %x\n",
-                       ch->ch_portnum, head, tail);
-               return;
-       }
-
-       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
-
-       if (data_len <= 0) {
-               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
-               return;
-       }
-
-       len = tty_buffer_request_room(tp, data_len);
-       n = len;
-
-       /*
-        * n now contains the most amount of data we can copy,
-        * bounded either by the flip buffer size or the amount
-        * of data the card actually has pending...
-        */
-       while (n) {
-               s = ((head >= tail) ? head : RQUEUESIZE) - tail;
-               s = min(s, n);
-
-               if (s <= 0)
-                       break;
-
-                       /*
-                        * If conditions are such that ld needs to see all
-                        * UART errors, we will have to walk each character
-                        * and error byte and send them to the buffer one at
-                        * a time.
-                        */
-
-               if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
-                       for (i = 0; i < s; i++) {
-                               /*
-                                * Give the Linux ld the flags in the
-                                * format it likes.
-                                */
-                               if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
-                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
-                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
-                               else
-                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
-                       }
-               } else {
-                       tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
-               }
-               tail += s;
-               n -= s;
-               /* Flip queue if needed */
-               tail &= rmask;
-       }
-
-       ch->ch_r_tail = tail & rmask;
-       ch->ch_e_tail = tail & rmask;
-       jsm_check_queue_flow_control(ch);
-       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
-       /* Tell the tty layer its okay to "eat" the data now */
-       tty_flip_buffer_push(tp);
-
-       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
-}
-
-static void jsm_carrier(struct jsm_channel *ch)
-{
-       struct jsm_board *bd;
-
-       int virt_carrier = 0;
-       int phys_carrier = 0;
-
-       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
-       if (!ch)
-               return;
-
-       bd = ch->ch_bd;
-
-       if (!bd)
-               return;
-
-       if (ch->ch_mistat & UART_MSR_DCD) {
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
-               phys_carrier = 1;
-       }
-
-       if (ch->ch_c_cflag & CLOCAL)
-               virt_carrier = 1;
-
-       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-               "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
-
-       /*
-        * Test for a VIRTUAL carrier transition to HIGH.
-        */
-       if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
-
-               /*
-                * When carrier rises, wake any threads waiting
-                * for carrier in the open routine.
-                */
-
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "carrier: virt DCD rose\n");
-
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        * Test for a PHYSICAL carrier transition to HIGH.
-        */
-       if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
-
-               /*
-                * When carrier rises, wake any threads waiting
-                * for carrier in the open routine.
-                */
-
-               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
-                       "carrier: physical DCD rose\n");
-
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        *  Test for a PHYSICAL transition to low, so long as we aren't
-        *  currently ignoring physical transitions (which is what "virtual
-        *  carrier" indicates).
-        *
-        *  The transition of the virtual carrier to low really doesn't
-        *  matter... it really only means "ignore carrier state", not
-        *  "make pretend that carrier is there".
-        */
-       if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
-                       && (phys_carrier == 0)) {
-               /*
-                *      When carrier drops:
-                *
-                *      Drop carrier on all open units.
-                *
-                *      Flush queues, waking up any task waiting in the
-                *      line discipline.
-                *
-                *      Send a hangup to the control terminal.
-                *
-                *      Enable all select calls.
-                */
-               if (waitqueue_active(&(ch->ch_flags_wait)))
-                       wake_up_interruptible(&ch->ch_flags_wait);
-       }
-
-       /*
-        *  Make sure that our cached values reflect the current reality.
-        */
-       if (virt_carrier == 1)
-               ch->ch_flags |= CH_FCAR;
-       else
-               ch->ch_flags &= ~CH_FCAR;
-
-       if (phys_carrier == 1)
-               ch->ch_flags |= CH_CD;
-       else
-               ch->ch_flags &= ~CH_CD;
-}
-
-
-void jsm_check_queue_flow_control(struct jsm_channel *ch)
-{
-       struct board_ops *bd_ops = ch->ch_bd->bd_ops;
-       int qleft;
-
-       /* Store how much space we have left in the queue */
-       if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
-               qleft += RQUEUEMASK + 1;
-
-       /*
-        * Check to see if we should enforce flow control on our queue because
-        * the ld (or user) isn't reading data out of our queue fast enuf.
-        *
-        * NOTE: This is done based on what the current flow control of the
-        * port is set for.
-        *
-        * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
-        *      This will cause the UART's FIFO to back up, and force
-        *      the RTS signal to be dropped.
-        * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
-        *      the other side, in hopes it will stop sending data to us.
-        * 3) NONE - Nothing we can do.  We will simply drop any extra data
-        *      that gets sent into us when the queue fills up.
-        */
-       if (qleft < 256) {
-               /* HWFLOW */
-               if (ch->ch_c_cflag & CRTSCTS) {
-                       if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
-                               bd_ops->disable_receiver(ch);
-                               ch->ch_flags |= (CH_RECEIVER_OFF);
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
-                                       qleft);
-                       }
-               }
-               /* SWFLOW */
-               else if (ch->ch_c_iflag & IXOFF) {
-                       if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
-                               bd_ops->send_stop_character(ch);
-                               ch->ch_stops_sent++;
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
-                       }
-               }
-       }
-
-       /*
-        * Check to see if we should unenforce flow control because
-        * ld (or user) finally read enuf data out of our queue.
-        *
-        * NOTE: This is done based on what the current flow control of the
-        * port is set for.
-        *
-        * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
-        *      This will cause the UART's FIFO to raise RTS back up,
-        *      which will allow the other side to start sending data again.
-        * 2) SWFLOW (IXOFF) - Send a start character to
-        *      the other side, so it will start sending data to us again.
-        * 3) NONE - Do nothing. Since we didn't do anything to turn off the
-        *      other side, we don't need to do anything now.
-        */
-       if (qleft > (RQUEUESIZE / 2)) {
-               /* HWFLOW */
-               if (ch->ch_c_cflag & CRTSCTS) {
-                       if (ch->ch_flags & CH_RECEIVER_OFF) {
-                               bd_ops->enable_receiver(ch);
-                               ch->ch_flags &= ~(CH_RECEIVER_OFF);
-                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
-                                       "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
-                                       qleft);
-                       }
-               }
-               /* SWFLOW */
-               else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
-                       ch->ch_stops_sent = 0;
-                       bd_ops->send_start_character(ch);
-                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
-               }
-       }
-}
-
-/*
- * jsm_tty_write()
- *
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-int jsm_tty_write(struct uart_port *port)
-{
-       int bufcount;
-       int data_count = 0,data_count1 =0;
-       u16 head;
-       u16 tail;
-       u16 tmask;
-       u32 remain;
-       int temp_tail = port->state->xmit.tail;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       tmask = WQUEUEMASK;
-       head = (channel->ch_w_head) & tmask;
-       tail = (channel->ch_w_tail) & tmask;
-
-       if ((bufcount = tail - head - 1) < 0)
-               bufcount += WQUEUESIZE;
-
-       bufcount = min(bufcount, 56);
-       remain = WQUEUESIZE - head;
-
-       data_count = 0;
-       if (bufcount >= remain) {
-               bufcount -= remain;
-               while ((port->state->xmit.head != temp_tail) &&
-               (data_count < remain)) {
-                       channel->ch_wqueue[head++] =
-                       port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count++;
-               }
-               if (data_count == remain) head = 0;
-       }
-
-       data_count1 = 0;
-       if (bufcount > 0) {
-               remain = bufcount;
-               while ((port->state->xmit.head != temp_tail) &&
-                       (data_count1 < remain)) {
-                       channel->ch_wqueue[head++] =
-                               port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count1++;
-
-               }
-       }
-
-       port->state->xmit.tail = temp_tail;
-
-       data_count += data_count1;
-       if (data_count) {
-               head &= tmask;
-               channel->ch_w_head = head;
-       }
-
-       if (data_count) {
-               channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
-       }
-
-       return data_count;
-}
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
deleted file mode 100644 (file)
index 25a8bc5..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Based on the same principle as kgdboe using the NETPOLL api, this
- * driver uses a console polling api to implement a gdb serial inteface
- * which is multiplexed on a console port.
- *
- * Maintainer: Jason Wessel <jason.wessel@windriver.com>
- *
- * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/kgdb.h>
-#include <linux/kdb.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-
-#define MAX_CONFIG_LEN         40
-
-static struct kgdb_io          kgdboc_io_ops;
-
-/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
-static int configured          = -1;
-
-static char config[MAX_CONFIG_LEN];
-static struct kparam_string kps = {
-       .string                 = config,
-       .maxlen                 = MAX_CONFIG_LEN,
-};
-
-static int kgdboc_use_kms;  /* 1 if we use kernel mode switching */
-static struct tty_driver       *kgdb_tty_driver;
-static int                     kgdb_tty_line;
-
-#ifdef CONFIG_KDB_KEYBOARD
-static int kgdboc_reset_connect(struct input_handler *handler,
-                               struct input_dev *dev,
-                               const struct input_device_id *id)
-{
-       input_reset_device(dev);
-
-       /* Retrun an error - we do not want to bind, just to reset */
-       return -ENODEV;
-}
-
-static void kgdboc_reset_disconnect(struct input_handle *handle)
-{
-       /* We do not expect anyone to actually bind to us */
-       BUG();
-}
-
-static const struct input_device_id kgdboc_reset_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-       },
-       { }
-};
-
-static struct input_handler kgdboc_reset_handler = {
-       .connect        = kgdboc_reset_connect,
-       .disconnect     = kgdboc_reset_disconnect,
-       .name           = "kgdboc_reset",
-       .id_table       = kgdboc_reset_ids,
-};
-
-static DEFINE_MUTEX(kgdboc_reset_mutex);
-
-static void kgdboc_restore_input_helper(struct work_struct *dummy)
-{
-       /*
-        * We need to take a mutex to prevent several instances of
-        * this work running on different CPUs so they don't try
-        * to register again already registered handler.
-        */
-       mutex_lock(&kgdboc_reset_mutex);
-
-       if (input_register_handler(&kgdboc_reset_handler) == 0)
-               input_unregister_handler(&kgdboc_reset_handler);
-
-       mutex_unlock(&kgdboc_reset_mutex);
-}
-
-static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
-
-static void kgdboc_restore_input(void)
-{
-       if (likely(system_state == SYSTEM_RUNNING))
-               schedule_work(&kgdboc_restore_input_work);
-}
-
-static int kgdboc_register_kbd(char **cptr)
-{
-       if (strncmp(*cptr, "kbd", 3) == 0) {
-               if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
-                       kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
-                       kdb_poll_idx++;
-                       if (cptr[0][3] == ',')
-                               *cptr += 4;
-                       else
-                               return 1;
-               }
-       }
-       return 0;
-}
-
-static void kgdboc_unregister_kbd(void)
-{
-       int i;
-
-       for (i = 0; i < kdb_poll_idx; i++) {
-               if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
-                       kdb_poll_idx--;
-                       kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
-                       kdb_poll_funcs[kdb_poll_idx] = NULL;
-                       i--;
-               }
-       }
-       flush_work_sync(&kgdboc_restore_input_work);
-}
-#else /* ! CONFIG_KDB_KEYBOARD */
-#define kgdboc_register_kbd(x) 0
-#define kgdboc_unregister_kbd()
-#define kgdboc_restore_input()
-#endif /* ! CONFIG_KDB_KEYBOARD */
-
-static int kgdboc_option_setup(char *opt)
-{
-       if (strlen(opt) > MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
-               return -ENOSPC;
-       }
-       strcpy(config, opt);
-
-       return 0;
-}
-
-__setup("kgdboc=", kgdboc_option_setup);
-
-static void cleanup_kgdboc(void)
-{
-       kgdboc_unregister_kbd();
-       if (configured == 1)
-               kgdb_unregister_io_module(&kgdboc_io_ops);
-}
-
-static int configure_kgdboc(void)
-{
-       struct tty_driver *p;
-       int tty_line = 0;
-       int err;
-       char *cptr = config;
-       struct console *cons;
-
-       err = kgdboc_option_setup(config);
-       if (err || !strlen(config) || isspace(config[0]))
-               goto noconfig;
-
-       err = -ENODEV;
-       kgdboc_io_ops.is_console = 0;
-       kgdb_tty_driver = NULL;
-
-       kgdboc_use_kms = 0;
-       if (strncmp(cptr, "kms,", 4) == 0) {
-               cptr += 4;
-               kgdboc_use_kms = 1;
-       }
-
-       if (kgdboc_register_kbd(&cptr))
-               goto do_register;
-
-       p = tty_find_polling_driver(cptr, &tty_line);
-       if (!p)
-               goto noconfig;
-
-       cons = console_drivers;
-       while (cons) {
-               int idx;
-               if (cons->device && cons->device(cons, &idx) == p &&
-                   idx == tty_line) {
-                       kgdboc_io_ops.is_console = 1;
-                       break;
-               }
-               cons = cons->next;
-       }
-
-       kgdb_tty_driver = p;
-       kgdb_tty_line = tty_line;
-
-do_register:
-       err = kgdb_register_io_module(&kgdboc_io_ops);
-       if (err)
-               goto noconfig;
-
-       configured = 1;
-
-       return 0;
-
-noconfig:
-       config[0] = 0;
-       configured = 0;
-       cleanup_kgdboc();
-
-       return err;
-}
-
-static int __init init_kgdboc(void)
-{
-       /* Already configured? */
-       if (configured == 1)
-               return 0;
-
-       return configure_kgdboc();
-}
-
-static int kgdboc_get_char(void)
-{
-       if (!kgdb_tty_driver)
-               return -1;
-       return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
-                                               kgdb_tty_line);
-}
-
-static void kgdboc_put_char(u8 chr)
-{
-       if (!kgdb_tty_driver)
-               return;
-       kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
-                                       kgdb_tty_line, chr);
-}
-
-static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
-{
-       int len = strlen(kmessage);
-
-       if (len >= MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
-               return -ENOSPC;
-       }
-
-       /* Only copy in the string if the init function has not run yet */
-       if (configured < 0) {
-               strcpy(config, kmessage);
-               return 0;
-       }
-
-       if (kgdb_connected) {
-               printk(KERN_ERR
-                      "kgdboc: Cannot reconfigure while KGDB is connected.\n");
-
-               return -EBUSY;
-       }
-
-       strcpy(config, kmessage);
-       /* Chop out \n char as a result of echo */
-       if (config[len - 1] == '\n')
-               config[len - 1] = '\0';
-
-       if (configured == 1)
-               cleanup_kgdboc();
-
-       /* Go and configure with the new params. */
-       return configure_kgdboc();
-}
-
-static int dbg_restore_graphics;
-
-static void kgdboc_pre_exp_handler(void)
-{
-       if (!dbg_restore_graphics && kgdboc_use_kms) {
-               dbg_restore_graphics = 1;
-               con_debug_enter(vc_cons[fg_console].d);
-       }
-       /* Increment the module count when the debugger is active */
-       if (!kgdb_connected)
-               try_module_get(THIS_MODULE);
-}
-
-static void kgdboc_post_exp_handler(void)
-{
-       /* decrement the module count when the debugger detaches */
-       if (!kgdb_connected)
-               module_put(THIS_MODULE);
-       if (kgdboc_use_kms && dbg_restore_graphics) {
-               dbg_restore_graphics = 0;
-               con_debug_leave();
-       }
-       kgdboc_restore_input();
-}
-
-static struct kgdb_io kgdboc_io_ops = {
-       .name                   = "kgdboc",
-       .read_char              = kgdboc_get_char,
-       .write_char             = kgdboc_put_char,
-       .pre_exception          = kgdboc_pre_exp_handler,
-       .post_exception         = kgdboc_post_exp_handler,
-};
-
-#ifdef CONFIG_KGDB_SERIAL_CONSOLE
-/* This is only available if kgdboc is a built in for early debugging */
-static int __init kgdboc_early_init(char *opt)
-{
-       /* save the first character of the config string because the
-        * init routine can destroy it.
-        */
-       char save_ch;
-
-       kgdboc_option_setup(opt);
-       save_ch = config[0];
-       init_kgdboc();
-       config[0] = save_ch;
-       return 0;
-}
-
-early_param("ekgdboc", kgdboc_early_init);
-#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
-
-module_init(init_kgdboc);
-module_exit(cleanup_kgdboc);
-module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
-MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
-MODULE_DESCRIPTION("KGDB Console TTY Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
deleted file mode 100644 (file)
index bea5c21..0000000
+++ /dev/null
@@ -1,1192 +0,0 @@
-/*
- *  m32r_sio.c
- *
- *  Driver for M32R serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/8250.c.
- *
- *  Copyright (C) 2001  Russell King.
- *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/*
- * A note about mapbase / membase
- *
- *  mapbase is the physical address of the IO port.  Currently, we don't
- *  support this very well, and it may well be dropped from this driver
- *  in future.  As such, mapbase should be NULL.
- *
- *  membase is an 'ioremapped' cookie.  This is compatible with the old
- *  serial.c driver, and is currently the preferred form.
- */
-
-#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/delay.h>
-
-#include <asm/m32r.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define PORT_M32R_BASE PORT_M32R_SIO
-#define PORT_INDEX(x)  (x - PORT_M32R_BASE + 1)
-#define BAUD_RATE      115200
-
-#include <linux/serial_core.h>
-#include "m32r_sio.h"
-#include "m32r_sio_reg.h"
-
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...)     printk(fmt)
-#else
-#define DEBUG_INTR(fmt...)     do { } while (0)
-#endif
-
-#define PASS_LIMIT     256
-
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq) ((irq) != 0)
-
-#define BASE_BAUD      115200
-
-/* Standard COM flags */
-#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
-
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism.   Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
-#if defined(CONFIG_PLAT_USRV)
-
-#define SERIAL_PORT_DFNS                                               \
-       /* UART  CLK     PORT   IRQ            FLAGS */                 \
-       { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
-       { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
-
-#else /* !CONFIG_PLAT_USRV */
-
-#if defined(CONFIG_SERIAL_M32R_PLDSIO)
-#define SERIAL_PORT_DFNS                                               \
-       { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
-         STD_COM_FLAGS }, /* ttyS0 */
-#else
-#define SERIAL_PORT_DFNS                                               \
-       { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R,               \
-         STD_COM_FLAGS }, /* ttyS0 */
-#endif
-
-#endif /* !CONFIG_PLAT_USRV */
-
-static struct old_serial_port old_serial_port[] = {
-       SERIAL_PORT_DFNS
-};
-
-#define UART_NR        ARRAY_SIZE(old_serial_port)
-
-struct uart_sio_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          rev;
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           lsr_break_flag;
-
-       /*
-        * We provide a per-port pm hook.
-        */
-       void                    (*pm)(struct uart_port *port,
-                                     unsigned int state, unsigned int old);
-};
-
-struct irq_info {
-       spinlock_t              lock;
-       struct list_head        *head;
-};
-
-static struct irq_info irq_lists[NR_IRQS];
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[] = {
-       [PORT_UNKNOWN] = {
-               .name                   = "unknown",
-               .dfl_xmit_fifo_size     = 1,
-               .flags                  = 0,
-       },
-       [PORT_INDEX(PORT_M32R_SIO)] = {
-               .name                   = "M32RSIO",
-               .dfl_xmit_fifo_size     = 1,
-               .flags                  = 0,
-       },
-};
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-
-#define __sio_in(x) inw((unsigned long)(x))
-#define __sio_out(v,x) outw((v),(unsigned long)(x))
-
-static inline void sio_set_baud_rate(unsigned long baud)
-{
-       unsigned short sbaud;
-       sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1;
-       __sio_out(sbaud, PLD_ESIO0BAUR);
-}
-
-static void sio_reset(void)
-{
-       unsigned short tmp;
-
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0CR);
-       sio_set_baud_rate(BAUD_RATE);
-       __sio_out(0x0300, PLD_ESIO0CR);
-       __sio_out(0x0003, PLD_ESIO0CR);
-}
-
-static void sio_init(void)
-{
-       unsigned short tmp;
-
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0RXB);
-       tmp = __sio_in(PLD_ESIO0CR);
-       __sio_out(0x0300, PLD_ESIO0CR);
-       __sio_out(0x0003, PLD_ESIO0CR);
-}
-
-static void sio_error(int *status)
-{
-       printk("SIO0 error[%04x]\n", *status);
-       do {
-               sio_init();
-       } while ((*status = __sio_in(PLD_ESIO0CR)) != 3);
-}
-
-#else /* not CONFIG_SERIAL_M32R_PLDSIO */
-
-#define __sio_in(x) inl(x)
-#define __sio_out(v,x) outl((v),(x))
-
-static inline void sio_set_baud_rate(unsigned long baud)
-{
-       unsigned long i, j;
-
-       i = boot_cpu_data.bus_clock / (baud * 16);
-       j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud;
-       i -= 1;
-       j = (j + 1) >> 1;
-
-       __sio_out(i, M32R_SIO0_BAUR_PORTL);
-       __sio_out(j, M32R_SIO0_RBAUR_PORTL);
-}
-
-static void sio_reset(void)
-{
-       __sio_out(0x00000300, M32R_SIO0_CR_PORTL);      /* init status */
-       __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL);    /* 8bit        */
-       __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL);    /* 1stop non   */
-       sio_set_baud_rate(BAUD_RATE);
-       __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL);
-       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);      /* RXCEN */
-}
-
-static void sio_init(void)
-{
-       unsigned int tmp;
-
-       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
-       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
-       tmp = __sio_in(M32R_SIO0_STS_PORTL);
-       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);
-}
-
-static void sio_error(int *status)
-{
-       printk("SIO0 error[%04x]\n", *status);
-       do {
-               sio_init();
-       } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3);
-}
-
-#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-
-static unsigned int sio_in(struct uart_sio_port *up, int offset)
-{
-       return __sio_in(up->port.iobase + offset);
-}
-
-static void sio_out(struct uart_sio_port *up, int offset, int value)
-{
-       __sio_out(value, up->port.iobase + offset);
-}
-
-static unsigned int serial_in(struct uart_sio_port *up, int offset)
-{
-       if (!offset)
-               return 0;
-
-       return __sio_in(offset);
-}
-
-static void serial_out(struct uart_sio_port *up, int offset, int value)
-{
-       if (!offset)
-               return;
-
-       __sio_out(value, offset);
-}
-
-static void m32r_sio_stop_tx(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void m32r_sio_start_tx(struct uart_port *port)
-{
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-       }
-       while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
-#else
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-#endif
-}
-
-static void m32r_sio_stop_rx(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void m32r_sio_enable_ms(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void receive_chars(struct uart_sio_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch;
-       unsigned char flag;
-       int max_count = 256;
-
-       do {
-               ch = sio_in(up, SIORXB);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-
-                       if (*status & UART_LSR_BI) {
-                               DEBUG_INTR("handling break....");
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               if ((*status & up->port.ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-
-               if (*status & UART_LSR_OE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_sio_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-#ifndef CONFIG_SERIAL_M32R_PLDSIO      /* XXX */
-               serial_out(up, UART_TX, up->port.x_char);
-#endif
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               m32r_sio_stop_tx(&up->port);
-               return;
-       }
-
-       count = up->port.fifosize;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-               while (!(serial_in(up, UART_LSR) & UART_LSR_THRE));
-
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       DEBUG_INTR("THRE...");
-
-       if (uart_circ_empty(xmit))
-               m32r_sio_stop_tx(&up->port);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline void m32r_sio_handle_port(struct uart_sio_port *up,
-       unsigned int status)
-{
-       DEBUG_INTR("status = %x...", status);
-
-       if (status & 0x04)
-               receive_chars(up, &status);
-       if (status & 0x01)
-               transmit_chars(up);
-}
-
-/*
- * This is the serial driver's interrupt routine.
- *
- * Arjan thinks the old way was overly complex, so it got simplified.
- * Alan disagrees, saying that need the complexity to handle the weird
- * nature of ISA shared interrupts.  (This is a special exception.)
- *
- * In order to handle ISA shared interrupts properly, we need to check
- * that all ports have been serviced, and therefore the ISA interrupt
- * line has been de-asserted.
- *
- * This means we need to loop through all ports. checking that they
- * don't have an interrupt pending.
- */
-static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
-{
-       struct irq_info *i = dev_id;
-       struct list_head *l, *end = NULL;
-       int pass_counter = 0;
-
-       DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-//     if (irq == PLD_IRQ_SIO0_SND)
-//             irq = PLD_IRQ_SIO0_RCV;
-#else
-       if (irq == M32R_IRQ_SIO0_S)
-               irq = M32R_IRQ_SIO0_R;
-#endif
-
-       spin_lock(&i->lock);
-
-       l = i->head;
-       do {
-               struct uart_sio_port *up;
-               unsigned int sts;
-
-               up = list_entry(l, struct uart_sio_port, list);
-
-               sts = sio_in(up, SIOSTS);
-               if (sts & 0x5) {
-                       spin_lock(&up->port.lock);
-                       m32r_sio_handle_port(up, sts);
-                       spin_unlock(&up->port.lock);
-
-                       end = NULL;
-               } else if (end == NULL)
-                       end = l;
-
-               l = l->next;
-
-               if (l == i->head && pass_counter++ > PASS_LIMIT) {
-                       if (sts & 0xe0)
-                               sio_error(&sts);
-                       break;
-               }
-       } while (l != end);
-
-       spin_unlock(&i->lock);
-
-       DEBUG_INTR("end.\n");
-
-       return IRQ_HANDLED;
-}
-
-/*
- * To support ISA shared interrupts, we need to have one interrupt
- * handler that ensures that the IRQ line has been deasserted
- * before returning.  Failing to do this will result in the IRQ
- * line being stuck active, and, since ISA irqs are edge triggered,
- * no more IRQs will be seen.
- */
-static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
-{
-       spin_lock_irq(&i->lock);
-
-       if (!list_empty(i->head)) {
-               if (i->head == &up->list)
-                       i->head = i->head->next;
-               list_del(&up->list);
-       } else {
-               BUG_ON(i->head != &up->list);
-               i->head = NULL;
-       }
-
-       spin_unlock_irq(&i->lock);
-}
-
-static int serial_link_irq_chain(struct uart_sio_port *up)
-{
-       struct irq_info *i = irq_lists + up->port.irq;
-       int ret, irq_flags = 0;
-
-       spin_lock_irq(&i->lock);
-
-       if (i->head) {
-               list_add(&up->list, i->head);
-               spin_unlock_irq(&i->lock);
-
-               ret = 0;
-       } else {
-               INIT_LIST_HEAD(&up->list);
-               i->head = &up->list;
-               spin_unlock_irq(&i->lock);
-
-               ret = request_irq(up->port.irq, m32r_sio_interrupt,
-                                 irq_flags, "SIO0-RX", i);
-               ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt,
-                                 irq_flags, "SIO0-TX", i);
-               if (ret < 0)
-                       serial_do_unlink(i, up);
-       }
-
-       return ret;
-}
-
-static void serial_unlink_irq_chain(struct uart_sio_port *up)
-{
-       struct irq_info *i = irq_lists + up->port.irq;
-
-       BUG_ON(i->head == NULL);
-
-       if (list_empty(i->head)) {
-               free_irq(up->port.irq, i);
-               free_irq(up->port.irq + 1, i);
-       }
-
-       serial_do_unlink(i, up);
-}
-
-/*
- * This function is used to handle ports that do not have an interrupt.
- */
-static void m32r_sio_timeout(unsigned long data)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)data;
-       unsigned int timeout;
-       unsigned int sts;
-
-       sts = sio_in(up, SIOSTS);
-       if (sts & 0x5) {
-               spin_lock(&up->port.lock);
-               m32r_sio_handle_port(up, sts);
-               spin_unlock(&up->port.lock);
-       }
-
-       timeout = up->port.timeout;
-       timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-       mod_timer(&up->timer, jiffies + timeout);
-}
-
-static unsigned int m32r_sio_tx_empty(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int m32r_sio_get_mctrl(struct uart_port *port)
-{
-       return 0;
-}
-
-static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-
-}
-
-static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
-{
-
-}
-
-static int m32r_sio_startup(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       int retval;
-
-       sio_init();
-
-       /*
-        * If the "interrupt" for this port doesn't correspond with any
-        * hardware interrupt, we use a timer-based system.  The original
-        * driver used to do this with IRQ0.
-        */
-       if (!is_real_interrupt(up->port.irq)) {
-               unsigned int timeout = up->port.timeout;
-
-               timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-
-               up->timer.data = (unsigned long)up;
-               mod_timer(&up->timer, jiffies + timeout);
-       } else {
-               retval = serial_link_irq_chain(up);
-               if (retval)
-                       return retval;
-       }
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        * - M32R_SIO: 0x0c
-        * - M32R_PLDSIO: 0x04
-        */
-       up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-       sio_out(up, SIOTRCR, up->ier);
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       sio_reset();
-
-       return 0;
-}
-
-static void m32r_sio_shutdown(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       sio_out(up, SIOTRCR, 0);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-
-       sio_init();
-
-       if (!is_real_interrupt(up->port.irq))
-               del_timer_sync(&up->timer);
-       else
-               serial_unlink_irq_chain(up);
-}
-
-static unsigned int m32r_sio_get_divisor(struct uart_port *port,
-       unsigned int baud)
-{
-       return uart_get_divisor(port, baud);
-}
-
-static void m32r_sio_set_termios(struct uart_port *port,
-       struct ktermios *termios, struct ktermios *old)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned char cval = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (termios->c_cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
-#else
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-#endif
-       quot = m32r_sio_get_divisor(port, baud);
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       sio_set_baud_rate(baud);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       up->lcr = cval;                                 /* Save LCR */
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void m32r_sio_pm(struct uart_port *port, unsigned int state,
-       unsigned int oldstate)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       if (up->pm)
-               up->pm(port, state, oldstate);
-}
-
-/*
- * Resource handling.  This is complicated by the fact that resources
- * depend on the port type.  Maybe we should be claiming the standard
- * 8250 ports, and then trying to get other resources as necessary?
- */
-static int
-m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
-{
-       unsigned int size = 8 << up->port.regshift;
-#ifndef CONFIG_SERIAL_M32R_PLDSIO
-       unsigned long start;
-#endif
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       case UPIO_MEM:
-               if (up->port.mapbase) {
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-                       *res = request_mem_region(up->port.mapbase, size, "serial");
-#else
-                       start = up->port.mapbase;
-                       *res = request_mem_region(start, size, "serial");
-#endif
-                       if (!*res)
-                               ret = -EBUSY;
-               }
-               break;
-
-       case UPIO_PORT:
-               *res = request_region(up->port.iobase, size, "serial");
-               if (!*res)
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void m32r_sio_release_port(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       unsigned long start, offset = 0, size = 0;
-
-       size <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_MEM:
-               if (up->port.mapbase) {
-                       /*
-                        * Unmap the area.
-                        */
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-
-                       start = up->port.mapbase;
-
-                       if (size)
-                               release_mem_region(start + offset, size);
-                       release_mem_region(start, 8 << up->port.regshift);
-               }
-               break;
-
-       case UPIO_PORT:
-               start = up->port.iobase;
-
-               if (size)
-                       release_region(start + offset, size);
-               release_region(start + offset, 8 << up->port.regshift);
-               break;
-
-       default:
-               break;
-       }
-}
-
-static int m32r_sio_request_port(struct uart_port *port)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-       struct resource *res = NULL;
-       int ret = 0;
-
-       ret = m32r_sio_request_std_resource(up, &res);
-
-       /*
-        * If we have a mapbase, then request that as well.
-        */
-       if (ret == 0 && up->port.flags & UPF_IOREMAP) {
-               int size = res->end - res->start + 1;
-
-               up->port.membase = ioremap(up->port.mapbase, size);
-               if (!up->port.membase)
-                       ret = -ENOMEM;
-       }
-
-       if (ret < 0) {
-               if (res)
-                       release_resource(res);
-       }
-
-       return ret;
-}
-
-static void m32r_sio_config_port(struct uart_port *port, int flags)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
-       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int
-m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->irq >= nr_irqs || ser->irq < 0 ||
-           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-           ser->type >= ARRAY_SIZE(uart_config))
-               return -EINVAL;
-       return 0;
-}
-
-static const char *
-m32r_sio_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops m32r_sio_pops = {
-       .tx_empty       = m32r_sio_tx_empty,
-       .set_mctrl      = m32r_sio_set_mctrl,
-       .get_mctrl      = m32r_sio_get_mctrl,
-       .stop_tx        = m32r_sio_stop_tx,
-       .start_tx       = m32r_sio_start_tx,
-       .stop_rx        = m32r_sio_stop_rx,
-       .enable_ms      = m32r_sio_enable_ms,
-       .break_ctl      = m32r_sio_break_ctl,
-       .startup        = m32r_sio_startup,
-       .shutdown       = m32r_sio_shutdown,
-       .set_termios    = m32r_sio_set_termios,
-       .pm             = m32r_sio_pm,
-       .type           = m32r_sio_type,
-       .release_port   = m32r_sio_release_port,
-       .request_port   = m32r_sio_request_port,
-       .config_port    = m32r_sio_config_port,
-       .verify_port    = m32r_sio_verify_port,
-};
-
-static struct uart_sio_port m32r_sio_ports[UART_NR];
-
-static void __init m32r_sio_init_ports(void)
-{
-       struct uart_sio_port *up;
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
-            i++, up++) {
-               up->port.iobase   = old_serial_port[i].port;
-               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
-               up->port.uartclk  = old_serial_port[i].baud_base * 16;
-               up->port.flags    = old_serial_port[i].flags;
-               up->port.membase  = old_serial_port[i].iomem_base;
-               up->port.iotype   = old_serial_port[i].io_type;
-               up->port.regshift = old_serial_port[i].iomem_reg_shift;
-               up->port.ops      = &m32r_sio_pops;
-       }
-}
-
-static void __init m32r_sio_register_ports(struct uart_driver *drv)
-{
-       int i;
-
-       m32r_sio_init_ports();
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_sio_port *up = &m32r_sio_ports[i];
-
-               up->port.line = i;
-               up->port.ops = &m32r_sio_pops;
-               init_timer(&up->timer);
-               up->timer.function = m32r_sio_timeout;
-
-               /*
-                * ALPHA_KLUDGE_MCR needs to be killed.
-                */
-               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-               up->mcr_force = ALPHA_KLUDGE_MCR;
-
-               uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_sio_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = sio_in(up, SIOSTS);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & UART_EMPTY) != UART_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout)
-                       udelay(1);
-       }
-}
-
-static void m32r_sio_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_sio_port *up = (struct uart_sio_port *)port;
-
-       wait_for_xmitr(up);
-       sio_out(up, SIOTXB, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void m32r_sio_console_write(struct console *co, const char *s,
-       unsigned int count)
-{
-       struct uart_sio_port *up = &m32r_sio_ports[co->index];
-       unsigned int ier;
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = sio_in(up, SIOTRCR);
-       sio_out(up, SIOTRCR, 0);
-
-       uart_console_write(&up->port, s, count, m32r_sio_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, SIOTRCR, ier);
-}
-
-static int __init m32r_sio_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       port = &m32r_sio_ports[co->index].port;
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&port->lock);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver m32r_sio_reg;
-static struct console m32r_sio_console = {
-       .name           = "ttyS",
-       .write          = m32r_sio_console_write,
-       .device         = uart_console_device,
-       .setup          = m32r_sio_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &m32r_sio_reg,
-};
-
-static int __init m32r_sio_console_init(void)
-{
-       sio_reset();
-       sio_init();
-       m32r_sio_init_ports();
-       register_console(&m32r_sio_console);
-       return 0;
-}
-console_initcall(m32r_sio_console_init);
-
-#define M32R_SIO_CONSOLE       &m32r_sio_console
-#else
-#define M32R_SIO_CONSOLE       NULL
-#endif
-
-static struct uart_driver m32r_sio_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sio",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = UART_NR,
-       .cons                   = M32R_SIO_CONSOLE,
-};
-
-/**
- *     m32r_sio_suspend_port - suspend one serial port
- *     @line: serial line number
- *
- *     Suspend one serial port.
- */
-void m32r_sio_suspend_port(int line)
-{
-       uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-/**
- *     m32r_sio_resume_port - resume one serial port
- *     @line: serial line number
- *
- *     Resume one serial port.
- */
-void m32r_sio_resume_port(int line)
-{
-       uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-static int __init m32r_sio_init(void)
-{
-       int ret, i;
-
-       printk(KERN_INFO "Serial: M32R SIO driver\n");
-
-       for (i = 0; i < nr_irqs; i++)
-               spin_lock_init(&irq_lists[i].lock);
-
-       ret = uart_register_driver(&m32r_sio_reg);
-       if (ret >= 0)
-               m32r_sio_register_ports(&m32r_sio_reg);
-
-       return ret;
-}
-
-static void __exit m32r_sio_exit(void)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++)
-               uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
-
-       uart_unregister_driver(&m32r_sio_reg);
-}
-
-module_init(m32r_sio_init);
-module_exit(m32r_sio_exit);
-
-EXPORT_SYMBOL(m32r_sio_suspend_port);
-EXPORT_SYMBOL(m32r_sio_resume_port);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
deleted file mode 100644 (file)
index e9b7e11..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  m32r_sio.h
- *
- *  Driver for M32R serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/8250.h.
- *
- *  Copyright (C) 2001  Russell King.
- *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-struct m32r_sio_probe {
-       struct module   *owner;
-       int             (*pci_init_one)(struct pci_dev *dev);
-       void            (*pci_remove_one)(struct pci_dev *dev);
-       void            (*pnp_init)(void);
-};
-
-int m32r_sio_register_probe(struct m32r_sio_probe *probe);
-void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
-void m32r_sio_get_irq_map(unsigned int *map);
-void m32r_sio_suspend_port(int line);
-void m32r_sio_resume_port(int line);
-
-struct old_serial_port {
-       unsigned int uart;
-       unsigned int baud_base;
-       unsigned int port;
-       unsigned int irq;
-       unsigned int flags;
-       unsigned char io_type;
-       unsigned char __iomem *iomem_base;
-       unsigned short iomem_reg_shift;
-};
-
-#define _INLINE_ inline
-
-#define PROBE_RSA      (1 << 0)
-#define PROBE_ANY      (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
deleted file mode 100644 (file)
index 4671473..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * m32r_sio_reg.h
- *
- * Copyright (C) 1992, 1994 by Theodore Ts'o.
- * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
- *
- * Redistribution of this file is permitted under the terms of the GNU
- * Public License (GPL)
- *
- * These are the UART port assignments, expressed as offsets from the base
- * register.  These assignments should hold for any serial port based on
- * a 8250, 16450, or 16550(A).
- */
-
-#ifndef _M32R_SIO_REG_H
-#define _M32R_SIO_REG_H
-
-
-#ifdef CONFIG_SERIAL_M32R_PLDSIO
-
-#define SIOCR          0x000
-#define SIOMOD0                0x002
-#define SIOMOD1                0x004
-#define SIOSTS         0x006
-#define SIOTRCR                0x008
-#define SIOBAUR                0x00a
-// #define SIORBAUR    0x018
-#define SIOTXB         0x00c
-#define SIORXB         0x00e
-
-#define UART_RX                ((unsigned long) PLD_ESIO0RXB)
-                               /* In:  Receive buffer (DLAB=0) */
-#define UART_TX                ((unsigned long) PLD_ESIO0TXB)
-                               /* Out: Transmit buffer (DLAB=0) */
-#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
-#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
-                                * In: Fifo count
-                                * Out: Fifo custom trigger levels
-                                * XR16C85x only */
-
-#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
-#define UART_IER       ((unsigned long) PLD_ESIO0INTCR)
-                               /* Out: Interrupt Enable Register */
-#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
-                                * XR16C85x only */
-
-#define UART_IIR       0       /* In:  Interrupt ID Register */
-#define UART_FCR       0       /* Out: FIFO Control Register */
-#define UART_EFR       0       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
-
-#define UART_LCR       0       /* Out: Line Control Register */
-#define UART_MCR       0       /* Out: Modem Control Register */
-#define UART_LSR       ((unsigned long) PLD_ESIO0STS)
-                               /* In:  Line Status Register */
-#define UART_MSR       0       /* In:  Modem Status Register */
-#define UART_SCR       0       /* I/O: Scratch Register */
-#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
-                                * FCTR bit 6 selects SCR or EMSR
-                                * XR16c85x only */
-
-#else /* not CONFIG_SERIAL_M32R_PLDSIO */
-
-#define SIOCR          0x000
-#define SIOMOD0                0x004
-#define SIOMOD1                0x008
-#define SIOSTS         0x00c
-#define SIOTRCR                0x010
-#define SIOBAUR                0x014
-#define SIORBAUR       0x018
-#define SIOTXB         0x01c
-#define SIORXB         0x020
-
-#define UART_RX                M32R_SIO0_RXB_PORTL     /* In:  Receive buffer (DLAB=0) */
-#define UART_TX                M32R_SIO0_TXB_PORTL     /* Out: Transmit buffer (DLAB=0) */
-#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
-#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
-                                * In: Fifo count
-                                * Out: Fifo custom trigger levels
-                                * XR16C85x only */
-
-#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
-#define UART_IER       M32R_SIO0_TRCR_PORTL    /* Out: Interrupt Enable Register */
-#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
-                                * XR16C85x only */
-
-#define UART_IIR       0       /* In:  Interrupt ID Register */
-#define UART_FCR       0       /* Out: FIFO Control Register */
-#define UART_EFR       0       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
-
-#define UART_LCR       0       /* Out: Line Control Register */
-#define UART_MCR       0       /* Out: Modem Control Register */
-#define UART_LSR       M32R_SIO0_STS_PORTL     /* In:  Line Status Register */
-#define UART_MSR       0       /* In:  Modem Status Register */
-#define UART_SCR       0       /* I/O: Scratch Register */
-#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
-                                * FCTR bit 6 selects SCR or EMSR
-                                * XR16c85x only */
-
-#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-
-#define UART_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- * These are the definitions for the Line Control Register
- *
- * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
- * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
- */
-#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
-#define UART_LCR_SBC   0x40    /* Set break control */
-#define UART_LCR_SPAR  0x20    /* Stick parity (?) */
-#define UART_LCR_EPAR  0x10    /* Even parity select */
-#define UART_LCR_PARITY        0x08    /* Parity Enable */
-#define UART_LCR_STOP  0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
-#define UART_LCR_WLEN5  0x00   /* Wordlength: 5 bits */
-#define UART_LCR_WLEN6  0x01   /* Wordlength: 6 bits */
-#define UART_LCR_WLEN7  0x02   /* Wordlength: 7 bits */
-#define UART_LCR_WLEN8  0x03   /* Wordlength: 8 bits */
-
-/*
- * These are the definitions for the Line Status Register
- */
-#define UART_LSR_TEMT  0x02    /* Transmitter empty */
-#define UART_LSR_THRE  0x01    /* Transmit-hold-register empty */
-#define UART_LSR_BI    0x00    /* Break interrupt indicator */
-#define UART_LSR_FE    0x80    /* Frame error indicator */
-#define UART_LSR_PE    0x40    /* Parity error indicator */
-#define UART_LSR_OE    0x20    /* Overrun error indicator */
-#define UART_LSR_DR    0x04    /* Receiver data ready */
-
-/*
- * These are the definitions for the Interrupt Identification Register
- */
-#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
-#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI   0x00    /* Modem status interrupt */
-#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
-#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
-#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
-
-/*
- * These are the definitions for the Interrupt Enable Register
- */
-#define UART_IER_MSI   0x00    /* Enable Modem status interrupt */
-#define UART_IER_RLSI  0x08    /* Enable receiver line status interrupt */
-#define UART_IER_THRI  0x03    /* Enable Transmitter holding register int. */
-#define UART_IER_RDI   0x04    /* Enable receiver data interrupt */
-
-#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/serial/max3100.c b/drivers/serial/max3100.c
deleted file mode 100644 (file)
index beb1afa..0000000
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
- *
- *  Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- *
- * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
- * to use polling for flow control. TX empty IRQ is unusable, since
- * writing conf clears FIFO buffer and we cannot have this interrupt
- * always asking us for attention.
- *
- * Example platform data:
-
- static struct plat_max3100 max3100_plat_data = {
- .loopback = 0,
- .crystal = 0,
- .poll_time = 100,
- };
-
- static struct spi_board_info spi_board_info[] = {
- {
- .modalias     = "max3100",
- .platform_data        = &max3100_plat_data,
- .irq          = IRQ_EINT12,
- .max_speed_hz = 5*1000*1000,
- .chip_select  = 0,
- },
- };
-
- * The initial minor number is 209 in the low-density serial port:
- * mknod /dev/ttyMAX0 c 204 209
- */
-
-#define MAX3100_MAJOR 204
-#define MAX3100_MINOR 209
-/* 4 MAX3100s should be enough for everyone */
-#define MAX_MAX3100 4
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-
-#include <linux/serial_max3100.h>
-
-#define MAX3100_C    (1<<14)
-#define MAX3100_D    (0<<14)
-#define MAX3100_W    (1<<15)
-#define MAX3100_RX   (0<<15)
-
-#define MAX3100_WC   (MAX3100_W  | MAX3100_C)
-#define MAX3100_RC   (MAX3100_RX | MAX3100_C)
-#define MAX3100_WD   (MAX3100_W  | MAX3100_D)
-#define MAX3100_RD   (MAX3100_RX | MAX3100_D)
-#define MAX3100_CMD  (3 << 14)
-
-#define MAX3100_T    (1<<14)
-#define MAX3100_R    (1<<15)
-
-#define MAX3100_FEN  (1<<13)
-#define MAX3100_SHDN (1<<12)
-#define MAX3100_TM   (1<<11)
-#define MAX3100_RM   (1<<10)
-#define MAX3100_PM   (1<<9)
-#define MAX3100_RAM  (1<<8)
-#define MAX3100_IR   (1<<7)
-#define MAX3100_ST   (1<<6)
-#define MAX3100_PE   (1<<5)
-#define MAX3100_L    (1<<4)
-#define MAX3100_BAUD (0xf)
-
-#define MAX3100_TE   (1<<10)
-#define MAX3100_RAFE (1<<10)
-#define MAX3100_RTS  (1<<9)
-#define MAX3100_CTS  (1<<9)
-#define MAX3100_PT   (1<<8)
-#define MAX3100_DATA (0xff)
-
-#define MAX3100_RT   (MAX3100_R | MAX3100_T)
-#define MAX3100_RTC  (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE)
-
-/* the following simulate a status reg for ignore_status_mask */
-#define MAX3100_STATUS_PE 1
-#define MAX3100_STATUS_FE 2
-#define MAX3100_STATUS_OE 4
-
-struct max3100_port {
-       struct uart_port port;
-       struct spi_device *spi;
-
-       int cts;                /* last CTS received for flow ctrl */
-       int tx_empty;           /* last TX empty bit */
-
-       spinlock_t conf_lock;   /* shared data */
-       int conf_commit;        /* need to make changes */
-       int conf;               /* configuration for the MAX31000
-                                * (bits 0-7, bits 8-11 are irqs) */
-       int rts_commit;         /* need to change rts */
-       int rts;                /* rts status */
-       int baud;               /* current baud rate */
-
-       int parity;             /* keeps track if we should send parity */
-#define MAX3100_PARITY_ON 1
-#define MAX3100_PARITY_ODD 2
-#define MAX3100_7BIT 4
-       int rx_enabled;         /* if we should rx chars */
-
-       int irq;                /* irq assigned to the max3100 */
-
-       int minor;              /* minor number */
-       int crystal;            /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
-       int loopback;           /* 1 if we are in loopback mode */
-
-       /* for handling irqs: need workqueue since we do spi_sync */
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-       /* set to 1 to make the workhandler exit as soon as possible */
-       int  force_end_work;
-       /* need to know we are suspending to avoid deadlock on workqueue */
-       int suspending;
-
-       /* hook for suspending MAX3100 via dedicated pin */
-       void (*max3100_hw_suspend) (int suspend);
-
-       /* poll time (in ms) for ctrl lines */
-       int poll_time;
-       /* and its timer */
-       struct timer_list       timer;
-};
-
-static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
-static DEFINE_MUTEX(max3100s_lock);               /* race on probe */
-
-static int max3100_do_parity(struct max3100_port *s, u16 c)
-{
-       int parity;
-
-       if (s->parity & MAX3100_PARITY_ODD)
-               parity = 1;
-       else
-               parity = 0;
-
-       if (s->parity & MAX3100_7BIT)
-               c &= 0x7f;
-       else
-               c &= 0xff;
-
-       parity = parity ^ (hweight8(c) & 1);
-       return parity;
-}
-
-static int max3100_check_parity(struct max3100_port *s, u16 c)
-{
-       return max3100_do_parity(s, c) == ((c >> 8) & 1);
-}
-
-static void max3100_calc_parity(struct max3100_port *s, u16 *c)
-{
-       if (s->parity & MAX3100_7BIT)
-               *c &= 0x7f;
-       else
-               *c &= 0xff;
-
-       if (s->parity & MAX3100_PARITY_ON)
-               *c |= max3100_do_parity(s, *c) << 8;
-}
-
-static void max3100_work(struct work_struct *w);
-
-static void max3100_dowork(struct max3100_port *s)
-{
-       if (!s->force_end_work && !work_pending(&s->work) &&
-           !freezing(current) && !s->suspending)
-               queue_work(s->workqueue, &s->work);
-}
-
-static void max3100_timeout(unsigned long data)
-{
-       struct max3100_port *s = (struct max3100_port *)data;
-
-       if (s->port.state) {
-               max3100_dowork(s);
-               mod_timer(&s->timer, jiffies + s->poll_time);
-       }
-}
-
-static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
-{
-       struct spi_message message;
-       u16 etx, erx;
-       int status;
-       struct spi_transfer tran = {
-               .tx_buf = &etx,
-               .rx_buf = &erx,
-               .len = 2,
-       };
-
-       etx = cpu_to_be16(tx);
-       spi_message_init(&message);
-       spi_message_add_tail(&tran, &message);
-       status = spi_sync(s->spi, &message);
-       if (status) {
-               dev_warn(&s->spi->dev, "error while calling spi_sync\n");
-               return -EIO;
-       }
-       *rx = be16_to_cpu(erx);
-       s->tx_empty = (*rx & MAX3100_T) > 0;
-       dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx);
-       return 0;
-}
-
-static int max3100_handlerx(struct max3100_port *s, u16 rx)
-{
-       unsigned int ch, flg, status = 0;
-       int ret = 0, cts;
-
-       if (rx & MAX3100_R && s->rx_enabled) {
-               dev_dbg(&s->spi->dev, "%s\n", __func__);
-               ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff);
-               if (rx & MAX3100_RAFE) {
-                       s->port.icount.frame++;
-                       flg = TTY_FRAME;
-                       status |= MAX3100_STATUS_FE;
-               } else {
-                       if (s->parity & MAX3100_PARITY_ON) {
-                               if (max3100_check_parity(s, rx)) {
-                                       s->port.icount.rx++;
-                                       flg = TTY_NORMAL;
-                               } else {
-                                       s->port.icount.parity++;
-                                       flg = TTY_PARITY;
-                                       status |= MAX3100_STATUS_PE;
-                               }
-                       } else {
-                               s->port.icount.rx++;
-                               flg = TTY_NORMAL;
-                       }
-               }
-               uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg);
-               ret = 1;
-       }
-
-       cts = (rx & MAX3100_CTS) > 0;
-       if (s->cts != cts) {
-               s->cts = cts;
-               uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
-       }
-
-       return ret;
-}
-
-static void max3100_work(struct work_struct *w)
-{
-       struct max3100_port *s = container_of(w, struct max3100_port, work);
-       int rxchars;
-       u16 tx, rx;
-       int conf, cconf, rts, crts;
-       struct circ_buf *xmit = &s->port.state->xmit;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       rxchars = 0;
-       do {
-               spin_lock(&s->conf_lock);
-               conf = s->conf;
-               cconf = s->conf_commit;
-               s->conf_commit = 0;
-               rts = s->rts;
-               crts = s->rts_commit;
-               s->rts_commit = 0;
-               spin_unlock(&s->conf_lock);
-               if (cconf)
-                       max3100_sr(s, MAX3100_WC | conf, &rx);
-               if (crts) {
-                       max3100_sr(s, MAX3100_WD | MAX3100_TE |
-                                  (s->rts ? MAX3100_RTS : 0), &rx);
-                       rxchars += max3100_handlerx(s, rx);
-               }
-
-               max3100_sr(s, MAX3100_RD, &rx);
-               rxchars += max3100_handlerx(s, rx);
-
-               if (rx & MAX3100_T) {
-                       tx = 0xffff;
-                       if (s->port.x_char) {
-                               tx = s->port.x_char;
-                               s->port.icount.tx++;
-                               s->port.x_char = 0;
-                       } else if (!uart_circ_empty(xmit) &&
-                                  !uart_tx_stopped(&s->port)) {
-                               tx = xmit->buf[xmit->tail];
-                               xmit->tail = (xmit->tail + 1) &
-                                       (UART_XMIT_SIZE - 1);
-                               s->port.icount.tx++;
-                       }
-                       if (tx != 0xffff) {
-                               max3100_calc_parity(s, &tx);
-                               tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0);
-                               max3100_sr(s, tx, &rx);
-                               rxchars += max3100_handlerx(s, rx);
-                       }
-               }
-
-               if (rxchars > 16 && s->port.state->port.tty != NULL) {
-                       tty_flip_buffer_push(s->port.state->port.tty);
-                       rxchars = 0;
-               }
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&s->port);
-
-       } while (!s->force_end_work &&
-                !freezing(current) &&
-                ((rx & MAX3100_R) ||
-                 (!uart_circ_empty(xmit) &&
-                  !uart_tx_stopped(&s->port))));
-
-       if (rxchars > 0 && s->port.state->port.tty != NULL)
-               tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-static irqreturn_t max3100_irq(int irqno, void *dev_id)
-{
-       struct max3100_port *s = dev_id;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       max3100_dowork(s);
-       return IRQ_HANDLED;
-}
-
-static void max3100_enable_ms(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       if (s->poll_time > 0)
-               mod_timer(&s->timer, jiffies);
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static void max3100_start_tx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       max3100_dowork(s);
-}
-
-static void max3100_stop_rx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       s->rx_enabled = 0;
-       spin_lock(&s->conf_lock);
-       s->conf &= ~MAX3100_RM;
-       s->conf_commit = 1;
-       spin_unlock(&s->conf_lock);
-       max3100_dowork(s);
-}
-
-static unsigned int max3100_tx_empty(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       /* may not be truly up-to-date */
-       max3100_dowork(s);
-       return s->tx_empty;
-}
-
-static unsigned int max3100_get_mctrl(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       /* may not be truly up-to-date */
-       max3100_dowork(s);
-       /* always assert DCD and DSR since these lines are not wired */
-       return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int rts;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       rts = (mctrl & TIOCM_RTS) > 0;
-
-       spin_lock(&s->conf_lock);
-       if (s->rts != rts) {
-               s->rts = rts;
-               s->rts_commit = 1;
-               max3100_dowork(s);
-       }
-       spin_unlock(&s->conf_lock);
-}
-
-static void
-max3100_set_termios(struct uart_port *port, struct ktermios *termios,
-                   struct ktermios *old)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int baud = 0;
-       unsigned cflag;
-       u32 param_new, param_mask, parity = 0;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       cflag = termios->c_cflag;
-       param_new = 0;
-       param_mask = 0;
-
-       baud = tty_termios_baud_rate(termios);
-       param_new = s->conf & MAX3100_BAUD;
-       switch (baud) {
-       case 300:
-               if (s->crystal)
-                       baud = s->baud;
-               else
-                       param_new = 15;
-               break;
-       case 600:
-               param_new = 14 + s->crystal;
-               break;
-       case 1200:
-               param_new = 13 + s->crystal;
-               break;
-       case 2400:
-               param_new = 12 + s->crystal;
-               break;
-       case 4800:
-               param_new = 11 + s->crystal;
-               break;
-       case 9600:
-               param_new = 10 + s->crystal;
-               break;
-       case 19200:
-               param_new = 9 + s->crystal;
-               break;
-       case 38400:
-               param_new = 8 + s->crystal;
-               break;
-       case 57600:
-               param_new = 1 + s->crystal;
-               break;
-       case 115200:
-               param_new = 0 + s->crystal;
-               break;
-       case 230400:
-               if (s->crystal)
-                       param_new = 0;
-               else
-                       baud = s->baud;
-               break;
-       default:
-               baud = s->baud;
-       }
-       tty_termios_encode_baud_rate(termios, baud, baud);
-       s->baud = baud;
-       param_mask |= MAX3100_BAUD;
-
-       if ((cflag & CSIZE) == CS8) {
-               param_new &= ~MAX3100_L;
-               parity &= ~MAX3100_7BIT;
-       } else {
-               param_new |= MAX3100_L;
-               parity |= MAX3100_7BIT;
-               cflag = (cflag & ~CSIZE) | CS7;
-       }
-       param_mask |= MAX3100_L;
-
-       if (cflag & CSTOPB)
-               param_new |= MAX3100_ST;
-       else
-               param_new &= ~MAX3100_ST;
-       param_mask |= MAX3100_ST;
-
-       if (cflag & PARENB) {
-               param_new |= MAX3100_PE;
-               parity |= MAX3100_PARITY_ON;
-       } else {
-               param_new &= ~MAX3100_PE;
-               parity &= ~MAX3100_PARITY_ON;
-       }
-       param_mask |= MAX3100_PE;
-
-       if (cflag & PARODD)
-               parity |= MAX3100_PARITY_ODD;
-       else
-               parity &= ~MAX3100_PARITY_ODD;
-
-       /* mask termios capabilities we don't support */
-       cflag &= ~CMSPAR;
-       termios->c_cflag = cflag;
-
-       s->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               s->port.ignore_status_mask |=
-                       MAX3100_STATUS_PE | MAX3100_STATUS_FE |
-                       MAX3100_STATUS_OE;
-
-       /* we are sending char from a workqueue so enable */
-       s->port.state->port.tty->low_latency = 1;
-
-       if (s->poll_time > 0)
-               del_timer_sync(&s->timer);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_lock(&s->conf_lock);
-       s->conf = (s->conf & ~param_mask) | (param_new & param_mask);
-       s->conf_commit = 1;
-       s->parity = parity;
-       spin_unlock(&s->conf_lock);
-       max3100_dowork(s);
-
-       if (UART_ENABLE_MS(&s->port, termios->c_cflag))
-               max3100_enable_ms(&s->port);
-}
-
-static void max3100_shutdown(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (s->suspending)
-               return;
-
-       s->force_end_work = 1;
-
-       if (s->poll_time > 0)
-               del_timer_sync(&s->timer);
-
-       if (s->workqueue) {
-               flush_workqueue(s->workqueue);
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-       }
-       if (s->irq)
-               free_irq(s->irq, s);
-
-       /* set shutdown mode to save power */
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(1);
-       else  {
-               u16 tx, rx;
-
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(s, tx, &rx);
-       }
-}
-
-static int max3100_startup(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       char b[12];
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       s->conf = MAX3100_RM;
-       s->baud = s->crystal ? 230400 : 115200;
-       s->rx_enabled = 1;
-
-       if (s->suspending)
-               return 0;
-
-       s->force_end_work = 0;
-       s->parity = 0;
-       s->rts = 0;
-
-       sprintf(b, "max3100-%d", s->minor);
-       s->workqueue = create_freezeable_workqueue(b);
-       if (!s->workqueue) {
-               dev_warn(&s->spi->dev, "cannot create workqueue\n");
-               return -EBUSY;
-       }
-       INIT_WORK(&s->work, max3100_work);
-
-       if (request_irq(s->irq, max3100_irq,
-                       IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
-               dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
-               s->irq = 0;
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-               return -EBUSY;
-       }
-
-       if (s->loopback) {
-               u16 tx, rx;
-               tx = 0x4001;
-               max3100_sr(s, tx, &rx);
-       }
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(0);
-       s->conf_commit = 1;
-       max3100_dowork(s);
-       /* wait for clock to settle */
-       msleep(50);
-
-       max3100_enable_ms(&s->port);
-
-       return 0;
-}
-
-static const char *max3100_type(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL;
-}
-
-static void max3100_release_port(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static void max3100_config_port(struct uart_port *port, int flags)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (flags & UART_CONFIG_TYPE)
-               s->port.type = PORT_MAX3100;
-}
-
-static int max3100_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-       int ret = -EINVAL;
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100)
-               ret = 0;
-       return ret;
-}
-
-static void max3100_stop_tx(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static int max3100_request_port(struct uart_port *port)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-       return 0;
-}
-
-static void max3100_break_ctl(struct uart_port *port, int break_state)
-{
-       struct max3100_port *s = container_of(port,
-                                             struct max3100_port,
-                                             port);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-}
-
-static struct uart_ops max3100_ops = {
-       .tx_empty       = max3100_tx_empty,
-       .set_mctrl      = max3100_set_mctrl,
-       .get_mctrl      = max3100_get_mctrl,
-       .stop_tx        = max3100_stop_tx,
-       .start_tx       = max3100_start_tx,
-       .stop_rx        = max3100_stop_rx,
-       .enable_ms      = max3100_enable_ms,
-       .break_ctl      = max3100_break_ctl,
-       .startup        = max3100_startup,
-       .shutdown       = max3100_shutdown,
-       .set_termios    = max3100_set_termios,
-       .type           = max3100_type,
-       .release_port   = max3100_release_port,
-       .request_port   = max3100_request_port,
-       .config_port    = max3100_config_port,
-       .verify_port    = max3100_verify_port,
-};
-
-static struct uart_driver max3100_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyMAX",
-       .dev_name       = "ttyMAX",
-       .major          = MAX3100_MAJOR,
-       .minor          = MAX3100_MINOR,
-       .nr             = MAX_MAX3100,
-};
-static int uart_driver_registered;
-
-static int __devinit max3100_probe(struct spi_device *spi)
-{
-       int i, retval;
-       struct plat_max3100 *pdata;
-       u16 tx, rx;
-
-       mutex_lock(&max3100s_lock);
-
-       if (!uart_driver_registered) {
-               uart_driver_registered = 1;
-               retval = uart_register_driver(&max3100_uart_driver);
-               if (retval) {
-                       printk(KERN_ERR "Couldn't register max3100 uart driver\n");
-                       mutex_unlock(&max3100s_lock);
-                       return retval;
-               }
-       }
-
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (!max3100s[i])
-                       break;
-       if (i == MAX_MAX3100) {
-               dev_warn(&spi->dev, "too many MAX3100 chips\n");
-               mutex_unlock(&max3100s_lock);
-               return -ENOMEM;
-       }
-
-       max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
-       if (!max3100s[i]) {
-               dev_warn(&spi->dev,
-                        "kmalloc for max3100 structure %d failed!\n", i);
-               mutex_unlock(&max3100s_lock);
-               return -ENOMEM;
-       }
-       max3100s[i]->spi = spi;
-       max3100s[i]->irq = spi->irq;
-       spin_lock_init(&max3100s[i]->conf_lock);
-       dev_set_drvdata(&spi->dev, max3100s[i]);
-       pdata = spi->dev.platform_data;
-       max3100s[i]->crystal = pdata->crystal;
-       max3100s[i]->loopback = pdata->loopback;
-       max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
-       if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
-               max3100s[i]->poll_time = 1;
-       max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
-       max3100s[i]->minor = i;
-       init_timer(&max3100s[i]->timer);
-       max3100s[i]->timer.function = max3100_timeout;
-       max3100s[i]->timer.data = (unsigned long) max3100s[i];
-
-       dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
-       max3100s[i]->port.irq = max3100s[i]->irq;
-       max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
-       max3100s[i]->port.fifosize = 16;
-       max3100s[i]->port.ops = &max3100_ops;
-       max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       max3100s[i]->port.line = i;
-       max3100s[i]->port.type = PORT_MAX3100;
-       max3100s[i]->port.dev = &spi->dev;
-       retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
-       if (retval < 0)
-               dev_warn(&spi->dev,
-                        "uart_add_one_port failed for line %d with error %d\n",
-                        i, retval);
-
-       /* set shutdown mode to save power. Will be woken-up on open */
-       if (max3100s[i]->max3100_hw_suspend)
-               max3100s[i]->max3100_hw_suspend(1);
-       else {
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(max3100s[i], tx, &rx);
-       }
-       mutex_unlock(&max3100s_lock);
-       return 0;
-}
-
-static int __devexit max3100_remove(struct spi_device *spi)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-       int i;
-
-       mutex_lock(&max3100s_lock);
-
-       /* find out the index for the chip we are removing */
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (max3100s[i] == s)
-                       break;
-
-       dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
-       uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
-       kfree(max3100s[i]);
-       max3100s[i] = NULL;
-
-       /* check if this is the last chip we have */
-       for (i = 0; i < MAX_MAX3100; i++)
-               if (max3100s[i]) {
-                       mutex_unlock(&max3100s_lock);
-                       return 0;
-               }
-       pr_debug("removing max3100 driver\n");
-       uart_unregister_driver(&max3100_uart_driver);
-
-       mutex_unlock(&max3100s_lock);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int max3100_suspend(struct spi_device *spi, pm_message_t state)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       disable_irq(s->irq);
-
-       s->suspending = 1;
-       uart_suspend_port(&max3100_uart_driver, &s->port);
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(1);
-       else {
-               /* no HW suspend, so do SW one */
-               u16 tx, rx;
-
-               tx = MAX3100_WC | MAX3100_SHDN;
-               max3100_sr(s, tx, &rx);
-       }
-       return 0;
-}
-
-static int max3100_resume(struct spi_device *spi)
-{
-       struct max3100_port *s = dev_get_drvdata(&spi->dev);
-
-       dev_dbg(&s->spi->dev, "%s\n", __func__);
-
-       if (s->max3100_hw_suspend)
-               s->max3100_hw_suspend(0);
-       uart_resume_port(&max3100_uart_driver, &s->port);
-       s->suspending = 0;
-
-       enable_irq(s->irq);
-
-       s->conf_commit = 1;
-       if (s->workqueue)
-               max3100_dowork(s);
-
-       return 0;
-}
-
-#else
-#define max3100_suspend NULL
-#define max3100_resume  NULL
-#endif
-
-static struct spi_driver max3100_driver = {
-       .driver = {
-               .name           = "max3100",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-
-       .probe          = max3100_probe,
-       .remove         = __devexit_p(max3100_remove),
-       .suspend        = max3100_suspend,
-       .resume         = max3100_resume,
-};
-
-static int __init max3100_init(void)
-{
-       return spi_register_driver(&max3100_driver);
-}
-module_init(max3100_init);
-
-static void __exit max3100_exit(void)
-{
-       spi_unregister_driver(&max3100_driver);
-}
-module_exit(max3100_exit);
-
-MODULE_DESCRIPTION("MAX3100 driver");
-MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:max3100");
diff --git a/drivers/serial/max3107-aava.c b/drivers/serial/max3107-aava.c
deleted file mode 100644 (file)
index a1fe304..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *  max3107.c - spi uart protocol driver for Maxim 3107
- *  Based on max3100.c
- *     by Christian Pellegrin <chripell@evolware.org>
- *  and        max3110.c
- *     by Feng Tang <feng.tang@intel.com>
- *
- *  Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/sfi.h>
-#include <asm/mrst.h>
-#include "max3107.h"
-
-/* GPIO direction to input function */
-static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[1];             /* Buffer for SPI transfer */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO configuration register */
-       buf[0] = MAX3107_GPIOCFG_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Set GPIO to input */
-       buf[0] &= ~(0x0001 << offset);
-
-       /* Write new GPIO configuration register value */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* GPIO direction to output function */
-static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
-                                       int value)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[2];     /* Buffer for SPI transfers */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO configuration and data registers */
-       buf[0] = MAX3107_GPIOCFG_REG;
-       buf[1] = MAX3107_GPIODATA_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
-               dev_err(&s->spi->dev, "SPI transfer gpio failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Set GPIO to output */
-       buf[0] |= (0x0001 << offset);
-       /* Set value */
-       if (value)
-               buf[1] |= (0x0001 << offset);
-       else
-               buf[1] &= ~(0x0001 << offset);
-
-       /* Write new GPIO configuration and data register values */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
-       buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for GPIO conf data w failed\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* GPIO value query function */
-static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[1];     /* Buffer for SPI transfer */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return -EINVAL;
-       }
-
-       /* Read current GPIO data register */
-       buf[0] = MAX3107_GPIODATA_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n");
-               return -EIO;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-
-       /* Return value */
-       return buf[0] & (0x0001 << offset);
-}
-
-/* GPIO value set function */
-static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
-       u16 buf[2];     /* Buffer for SPI transfers */
-
-       if (offset >= MAX3107_GPIO_COUNT) {
-               dev_err(&s->spi->dev, "Invalid GPIO\n");
-               return;
-       }
-
-       /* Read current GPIO configuration registers*/
-       buf[0] = MAX3107_GPIODATA_REG;
-       buf[1] = MAX3107_GPIOCFG_REG;
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for GPIO data and config read failed\n");
-               return;
-       }
-       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
-       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
-
-       if (!(buf[1] & (0x0001 << offset))) {
-               /* Configured as input, can't set value */
-               dev_warn(&s->spi->dev,
-                               "Trying to set value for input GPIO\n");
-               return;
-       }
-
-       /* Set value */
-       if (value)
-               buf[0] |= (0x0001 << offset);
-       else
-               buf[0] &= ~(0x0001 << offset);
-
-       /* Write new GPIO data register value */
-       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 2))
-               dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n");
-}
-
-/* GPIO chip data */
-static struct gpio_chip max3107_gpio_chip = {
-       .owner                  = THIS_MODULE,
-       .direction_input        = max3107_gpio_direction_in,
-       .direction_output       = max3107_gpio_direction_out,
-       .get                    = max3107_gpio_get,
-       .set                    = max3107_gpio_set,
-       .can_sleep              = 1,
-       .base                   = MAX3107_GPIO_BASE,
-       .ngpio                  = MAX3107_GPIO_COUNT,
-};
-
-/**
- *     max3107_aava_reset      -       reset on AAVA systems
- *     @spi: The SPI device we are probing
- *
- *     Reset the device ready for probing.
- */
-
-static int max3107_aava_reset(struct spi_device *spi)
-{
-       /* Reset the chip */
-       if (gpio_request(MAX3107_RESET_GPIO, "max3107")) {
-               pr_err("Requesting RESET GPIO failed\n");
-               return -EIO;
-       }
-       if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) {
-               pr_err("Setting RESET GPIO to 0 failed\n");
-               gpio_free(MAX3107_RESET_GPIO);
-               return -EIO;
-       }
-       msleep(MAX3107_RESET_DELAY);
-       if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) {
-               pr_err("Setting RESET GPIO to 1 failed\n");
-               gpio_free(MAX3107_RESET_GPIO);
-               return -EIO;
-       }
-       gpio_free(MAX3107_RESET_GPIO);
-       msleep(MAX3107_WAKEUP_DELAY);
-       return 0;
-}
-
-static int max3107_aava_configure(struct max3107_port *s)
-{
-       int retval;
-
-       /* Initialize GPIO chip data */
-       s->chip = max3107_gpio_chip;
-       s->chip.label = s->spi->modalias;
-       s->chip.dev = &s->spi->dev;
-
-       /* Add GPIO chip */
-       retval = gpiochip_add(&s->chip);
-       if (retval) {
-               dev_err(&s->spi->dev, "Adding GPIO chip failed\n");
-               return retval;
-       }
-
-       /* Temporary fix for EV2 boot problems, set modem reset to 0 */
-       max3107_gpio_direction_out(&s->chip, 3, 0);
-       return 0;
-}
-
-#if 0
-/* This will get enabled once we have the board stuff merged for this
-   specific case */
-
-static const struct baud_table brg13_ext[] = {
-       { 300,    MAX3107_BRG13_B300 },
-       { 600,    MAX3107_BRG13_B600 },
-       { 1200,   MAX3107_BRG13_B1200 },
-       { 2400,   MAX3107_BRG13_B2400 },
-       { 4800,   MAX3107_BRG13_B4800 },
-       { 9600,   MAX3107_BRG13_B9600 },
-       { 19200,  MAX3107_BRG13_B19200 },
-       { 57600,  MAX3107_BRG13_B57600 },
-       { 115200, MAX3107_BRG13_B115200 },
-       { 230400, MAX3107_BRG13_B230400 },
-       { 460800, MAX3107_BRG13_B460800 },
-       { 921600, MAX3107_BRG13_B921600 },
-       { 0, 0 }
-};
-
-static void max3107_aava_init(struct max3107_port *s)
-{
-       /*override for AAVA SC specific*/
-       if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) {
-               if (get_koski_build_id() <= KOSKI_EV2)
-                       if (s->ext_clk) {
-                               s->brg_cfg = MAX3107_BRG13_B9600;
-                               s->baud_tbl = (struct baud_table *)brg13_ext;
-                       }
-       }
-}
-#endif
-
-static int __devexit max3107_aava_remove(struct spi_device *spi)
-{
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       /* Remove GPIO chip */
-       if (gpiochip_remove(&s->chip))
-               dev_warn(&spi->dev, "Removing GPIO chip failed\n");
-
-       /* Then do the default remove */
-       return max3107_remove(spi);
-}
-
-/* Platform data */
-static struct max3107_plat aava_plat_data = {
-       .loopback               = 0,
-       .ext_clk                = 1,
-/*     .init                   = max3107_aava_init, */
-       .configure              = max3107_aava_configure,
-       .hw_suspend             = max3107_hw_susp,
-       .polled_mode            = 0,
-       .poll_time              = 0,
-};
-
-
-static int __devinit max3107_probe_aava(struct spi_device *spi)
-{
-       int err = max3107_aava_reset(spi);
-       if (err < 0)
-               return err;
-       return max3107_probe(spi, &aava_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
-       .driver = {
-               .name           = "aava-max3107",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-       .probe          = max3107_probe_aava,
-       .remove         = __devexit_p(max3107_aava_remove),
-       .suspend        = max3107_suspend,
-       .resume         = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
-       return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
-       spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("aava-max3107-spi");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/max3107.c b/drivers/serial/max3107.c
deleted file mode 100644 (file)
index 910870e..0000000
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- *  max3107.c - spi uart protocol driver for Maxim 3107
- *  Based on max3100.c
- *     by Christian Pellegrin <chripell@evolware.org>
- *  and        max3110.c
- *     by Feng Tang <feng.tang@intel.com>
- *
- *  Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include "max3107.h"
-
-static const struct baud_table brg26_ext[] = {
-       { 300,    MAX3107_BRG26_B300 },
-       { 600,    MAX3107_BRG26_B600 },
-       { 1200,   MAX3107_BRG26_B1200 },
-       { 2400,   MAX3107_BRG26_B2400 },
-       { 4800,   MAX3107_BRG26_B4800 },
-       { 9600,   MAX3107_BRG26_B9600 },
-       { 19200,  MAX3107_BRG26_B19200 },
-       { 57600,  MAX3107_BRG26_B57600 },
-       { 115200, MAX3107_BRG26_B115200 },
-       { 230400, MAX3107_BRG26_B230400 },
-       { 460800, MAX3107_BRG26_B460800 },
-       { 921600, MAX3107_BRG26_B921600 },
-       { 0, 0 }
-};
-
-static const struct baud_table brg13_int[] = {
-       { 300,    MAX3107_BRG13_IB300 },
-       { 600,    MAX3107_BRG13_IB600 },
-       { 1200,   MAX3107_BRG13_IB1200 },
-       { 2400,   MAX3107_BRG13_IB2400 },
-       { 4800,   MAX3107_BRG13_IB4800 },
-       { 9600,   MAX3107_BRG13_IB9600 },
-       { 19200,  MAX3107_BRG13_IB19200 },
-       { 57600,  MAX3107_BRG13_IB57600 },
-       { 115200, MAX3107_BRG13_IB115200 },
-       { 230400, MAX3107_BRG13_IB230400 },
-       { 460800, MAX3107_BRG13_IB460800 },
-       { 921600, MAX3107_BRG13_IB921600 },
-       { 0, 0 }
-};
-
-static u32 get_new_brg(int baud, struct max3107_port *s)
-{
-       int i;
-       const struct baud_table *baud_tbl = s->baud_tbl;
-
-       for (i = 0; i < 13; i++) {
-               if (baud == baud_tbl[i].baud)
-                       return baud_tbl[i].new_brg;
-       }
-
-       return 0;
-}
-
-/* Perform SPI transfer for write/read of device register(s) */
-int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
-{
-       struct spi_message spi_msg;
-       struct spi_transfer spi_xfer;
-
-       /* Initialize SPI ,message */
-       spi_message_init(&spi_msg);
-
-       /* Initialize SPI transfer */
-       memset(&spi_xfer, 0, sizeof spi_xfer);
-       spi_xfer.len = len;
-       spi_xfer.tx_buf = tx;
-       spi_xfer.rx_buf = rx;
-       spi_xfer.speed_hz = MAX3107_SPI_SPEED;
-
-       /* Add SPI transfer to SPI message */
-       spi_message_add_tail(&spi_xfer, &spi_msg);
-
-#ifdef DBG_TRACE_SPI_DATA
-       {
-               int i;
-               pr_info("tx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-
-       /* Perform synchronous SPI transfer */
-       if (spi_sync(s->spi, &spi_msg)) {
-               dev_err(&s->spi->dev, "spi_sync failure\n");
-               return -EIO;
-       }
-
-#ifdef DBG_TRACE_SPI_DATA
-       if (spi_xfer.rx_buf) {
-               int i;
-               pr_info("rx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_rw);
-
-/* Puts received data to circular buffer */
-static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
-                                       int len)
-{
-       struct uart_port *port = &s->port;
-       struct tty_struct *tty;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Insert received data */
-       tty_insert_flip_string(tty, data, len);
-       /* Update RX counter */
-       port->icount.rx += len;
-}
-
-/* Handle data receiving */
-static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
-{
-       int i;
-       int j;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-       u8 *valid_str;
-
-       if (!s->rx_enabled)
-               /* RX is disabled */
-               return;
-
-       if (rxlvl == 0) {
-               /* RX fifo is empty */
-               return;
-       } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
-               dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
-               /* Ensure sanity of RX level */
-               rxlvl = MAX3107_RX_FIFO_SIZE;
-       }
-       if ((s->rxbuf == 0) || (s->rxstr == 0)) {
-               dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
-               return;
-       }
-       buf = s->rxbuf;
-       valid_str = s->rxstr;
-       while (rxlvl) {
-               pr_debug("rxlvl %d\n", rxlvl);
-               /* Clear buffer */
-               memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
-               len = 0;
-               if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
-                       /* First disable RX FIFO interrupt */
-                       pr_debug("Disabling RX INT\n");
-                       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
-                       buf[0] |= s->irqen_reg;
-                       len++;
-               }
-               /* Just increase the length by amount of words in FIFO since
-                * buffer was zeroed and SPI transfer of 0x0000 means reading
-                * from RX FIFO
-                */
-               len += rxlvl;
-               /* Append RX level query */
-               buf[len] = MAX3107_RXFIFOLVL_REG;
-               len++;
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
-                       dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
-                       return;
-               }
-
-               /* Skip RX FIFO interrupt disabling word if it was added */
-               j = ((len - 1) - rxlvl);
-               /* Read received words */
-               for (i = 0; i < rxlvl; i++, j++)
-                       valid_str[i] = (u8)buf[j];
-               put_data_to_circ_buf(s, valid_str, rxlvl);
-               /* Get new RX level */
-               rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       if (s->rx_enabled) {
-               /* RX still enabled, re-enable RX FIFO interrupt */
-               pr_debug("Enabling RX INT\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-               s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-               buf[0] |= s->irqen_reg;
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
-       }
-
-       /* Push the received data to receivers */
-       if (s->port.state->port.tty)
-               tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-
-/* Handle data sending */
-static void max3107_handletx(struct max3107_port *s)
-{
-       struct circ_buf *xmit = &s->port.state->xmit;
-       int i;
-       unsigned long flags;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-
-       if (!s->tx_fifo_empty)
-               /* Don't send more data before previous data is sent */
-               return;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
-               /* No data to send or TX is stopped */
-               return;
-
-       if (!s->txbuf) {
-               dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
-               return;
-       }
-       buf = s->txbuf;
-       /* Get length of data pending in circular buffer */
-       len = uart_circ_chars_pending(xmit);
-       if (len) {
-               /* Limit to size of TX FIFO */
-               if (len > MAX3107_TX_FIFO_SIZE)
-                       len = MAX3107_TX_FIFO_SIZE;
-
-               pr_debug("txlen %d\n", len);
-
-               /* Update TX counter */
-               s->port.icount.tx += len;
-
-               /* TX FIFO will no longer be empty */
-               s->tx_fifo_empty = 0;
-
-               i = 0;
-               if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
-                       /* First disable TX empty interrupt */
-                       pr_debug("Disabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               /* Add data to send */
-               spin_lock_irqsave(&s->port.lock, flags);
-               for ( ; i < len ; i++) {
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
-                       buf[i] |= ((u16)xmit->buf[xmit->tail] &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               }
-               spin_unlock_irqrestore(&s->port.lock, flags);
-               if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
-                       /* Enable TX empty interrupt */
-                       pr_debug("Enabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               if (!s->tx_enabled) {
-                       /* Enable TX */
-                       pr_debug("Enable TX\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       spin_lock_irqsave(&s->data_lock, flags);
-                       s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
-                       buf[i] |= s->mode1_reg;
-                       spin_unlock_irqrestore(&s->data_lock, flags);
-                       s->tx_enabled = 1;
-                       i++;
-                       len++;
-               }
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
-                       dev_err(&s->spi->dev,
-                               "SPI transfer TX handling failed\n");
-                       return;
-               }
-       }
-
-       /* Indicate wake up if circular buffer is getting low on data */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&s->port);
-
-}
-
-/* Handle interrupts
- * Also reads and returns current RX FIFO level
- */
-static u16 handle_interrupt(struct max3107_port *s)
-{
-       u16 buf[4];     /* Buffer for SPI transfers */
-       u8 irq_status;
-       u16 rx_level;
-       unsigned long flags;
-
-       /* Read IRQ status register */
-       buf[0] = MAX3107_IRQSTS_REG;
-       /* Read status IRQ status register */
-       buf[1] = MAX3107_STS_IRQSTS_REG;
-       /* Read LSR IRQ status register */
-       buf[2] = MAX3107_LSR_IRQSTS_REG;
-       /* Query RX level */
-       buf[3] = MAX3107_RXFIFOLVL_REG;
-
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for INTR handling failed\n");
-               return 0;
-       }
-
-       irq_status = (u8)buf[0];
-       pr_debug("IRQSTS %x\n", irq_status);
-       rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
-
-       if (irq_status & MAX3107_IRQ_LSR_BIT) {
-               /* LSR interrupt */
-               if (buf[2] & MAX3107_LSR_RXTO_BIT)
-                       /* RX timeout interrupt,
-                        * handled by normal RX handling
-                        */
-                       pr_debug("RX TO INT\n");
-       }
-
-       if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
-               /* Tx empty interrupt,
-                * disable TX and set tx_fifo_empty flag
-                */
-               pr_debug("TE INT, disabling TX\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-               spin_lock_irqsave(&s->data_lock, flags);
-               s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-               buf[0] |= s->mode1_reg;
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
-               s->tx_enabled = 0;
-               s->tx_fifo_empty = 1;
-       }
-
-       if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
-               /* RX FIFO interrupt,
-                * handled by normal RX handling
-                */
-               pr_debug("RFIFO INT\n");
-
-       /* Return RX level */
-       return rx_level;
-}
-
-/* Trigger work thread*/
-static void max3107_dowork(struct max3107_port *s)
-{
-       if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
-               queue_work(s->workqueue, &s->work);
-       else
-               dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
-}
-
-/* Work thread */
-static void max3107_work(struct work_struct *w)
-{
-       struct max3107_port *s = container_of(w, struct max3107_port, work);
-       u16 rxlvl = 0;
-       int len;        /* SPI transfer buffer length */
-       u16 buf[5];     /* Buffer for SPI transfers */
-       unsigned long flags;
-
-       /* Start by reading current RX FIFO level */
-       buf[0] = MAX3107_RXFIFOLVL_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
-               rxlvl = 0;
-       } else {
-               rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       do {
-               pr_debug("rxlvl %d\n", rxlvl);
-
-               /* Handle RX */
-               max3107_handlerx(s, rxlvl);
-               rxlvl = 0;
-
-               if (s->handle_irq) {
-                       /* Handle pending interrupts
-                        * We also get new RX FIFO level since new data may
-                        * have been received while pushing received data to
-                        * receivers
-                        */
-                       s->handle_irq = 0;
-                       rxlvl = handle_interrupt(s);
-               }
-
-               /* Handle TX */
-               max3107_handletx(s);
-
-               /* Handle configuration changes */
-               len = 0;
-               spin_lock_irqsave(&s->data_lock, flags);
-               if (s->mode1_commit) {
-                       pr_debug("mode1_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       buf[len++] |= s->mode1_reg;
-                       s->mode1_commit = 0;
-               }
-               if (s->lcr_commit) {
-                       pr_debug("lcr_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
-                       buf[len++] |= s->lcr_reg;
-                       s->lcr_commit = 0;
-               }
-               if (s->brg_commit) {
-                       pr_debug("brg_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 16) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 8) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
-                       buf[len++] |= ((s->brg_cfg) & 0xff);
-                       s->brg_commit = 0;
-               }
-               spin_unlock_irqrestore(&s->data_lock, flags);
-
-               if (len > 0) {
-                       if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
-                               dev_err(&s->spi->dev,
-                                       "SPI transfer config failed\n");
-               }
-
-               /* Reloop if interrupt handling indicated data in RX FIFO */
-       } while (rxlvl);
-
-}
-
-/* Set sleep mode */
-static void max3107_set_sleep(struct max3107_port *s, int mode)
-{
-       u16 buf[1];     /* Buffer for SPI transfer */
-       unsigned long flags;
-       pr_debug("enter, mode %d\n", mode);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-       spin_lock_irqsave(&s->data_lock, flags);
-       switch (mode) {
-       case MAX3107_DISABLE_FORCED_SLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_FORCED_SLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_DISABLE_AUTOSLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_AUTOSLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       default:
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               dev_warn(&s->spi->dev, "invalid sleep mode\n");
-               return;
-       }
-       buf[0] |= s->mode1_reg;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       if (max3107_rw(s, (u8 *)buf, NULL, 2))
-               dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
-
-       if (mode == MAX3107_DISABLE_AUTOSLEEP ||
-                       mode == MAX3107_DISABLE_FORCED_SLEEP)
-               msleep(MAX3107_WAKEUP_DELAY);
-}
-
-/* Perform full register initialization */
-static void max3107_register_init(struct max3107_port *s)
-{
-       u16 buf[11];    /* Buffer for SPI transfers */
-
-       /* 1. Configure baud rate, 9600 as default */
-       s->baud = 9600;
-       /* the below is default*/
-       if (s->ext_clk) {
-               s->brg_cfg = MAX3107_BRG26_B9600;
-               s->baud_tbl = (struct baud_table *)brg26_ext;
-       } else {
-               s->brg_cfg = MAX3107_BRG13_IB9600;
-               s->baud_tbl = (struct baud_table *)brg13_int;
-       }
-
-       if (s->pdata->init)
-               s->pdata->init(s);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
-               | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
-               | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
-               | ((s->brg_cfg) & 0xff);
-
-       /* 2. Configure LCR register, 8N1 mode by default */
-       s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
-       buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
-               | s->lcr_reg;
-
-       /* 3. Configure MODE 1 register */
-       s->mode1_reg = 0;
-       /* Enable IRQ pin */
-       s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
-       /* Disable TX */
-       s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-       s->tx_enabled = 0;
-       /* RX is enabled */
-       s->rx_enabled = 1;
-       buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
-               | s->mode1_reg;
-
-       /* 4. Configure MODE 2 register */
-       buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Enable loopback */
-               buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-       /* Reset FIFOs */
-       buf[5] |= MAX3107_MODE2_FIFORST_BIT;
-       s->tx_fifo_empty = 1;
-
-       /* 5. Configure FIFO trigger level register */
-       buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
-       /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
-       buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
-
-       /* 6. Configure flow control levels */
-       buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
-       /* Flow control halt level 96, resume level 48 */
-       buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
-
-       /* 7. Configure flow control */
-       buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
-       /* Enable auto CTS and auto RTS flow control */
-       buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
-
-       /* 8. Configure RX timeout register */
-       buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
-       /* Timeout after 48 character intervals */
-       buf[9] |= 0x0030;
-
-       /* 9. Configure LSR interrupt enable register */
-       buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
-       /* Enable RX timeout interrupt */
-       buf[10] |= MAX3107_LSR_RXTO_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 22))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-       /* 10. Clear IRQ status register by reading it */
-       buf[0] = MAX3107_IRQSTS_REG;
-
-       /* 11. Configure interrupt enable register */
-       /* Enable LSR interrupt */
-       s->irqen_reg = MAX3107_IRQ_LSR_BIT;
-       /* Enable RX FIFO interrupt */
-       s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
-               | s->irqen_reg;
-
-       /* 12. Clear FIFO reset that was set in step 6 */
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Keep loopback enabled */
-               buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-}
-
-/* IRQ handler */
-static irqreturn_t max3107_irq(int irqno, void *dev_id)
-{
-       struct max3107_port *s = dev_id;
-
-       if (irqno != s->spi->irq) {
-               /* Unexpected IRQ */
-               return IRQ_NONE;
-       }
-
-       /* Indicate irq */
-       s->handle_irq = 1;
-
-       /* Trigger work thread */
-       max3107_dowork(s);
-
-       return IRQ_HANDLED;
-}
-
-/* HW suspension function
- *
- * Currently autosleep is used to decrease current consumption, alternative
- * approach would be to set the chip to reset mode if UART is not being
- * used but that would mess the GPIOs
- *
- */
-void max3107_hw_susp(struct max3107_port *s, int suspend)
-{
-       pr_debug("enter, suspend %d\n", suspend);
-
-       if (suspend) {
-               /* Suspend requested,
-                * enable autosleep to decrease current consumption
-                */
-               s->suspended = 1;
-               max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
-       } else {
-               /* Resume requested,
-                * disable autosleep
-                */
-               s->suspended = 0;
-               max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
-       }
-}
-EXPORT_SYMBOL_GPL(max3107_hw_susp);
-
-/* Modem status IRQ enabling */
-static void max3107_enable_ms(struct uart_port *port)
-{
-       /* Modem status not supported */
-}
-
-/* Data send function */
-static void max3107_start_tx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Trigger work thread for sending data */
-       max3107_dowork(s);
-}
-
-/* Function for checking that there is no pending transfers */
-static unsigned int max3107_tx_empty(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       pr_debug("returning %d\n",
-                 (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
-       return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
-}
-
-/* Function for stopping RX */
-static void max3107_stop_rx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       unsigned long flags;
-
-       /* Set RX disabled in MODE 1 register */
-       spin_lock_irqsave(&s->data_lock, flags);
-       s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
-       s->mode1_commit = 1;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       /* Set RX disabled */
-       s->rx_enabled = 0;
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Function for returning control pin states */
-static unsigned int max3107_get_mctrl(struct uart_port *port)
-{
-       /* DCD and DSR are not wired and CTS/RTS is handled automatically
-        * so just indicate DSR and CAR asserted
-        */
-       return TIOCM_DSR | TIOCM_CAR;
-}
-
-/* Function for setting control pin states */
-static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
-        * so do nothing
-        */
-}
-
-/* Function for configuring UART parameters */
-static void max3107_set_termios(struct uart_port *port,
-                               struct ktermios *termios,
-                               struct ktermios *old)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       struct tty_struct *tty;
-       int baud;
-       u16 new_lcr = 0;
-       u32 new_brg = 0;
-       unsigned long flags;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Get new LCR register values */
-       /* Word size */
-       if ((termios->c_cflag & CSIZE) == CS7)
-               new_lcr |= MAX3107_LCR_WORD_LEN_7;
-       else
-               new_lcr |= MAX3107_LCR_WORD_LEN_8;
-
-       /* Parity */
-       if (termios->c_cflag & PARENB) {
-               new_lcr |= MAX3107_LCR_PARITY_BIT;
-               if (!(termios->c_cflag & PARODD))
-                       new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
-       }
-
-       /* Stop bits */
-       if (termios->c_cflag & CSTOPB) {
-               /* 2 stop bits */
-               new_lcr |= MAX3107_LCR_STOPLEN_BIT;
-       }
-
-       /* Mask termios capabilities we don't support */
-       termios->c_cflag &= ~CMSPAR;
-
-       /* Set status ignore mask */
-       s->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
-
-       /* Set low latency to immediately handle pushed data */
-       s->port.state->port.tty->low_latency = 1;
-
-       /* Get new baud rate generator configuration */
-       baud = tty_get_baud_rate(tty);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       new_brg = get_new_brg(baud, s);
-       /* if can't find the corrent config, use previous */
-       if (!new_brg) {
-               baud = s->baud;
-               new_brg = s->brg_cfg;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-       s->baud = baud;
-
-       /* Update timeout according to new baud rate */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       if (s->lcr_reg != new_lcr) {
-               s->lcr_reg = new_lcr;
-               s->lcr_commit = 1;
-       }
-       if (s->brg_cfg != new_brg) {
-               s->brg_cfg = new_brg;
-               s->brg_commit = 1;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Port shutdown function */
-static void max3107_shutdown(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       if (s->suspended && s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Free the interrupt */
-       free_irq(s->spi->irq, s);
-
-       if (s->workqueue) {
-               /* Flush and destroy work queue */
-               flush_workqueue(s->workqueue);
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-       }
-
-       /* Suspend HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-}
-
-/* Port startup function */
-static int max3107_startup(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Initialize work queue */
-       s->workqueue = create_freezeable_workqueue("max3107");
-       if (!s->workqueue) {
-               dev_err(&s->spi->dev, "Workqueue creation failed\n");
-               return -EBUSY;
-       }
-       INIT_WORK(&s->work, max3107_work);
-
-       /* Setup IRQ */
-       if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
-                       "max3107", s)) {
-               dev_err(&s->spi->dev, "IRQ reguest failed\n");
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-               return -EBUSY;
-       }
-
-       /* Resume HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Init registers */
-       max3107_register_init(s);
-
-       return 0;
-}
-
-/* Port type function */
-static const char *max3107_type(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       return s->spi->modalias;
-}
-
-/* Port release function */
-static void max3107_release_port(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port request function */
-static int max3107_request_port(struct uart_port *port)
-{
-       /* Do nothing */
-       return 0;
-}
-
-/* Port config function */
-static void max3107_config_port(struct uart_port *port, int flags)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       s->port.type = PORT_MAX3107;
-}
-
-/* Port verify function */
-static int max3107_verify_port(struct uart_port *port,
-                               struct serial_struct *ser)
-{
-       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
-               return 0;
-
-       return -EINVAL;
-}
-
-/* Port stop TX function */
-static void max3107_stop_tx(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port break control function */
-static void max3107_break_ctl(struct uart_port *port, int break_state)
-{
-       /* We don't support break control, do nothing */
-}
-
-
-/* Port functions */
-static struct uart_ops max3107_ops = {
-       .tx_empty       = max3107_tx_empty,
-       .set_mctrl      = max3107_set_mctrl,
-       .get_mctrl      = max3107_get_mctrl,
-       .stop_tx        = max3107_stop_tx,
-       .start_tx       = max3107_start_tx,
-       .stop_rx        = max3107_stop_rx,
-       .enable_ms      = max3107_enable_ms,
-       .break_ctl      = max3107_break_ctl,
-       .startup        = max3107_startup,
-       .shutdown       = max3107_shutdown,
-       .set_termios    = max3107_set_termios,
-       .type           = max3107_type,
-       .release_port   = max3107_release_port,
-       .request_port   = max3107_request_port,
-       .config_port    = max3107_config_port,
-       .verify_port    = max3107_verify_port,
-};
-
-/* UART driver data */
-static struct uart_driver max3107_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyMAX",
-       .dev_name       = "ttyMAX",
-       .nr             = 1,
-};
-
-static int driver_registered = 0;
-
-
-
-/* 'Generic' platform data */
-static struct max3107_plat generic_plat_data = {
-       .loopback               = 0,
-       .ext_clk                = 1,
-       .hw_suspend             = max3107_hw_susp,
-       .polled_mode            = 0,
-       .poll_time              = 0,
-};
-
-
-/*******************************************************************/
-
-/**
- *     max3107_probe           -       SPI bus probe entry point
- *     @spi: the spi device
- *
- *     SPI wants us to probe this device and if appropriate claim it.
- *     Perform any platform specific requirements and then initialise
- *     the device.
- */
-
-int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
-{
-       struct max3107_port *s;
-       u16 buf[2];     /* Buffer for SPI transfers */
-       int retval;
-
-       pr_info("enter max3107 probe\n");
-
-       /* Allocate port structure */
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (!s) {
-               pr_err("Allocating port structure failed\n");
-               return -ENOMEM;
-       }
-
-       s->pdata = pdata;
-
-       /* SPI Rx buffer
-        * +2 for RX FIFO interrupt
-        * disabling and RX level query
-        */
-       s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
-       if (!s->rxbuf) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free4;
-       }
-       s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
-       if (!s->rxstr) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free3;
-       }
-       /* SPI Tx buffer
-        * SPI transfer buffer
-        * +3 for TX FIFO empty
-        * interrupt disabling and
-        * enabling and TX enabling
-        */
-       s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
-       if (!s->txbuf) {
-               pr_err("Allocating TX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free2;
-       }
-       /* Initialize shared data lock */
-       spin_lock_init(&s->data_lock);
-
-       /* SPI intializations */
-       dev_set_drvdata(&spi->dev, s);
-       spi->mode = SPI_MODE_0;
-       spi->dev.platform_data = pdata;
-       spi->bits_per_word = 16;
-       s->ext_clk = pdata->ext_clk;
-       s->loopback = pdata->loopback;
-       spi_setup(spi);
-       s->spi = spi;
-
-       /* Check REV ID to ensure we are talking to what we expect */
-       buf[0] = MAX3107_REVID_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-       if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
-               (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
-               dev_err(&s->spi->dev, "REVID %x does not match\n",
-                               (buf[0] & MAX3107_SPI_RX_DATA_MASK));
-               retval = -ENODEV;
-               goto err_free1;
-       }
-
-       /* Disable all interrupts */
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
-       buf[0] |= 0x0000;
-
-       /* Configure clock source */
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
-       if (s->ext_clk) {
-               /* External clock */
-               buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
-       }
-
-       /* PLL bypass ON */
-       buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-
-       /* Register UART driver */
-       if (!driver_registered) {
-               retval = uart_register_driver(&max3107_uart_driver);
-               if (retval) {
-                       dev_err(&s->spi->dev, "Registering UART driver failed\n");
-                       goto err_free1;
-               }
-               driver_registered = 1;
-       }
-
-       /* Initialize UART port data */
-       s->port.fifosize = 128;
-       s->port.ops = &max3107_ops;
-       s->port.line = 0;
-       s->port.dev = &spi->dev;
-       s->port.uartclk = 9600;
-       s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       s->port.irq = s->spi->irq;
-       s->port.type = PORT_MAX3107;
-
-       /* Add UART port */
-       retval = uart_add_one_port(&max3107_uart_driver, &s->port);
-       if (retval < 0) {
-               dev_err(&s->spi->dev, "Adding UART port failed\n");
-               goto err_free1;
-       }
-
-       if (pdata->configure) {
-               retval = pdata->configure(s);
-               if (retval < 0)
-                       goto err_free1;
-       }
-
-       /* Go to suspend mode */
-       if (pdata->hw_suspend)
-               pdata->hw_suspend(s, 1);
-
-       return 0;
-
-err_free1:
-       kfree(s->txbuf);
-err_free2:
-       kfree(s->rxstr);
-err_free3:
-       kfree(s->rxbuf);
-err_free4:
-       kfree(s);
-       return retval;
-}
-EXPORT_SYMBOL_GPL(max3107_probe);
-
-/* Driver remove function */
-int max3107_remove(struct spi_device *spi)
-{
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_info("enter max3107 remove\n");
-
-       /* Remove port */
-       if (uart_remove_one_port(&max3107_uart_driver, &s->port))
-               dev_warn(&s->spi->dev, "Removing UART port failed\n");
-
-
-       /* Free TxRx buffer */
-       kfree(s->rxbuf);
-       kfree(s->rxstr);
-       kfree(s->txbuf);
-
-       /* Free port structure */
-       kfree(s);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_remove);
-
-/* Driver suspend function */
-int max3107_suspend(struct spi_device *spi, pm_message_t state)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter suspend\n");
-
-       /* Suspend UART port */
-       uart_suspend_port(&max3107_uart_driver, &s->port);
-
-       /* Go to suspend mode */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_suspend);
-
-/* Driver resume function */
-int max3107_resume(struct spi_device *spi)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter resume\n");
-
-       /* Resume from suspend */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Resume UART port */
-       uart_resume_port(&max3107_uart_driver, &s->port);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_resume);
-
-static int max3107_probe_generic(struct spi_device *spi)
-{
-       return max3107_probe(spi, &generic_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
-       .driver = {
-               .name           = "max3107",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-       .probe          = max3107_probe_generic,
-       .remove         = __devexit_p(max3107_remove),
-       .suspend        = max3107_suspend,
-       .resume         = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
-       pr_info("enter max3107 init\n");
-       return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
-       pr_info("enter max3107 exit\n");
-       /* Unregister UART driver */
-       if (driver_registered)
-               uart_unregister_driver(&max3107_uart_driver);
-       spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("max3107-spi");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/max3107.h b/drivers/serial/max3107.h
deleted file mode 100644 (file)
index 7ab6323..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * max3107.h - spi uart protocol driver header for Maxim 3107
- *
- * Copyright (C) Aavamobile 2009
- * Based on serial_max3100.h by Christian Pellegrin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _MAX3107_H
-#define _MAX3107_H
-
-/* Serial error status definitions */
-#define MAX3107_PARITY_ERROR   1
-#define MAX3107_FRAME_ERROR    2
-#define MAX3107_OVERRUN_ERROR  4
-#define MAX3107_ALL_ERRORS     (MAX3107_PARITY_ERROR | \
-                                MAX3107_FRAME_ERROR | \
-                                MAX3107_OVERRUN_ERROR)
-
-/* GPIO definitions */
-#define MAX3107_GPIO_BASE      88
-#define MAX3107_GPIO_COUNT     4
-
-
-/* GPIO connected to chip's reset pin */
-#define MAX3107_RESET_GPIO     87
-
-
-/* Chip reset delay */
-#define MAX3107_RESET_DELAY    10
-
-/* Chip wakeup delay */
-#define MAX3107_WAKEUP_DELAY   50
-
-
-/* Sleep mode definitions */
-#define MAX3107_DISABLE_FORCED_SLEEP   0
-#define MAX3107_ENABLE_FORCED_SLEEP    1
-#define MAX3107_DISABLE_AUTOSLEEP      2
-#define MAX3107_ENABLE_AUTOSLEEP       3
-
-
-/* Definitions for register access with SPI transfers
- *
- * SPI transfer format:
- *
- * Master to slave bits xzzzzzzzyyyyyyyy
- * Slave to master bits aaaaaaaabbbbbbbb
- *
- * where:
- * x = 0 for reads, 1 for writes
- * z = register address
- * y = new register value if write, 0 if read
- * a = unspecified
- * b = register value if read, unspecified if write
- */
-
-/* SPI speed */
-#define MAX3107_SPI_SPEED      (3125000 * 2)
-
-/* Write bit */
-#define MAX3107_WRITE_BIT      (1 << 15)
-
-/* SPI TX data mask */
-#define MAX3107_SPI_RX_DATA_MASK       (0x00ff)
-
-/* SPI RX data mask */
-#define MAX3107_SPI_TX_DATA_MASK       (0x00ff)
-
-/* Register access masks */
-#define MAX3107_RHR_REG                        (0x0000) /* RX FIFO */
-#define MAX3107_THR_REG                        (0x0000) /* TX FIFO */
-#define MAX3107_IRQEN_REG              (0x0100) /* IRQ enable */
-#define MAX3107_IRQSTS_REG             (0x0200) /* IRQ status */
-#define MAX3107_LSR_IRQEN_REG          (0x0300) /* LSR IRQ enable */
-#define MAX3107_LSR_IRQSTS_REG         (0x0400) /* LSR IRQ status */
-#define MAX3107_SPCHR_IRQEN_REG                (0x0500) /* Special char IRQ enable */
-#define MAX3107_SPCHR_IRQSTS_REG       (0x0600) /* Special char IRQ status */
-#define MAX3107_STS_IRQEN_REG          (0x0700) /* Status IRQ enable */
-#define MAX3107_STS_IRQSTS_REG         (0x0800) /* Status IRQ status */
-#define MAX3107_MODE1_REG              (0x0900) /* MODE1 */
-#define MAX3107_MODE2_REG              (0x0a00) /* MODE2 */
-#define MAX3107_LCR_REG                        (0x0b00) /* LCR */
-#define MAX3107_RXTO_REG               (0x0c00) /* RX timeout */
-#define MAX3107_HDPIXDELAY_REG         (0x0d00) /* Auto transceiver delays */
-#define MAX3107_IRDA_REG               (0x0e00) /* IRDA settings */
-#define MAX3107_FLOWLVL_REG            (0x0f00) /* Flow control levels */
-#define MAX3107_FIFOTRIGLVL_REG                (0x1000) /* FIFO IRQ trigger levels */
-#define MAX3107_TXFIFOLVL_REG          (0x1100) /* TX FIFO level */
-#define MAX3107_RXFIFOLVL_REG          (0x1200) /* RX FIFO level */
-#define MAX3107_FLOWCTRL_REG           (0x1300) /* Flow control */
-#define MAX3107_XON1_REG               (0x1400) /* XON1 character */
-#define MAX3107_XON2_REG               (0x1500) /* XON2 character */
-#define MAX3107_XOFF1_REG              (0x1600) /* XOFF1 character */
-#define MAX3107_XOFF2_REG              (0x1700) /* XOFF2 character */
-#define MAX3107_GPIOCFG_REG            (0x1800) /* GPIO config */
-#define MAX3107_GPIODATA_REG           (0x1900) /* GPIO data */
-#define MAX3107_PLLCFG_REG             (0x1a00) /* PLL config */
-#define MAX3107_BRGCFG_REG             (0x1b00) /* Baud rate generator conf */
-#define MAX3107_BRGDIVLSB_REG          (0x1c00) /* Baud rate divisor LSB */
-#define MAX3107_BRGDIVMSB_REG          (0x1d00) /* Baud rate divisor MSB */
-#define MAX3107_CLKSRC_REG             (0x1e00) /* Clock source */
-#define MAX3107_REVID_REG              (0x1f00) /* Revision identification */
-
-/* IRQ register bits */
-#define MAX3107_IRQ_LSR_BIT    (1 << 0) /* LSR interrupt */
-#define MAX3107_IRQ_SPCHR_BIT  (1 << 1) /* Special char interrupt */
-#define MAX3107_IRQ_STS_BIT    (1 << 2) /* Status interrupt */
-#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
-#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
-#define MAX3107_IRQ_TXEMPTY_BIT        (1 << 5) /* TX FIFO empty interrupt */
-#define MAX3107_IRQ_RXEMPTY_BIT        (1 << 6) /* RX FIFO empty interrupt */
-#define MAX3107_IRQ_CTS_BIT    (1 << 7) /* CTS interrupt */
-
-/* LSR register bits */
-#define MAX3107_LSR_RXTO_BIT   (1 << 0) /* RX timeout */
-#define MAX3107_LSR_RXOVR_BIT  (1 << 1) /* RX overrun */
-#define MAX3107_LSR_RXPAR_BIT  (1 << 2) /* RX parity error */
-#define MAX3107_LSR_FRERR_BIT  (1 << 3) /* Frame error */
-#define MAX3107_LSR_RXBRK_BIT  (1 << 4) /* RX break */
-#define MAX3107_LSR_RXNOISE_BIT        (1 << 5) /* RX noise */
-#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_LSR_CTS_BIT    (1 << 7) /* CTS pin state */
-
-/* Special character register bits */
-#define MAX3107_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
-#define MAX3107_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
-#define MAX3107_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
-#define MAX3107_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
-#define MAX3107_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
-#define MAX3107_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
-#define MAX3107_SPCHR_UNDEF6_BIT       (1 << 6) /* Undefined/not used */
-#define MAX3107_SPCHR_UNDEF7_BIT       (1 << 7) /* Undefined/not used */
-
-/* Status register bits */
-#define MAX3107_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
-#define MAX3107_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
-#define MAX3107_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
-#define MAX3107_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
-#define MAX3107_STS_UNDEF4_BIT         (1 << 4) /* Undefined/not used */
-#define MAX3107_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
-#define MAX3107_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
-#define MAX3107_STS_UNDEF7_BIT         (1 << 7) /* Undefined/not used */
-
-/* MODE1 register bits */
-#define MAX3107_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
-#define MAX3107_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
-#define MAX3107_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
-#define MAX3107_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
-#define MAX3107_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
-#define MAX3107_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
-#define MAX3107_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
-#define MAX3107_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
-
-/* MODE2 register bits */
-#define MAX3107_MODE2_RST_BIT          (1 << 0) /* Chip reset */
-#define MAX3107_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
-#define MAX3107_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
-#define MAX3107_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
-#define MAX3107_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
-#define MAX3107_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
-#define MAX3107_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
-#define MAX3107_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
-
-/* LCR register bits */
-#define MAX3107_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
-#define MAX3107_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
-                                                 *
-                                                 * Word length bits table:
-                                                 * 00 -> 5 bit words
-                                                 * 01 -> 6 bit words
-                                                 * 10 -> 7 bit words
-                                                 * 11 -> 8 bit words
-                                                 */
-#define MAX3107_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
-                                                 *
-                                                 * STOP length bit table:
-                                                 * 0 -> 1 stop bit
-                                                 * 1 -> 1-1.5 stop bits if
-                                                 *      word length is 5,
-                                                 *      2 stop bits otherwise
-                                                 */
-#define MAX3107_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
-#define MAX3107_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
-#define MAX3107_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
-#define MAX3107_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
-#define MAX3107_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
-#define MAX3107_LCR_WORD_LEN_5         (0x0000)
-#define MAX3107_LCR_WORD_LEN_6         (0x0001)
-#define MAX3107_LCR_WORD_LEN_7         (0x0002)
-#define MAX3107_LCR_WORD_LEN_8         (0x0003)
-
-
-/* IRDA register bits */
-#define MAX3107_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
-#define MAX3107_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
-#define MAX3107_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
-#define MAX3107_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
-#define MAX3107_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
-#define MAX3107_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
-#define MAX3107_IRDA_UNDEF6_BIT                (1 << 6) /* Undefined/not used */
-#define MAX3107_IRDA_UNDEF7_BIT                (1 << 7) /* Undefined/not used */
-
-/* Flow control trigger level register masks */
-#define MAX3107_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
-#define MAX3107_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
-#define MAX3107_FLOWLVL_HALT(words)    ((words/8) & 0x000f)
-#define MAX3107_FLOWLVL_RES(words)     (((words/8) & 0x000f) << 4)
-
-/* FIFO interrupt trigger level register masks */
-#define MAX3107_FIFOTRIGLVL_TX_MASK    (0x000f) /* TX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_RX_MASK    (0x00f0) /* RX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_TX(words)  ((words/8) & 0x000f)
-#define MAX3107_FIFOTRIGLVL_RX(words)  (((words/8) & 0x000f) << 4)
-
-/* Flow control register bits */
-#define MAX3107_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
-                                                 * are used in conjunction with
-                                                 * XOFF2 for definition of
-                                                 * special character */
-#define MAX3107_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
-#define MAX3107_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
-#define MAX3107_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
-                                                 *
-                                                 * SWFLOW bits 1 & 0 table:
-                                                 * 00 -> no transmitter flow
-                                                 *       control
-                                                 * 01 -> receiver compares
-                                                 *       XON2 and XOFF2
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 10 -> receiver compares
-                                                 *       XON1 and XOFF1
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 11 -> receiver compares
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2 and controls
-                                                 *       transmitter
-                                                 */
-#define MAX3107_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
-#define MAX3107_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
-                                                 *
-                                                 * SWFLOW bits 3 & 2 table:
-                                                 * 00 -> no received flow
-                                                 *       control
-                                                 * 01 -> transmitter generates
-                                                 *       XON2 and XOFF2
-                                                 * 10 -> transmitter generates
-                                                 *       XON1 and XOFF1
-                                                 * 11 -> transmitter generates
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2
-                                                 */
-
-/* GPIO configuration register bits */
-#define MAX3107_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
-#define MAX3107_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
-#define MAX3107_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
-#define MAX3107_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
-#define MAX3107_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX3107_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX3107_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX3107_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX3107_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
-#define MAX3107_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
-#define MAX3107_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
-#define MAX3107_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
-#define MAX3107_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
-#define MAX3107_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
-#define MAX3107_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
-#define MAX3107_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
-
-/* PLL configuration register masks */
-#define MAX3107_PLLCFG_PREDIV_MASK     (0x003f) /* PLL predivision value */
-#define MAX3107_PLLCFG_PLLFACTOR_MASK  (0x00c0) /* PLL multiplication factor */
-
-/* Baud rate generator configuration register masks and bits */
-#define MAX3107_BRGCFG_FRACT_MASK      (0x000f) /* Fractional portion of
-                                                 * Baud rate generator divisor
-                                                 */
-#define MAX3107_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
-#define MAX3107_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
-#define MAX3107_BRGCFG_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_BRGCFG_UNDEF7_BIT      (1 << 7) /* Undefined/not used */
-
-/* Clock source register bits */
-#define MAX3107_CLKSRC_INTOSC_BIT      (1 << 0) /* Internal osc enable */
-#define MAX3107_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
-#define MAX3107_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
-#define MAX3107_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
-#define MAX3107_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
-#define MAX3107_CLKSRC_UNDEF5_BIT      (1 << 5) /* Undefined/not used */
-#define MAX3107_CLKSRC_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
-
-
-/* HW definitions */
-#define MAX3107_RX_FIFO_SIZE   128
-#define MAX3107_TX_FIFO_SIZE   128
-#define MAX3107_REVID1         0x00a0
-#define MAX3107_REVID2         0x00a1
-
-
-/* Baud rate generator configuration values for external clock 13MHz */
-#define MAX3107_BRG13_B300     (0x0A9400 | 0x05)
-#define MAX3107_BRG13_B600     (0x054A00 | 0x03)
-#define MAX3107_BRG13_B1200    (0x02A500 | 0x01)
-#define MAX3107_BRG13_B2400    (0x015200 | 0x09)
-#define MAX3107_BRG13_B4800    (0x00A900 | 0x04)
-#define MAX3107_BRG13_B9600    (0x005400 | 0x0A)
-#define MAX3107_BRG13_B19200   (0x002A00 | 0x05)
-#define MAX3107_BRG13_B38400   (0x001500 | 0x03)
-#define MAX3107_BRG13_B57600   (0x000E00 | 0x02)
-#define MAX3107_BRG13_B115200  (0x000700 | 0x01)
-#define MAX3107_BRG13_B230400  (0x000300 | 0x08)
-#define MAX3107_BRG13_B460800  (0x000100 | 0x0c)
-#define MAX3107_BRG13_B921600  (0x000100 | 0x1c)
-
-/* Baud rate generator configuration values for external clock 26MHz */
-#define MAX3107_BRG26_B300     (0x152800 | 0x0A)
-#define MAX3107_BRG26_B600     (0x0A9400 | 0x05)
-#define MAX3107_BRG26_B1200    (0x054A00 | 0x03)
-#define MAX3107_BRG26_B2400    (0x02A500 | 0x01)
-#define MAX3107_BRG26_B4800    (0x015200 | 0x09)
-#define MAX3107_BRG26_B9600    (0x00A900 | 0x04)
-#define MAX3107_BRG26_B19200   (0x005400 | 0x0A)
-#define MAX3107_BRG26_B38400   (0x002A00 | 0x05)
-#define MAX3107_BRG26_B57600   (0x001C00 | 0x03)
-#define MAX3107_BRG26_B115200  (0x000E00 | 0x02)
-#define MAX3107_BRG26_B230400  (0x000700 | 0x01)
-#define MAX3107_BRG26_B460800  (0x000300 | 0x08)
-#define MAX3107_BRG26_B921600  (0x000100 | 0x0C)
-
-/* Baud rate generator configuration values for internal clock */
-#define MAX3107_BRG13_IB300    (0x008000 | 0x00)
-#define MAX3107_BRG13_IB600    (0x004000 | 0x00)
-#define MAX3107_BRG13_IB1200   (0x002000 | 0x00)
-#define MAX3107_BRG13_IB2400   (0x001000 | 0x00)
-#define MAX3107_BRG13_IB4800   (0x000800 | 0x00)
-#define MAX3107_BRG13_IB9600   (0x000400 | 0x00)
-#define MAX3107_BRG13_IB19200  (0x000200 | 0x00)
-#define MAX3107_BRG13_IB38400  (0x000100 | 0x00)
-#define MAX3107_BRG13_IB57600  (0x000000 | 0x0B)
-#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
-#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
-#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
-#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
-
-
-struct baud_table {
-       int baud;
-       u32 new_brg;
-};
-
-struct max3107_port {
-       /* UART port structure */
-       struct uart_port port;
-
-       /* SPI device structure */
-       struct spi_device *spi;
-
-#if defined(CONFIG_GPIOLIB)
-       /* GPIO chip stucture */
-       struct gpio_chip chip;
-#endif
-
-       /* Workqueue that does all the magic */
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-
-       /* Lock for shared data */
-       spinlock_t data_lock;
-
-       /* Device configuration */
-       int ext_clk;            /* 1 if external clock used */
-       int loopback;           /* Current loopback mode state */
-       int baud;                       /* Current baud rate */
-
-       /* State flags */
-       int suspended;          /* Indicates suspend mode */
-       int tx_fifo_empty;      /* Flag for TX FIFO state */
-       int rx_enabled;         /* Flag for receiver state */
-       int tx_enabled;         /* Flag for transmitter state */
-
-       u16 irqen_reg;          /* Current IRQ enable register value */
-       /* Shared data */
-       u16 mode1_reg;          /* Current mode1 register value*/
-       int mode1_commit;       /* Flag for setting new mode1 register value */
-       u16 lcr_reg;            /* Current LCR register value */
-       int lcr_commit;         /* Flag for setting new LCR register value */
-       u32 brg_cfg;            /* Current Baud rate generator config  */
-       int brg_commit;         /* Flag for setting new baud rate generator
-                                * config
-                                */
-       struct baud_table *baud_tbl;
-       int handle_irq;         /* Indicates that IRQ should be handled */
-
-       /* Rx buffer and str*/
-       u16 *rxbuf;
-       u8  *rxstr;
-       /* Tx buffer*/
-       u16 *txbuf;
-
-       struct max3107_plat *pdata;     /* Platform data */
-};
-
-/* Platform data structure */
-struct max3107_plat {
-       /* Loopback mode enable */
-       int loopback;
-       /* External clock enable */
-       int ext_clk;
-       /* Called during the register initialisation */
-       void (*init)(struct max3107_port *s);
-       /* Called when the port is found and configured */
-       int (*configure)(struct max3107_port *s);
-       /* HW suspend function */
-       void (*hw_suspend) (struct max3107_port *s, int suspend);
-       /* Polling mode enable */
-       int polled_mode;
-       /* Polling period if polling mode enabled */
-       int poll_time;
-};
-
-extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
-extern void max3107_hw_susp(struct max3107_port *s, int suspend);
-extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
-extern int max3107_remove(struct spi_device *spi);
-extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
-extern int max3107_resume(struct spi_device *spi);
-
-#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
deleted file mode 100644 (file)
index 3394b7c..0000000
+++ /dev/null
@@ -1,662 +0,0 @@
-/****************************************************************************/
-
-/*
- *     mcf.c -- Freescale ColdFire UART driver
- *
- *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-
-/****************************************************************************/
-
-/*
- *     Some boards implement the DTR/DCD lines using GPIO lines, most
- *     don't. Dummy out the access macros for those that don't. Those
- *     that do should define these macros somewhere in there board
- *     specific inlude files.
- */
-#if !defined(mcf_getppdcd)
-#define        mcf_getppdcd(p)         (1)
-#endif
-#if !defined(mcf_getppdtr)
-#define        mcf_getppdtr(p)         (1)
-#endif
-#if !defined(mcf_setppdtr)
-#define        mcf_setppdtr(p, v)      do { } while (0)
-#endif
-
-/****************************************************************************/
-
-/*
- *     Local per-uart structure.
- */
-struct mcf_uart {
-       struct uart_port        port;
-       unsigned int            sigs;           /* Local copy of line sigs */
-       unsigned char           imr;            /* Local IMR mirror */
-};
-
-/****************************************************************************/
-
-static unsigned int mcf_tx_empty(struct uart_port *port)
-{
-       return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
-               TIOCSER_TEMT : 0;
-}
-
-/****************************************************************************/
-
-static unsigned int mcf_get_mctrl(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned int sigs;
-
-       sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
-               0 : TIOCM_CTS;
-       sigs |= (pp->sigs & TIOCM_RTS);
-       sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
-       sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
-
-       return sigs;
-}
-
-/****************************************************************************/
-
-static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->sigs = sigs;
-       mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
-       if (sigs & TIOCM_RTS)
-               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
-       else
-               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
-}
-
-/****************************************************************************/
-
-static void mcf_start_tx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr |= MCFUART_UIR_TXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_stop_tx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr &= ~MCFUART_UIR_TXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_stop_rx(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-
-       pp->imr &= ~MCFUART_UIR_RXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-}
-
-/****************************************************************************/
-
-static void mcf_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
-       else
-               writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_enable_ms(struct uart_port *port)
-{
-}
-
-/****************************************************************************/
-
-static int mcf_startup(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Reset UART, get it into known state... */
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-
-       /* Enable the UART transmitter and receiver */
-       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
-               port->membase + MCFUART_UCR);
-
-       /* Enable RX interrupts now */
-       pp->imr = MCFUART_UIR_RXREADY;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_shutdown(struct uart_port *port)
-{
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Disable all interrupts now */
-       pp->imr = 0;
-       writeb(pp->imr, port->membase + MCFUART_UIMR);
-
-       /* Disable UART transmitter and receiver */
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
-       struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, baudclk;
-#if defined(CONFIG_M5272)
-       unsigned int baudfr;
-#endif
-       unsigned char mr1, mr2;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-#if defined(CONFIG_M5272)
-       baudclk = (MCF_BUSCLK / baud) / 32;
-       baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
-#else
-       baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
-#endif
-
-       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
-       mr2 = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5: mr1 |= MCFUART_MR1_CS5; break;
-       case CS6: mr1 |= MCFUART_MR1_CS6; break;
-       case CS7: mr1 |= MCFUART_MR1_CS7; break;
-       case CS8:
-       default:  mr1 |= MCFUART_MR1_CS8; break;
-       }
-
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYMARK;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYSPACE;
-               } else {
-                       if (termios->c_cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYODD;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYEVEN;
-               }
-       } else {
-               mr1 |= MCFUART_MR1_PARITYNONE;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               mr2 |= MCFUART_MR2_STOP2;
-       else
-               mr2 |= MCFUART_MR2_STOP1;
-
-       if (termios->c_cflag & CRTSCTS) {
-               mr1 |= MCFUART_MR1_RXRTS;
-               mr2 |= MCFUART_MR2_TXCTS;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
-       writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
-       writeb(mr1, port->membase + MCFUART_UMR);
-       writeb(mr2, port->membase + MCFUART_UMR);
-       writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
-       writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
-#if defined(CONFIG_M5272)
-       writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
-#endif
-       writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
-               port->membase + MCFUART_UCSR);
-       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
-               port->membase + MCFUART_UCR);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_rx_chars(struct mcf_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       unsigned char status, ch, flag;
-
-       while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
-               ch = readb(port->membase + MCFUART_URB);
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (status & MCFUART_USR_RXERR) {
-                       writeb(MCFUART_UCR_CMDRESETERR,
-                               port->membase + MCFUART_UCR);
-
-                       if (status & MCFUART_USR_RXBREAK) {
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & MCFUART_USR_RXPARITY) {
-                               port->icount.parity++;
-                       } else if (status & MCFUART_USR_RXOVERRUN) {
-                               port->icount.overrun++;
-                       } else if (status & MCFUART_USR_RXFRAMING) {
-                               port->icount.frame++;
-                       }
-
-                       status &= port->read_status_mask;
-
-                       if (status & MCFUART_USR_RXBREAK)
-                               flag = TTY_BREAK;
-                       else if (status & MCFUART_USR_RXPARITY)
-                               flag = TTY_PARITY;
-                       else if (status & MCFUART_USR_RXFRAMING)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-               uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
-       }
-
-       tty_flip_buffer_push(port->state->port.tty);
-}
-
-/****************************************************************************/
-
-static void mcf_tx_chars(struct mcf_uart *pp)
-{
-       struct uart_port *port = &pp->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               /* Send special char - probably flow control */
-               writeb(port->x_char, port->membase + MCFUART_UTB);
-               port->x_char = 0;
-               port->icount.tx++;
-               return;
-       }
-
-       while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
-               if (xmit->head == xmit->tail)
-                       break;
-               writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (xmit->head == xmit->tail) {
-               pp->imr &= ~MCFUART_UIR_TXREADY;
-               writeb(pp->imr, port->membase + MCFUART_UIMR);
-       }
-}
-
-/****************************************************************************/
-
-static irqreturn_t mcf_interrupt(int irq, void *data)
-{
-       struct uart_port *port = data;
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
-       unsigned int isr;
-       irqreturn_t ret = IRQ_NONE;
-
-       isr = readb(port->membase + MCFUART_UISR) & pp->imr;
-
-       spin_lock(&port->lock);
-       if (isr & MCFUART_UIR_RXREADY) {
-               mcf_rx_chars(pp);
-               ret = IRQ_HANDLED;
-       }
-       if (isr & MCFUART_UIR_TXREADY) {
-               mcf_tx_chars(pp);
-               ret = IRQ_HANDLED;
-       }
-       spin_unlock(&port->lock);
-
-       return ret;
-}
-
-/****************************************************************************/
-
-static void mcf_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_MCF;
-       port->fifosize = MCFUART_TXFIFOSIZE;
-
-       /* Clear mask, so no surprise interrupts. */
-       writeb(0, port->membase + MCFUART_UIMR);
-
-       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
-               printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
-                       "interrupt vector=%d\n", port->line, port->irq);
-}
-
-/****************************************************************************/
-
-static const char *mcf_type(struct uart_port *port)
-{
-       return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
-}
-
-/****************************************************************************/
-
-static int mcf_request_port(struct uart_port *port)
-{
-       /* UARTs always present */
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_release_port(struct uart_port *port)
-{
-       /* Nothing to release... */
-}
-
-/****************************************************************************/
-
-static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
-               return -EINVAL;
-       return 0;
-}
-
-/****************************************************************************/
-
-/*
- *     Define the basic serial functions we support.
- */
-static const struct uart_ops mcf_uart_ops = {
-       .tx_empty       = mcf_tx_empty,
-       .get_mctrl      = mcf_get_mctrl,
-       .set_mctrl      = mcf_set_mctrl,
-       .start_tx       = mcf_start_tx,
-       .stop_tx        = mcf_stop_tx,
-       .stop_rx        = mcf_stop_rx,
-       .enable_ms      = mcf_enable_ms,
-       .break_ctl      = mcf_break_ctl,
-       .startup        = mcf_startup,
-       .shutdown       = mcf_shutdown,
-       .set_termios    = mcf_set_termios,
-       .type           = mcf_type,
-       .request_port   = mcf_request_port,
-       .release_port   = mcf_release_port,
-       .config_port    = mcf_config_port,
-       .verify_port    = mcf_verify_port,
-};
-
-static struct mcf_uart mcf_ports[4];
-
-#define        MCF_MAXPORTS    ARRAY_SIZE(mcf_ports)
-
-/****************************************************************************/
-#if defined(CONFIG_SERIAL_MCF_CONSOLE)
-/****************************************************************************/
-
-int __init early_mcf_setup(struct mcf_platform_uart *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
-               port = &mcf_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_MCF;
-               port->mapbase = platp[i].mapbase;
-               port->membase = (platp[i].membase) ? platp[i].membase :
-                       (unsigned char __iomem *) port->mapbase;
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = MCF_BUSCLK;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-               port->ops = &mcf_uart_ops;
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static void mcf_console_putc(struct console *co, const char c)
-{
-       struct uart_port *port = &(mcf_ports + co->index)->port;
-       int i;
-
-       for (i = 0; (i < 0x10000); i++) {
-               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
-                       break;
-       }
-       writeb(c, port->membase + MCFUART_UTB);
-       for (i = 0; (i < 0x10000); i++) {
-               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
-                       break;
-       }
-}
-
-/****************************************************************************/
-
-static void mcf_console_write(struct console *co, const char *s, unsigned int count)
-{
-       for (; (count); count--, s++) {
-               mcf_console_putc(co, *s);
-               if (*s == '\n')
-                       mcf_console_putc(co, '\r');
-       }
-}
-
-/****************************************************************************/
-
-static int __init mcf_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = CONFIG_SERIAL_MCF_BAUDRATE;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
-               co->index = 0;
-       port = &mcf_ports[co->index].port;
-       if (port->membase == 0)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-/****************************************************************************/
-
-static struct uart_driver mcf_driver;
-
-static struct console mcf_console = {
-       .name           = "ttyS",
-       .write          = mcf_console_write,
-       .device         = uart_console_device,
-       .setup          = mcf_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &mcf_driver,
-};
-
-static int __init mcf_console_init(void)
-{
-       register_console(&mcf_console);
-       return 0;
-}
-
-console_initcall(mcf_console_init);
-
-#define        MCF_CONSOLE     &mcf_console
-
-/****************************************************************************/
-#else
-/****************************************************************************/
-
-#define        MCF_CONSOLE     NULL
-
-/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
-/****************************************************************************/
-
-/*
- *     Define the mcf UART driver structure.
- */
-static struct uart_driver mcf_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "mcf",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = MCF_MAXPORTS,
-       .cons           = MCF_CONSOLE,
-};
-
-/****************************************************************************/
-
-static int __devinit mcf_probe(struct platform_device *pdev)
-{
-       struct mcf_platform_uart *platp = pdev->dev.platform_data;
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
-               port = &mcf_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_MCF;
-               port->mapbase = platp[i].mapbase;
-               port->membase = (platp[i].membase) ? platp[i].membase :
-                       (unsigned char __iomem *) platp[i].mapbase;
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = MCF_BUSCLK;
-               port->ops = &mcf_uart_ops;
-               port->flags = ASYNC_BOOT_AUTOCONF;
-
-               uart_add_one_port(&mcf_driver, port);
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static int __devexit mcf_remove(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; (i < MCF_MAXPORTS); i++) {
-               port = &mcf_ports[i].port;
-               if (port)
-                       uart_remove_one_port(&mcf_driver, port);
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
-static struct platform_driver mcf_platform_driver = {
-       .probe          = mcf_probe,
-       .remove         = __devexit_p(mcf_remove),
-       .driver         = {
-               .name   = "mcfuart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-/****************************************************************************/
-
-static int __init mcf_init(void)
-{
-       int rc;
-
-       printk("ColdFire internal UART serial driver\n");
-
-       rc = uart_register_driver(&mcf_driver);
-       if (rc)
-               return rc;
-       rc = platform_driver_register(&mcf_platform_driver);
-       if (rc)
-               return rc;
-       return 0;
-}
-
-/****************************************************************************/
-
-static void __exit mcf_exit(void)
-{
-       platform_driver_unregister(&mcf_platform_driver);
-       uart_unregister_driver(&mcf_driver);
-}
-
-/****************************************************************************/
-
-module_init(mcf_init);
-module_exit(mcf_exit);
-
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
-MODULE_DESCRIPTION("Freescale ColdFire UART driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mcfuart");
-
-/****************************************************************************/
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
deleted file mode 100644 (file)
index d40010a..0000000
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- * mfd.c: driver for High Speed UART device of Intel Medfield platform
- *
- * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
- *
- * (C) Copyright 2010 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-/* Notes:
- * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
- *    2/3 chan to port 1, 4/5 chan to port 3. Even number chans
- *    are used for RX, odd chans for TX
- *
- * 2. In A0 stepping, UART will not support TX half empty flag
- *
- * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
- *    asserted, only when the HW is reset the DDCD and DDSR will
- *    be triggered
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/slab.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_mfd.h>
-#include <linux/dma-mapping.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <linux/debugfs.h>
-
-#define  MFD_HSU_A0_STEPPING   1
-
-#define HSU_DMA_BUF_SIZE       2048
-
-#define chan_readl(chan, offset)       readl(chan->reg + offset)
-#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
-
-#define mfd_readl(obj, offset)         readl(obj->reg + offset)
-#define mfd_writel(obj, offset, val)   writel(val, obj->reg + offset)
-
-#define HSU_DMA_TIMEOUT_CHECK_FREQ     (HZ/10)
-
-struct hsu_dma_buffer {
-       u8              *buf;
-       dma_addr_t      dma_addr;
-       u32             dma_size;
-       u32             ofs;
-};
-
-struct hsu_dma_chan {
-       u32     id;
-       enum dma_data_direction dirt;
-       struct uart_hsu_port    *uport;
-       void __iomem            *reg;
-       struct timer_list       rx_timer; /* only needed by RX channel */
-};
-
-struct uart_hsu_port {
-       struct uart_port        port;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned int            lsr_break_flag;
-       char                    name[12];
-       int                     index;
-       struct device           *dev;
-
-       struct hsu_dma_chan     *txc;
-       struct hsu_dma_chan     *rxc;
-       struct hsu_dma_buffer   txbuf;
-       struct hsu_dma_buffer   rxbuf;
-       int                     use_dma;        /* flag for DMA/PIO */
-       int                     running;
-       int                     dma_tx_on;
-};
-
-/* Top level data structure of HSU */
-struct hsu_port {
-       void __iomem    *reg;
-       unsigned long   paddr;
-       unsigned long   iolen;
-       u32             irq;
-
-       struct uart_hsu_port    port[3];
-       struct hsu_dma_chan     chans[10];
-
-       struct dentry *debugfs;
-};
-
-static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
-{
-       unsigned int val;
-
-       if (offset > UART_MSR) {
-               offset <<= 2;
-               val = readl(up->port.membase + offset);
-       } else
-               val = (unsigned int)readb(up->port.membase + offset);
-
-       return val;
-}
-
-static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
-{
-       if (offset > UART_MSR) {
-               offset <<= 2;
-               writel(value, up->port.membase + offset);
-       } else {
-               unsigned char val = value & 0xff;
-               writeb(val, up->port.membase + offset);
-       }
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#define HSU_REGS_BUFSIZE       1024
-
-static int hsu_show_regs_open(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t port_show_regs(struct file *file, char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct uart_hsu_port *up = file->private_data;
-       char *buf;
-       u32 len = 0;
-       ssize_t ret;
-
-       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
-       if (!buf)
-               return 0;
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MFD HSU port[%d] regs:\n", up->index);
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "=================================\n");
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
-
-       if (len > HSU_REGS_BUFSIZE)
-               len = HSU_REGS_BUFSIZE;
-
-       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct hsu_dma_chan *chan = file->private_data;
-       char *buf;
-       u32 len = 0;
-       ssize_t ret;
-
-       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
-       if (!buf)
-               return 0;
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MFD HSU DMA channel [%d] regs:\n", chan->id);
-
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "=================================\n");
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
-       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
-                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
-
-       if (len > HSU_REGS_BUFSIZE)
-               len = HSU_REGS_BUFSIZE;
-
-       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-       return ret;
-}
-
-static const struct file_operations port_regs_ops = {
-       .owner          = THIS_MODULE,
-       .open           = hsu_show_regs_open,
-       .read           = port_show_regs,
-       .llseek         = default_llseek,
-};
-
-static const struct file_operations dma_regs_ops = {
-       .owner          = THIS_MODULE,
-       .open           = hsu_show_regs_open,
-       .read           = dma_show_regs,
-       .llseek         = default_llseek,
-};
-
-static int hsu_debugfs_init(struct hsu_port *hsu)
-{
-       int i;
-       char name[32];
-
-       hsu->debugfs = debugfs_create_dir("hsu", NULL);
-       if (!hsu->debugfs)
-               return -ENOMEM;
-
-       for (i = 0; i < 3; i++) {
-               snprintf(name, sizeof(name), "port_%d_regs", i);
-               debugfs_create_file(name, S_IFREG | S_IRUGO,
-                       hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
-       }
-
-       for (i = 0; i < 6; i++) {
-               snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
-               debugfs_create_file(name, S_IFREG | S_IRUGO,
-                       hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
-       }
-
-       return 0;
-}
-
-static void hsu_debugfs_remove(struct hsu_port *hsu)
-{
-       if (hsu->debugfs)
-               debugfs_remove_recursive(hsu->debugfs);
-}
-
-#else
-static inline int hsu_debugfs_init(struct hsu_port *hsu)
-{
-       return 0;
-}
-
-static inline void hsu_debugfs_remove(struct hsu_port *hsu)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void serial_hsu_enable_ms(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-void hsu_dma_tx(struct uart_hsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       struct hsu_dma_buffer *dbuf = &up->txbuf;
-       int count;
-
-       /* test_and_set_bit may be better, but anyway it's in lock protected mode */
-       if (up->dma_tx_on)
-               return;
-
-       /* Update the circ buf info */
-       xmit->tail += dbuf->ofs;
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       up->port.icount.tx += dbuf->ofs;
-       dbuf->ofs = 0;
-
-       /* Disable the channel */
-       chan_writel(up->txc, HSU_CH_CR, 0x0);
-
-       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
-               dma_sync_single_for_device(up->port.dev,
-                                          dbuf->dma_addr,
-                                          dbuf->dma_size,
-                                          DMA_TO_DEVICE);
-
-               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               dbuf->ofs = count;
-
-               /* Reprogram the channel */
-               chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
-               chan_writel(up->txc, HSU_CH_D0TSR, count);
-
-               /* Reenable the channel */
-               chan_writel(up->txc, HSU_CH_DCR, 0x1
-                                                | (0x1 << 8)
-                                                | (0x1 << 16)
-                                                | (0x1 << 24));
-               up->dma_tx_on = 1;
-               chan_writel(up->txc, HSU_CH_CR, 0x1);
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-}
-
-/* The buffer is already cache coherent */
-void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
-{
-       dbuf->ofs = 0;
-
-       chan_writel(rxc, HSU_CH_BSR, 32);
-       chan_writel(rxc, HSU_CH_MOTSR, 4);
-
-       chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
-       chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
-       chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
-                                        | (0x1 << 16)
-                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
-                                        );
-       chan_writel(rxc, HSU_CH_CR, 0x3);
-
-       mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
-}
-
-/* Protected by spin_lock_irqsave(port->lock) */
-static void serial_hsu_start_tx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       if (up->use_dma) {
-               hsu_dma_tx(up);
-       } else if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_hsu_stop_tx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       struct hsu_dma_chan *txc = up->txc;
-
-       if (up->use_dma)
-               chan_writel(txc, HSU_CH_CR, 0x0);
-       else if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-/* This is always called in spinlock protected mode, so
- * modify timeout timer is safe here */
-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
-{
-       struct hsu_dma_buffer *dbuf = &up->rxbuf;
-       struct hsu_dma_chan *chan = up->rxc;
-       struct uart_port *port = &up->port;
-       struct tty_struct *tty = port->state->port.tty;
-       int count;
-
-       if (!tty)
-               return;
-
-       /*
-        * First need to know how many is already transferred,
-        * then check if its a timeout DMA irq, and return
-        * the trail bytes out, push them up and reenable the
-        * channel
-        */
-
-       /* Timeout IRQ, need wait some time, see Errata 2 */
-       if (int_sts & 0xf00)
-               udelay(2);
-
-       /* Stop the channel */
-       chan_writel(chan, HSU_CH_CR, 0x0);
-
-       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
-       if (!count) {
-               /* Restart the channel before we leave */
-               chan_writel(chan, HSU_CH_CR, 0x3);
-               return;
-       }
-       del_timer(&chan->rx_timer);
-
-       dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
-                       dbuf->dma_size, DMA_FROM_DEVICE);
-
-       /*
-        * Head will only wrap around when we recycle
-        * the DMA buffer, and when that happens, we
-        * explicitly set tail to 0. So head will
-        * always be greater than tail.
-        */
-       tty_insert_flip_string(tty, dbuf->buf, count);
-       port->icount.rx += count;
-
-       dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
-                       dbuf->dma_size, DMA_FROM_DEVICE);
-
-       /* Reprogram the channel */
-       chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
-       chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
-       chan_writel(chan, HSU_CH_DCR, 0x1
-                                        | (0x1 << 8)
-                                        | (0x1 << 16)
-                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
-                                        );
-       tty_flip_buffer_push(tty);
-
-       chan_writel(chan, HSU_CH_CR, 0x3);
-       chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
-       add_timer(&chan->rx_timer);
-
-}
-
-static void serial_hsu_stop_rx(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       struct hsu_dma_chan *chan = up->rxc;
-
-       if (up->use_dma)
-               chan_writel(chan, HSU_CH_CR, 0x2);
-       else {
-               up->ier &= ~UART_IER_RLSI;
-               up->port.read_status_mask &= ~UART_LSR_DR;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static inline void receive_chars(struct uart_hsu_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch, flag;
-       unsigned int max_count = 256;
-
-       if (!tty)
-               return;
-
-       do {
-               ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-
-                       dev_warn(up->dev, "We really rush into ERR/BI case"
-                               "status = 0x%02x", *status);
-                       /* For statistics only */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /* Mask off conditions which should be ignored. */
-                       *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-                       if (up->port.cons &&
-                               up->port.cons->index == up->port.line) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && max_count--);
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_hsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_hsu_stop_tx(&up->port);
-               return;
-       }
-
-#ifndef MFD_HSU_A0_STEPPING
-       count = up->port.fifosize / 2;
-#else
-       /*
-        * A0 only supports fully empty IRQ, and the first char written
-        * into it won't clear the EMPT bit, so we may need be cautious
-        * by useing a shorter buffer
-        */
-       count = up->port.fifosize - 4;
-#endif
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_hsu_stop_tx(&up->port);
-}
-
-static inline void check_modem_status(struct uart_hsu_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       /* We may only get DDCD when HW init and reset */
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       /* Will start/stop_tx accordingly */
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static irqreturn_t port_irq(int irq, void *dev_id)
-{
-       struct uart_hsu_port *up = dev_id;
-       unsigned int iir, lsr;
-       unsigned long flags;
-
-       if (unlikely(!up->running))
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->use_dma) {
-               lsr = serial_in(up, UART_LSR);
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE)))
-                       dev_warn(up->dev,
-                               "Got lsr irq while using DMA, lsr = 0x%2x\n",
-                               lsr);
-               check_modem_status(up);
-               spin_unlock_irqrestore(&up->port.lock, flags);
-               return IRQ_HANDLED;
-       }
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT) {
-               spin_unlock_irqrestore(&up->port.lock, flags);
-               return IRQ_NONE;
-       }
-
-       lsr = serial_in(up, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(up, &lsr);
-       check_modem_status(up);
-
-       /* lsr will be renewed during the receive_chars */
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-static inline void dma_chan_irq(struct hsu_dma_chan *chan)
-{
-       struct uart_hsu_port *up = chan->uport;
-       unsigned long flags;
-       u32 int_sts;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (!up->use_dma || !up->running)
-               goto exit;
-
-       /*
-        * No matter what situation, need read clear the IRQ status
-        * There is a bug, see Errata 5, HSD 2900918
-        */
-       int_sts = chan_readl(chan, HSU_CH_SR);
-
-       /* Rx channel */
-       if (chan->dirt == DMA_FROM_DEVICE)
-               hsu_dma_rx(up, int_sts);
-
-       /* Tx channel */
-       if (chan->dirt == DMA_TO_DEVICE) {
-               chan_writel(chan, HSU_CH_CR, 0x0);
-               up->dma_tx_on = 0;
-               hsu_dma_tx(up);
-       }
-
-exit:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       return;
-}
-
-static irqreturn_t dma_irq(int irq, void *dev_id)
-{
-       struct hsu_port *hsu = dev_id;
-       u32 int_sts, i;
-
-       int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
-
-       /* Currently we only have 6 channels may be used */
-       for (i = 0; i < 6; i++) {
-               if (int_sts & 0x1)
-                       dma_chan_irq(&hsu->chans[i]);
-               int_sts >>= 1;
-       }
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_hsu_tx_empty(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- * What special to do:
- * 1. chose the 64B fifo mode
- * 2. make sure not to select half empty mode for A0 stepping
- * 3. start dma or pio depends on configuration
- * 4. we only allocate dma memory when needed
- */
-static int serial_hsu_startup(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-
-       /* Clear the interrupt registers. */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /* Now, initialize the UART, default is 8n1 */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       if (!up->use_dma)
-               up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
-       else
-               up->ier = 0;
-       serial_out(up, UART_IER, up->ier);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* DMA init */
-       if (up->use_dma) {
-               struct hsu_dma_buffer *dbuf;
-               struct circ_buf *xmit = &port->state->xmit;
-
-               up->dma_tx_on = 0;
-
-               /* First allocate the RX buffer */
-               dbuf = &up->rxbuf;
-               dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
-               if (!dbuf->buf) {
-                       up->use_dma = 0;
-                       goto exit;
-               }
-               dbuf->dma_addr = dma_map_single(port->dev,
-                                               dbuf->buf,
-                                               HSU_DMA_BUF_SIZE,
-                                               DMA_FROM_DEVICE);
-               dbuf->dma_size = HSU_DMA_BUF_SIZE;
-
-               /* Start the RX channel right now */
-               hsu_dma_start_rx_chan(up->rxc, dbuf);
-
-               /* Next init the TX DMA */
-               dbuf = &up->txbuf;
-               dbuf->buf = xmit->buf;
-               dbuf->dma_addr = dma_map_single(port->dev,
-                                              dbuf->buf,
-                                              UART_XMIT_SIZE,
-                                              DMA_TO_DEVICE);
-               dbuf->dma_size = UART_XMIT_SIZE;
-
-               /* This should not be changed all around */
-               chan_writel(up->txc, HSU_CH_BSR, 32);
-               chan_writel(up->txc, HSU_CH_MOTSR, 4);
-               dbuf->ofs = 0;
-       }
-
-exit:
-        /* And clear the interrupt registers again for luck. */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       up->running = 1;
-       return 0;
-}
-
-static void serial_hsu_shutdown(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       unsigned long flags;
-
-       del_timer_sync(&up->rxc->rx_timer);
-
-       /* Disable interrupts from this port */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-       up->running = 0;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* Disable break condition and FIFOs */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_hsu_port *up =
-                       container_of(port, struct uart_hsu_port, port);
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-       u32 ps, mul;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       /* CMSPAR isn't supported by this driver */
-       if (tty)
-               tty->termios->c_cflag &= ~CMSPAR;
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * The base clk is 50Mhz, and the baud rate come from:
-        *      baud = 50M * MUL / (DIV * PS * DLAB)
-        *
-        * For those basic low baud rate we can get the direct
-        * scalar from 2746800, like 115200 = 2746800/24. For those
-        * higher baud rate, we handle them case by case, mainly by
-        * adjusting the MUL/PS registers, and DIV register is kept
-        * as default value 0x3d09 to make things simple
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-
-       quot = 1;
-       ps = 0x10;
-       mul = 0x3600;
-       switch (baud) {
-       case 3500000:
-               mul = 0x3345;
-               ps = 0xC;
-               break;
-       case 1843200:
-               mul = 0x2400;
-               break;
-       case 3000000:
-       case 2500000:
-       case 2000000:
-       case 1500000:
-       case 1000000:
-       case 500000:
-               /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
-               mul = baud / 500000 * 0x9C4;
-               break;
-       default:
-               /* Use uart_get_divisor to get quot for other baud rates */
-               quot = 0;
-       }
-
-       if (!quot)
-               quot = uart_get_divisor(port, baud);
-
-       if ((up->port.uartclk / quot) < (2400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
-       else if ((up->port.uartclk / quot) < (230400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
-       else
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
-
-       fcr |= UART_FCR_HSU_64B_FIFO;
-#ifdef MFD_HSU_A0_STEPPING
-       /* A0 doesn't support half empty IRQ */
-       fcr |= UART_FCR_FULL_EMPT_TXI;
-#endif
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /* Update the per-port timeout */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /* Characters to ignore */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /* Ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts, disable
-        * MSI by default
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (termios->c_cflag & CRTSCTS)
-               up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
-       else
-               up->mcr &= ~UART_MCR_AFE;
-
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
-       serial_out(up, UART_MUL, mul);                  /* set MUL */
-       serial_out(up, UART_PS, ps);                    /* set PS */
-       up->lcr = cval;                                 /* Save LCR */
-       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-       serial_out(up, UART_FCR, fcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_hsu_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-}
-
-static void serial_hsu_release_port(struct uart_port *port)
-{
-}
-
-static int serial_hsu_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_hsu_config_port(struct uart_port *port, int flags)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       up->port.type = PORT_MFD;
-}
-
-static int
-serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* We don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static const char *
-serial_hsu_type(struct uart_port *port)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-       return up->name;
-}
-
-/* Mainly for uart console use */
-static struct uart_hsu_port *serial_hsu_ports[3];
-static struct uart_driver serial_hsu_reg;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/* Wait for transmitter & holding register to empty */
-static inline void wait_for_xmitr(struct uart_hsu_port *up)
-{
-       unsigned int status, tmout = 1000;
-
-       /* Wait up to 1ms for the character to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while (!(status & BOTH_EMPTY));
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void serial_hsu_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_hsu_port *up =
-               container_of(port, struct uart_hsu_port, port);
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void
-serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_hsu_port *up = serial_hsu_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /* First save the IER then disable the interrupts */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static struct console serial_hsu_console;
-
-static int __init
-serial_hsu_console_setup(struct console *co, char *options)
-{
-       struct uart_hsu_port *up;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       if (co->index == -1 || co->index >= serial_hsu_reg.nr)
-               co->index = 0;
-       up = serial_hsu_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
-
-       return ret;
-}
-
-static struct console serial_hsu_console = {
-       .name           = "ttyMFD",
-       .write          = serial_hsu_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_hsu_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = 2,
-       .data           = &serial_hsu_reg,
-};
-#endif
-
-struct uart_ops serial_hsu_pops = {
-       .tx_empty       = serial_hsu_tx_empty,
-       .set_mctrl      = serial_hsu_set_mctrl,
-       .get_mctrl      = serial_hsu_get_mctrl,
-       .stop_tx        = serial_hsu_stop_tx,
-       .start_tx       = serial_hsu_start_tx,
-       .stop_rx        = serial_hsu_stop_rx,
-       .enable_ms      = serial_hsu_enable_ms,
-       .break_ctl      = serial_hsu_break_ctl,
-       .startup        = serial_hsu_startup,
-       .shutdown       = serial_hsu_shutdown,
-       .set_termios    = serial_hsu_set_termios,
-       .pm             = serial_hsu_pm,
-       .type           = serial_hsu_type,
-       .release_port   = serial_hsu_release_port,
-       .request_port   = serial_hsu_request_port,
-       .config_port    = serial_hsu_config_port,
-       .verify_port    = serial_hsu_verify_port,
-};
-
-static struct uart_driver serial_hsu_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "MFD serial",
-       .dev_name       = "ttyMFD",
-       .major          = TTY_MAJOR,
-       .minor          = 128,
-       .nr             = 3,
-};
-
-#ifdef CONFIG_PM
-static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-
-       /* Make sure this is not the internal dma controller */
-       if (priv && (pdev->device != 0x081E)) {
-               up = priv;
-               uart_suspend_port(&serial_hsu_reg, &up->port);
-       }
-
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-        return 0;
-}
-
-static int serial_hsu_resume(struct pci_dev *pdev)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-       int ret;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               dev_warn(&pdev->dev,
-                       "HSU: can't re-enable device, try to continue\n");
-
-       if (priv && (pdev->device != 0x081E)) {
-               up = priv;
-               uart_resume_port(&serial_hsu_reg, &up->port);
-       }
-       return 0;
-}
-#else
-#define serial_hsu_suspend     NULL
-#define serial_hsu_resume      NULL
-#endif
-
-/* temp global pointer before we settle down on using one or four PCI dev */
-static struct hsu_port *phsu;
-
-static int serial_hsu_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       struct uart_hsu_port *uport;
-       int index, ret;
-
-       printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
-               pdev->vendor, pdev->device);
-
-       switch (pdev->device) {
-       case 0x081B:
-               index = 0;
-               break;
-       case 0x081C:
-               index = 1;
-               break;
-       case 0x081D:
-               index = 2;
-               break;
-       case 0x081E:
-               /* internal DMA controller */
-               index = 3;
-               break;
-       default:
-               dev_err(&pdev->dev, "HSU: out of index!");
-               return -ENODEV;
-       }
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-
-       if (index == 3) {
-               /* DMA controller */
-               ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
-               if (ret) {
-                       dev_err(&pdev->dev, "can not get IRQ\n");
-                       goto err_disable;
-               }
-               pci_set_drvdata(pdev, phsu);
-       } else {
-               /* UART port 0~2 */
-               uport = &phsu->port[index];
-               uport->port.irq = pdev->irq;
-               uport->port.dev = &pdev->dev;
-               uport->dev = &pdev->dev;
-
-               ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
-               if (ret) {
-                       dev_err(&pdev->dev, "can not get IRQ\n");
-                       goto err_disable;
-               }
-               uart_add_one_port(&serial_hsu_reg, &uport->port);
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-               if (index == 2) {
-                       register_console(&serial_hsu_console);
-                       uport->port.cons = &serial_hsu_console;
-               }
-#endif
-               pci_set_drvdata(pdev, uport);
-       }
-
-       return 0;
-
-err_disable:
-       pci_disable_device(pdev);
-       return ret;
-}
-
-static void hsu_dma_rx_timeout(unsigned long data)
-{
-       struct hsu_dma_chan *chan = (void *)data;
-       struct uart_hsu_port *up = chan->uport;
-       struct hsu_dma_buffer *dbuf = &up->rxbuf;
-       int count = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
-
-       if (!count) {
-               mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
-               goto exit;
-       }
-
-       hsu_dma_rx(up, 0);
-exit:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void hsu_global_init(void)
-{
-       struct hsu_port *hsu;
-       struct uart_hsu_port *uport;
-       struct hsu_dma_chan *dchan;
-       int i, ret;
-
-       hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
-       if (!hsu)
-               return;
-
-       /* Get basic io resource and map it */
-       hsu->paddr = 0xffa28000;
-       hsu->iolen = 0x1000;
-
-       if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
-               pr_warning("HSU: error in request mem region\n");
-
-       hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
-       if (!hsu->reg) {
-               pr_err("HSU: error in ioremap\n");
-               ret = -ENOMEM;
-               goto err_free_region;
-       }
-
-       /* Initialise the 3 UART ports */
-       uport = hsu->port;
-       for (i = 0; i < 3; i++) {
-               uport->port.type = PORT_MFD;
-               uport->port.iotype = UPIO_MEM;
-               uport->port.mapbase = (resource_size_t)hsu->paddr
-                                       + HSU_PORT_REG_OFFSET
-                                       + i * HSU_PORT_REG_LENGTH;
-               uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
-                                       + i * HSU_PORT_REG_LENGTH;
-
-               sprintf(uport->name, "hsu_port%d", i);
-               uport->port.fifosize = 64;
-               uport->port.ops = &serial_hsu_pops;
-               uport->port.line = i;
-               uport->port.flags = UPF_IOREMAP;
-               /* set the scalable maxim support rate to 2746800 bps */
-               uport->port.uartclk = 115200 * 24 * 16;
-
-               uport->running = 0;
-               uport->txc = &hsu->chans[i * 2];
-               uport->rxc = &hsu->chans[i * 2 + 1];
-
-               serial_hsu_ports[i] = uport;
-               uport->index = i;
-               uport++;
-       }
-
-       /* Initialise 6 dma channels */
-       dchan = hsu->chans;
-       for (i = 0; i < 6; i++) {
-               dchan->id = i;
-               dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-               dchan->uport = &hsu->port[i/2];
-               dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
-                               i * HSU_DMA_CHANS_REG_LENGTH;
-
-               /* Work around for RX */
-               if (dchan->dirt == DMA_FROM_DEVICE) {
-                       init_timer(&dchan->rx_timer);
-                       dchan->rx_timer.function = hsu_dma_rx_timeout;
-                       dchan->rx_timer.data = (unsigned long)dchan;
-               }
-               dchan++;
-       }
-
-       phsu = hsu;
-       hsu_debugfs_init(hsu);
-       return;
-
-err_free_region:
-       release_mem_region(hsu->paddr, hsu->iolen);
-       kfree(hsu);
-       return;
-}
-
-static void serial_hsu_remove(struct pci_dev *pdev)
-{
-       void *priv = pci_get_drvdata(pdev);
-       struct uart_hsu_port *up;
-
-       if (!priv)
-               return;
-
-       /* For port 0/1/2, priv is the address of uart_hsu_port */
-       if (pdev->device != 0x081E) {
-               up = priv;
-               uart_remove_one_port(&serial_hsu_reg, &up->port);
-       }
-
-       pci_set_drvdata(pdev, NULL);
-       free_irq(pdev->irq, priv);
-       pci_disable_device(pdev);
-}
-
-/* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
-       {},
-};
-
-static struct pci_driver hsu_pci_driver = {
-       .name =         "HSU serial",
-       .id_table =     pci_ids,
-       .probe =        serial_hsu_probe,
-       .remove =       __devexit_p(serial_hsu_remove),
-       .suspend =      serial_hsu_suspend,
-       .resume =       serial_hsu_resume,
-};
-
-static int __init hsu_pci_init(void)
-{
-       int ret;
-
-       hsu_global_init();
-
-       ret = uart_register_driver(&serial_hsu_reg);
-       if (ret)
-               return ret;
-
-       return pci_register_driver(&hsu_pci_driver);
-}
-
-static void __exit hsu_pci_exit(void)
-{
-       pci_unregister_driver(&hsu_pci_driver);
-       uart_unregister_driver(&serial_hsu_reg);
-
-       hsu_debugfs_remove(phsu);
-
-       kfree(phsu);
-}
-
-module_init(hsu_pci_init);
-module_exit(hsu_pci_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:medfield-hsu");
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
deleted file mode 100644 (file)
index 126ec7f..0000000
+++ /dev/null
@@ -1,1527 +0,0 @@
-/*
- * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
- *
- * FIXME According to the usermanual the status bits in the status register
- * are only updated when the peripherals access the FIFO and not when the
- * CPU access them. So since we use this bits to know when we stop writing
- * and reading, they may not be updated in-time and a race condition may
- * exists. But I haven't be able to prove this and I don't care. But if
- * any problem arises, it might worth checking. The TX/RX FIFO Stats
- * registers should be used in addition.
- * Update: Actually, they seem updated ... At least the bits we use.
- *
- *
- * Maintainer : Sylvain Munaut <tnt@246tNt.com>
- *
- * Some of the code has been inspired/copied from the 2.4 code written
- * by Dale Farnsworth <dfarnsworth@mvista.com>.
- *
- * Copyright (C) 2008 Freescale Semiconductor Inc.
- *                    John Rigby <jrigby@gmail.com>
- * Added support for MPC5121
- * Copyright (C) 2006 Secret Lab Technologies Ltd.
- *                    Grant Likely <grant.likely@secretlab.ca>
- * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
- * Copyright (C) 2003 MontaVista, Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-
-#include <asm/mpc52xx.h>
-#include <asm/mpc52xx_psc.h>
-
-#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_PSC_MAJOR       204
-#define SERIAL_PSC_MINOR       148
-
-
-#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
-
-
-static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
-       /* Rem: - We use the read_status_mask as a shadow of
-        *        psc->mpc52xx_psc_imr
-        *      - It's important that is array is all zero on start as we
-        *        use it to know if it's initialized or not ! If it's not sure
-        *        it's cleared, then a memset(...,0,...) should be added to
-        *        the console_init
-        */
-
-/* lookup table for matching device nodes to index numbers */
-static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
-
-static void mpc52xx_uart_of_enumerate(void);
-
-
-#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
-
-
-/* Forward declaration of the interruption handling routine */
-static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
-static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
-
-
-/* Simple macro to test if a port is console or not. This one is taken
- * for serial_core.c and maybe should be moved to serial_core.h ? */
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port) \
-       ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port)     (0)
-#endif
-
-/* ======================================================================== */
-/* PSC fifo operations for isolating differences between 52xx and 512x      */
-/* ======================================================================== */
-
-struct psc_ops {
-       void            (*fifo_init)(struct uart_port *port);
-       int             (*raw_rx_rdy)(struct uart_port *port);
-       int             (*raw_tx_rdy)(struct uart_port *port);
-       int             (*rx_rdy)(struct uart_port *port);
-       int             (*tx_rdy)(struct uart_port *port);
-       int             (*tx_empty)(struct uart_port *port);
-       void            (*stop_rx)(struct uart_port *port);
-       void            (*start_tx)(struct uart_port *port);
-       void            (*stop_tx)(struct uart_port *port);
-       void            (*rx_clr_irq)(struct uart_port *port);
-       void            (*tx_clr_irq)(struct uart_port *port);
-       void            (*write_char)(struct uart_port *port, unsigned char c);
-       unsigned char   (*read_char)(struct uart_port *port);
-       void            (*cw_disable_ints)(struct uart_port *port);
-       void            (*cw_restore_ints)(struct uart_port *port);
-       unsigned int    (*set_baudrate)(struct uart_port *port,
-                                       struct ktermios *new,
-                                       struct ktermios *old);
-       int             (*clock)(struct uart_port *port, int enable);
-       int             (*fifoc_init)(void);
-       void            (*fifoc_uninit)(void);
-       void            (*get_irq)(struct uart_port *, struct device_node *);
-       irqreturn_t     (*handle_irq)(struct uart_port *port);
-};
-
-/* setting the prescaler and divisor reg is common for all chips */
-static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
-                                      u16 prescaler, unsigned int divisor)
-{
-       /* select prescaler */
-       out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
-       out_8(&psc->ctur, divisor >> 8);
-       out_8(&psc->ctlr, divisor & 0xff);
-}
-
-#ifdef CONFIG_PPC_MPC52xx
-#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
-static void mpc52xx_psc_fifo_init(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
-
-       out_8(&fifo->rfcntl, 0x00);
-       out_be16(&fifo->rfalarm, 0x1ff);
-       out_8(&fifo->tfcntl, 0x07);
-       out_be16(&fifo->tfalarm, 0x80);
-
-       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_RXRDY;
-}
-
-static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_TXRDY;
-}
-
-
-static int mpc52xx_psc_rx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_isr)
-           & port->read_status_mask
-           & MPC52xx_PSC_IMR_RXRDY;
-}
-
-static int mpc52xx_psc_tx_rdy(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_isr)
-           & port->read_status_mask
-           & MPC52xx_PSC_IMR_TXRDY;
-}
-
-static int mpc52xx_psc_tx_empty(struct uart_port *port)
-{
-       return in_be16(&PSC(port)->mpc52xx_psc_status)
-           & MPC52xx_PSC_SR_TXEMP;
-}
-
-static void mpc52xx_psc_start_tx(struct uart_port *port)
-{
-       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_stop_tx(struct uart_port *port)
-{
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_stop_rx(struct uart_port *port)
-{
-       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
-{
-}
-
-static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
-{
-}
-
-static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
-{
-       out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
-}
-
-static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
-{
-       return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
-}
-
-static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
-{
-       out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
-}
-
-static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
-{
-       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
-                                            struct ktermios *new,
-                                            struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-
-       /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (32 * 0xffff) + 1,
-                                 port->uartclk / 32);
-       divisor = (port->uartclk + 16 * baud) / (32 * baud);
-
-       /* enable the /32 prescaler and set the divisor */
-       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
-       return baud;
-}
-
-static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
-                                             struct ktermios *new,
-                                             struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-       u16 prescaler;
-
-       /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
-        * ipb freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (32 * 0xffff) + 1,
-                                 port->uartclk / 4);
-       divisor = (port->uartclk + 2 * baud) / (4 * baud);
-
-       /* select the proper prescaler and set the divisor */
-       if (divisor > 0xffff) {
-               divisor = (divisor + 4) / 8;
-               prescaler = 0xdd00; /* /32 */
-       } else
-               prescaler = 0xff00; /* /4 */
-       mpc52xx_set_divisor(PSC(port), prescaler, divisor);
-       return baud;
-}
-
-static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
-{
-       port->irqflags = IRQF_DISABLED;
-       port->irq = irq_of_parse_and_map(np, 0);
-}
-
-/* 52xx specific interrupt handler. The caller holds the port lock */
-static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
-{
-       return mpc5xxx_uart_process_int(port);
-}
-
-static struct psc_ops mpc52xx_psc_ops = {
-       .fifo_init = mpc52xx_psc_fifo_init,
-       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
-       .rx_rdy = mpc52xx_psc_rx_rdy,
-       .tx_rdy = mpc52xx_psc_tx_rdy,
-       .tx_empty = mpc52xx_psc_tx_empty,
-       .stop_rx = mpc52xx_psc_stop_rx,
-       .start_tx = mpc52xx_psc_start_tx,
-       .stop_tx = mpc52xx_psc_stop_tx,
-       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
-       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
-       .write_char = mpc52xx_psc_write_char,
-       .read_char = mpc52xx_psc_read_char,
-       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
-       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
-       .set_baudrate = mpc5200_psc_set_baudrate,
-       .get_irq = mpc52xx_psc_get_irq,
-       .handle_irq = mpc52xx_psc_handle_irq,
-};
-
-static struct psc_ops mpc5200b_psc_ops = {
-       .fifo_init = mpc52xx_psc_fifo_init,
-       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
-       .rx_rdy = mpc52xx_psc_rx_rdy,
-       .tx_rdy = mpc52xx_psc_tx_rdy,
-       .tx_empty = mpc52xx_psc_tx_empty,
-       .stop_rx = mpc52xx_psc_stop_rx,
-       .start_tx = mpc52xx_psc_start_tx,
-       .stop_tx = mpc52xx_psc_stop_tx,
-       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
-       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
-       .write_char = mpc52xx_psc_write_char,
-       .read_char = mpc52xx_psc_read_char,
-       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
-       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
-       .set_baudrate = mpc5200b_psc_set_baudrate,
-       .get_irq = mpc52xx_psc_get_irq,
-       .handle_irq = mpc52xx_psc_handle_irq,
-};
-
-#endif /* CONFIG_MPC52xx */
-
-#ifdef CONFIG_PPC_MPC512x
-#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
-
-/* PSC FIFO Controller for mpc512x */
-struct psc_fifoc {
-       u32 fifoc_cmd;
-       u32 fifoc_int;
-       u32 fifoc_dma;
-       u32 fifoc_axe;
-       u32 fifoc_debug;
-};
-
-static struct psc_fifoc __iomem *psc_fifoc;
-static unsigned int psc_fifoc_irq;
-
-static void mpc512x_psc_fifo_init(struct uart_port *port)
-{
-       /* /32 prescaler */
-       out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
-
-       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
-       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
-       out_be32(&FIFO_512x(port)->txalarm, 1);
-       out_be32(&FIFO_512x(port)->tximr, 0);
-
-       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
-       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
-       out_be32(&FIFO_512x(port)->rxalarm, 1);
-       out_be32(&FIFO_512x(port)->rximr, 0);
-
-       out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
-       out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
-}
-
-static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
-{
-       return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
-}
-
-static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
-{
-       return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
-}
-
-static int mpc512x_psc_rx_rdy(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->rxsr)
-           & in_be32(&FIFO_512x(port)->rximr)
-           & MPC512x_PSC_FIFO_ALARM;
-}
-
-static int mpc512x_psc_tx_rdy(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->txsr)
-           & in_be32(&FIFO_512x(port)->tximr)
-           & MPC512x_PSC_FIFO_ALARM;
-}
-
-static int mpc512x_psc_tx_empty(struct uart_port *port)
-{
-       return in_be32(&FIFO_512x(port)->txsr)
-           & MPC512x_PSC_FIFO_EMPTY;
-}
-
-static void mpc512x_psc_stop_rx(struct uart_port *port)
-{
-       unsigned long rx_fifo_imr;
-
-       rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
-       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
-}
-
-static void mpc512x_psc_start_tx(struct uart_port *port)
-{
-       unsigned long tx_fifo_imr;
-
-       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
-       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
-}
-
-static void mpc512x_psc_stop_tx(struct uart_port *port)
-{
-       unsigned long tx_fifo_imr;
-
-       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
-       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
-       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
-}
-
-static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
-}
-
-static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
-}
-
-static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
-{
-       out_8(&FIFO_512x(port)->txdata_8, c);
-}
-
-static unsigned char mpc512x_psc_read_char(struct uart_port *port)
-{
-       return in_8(&FIFO_512x(port)->rxdata_8);
-}
-
-static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
-{
-       port->read_status_mask =
-               in_be32(&FIFO_512x(port)->tximr) << 16 |
-               in_be32(&FIFO_512x(port)->rximr);
-       out_be32(&FIFO_512x(port)->tximr, 0);
-       out_be32(&FIFO_512x(port)->rximr, 0);
-}
-
-static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
-{
-       out_be32(&FIFO_512x(port)->tximr,
-               (port->read_status_mask >> 16) & 0x7f);
-       out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
-}
-
-static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
-                                            struct ktermios *new,
-                                            struct ktermios *old)
-{
-       unsigned int baud;
-       unsigned int divisor;
-
-       /*
-        * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
-        * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
-        * Furthermore, it states that "After reset, the prescaler by 10
-        * for the UART mode is selected", but the reset register value is
-        * 0x0000 which means a /32 prescaler. This is wrong.
-        *
-        * In reality using /32 prescaler doesn't work, as it is not supported!
-        * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
-        * Chapter 4.1 PSC in UART Mode.
-        * Calculate with a /16 prescaler here.
-        */
-
-       /* uartclk contains the ips freq */
-       baud = uart_get_baud_rate(port, new, old,
-                                 port->uartclk / (16 * 0xffff) + 1,
-                                 port->uartclk / 16);
-       divisor = (port->uartclk + 8 * baud) / (16 * baud);
-
-       /* enable the /16 prescaler and set the divisor */
-       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
-       return baud;
-}
-
-/* Init PSC FIFO Controller */
-static int __init mpc512x_psc_fifoc_init(void)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL,
-                                    "fsl,mpc5121-psc-fifo");
-       if (!np) {
-               pr_err("%s: Can't find FIFOC node\n", __func__);
-               return -ENODEV;
-       }
-
-       psc_fifoc = of_iomap(np, 0);
-       if (!psc_fifoc) {
-               pr_err("%s: Can't map FIFOC\n", __func__);
-               of_node_put(np);
-               return -ENODEV;
-       }
-
-       psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-       of_node_put(np);
-       if (psc_fifoc_irq == NO_IRQ) {
-               pr_err("%s: Can't get FIFOC irq\n", __func__);
-               iounmap(psc_fifoc);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void __exit mpc512x_psc_fifoc_uninit(void)
-{
-       iounmap(psc_fifoc);
-}
-
-/* 512x specific interrupt handler. The caller holds the port lock */
-static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
-{
-       unsigned long fifoc_int;
-       int psc_num;
-
-       /* Read pending PSC FIFOC interrupts */
-       fifoc_int = in_be32(&psc_fifoc->fifoc_int);
-
-       /* Check if it is an interrupt for this port */
-       psc_num = (port->mapbase & 0xf00) >> 8;
-       if (test_bit(psc_num, &fifoc_int) ||
-           test_bit(psc_num + 16, &fifoc_int))
-               return mpc5xxx_uart_process_int(port);
-
-       return IRQ_NONE;
-}
-
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
-{
-       struct clk *psc_clk;
-       int psc_num;
-       char clk_name[10];
-
-       if (uart_console(port))
-               return 0;
-
-       psc_num = (port->mapbase & 0xf00) >> 8;
-       snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
-       psc_clk = clk_get(port->dev, clk_name);
-       if (IS_ERR(psc_clk)) {
-               dev_err(port->dev, "Failed to get PSC clock entry!\n");
-               return -ENODEV;
-       }
-
-       dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-       if (enable)
-               clk_enable(psc_clk);
-       else
-               clk_disable(psc_clk);
-
-       return 0;
-}
-
-static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
-{
-       port->irqflags = IRQF_SHARED;
-       port->irq = psc_fifoc_irq;
-}
-
-static struct psc_ops mpc512x_psc_ops = {
-       .fifo_init = mpc512x_psc_fifo_init,
-       .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
-       .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
-       .rx_rdy = mpc512x_psc_rx_rdy,
-       .tx_rdy = mpc512x_psc_tx_rdy,
-       .tx_empty = mpc512x_psc_tx_empty,
-       .stop_rx = mpc512x_psc_stop_rx,
-       .start_tx = mpc512x_psc_start_tx,
-       .stop_tx = mpc512x_psc_stop_tx,
-       .rx_clr_irq = mpc512x_psc_rx_clr_irq,
-       .tx_clr_irq = mpc512x_psc_tx_clr_irq,
-       .write_char = mpc512x_psc_write_char,
-       .read_char = mpc512x_psc_read_char,
-       .cw_disable_ints = mpc512x_psc_cw_disable_ints,
-       .cw_restore_ints = mpc512x_psc_cw_restore_ints,
-       .set_baudrate = mpc512x_psc_set_baudrate,
-       .clock = mpc512x_psc_clock,
-       .fifoc_init = mpc512x_psc_fifoc_init,
-       .fifoc_uninit = mpc512x_psc_fifoc_uninit,
-       .get_irq = mpc512x_psc_get_irq,
-       .handle_irq = mpc512x_psc_handle_irq,
-};
-#endif
-
-static struct psc_ops *psc_ops;
-
-/* ======================================================================== */
-/* UART operations                                                          */
-/* ======================================================================== */
-
-static unsigned int
-mpc52xx_uart_tx_empty(struct uart_port *port)
-{
-       return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
-}
-
-static void
-mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       if (mctrl & TIOCM_RTS)
-               out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
-       else
-               out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
-}
-
-static unsigned int
-mpc52xx_uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int ret = TIOCM_DSR;
-       u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
-
-       if (!(status & MPC52xx_PSC_CTS))
-               ret |= TIOCM_CTS;
-       if (!(status & MPC52xx_PSC_DCD))
-               ret |= TIOCM_CAR;
-
-       return ret;
-}
-
-static void
-mpc52xx_uart_stop_tx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->stop_tx(port);
-}
-
-static void
-mpc52xx_uart_start_tx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->start_tx(port);
-}
-
-static void
-mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->x_char = ch;
-       if (ch) {
-               /* Make sure tx interrupts are on */
-               /* Truly necessary ??? They should be anyway */
-               psc_ops->start_tx(port);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void
-mpc52xx_uart_stop_rx(struct uart_port *port)
-{
-       /* port->lock taken by caller */
-       psc_ops->stop_rx(port);
-}
-
-static void
-mpc52xx_uart_enable_ms(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-
-       /* clear D_*-bits by reading them */
-       in_8(&psc->mpc52xx_psc_ipcr);
-       /* enable CTS and DCD as IPC interrupts */
-       out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
-
-       port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-}
-
-static void
-mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (ctl == -1)
-               out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
-       else
-               out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int
-mpc52xx_uart_startup(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       int ret;
-
-       if (psc_ops->clock) {
-               ret = psc_ops->clock(port, 1);
-               if (ret)
-                       return ret;
-       }
-
-       /* Request IRQ */
-       ret = request_irq(port->irq, mpc52xx_uart_int,
-                         port->irqflags, "mpc52xx_psc_uart", port);
-       if (ret)
-               return ret;
-
-       /* Reset/activate the port, clear and enable interrupts */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
-
-       psc_ops->fifo_init(port);
-
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
-       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
-
-       return 0;
-}
-
-static void
-mpc52xx_uart_shutdown(struct uart_port *port)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-
-       /* Shut down the port.  Leave TX active if on a console port */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       if (!uart_console(port))
-               out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       port->read_status_mask = 0;
-       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
-
-       if (psc_ops->clock)
-               psc_ops->clock(port, 0);
-
-       /* Release interrupt */
-       free_irq(port->irq, port);
-}
-
-static void
-mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
-                        struct ktermios *old)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       unsigned long flags;
-       unsigned char mr1, mr2;
-       unsigned int j;
-       unsigned int baud;
-
-       /* Prepare what we're gonna write */
-       mr1 = 0;
-
-       switch (new->c_cflag & CSIZE) {
-       case CS5:       mr1 |= MPC52xx_PSC_MODE_5_BITS;
-               break;
-       case CS6:       mr1 |= MPC52xx_PSC_MODE_6_BITS;
-               break;
-       case CS7:       mr1 |= MPC52xx_PSC_MODE_7_BITS;
-               break;
-       case CS8:
-       default:        mr1 |= MPC52xx_PSC_MODE_8_BITS;
-       }
-
-       if (new->c_cflag & PARENB) {
-               mr1 |= (new->c_cflag & PARODD) ?
-                       MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
-       } else
-               mr1 |= MPC52xx_PSC_MODE_PARNONE;
-
-
-       mr2 = 0;
-
-       if (new->c_cflag & CSTOPB)
-               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
-       else
-               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
-                       MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
-                       MPC52xx_PSC_MODE_ONE_STOP;
-
-       if (new->c_cflag & CRTSCTS) {
-               mr1 |= MPC52xx_PSC_MODE_RXRTS;
-               mr2 |= MPC52xx_PSC_MODE_TXCTS;
-       }
-
-       /* Get the lock */
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* Do our best to flush TX & RX, so we don't lose anything */
-       /* But we don't wait indefinitely ! */
-       j = 5000000;    /* Maximum wait */
-       /* FIXME Can't receive chars since set_termios might be called at early
-        * boot for the console, all stuff is not yet ready to receive at that
-        * time and that just makes the kernel oops */
-       /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
-       while (!mpc52xx_uart_tx_empty(port) && --j)
-               udelay(1);
-
-       if (!j)
-               printk(KERN_ERR "mpc52xx_uart.c: "
-                       "Unable to flush RX & TX fifos in-time in set_termios."
-                       "Some chars may have been lost.\n");
-
-       /* Reset the TX & RX */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       out_8(&psc->command, MPC52xx_PSC_RST_TX);
-
-       /* Send new mode settings */
-       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
-       out_8(&psc->mode, mr1);
-       out_8(&psc->mode, mr2);
-       baud = psc_ops->set_baudrate(port, new, old);
-
-       /* Update the per-port timeout */
-       uart_update_timeout(port, new->c_cflag, baud);
-
-       if (UART_ENABLE_MS(port, new->c_cflag))
-               mpc52xx_uart_enable_ms(port);
-
-       /* Reenable TX & RX */
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
-       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
-
-       /* We're all set, release the lock */
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *
-mpc52xx_uart_type(struct uart_port *port)
-{
-       /*
-        * We keep using PORT_MPC52xx for historic reasons although it applies
-        * for MPC512x, too, but print "MPC5xxx" to not irritate users
-        */
-       return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
-}
-
-static void
-mpc52xx_uart_release_port(struct uart_port *port)
-{
-       /* remapped by us ? */
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
-}
-
-static int
-mpc52xx_uart_request_port(struct uart_port *port)
-{
-       int err;
-
-       if (port->flags & UPF_IOREMAP) /* Need to remap ? */
-               port->membase = ioremap(port->mapbase,
-                                       sizeof(struct mpc52xx_psc));
-
-       if (!port->membase)
-               return -EINVAL;
-
-       err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
-                       "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
-
-       if (err && (port->flags & UPF_IOREMAP)) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       return err;
-}
-
-static void
-mpc52xx_uart_config_port(struct uart_port *port, int flags)
-{
-       if ((flags & UART_CONFIG_TYPE)
-               && (mpc52xx_uart_request_port(port) == 0))
-               port->type = PORT_MPC52xx;
-}
-
-static int
-mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
-               return -EINVAL;
-
-       if ((ser->irq != port->irq) ||
-           (ser->io_type != UPIO_MEM) ||
-           (ser->baud_base != port->uartclk)  ||
-           (ser->iomem_base != (void *)port->mapbase) ||
-           (ser->hub6 != 0))
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static struct uart_ops mpc52xx_uart_ops = {
-       .tx_empty       = mpc52xx_uart_tx_empty,
-       .set_mctrl      = mpc52xx_uart_set_mctrl,
-       .get_mctrl      = mpc52xx_uart_get_mctrl,
-       .stop_tx        = mpc52xx_uart_stop_tx,
-       .start_tx       = mpc52xx_uart_start_tx,
-       .send_xchar     = mpc52xx_uart_send_xchar,
-       .stop_rx        = mpc52xx_uart_stop_rx,
-       .enable_ms      = mpc52xx_uart_enable_ms,
-       .break_ctl      = mpc52xx_uart_break_ctl,
-       .startup        = mpc52xx_uart_startup,
-       .shutdown       = mpc52xx_uart_shutdown,
-       .set_termios    = mpc52xx_uart_set_termios,
-/*     .pm             = mpc52xx_uart_pm,              Not supported yet */
-/*     .set_wake       = mpc52xx_uart_set_wake,        Not supported yet */
-       .type           = mpc52xx_uart_type,
-       .release_port   = mpc52xx_uart_release_port,
-       .request_port   = mpc52xx_uart_request_port,
-       .config_port    = mpc52xx_uart_config_port,
-       .verify_port    = mpc52xx_uart_verify_port
-};
-
-
-/* ======================================================================== */
-/* Interrupt handling                                                       */
-/* ======================================================================== */
-
-static inline int
-mpc52xx_uart_int_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char ch, flag;
-       unsigned short status;
-
-       /* While we can read, do so ! */
-       while (psc_ops->raw_rx_rdy(port)) {
-               /* Get the char */
-               ch = psc_ops->read_char(port);
-
-               /* Handle sysreq char */
-#ifdef SUPPORT_SYSRQ
-               if (uart_handle_sysrq_char(port, ch)) {
-                       port->sysrq = 0;
-                       continue;
-               }
-#endif
-
-               /* Store it */
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               status = in_be16(&PSC(port)->mpc52xx_psc_status);
-
-               if (status & (MPC52xx_PSC_SR_PE |
-                             MPC52xx_PSC_SR_FE |
-                             MPC52xx_PSC_SR_RB)) {
-
-                       if (status & MPC52xx_PSC_SR_RB) {
-                               flag = TTY_BREAK;
-                               uart_handle_break(port);
-                               port->icount.brk++;
-                       } else if (status & MPC52xx_PSC_SR_PE) {
-                               flag = TTY_PARITY;
-                               port->icount.parity++;
-                       }
-                       else if (status & MPC52xx_PSC_SR_FE) {
-                               flag = TTY_FRAME;
-                               port->icount.frame++;
-                       }
-
-                       /* Clear error condition */
-                       out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
-
-               }
-               tty_insert_flip_char(tty, ch, flag);
-               if (status & MPC52xx_PSC_SR_OE) {
-                       /*
-                        * Overrun is special, since it's
-                        * reported immediately, and doesn't
-                        * affect the current character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-                       port->icount.overrun++;
-               }
-       }
-
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&port->lock);
-
-       return psc_ops->raw_rx_rdy(port);
-}
-
-static inline int
-mpc52xx_uart_int_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       /* Process out of band chars */
-       if (port->x_char) {
-               psc_ops->write_char(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       /* Nothing to do ? */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mpc52xx_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Send chars */
-       while (psc_ops->raw_tx_rdy(port)) {
-               psc_ops->write_char(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Wake up */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       /* Maybe we're done after all */
-       if (uart_circ_empty(xmit)) {
-               mpc52xx_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-static irqreturn_t
-mpc5xxx_uart_process_int(struct uart_port *port)
-{
-       unsigned long pass = ISR_PASS_LIMIT;
-       unsigned int keepgoing;
-       u8 status;
-
-       /* While we have stuff to do, we continue */
-       do {
-               /* If we don't find anything to do, we stop */
-               keepgoing = 0;
-
-               psc_ops->rx_clr_irq(port);
-               if (psc_ops->rx_rdy(port))
-                       keepgoing |= mpc52xx_uart_int_rx_chars(port);
-
-               psc_ops->tx_clr_irq(port);
-               if (psc_ops->tx_rdy(port))
-                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
-
-               status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
-               if (status & MPC52xx_PSC_D_DCD)
-                       uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
-
-               if (status & MPC52xx_PSC_D_CTS)
-                       uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
-
-               /* Limit number of iteration */
-               if (!(--pass))
-                       keepgoing = 0;
-
-       } while (keepgoing);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t
-mpc52xx_uart_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       irqreturn_t ret;
-
-       spin_lock(&port->lock);
-
-       ret = psc_ops->handle_irq(port);
-
-       spin_unlock(&port->lock);
-
-       return ret;
-}
-
-/* ======================================================================== */
-/* Console ( if applicable )                                                */
-/* ======================================================================== */
-
-#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
-
-static void __init
-mpc52xx_console_get_options(struct uart_port *port,
-                           int *baud, int *parity, int *bits, int *flow)
-{
-       struct mpc52xx_psc __iomem *psc = PSC(port);
-       unsigned char mr1;
-
-       pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
-
-       /* Read the mode registers */
-       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
-       mr1 = in_8(&psc->mode);
-
-       /* CT{U,L}R are write-only ! */
-       *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-
-       /* Parse them */
-       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
-       case MPC52xx_PSC_MODE_5_BITS:
-               *bits = 5;
-               break;
-       case MPC52xx_PSC_MODE_6_BITS:
-               *bits = 6;
-               break;
-       case MPC52xx_PSC_MODE_7_BITS:
-               *bits = 7;
-               break;
-       case MPC52xx_PSC_MODE_8_BITS:
-       default:
-               *bits = 8;
-       }
-
-       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
-               *parity = 'n';
-       else
-               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
-}
-
-static void
-mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &mpc52xx_uart_ports[co->index];
-       unsigned int i, j;
-
-       /* Disable interrupts */
-       psc_ops->cw_disable_ints(port);
-
-       /* Wait the TX buffer to be empty */
-       j = 5000000;    /* Maximum wait */
-       while (!mpc52xx_uart_tx_empty(port) && --j)
-               udelay(1);
-
-       /* Write all the chars */
-       for (i = 0; i < count; i++, s++) {
-               /* Line return handling */
-               if (*s == '\n')
-                       psc_ops->write_char(port, '\r');
-
-               /* Send the char */
-               psc_ops->write_char(port, *s);
-
-               /* Wait the TX buffer to be empty */
-               j = 20000;      /* Maximum wait */
-               while (!mpc52xx_uart_tx_empty(port) && --j)
-                       udelay(1);
-       }
-
-       /* Restore interrupt state */
-       psc_ops->cw_restore_ints(port);
-}
-
-
-static int __init
-mpc52xx_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &mpc52xx_uart_ports[co->index];
-       struct device_node *np = mpc52xx_uart_nodes[co->index];
-       unsigned int uartclk;
-       struct resource res;
-       int ret;
-
-       int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
-                co, co->index, options);
-
-       if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) {
-               pr_debug("PSC%x out of range\n", co->index);
-               return -EINVAL;
-       }
-
-       if (!np) {
-               pr_debug("PSC%x not found in device tree\n", co->index);
-               return -EINVAL;
-       }
-
-       pr_debug("Console on ttyPSC%x is %s\n",
-                co->index, mpc52xx_uart_nodes[co->index]->full_name);
-
-       /* Fetch register locations */
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               pr_debug("Could not get resources for PSC%x\n", co->index);
-               return ret;
-       }
-
-       uartclk = mpc5xxx_get_bus_frequency(np);
-       if (uartclk == 0) {
-               pr_debug("Could not find uart clock frequency!\n");
-               return -EINVAL;
-       }
-
-       /* Basic port init. Needed since we use some uart_??? func before
-        * real init for early access */
-       spin_lock_init(&port->lock);
-       port->uartclk = uartclk;
-       port->ops       = &mpc52xx_uart_ops;
-       port->mapbase = res.start;
-       port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
-       port->irq = irq_of_parse_and_map(np, 0);
-
-       if (port->membase == NULL)
-               return -EINVAL;
-
-       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
-                (void *)port->mapbase, port->membase,
-                port->irq, port->uartclk);
-
-       /* Setup the port parameters accoding to options */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
-
-       pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
-                baud, bits, parity, flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-
-static struct uart_driver mpc52xx_uart_driver;
-
-static struct console mpc52xx_console = {
-       .name   = "ttyPSC",
-       .write  = mpc52xx_console_write,
-       .device = uart_console_device,
-       .setup  = mpc52xx_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,   /* Specified on the cmdline (e.g. console=ttyPSC0) */
-       .data   = &mpc52xx_uart_driver,
-};
-
-
-static int __init
-mpc52xx_console_init(void)
-{
-       mpc52xx_uart_of_enumerate();
-       register_console(&mpc52xx_console);
-       return 0;
-}
-
-console_initcall(mpc52xx_console_init);
-
-#define MPC52xx_PSC_CONSOLE &mpc52xx_console
-#else
-#define MPC52xx_PSC_CONSOLE NULL
-#endif
-
-
-/* ======================================================================== */
-/* UART Driver                                                              */
-/* ======================================================================== */
-
-static struct uart_driver mpc52xx_uart_driver = {
-       .driver_name    = "mpc52xx_psc_uart",
-       .dev_name       = "ttyPSC",
-       .major          = SERIAL_PSC_MAJOR,
-       .minor          = SERIAL_PSC_MINOR,
-       .nr             = MPC52xx_PSC_MAXNUM,
-       .cons           = MPC52xx_PSC_CONSOLE,
-};
-
-/* ======================================================================== */
-/* OF Platform Driver                                                       */
-/* ======================================================================== */
-
-static struct of_device_id mpc52xx_uart_of_match[] = {
-#ifdef CONFIG_PPC_MPC52xx
-       { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
-       { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
-       /* binding used by old lite5200 device trees: */
-       { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
-       /* binding used by efika: */
-       { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
-#endif
-#ifdef CONFIG_PPC_MPC512x
-       { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
-#endif
-       {},
-};
-
-static int __devinit
-mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       int idx = -1;
-       unsigned int uartclk;
-       struct uart_port *port = NULL;
-       struct resource res;
-       int ret;
-
-       dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
-
-       /* Check validity & presence */
-       for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
-               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
-                       break;
-       if (idx >= MPC52xx_PSC_MAXNUM)
-               return -EINVAL;
-       pr_debug("Found %s assigned to ttyPSC%x\n",
-                mpc52xx_uart_nodes[idx]->full_name, idx);
-
-       /* set the uart clock to the input clock of the psc, the different
-        * prescalers are taken into account in the set_baudrate() methods
-        * of the respective chip */
-       uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
-       if (uartclk == 0) {
-               dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
-               return -EINVAL;
-       }
-
-       /* Init the port structure */
-       port = &mpc52xx_uart_ports[idx];
-
-       spin_lock_init(&port->lock);
-       port->uartclk = uartclk;
-       port->fifosize  = 512;
-       port->iotype    = UPIO_MEM;
-       port->flags     = UPF_BOOT_AUTOCONF |
-                         (uart_console(port) ? 0 : UPF_IOREMAP);
-       port->line      = idx;
-       port->ops       = &mpc52xx_uart_ops;
-       port->dev       = &op->dev;
-
-       /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(op->dev.of_node, 0, &res);
-       if (ret)
-               return ret;
-
-       port->mapbase = res.start;
-       if (!port->mapbase) {
-               dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
-               return -EINVAL;
-       }
-
-       psc_ops->get_irq(port, op->dev.of_node);
-       if (port->irq == NO_IRQ) {
-               dev_dbg(&op->dev, "Could not get irq\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
-               (void *)port->mapbase, port->irq, port->uartclk);
-
-       /* Add the port to the uart sub-system */
-       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
-       if (ret)
-               return ret;
-
-       dev_set_drvdata(&op->dev, (void *)port);
-       return 0;
-}
-
-static int
-mpc52xx_uart_of_remove(struct platform_device *op)
-{
-       struct uart_port *port = dev_get_drvdata(&op->dev);
-       dev_set_drvdata(&op->dev, NULL);
-
-       if (port)
-               uart_remove_one_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
-{
-       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
-
-       if (port)
-               uart_suspend_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-static int
-mpc52xx_uart_of_resume(struct platform_device *op)
-{
-       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
-
-       if (port)
-               uart_resume_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-#endif
-
-static void
-mpc52xx_uart_of_assign(struct device_node *np)
-{
-       int i;
-
-       /* Find the first free PSC number */
-       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
-               if (mpc52xx_uart_nodes[i] == NULL) {
-                       of_node_get(np);
-                       mpc52xx_uart_nodes[i] = np;
-                       return;
-               }
-       }
-}
-
-static void
-mpc52xx_uart_of_enumerate(void)
-{
-       static int enum_done;
-       struct device_node *np;
-       const struct  of_device_id *match;
-       int i;
-
-       if (enum_done)
-               return;
-
-       /* Assign index to each PSC in device tree */
-       for_each_matching_node(np, mpc52xx_uart_of_match) {
-               match = of_match_node(mpc52xx_uart_of_match, np);
-               psc_ops = match->data;
-               mpc52xx_uart_of_assign(np);
-       }
-
-       enum_done = 1;
-
-       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
-               if (mpc52xx_uart_nodes[i])
-                       pr_debug("%s assigned to ttyPSC%x\n",
-                                mpc52xx_uart_nodes[i]->full_name, i);
-       }
-}
-
-MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
-
-static struct of_platform_driver mpc52xx_uart_of_driver = {
-       .probe          = mpc52xx_uart_of_probe,
-       .remove         = mpc52xx_uart_of_remove,
-#ifdef CONFIG_PM
-       .suspend        = mpc52xx_uart_of_suspend,
-       .resume         = mpc52xx_uart_of_resume,
-#endif
-       .driver = {
-               .name = "mpc52xx-psc-uart",
-               .owner = THIS_MODULE,
-               .of_match_table = mpc52xx_uart_of_match,
-       },
-};
-
-
-/* ======================================================================== */
-/* Module                                                                   */
-/* ======================================================================== */
-
-static int __init
-mpc52xx_uart_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
-
-       ret = uart_register_driver(&mpc52xx_uart_driver);
-       if (ret) {
-               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
-                      __FILE__, ret);
-               return ret;
-       }
-
-       mpc52xx_uart_of_enumerate();
-
-       /*
-        * Map the PSC FIFO Controller and init if on MPC512x.
-        */
-       if (psc_ops && psc_ops->fifoc_init) {
-               ret = psc_ops->fifoc_init();
-               if (ret)
-                       return ret;
-       }
-
-       ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
-       if (ret) {
-               printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
-                      __FILE__, ret);
-               uart_unregister_driver(&mpc52xx_uart_driver);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void __exit
-mpc52xx_uart_exit(void)
-{
-       if (psc_ops->fifoc_uninit)
-               psc_ops->fifoc_uninit();
-
-       of_unregister_platform_driver(&mpc52xx_uart_of_driver);
-       uart_unregister_driver(&mpc52xx_uart_driver);
-}
-
-
-module_init(mpc52xx_uart_init);
-module_exit(mpc52xx_uart_exit);
-
-MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
-MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
deleted file mode 100644 (file)
index 6a9c660..0000000
+++ /dev/null
@@ -1,2159 +0,0 @@
-/*
- * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
- * GT64260, MV64340, MV64360, GT96100, ... ).
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * Based on an old MPSC driver that was in the linuxppc tree.  It appears to
- * have been created by Chris Zankel (formerly of MontaVista) but there
- * is no proper Copyright so I'm not sure.  Apparently, parts were also
- * taken from PPCBoot (now U-Boot).  Also based on drivers/serial/8250.c
- * by Russell King.
- *
- * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * The MPSC interface is much like a typical network controller's interface.
- * That is, you set up separate rings of descriptors for transmitting and
- * receiving data.  There is also a pool of buffers with (one buffer per
- * descriptor) that incoming data are dma'd into or outgoing data are dma'd
- * out of.
- *
- * The MPSC requires two other controllers to be able to work.  The Baud Rate
- * Generator (BRG) provides a clock at programmable frequencies which determines
- * the baud rate.  The Serial DMA Controller (SDMA) takes incoming data from the
- * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
- * MPSC.  It is actually the SDMA interrupt that the driver uses to keep the
- * transmit and receive "engines" going (i.e., indicate data has been
- * transmitted or received).
- *
- * NOTES:
- *
- * 1) Some chips have an erratum where several regs cannot be
- * read.  To work around that, we keep a local copy of those regs in
- * 'mpsc_port_info'.
- *
- * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
- * accesses system mem with coherency enabled.  For that reason, the driver
- * assumes that coherency for that ctlr has been disabled.  This means
- * that when in a cache coherent system, the driver has to manually manage
- * the data cache on the areas that it touches because the dma_* macro are
- * basically no-ops.
- *
- * 3) There is an erratum (on PPC) where you can't use the instruction to do
- * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
- * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
- *
- * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
- */
-
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mv643xx.h>
-#include <linux/platform_device.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define        MPSC_NUM_CTLRS          2
-
-/*
- * Descriptors and buffers must be cache line aligned.
- * Buffers lengths must be multiple of cache line size.
- * Number of Tx & Rx descriptors must be powers of 2.
- */
-#define        MPSC_RXR_ENTRIES        32
-#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
-#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
-
-#define        MPSC_TXR_ENTRIES        32
-#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
-#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-
-#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
-               + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
-
-/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
-struct mpsc_rx_desc {
-       u16 bufsize;
-       u16 bytecnt;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-struct mpsc_tx_desc {
-       u16 bytecnt;
-       u16 shadow;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-/*
- * Some regs that have the erratum that you can't read them are are shared
- * between the two MPSC controllers.  This struct contains those shared regs.
- */
-struct mpsc_shared_regs {
-       phys_addr_t mpsc_routing_base_p;
-       phys_addr_t sdma_intr_base_p;
-
-       void __iomem *mpsc_routing_base;
-       void __iomem *sdma_intr_base;
-
-       u32 MPSC_MRR_m;
-       u32 MPSC_RCRR_m;
-       u32 MPSC_TCRR_m;
-       u32 SDMA_INTR_CAUSE_m;
-       u32 SDMA_INTR_MASK_m;
-};
-
-/* The main driver data structure */
-struct mpsc_port_info {
-       struct uart_port port;  /* Overlay uart_port structure */
-
-       /* Internal driver state for this ctlr */
-       u8 ready;
-       u8 rcv_data;
-       tcflag_t c_iflag;       /* save termios->c_iflag */
-       tcflag_t c_cflag;       /* save termios->c_cflag */
-
-       /* Info passed in from platform */
-       u8 mirror_regs;         /* Need to mirror regs? */
-       u8 cache_mgmt;          /* Need manual cache mgmt? */
-       u8 brg_can_tune;        /* BRG has baud tuning? */
-       u32 brg_clk_src;
-       u16 mpsc_max_idle;
-       int default_baud;
-       int default_bits;
-       int default_parity;
-       int default_flow;
-
-       /* Physical addresses of various blocks of registers (from platform) */
-       phys_addr_t mpsc_base_p;
-       phys_addr_t sdma_base_p;
-       phys_addr_t brg_base_p;
-
-       /* Virtual addresses of various blocks of registers (from platform) */
-       void __iomem *mpsc_base;
-       void __iomem *sdma_base;
-       void __iomem *brg_base;
-
-       /* Descriptor ring and buffer allocations */
-       void *dma_region;
-       dma_addr_t dma_region_p;
-
-       dma_addr_t rxr;         /* Rx descriptor ring */
-       dma_addr_t rxr_p;       /* Phys addr of rxr */
-       u8 *rxb;                /* Rx Ring I/O buf */
-       u8 *rxb_p;              /* Phys addr of rxb */
-       u32 rxr_posn;           /* First desc w/ Rx data */
-
-       dma_addr_t txr;         /* Tx descriptor ring */
-       dma_addr_t txr_p;       /* Phys addr of txr */
-       u8 *txb;                /* Tx Ring I/O buf */
-       u8 *txb_p;              /* Phys addr of txb */
-       int txr_head;           /* Where new data goes */
-       int txr_tail;           /* Where sent data comes off */
-       spinlock_t tx_lock;     /* transmit lock */
-
-       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
-       u32 MPSC_MPCR_m;
-       u32 MPSC_CHR_1_m;
-       u32 MPSC_CHR_2_m;
-       u32 MPSC_CHR_10_m;
-       u32 BRG_BCR_m;
-       struct mpsc_shared_regs *shared_regs;
-};
-
-/* Hooks to platform-specific code */
-int mpsc_platform_register_driver(void);
-void mpsc_platform_unregister_driver(void);
-
-/* Hooks back in to mpsc common to be called by platform-specific code */
-struct mpsc_port_info *mpsc_device_probe(int index);
-struct mpsc_port_info *mpsc_device_remove(int index);
-
-/* Main MPSC Configuration Register Offsets */
-#define        MPSC_MMCRL                      0x0000
-#define        MPSC_MMCRH                      0x0004
-#define        MPSC_MPCR                       0x0008
-#define        MPSC_CHR_1                      0x000c
-#define        MPSC_CHR_2                      0x0010
-#define        MPSC_CHR_3                      0x0014
-#define        MPSC_CHR_4                      0x0018
-#define        MPSC_CHR_5                      0x001c
-#define        MPSC_CHR_6                      0x0020
-#define        MPSC_CHR_7                      0x0024
-#define        MPSC_CHR_8                      0x0028
-#define        MPSC_CHR_9                      0x002c
-#define        MPSC_CHR_10                     0x0030
-#define        MPSC_CHR_11                     0x0034
-
-#define        MPSC_MPCR_FRZ                   (1 << 9)
-#define        MPSC_MPCR_CL_5                  0
-#define        MPSC_MPCR_CL_6                  1
-#define        MPSC_MPCR_CL_7                  2
-#define        MPSC_MPCR_CL_8                  3
-#define        MPSC_MPCR_SBL_1                 0
-#define        MPSC_MPCR_SBL_2                 1
-
-#define        MPSC_CHR_2_TEV                  (1<<1)
-#define        MPSC_CHR_2_TA                   (1<<7)
-#define        MPSC_CHR_2_TTCS                 (1<<9)
-#define        MPSC_CHR_2_REV                  (1<<17)
-#define        MPSC_CHR_2_RA                   (1<<23)
-#define        MPSC_CHR_2_CRD                  (1<<25)
-#define        MPSC_CHR_2_EH                   (1<<31)
-#define        MPSC_CHR_2_PAR_ODD              0
-#define        MPSC_CHR_2_PAR_SPACE            1
-#define        MPSC_CHR_2_PAR_EVEN             2
-#define        MPSC_CHR_2_PAR_MARK             3
-
-/* MPSC Signal Routing */
-#define        MPSC_MRR                        0x0000
-#define        MPSC_RCRR                       0x0004
-#define        MPSC_TCRR                       0x0008
-
-/* Serial DMA Controller Interface Registers */
-#define        SDMA_SDC                        0x0000
-#define        SDMA_SDCM                       0x0008
-#define        SDMA_RX_DESC                    0x0800
-#define        SDMA_RX_BUF_PTR                 0x0808
-#define        SDMA_SCRDP                      0x0810
-#define        SDMA_TX_DESC                    0x0c00
-#define        SDMA_SCTDP                      0x0c10
-#define        SDMA_SFTDP                      0x0c14
-
-#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
-#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
-#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
-#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
-#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
-#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
-#define        SDMA_DESC_CMDSTAT_A             (1<<11)
-#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
-#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
-#define        SDMA_DESC_CMDSTAT_C             (1<<14)
-#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
-#define        SDMA_DESC_CMDSTAT_L             (1<<16)
-#define        SDMA_DESC_CMDSTAT_F             (1<<17)
-#define        SDMA_DESC_CMDSTAT_P             (1<<18)
-#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
-#define        SDMA_DESC_CMDSTAT_O             (1<<31)
-
-#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O \
-               | SDMA_DESC_CMDSTAT_EI)
-
-#define        SDMA_SDC_RFT                    (1<<0)
-#define        SDMA_SDC_SFM                    (1<<1)
-#define        SDMA_SDC_BLMR                   (1<<6)
-#define        SDMA_SDC_BLMT                   (1<<7)
-#define        SDMA_SDC_POVR                   (1<<8)
-#define        SDMA_SDC_RIFB                   (1<<9)
-
-#define        SDMA_SDCM_ERD                   (1<<7)
-#define        SDMA_SDCM_AR                    (1<<15)
-#define        SDMA_SDCM_STD                   (1<<16)
-#define        SDMA_SDCM_TXD                   (1<<23)
-#define        SDMA_SDCM_AT                    (1<<31)
-
-#define        SDMA_0_CAUSE_RXBUF              (1<<0)
-#define        SDMA_0_CAUSE_RXERR              (1<<1)
-#define        SDMA_0_CAUSE_TXBUF              (1<<2)
-#define        SDMA_0_CAUSE_TXEND              (1<<3)
-#define        SDMA_1_CAUSE_RXBUF              (1<<8)
-#define        SDMA_1_CAUSE_RXERR              (1<<9)
-#define        SDMA_1_CAUSE_TXBUF              (1<<10)
-#define        SDMA_1_CAUSE_TXEND              (1<<11)
-
-#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
-               | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
-               | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
-
-/* SDMA Interrupt registers */
-#define        SDMA_INTR_CAUSE                 0x0000
-#define        SDMA_INTR_MASK                  0x0080
-
-/* Baud Rate Generator Interface Registers */
-#define        BRG_BCR                         0x0000
-#define        BRG_BTR                         0x0004
-
-/*
- * Define how this driver is known to the outside (we've been assigned a
- * range on the "Low-density serial ports" major).
- */
-#define MPSC_MAJOR                     204
-#define MPSC_MINOR_START               44
-#define        MPSC_DRIVER_NAME                "MPSC"
-#define        MPSC_DEV_NAME                   "ttyMM"
-#define        MPSC_VERSION                    "1.00"
-
-static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
-static struct mpsc_shared_regs mpsc_shared_regs;
-static struct uart_driver mpsc_reg;
-
-static void mpsc_start_rx(struct mpsc_port_info *pi);
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
-static void mpsc_release_port(struct uart_port *port);
-/*
- ******************************************************************************
- *
- * Baud Rate Generator Routines (BRG)
- *
- ******************************************************************************
- */
-static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
-
-       if (pi->brg_can_tune)
-               v &= ~(1 << 25);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-
-       writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
-               pi->brg_base + BRG_BTR);
-}
-
-static void mpsc_brg_enable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v |= (1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-static void mpsc_brg_disable(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v &= ~(1 << 16);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-}
-
-/*
- * To set the baud, we adjust the CDV field in the BRG_BCR reg.
- * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
- * However, the input clock is divided by 16 in the MPSC b/c of how
- * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
- * calculation by 16 to account for that.  So the real calculation
- * that accounts for the way the mpsc is set up is:
- * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
- */
-static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
-{
-       u32     cdv = (pi->port.uartclk / (baud << 5)) - 1;
-       u32     v;
-
-       mpsc_brg_disable(pi);
-       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
-       v = (v & 0xffff0000) | (cdv & 0xffff);
-
-       if (pi->mirror_regs)
-               pi->BRG_BCR_m = v;
-       writel(v, pi->brg_base + BRG_BCR);
-       mpsc_brg_enable(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Serial DMA Routines (SDMA)
- *
- ******************************************************************************
- */
-
-static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
-                       pi->port.line, burst_size);
-
-       burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
-
-       if (burst_size < 2)
-               v = 0x0;        /* 1 64-bit word */
-       else if (burst_size < 4)
-               v = 0x1;        /* 2 64-bit words */
-       else if (burst_size < 8)
-               v = 0x2;        /* 4 64-bit words */
-       else
-               v = 0x3;        /* 8 64-bit words */
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
-               pi->sdma_base + SDMA_SDC);
-}
-
-static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
-{
-       pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
-               burst_size);
-
-       writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
-               pi->sdma_base + SDMA_SDC);
-       mpsc_sdma_burstsize(pi, burst_size);
-}
-
-static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     old, v;
-
-       pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
-
-       old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
-               readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v &= ~mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       if (pi->port.line)
-               old >>= 8;
-       return old & 0xf;
-}
-
-static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
-{
-       u32     v;
-
-       pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
-
-       v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
-               : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
-       mask &= 0xf;
-       if (pi->port.line)
-               mask <<= 8;
-       v |= mask;
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_MASK_m = v;
-       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-}
-
-static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
-
-       if (pi->mirror_regs)
-               pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
-       writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
-                       + pi->port.line);
-}
-
-static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
-               struct mpsc_rx_desc *rxre_p)
-{
-       pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
-               pi->port.line, (u32)rxre_p);
-
-       writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
-}
-
-static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
-               struct mpsc_tx_desc *txre_p)
-{
-       writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
-       writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
-}
-
-static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
-{
-       u32     v;
-
-       v = readl(pi->sdma_base + SDMA_SDCM);
-       if (val)
-               v |= val;
-       else
-               v = 0;
-       wmb();
-       writel(v, pi->sdma_base + SDMA_SDCM);
-       wmb();
-}
-
-static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
-{
-       return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
-}
-
-static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre, *txre_p;
-
-       /* If tx isn't running & there's a desc ready to go, start it */
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
-                       txre_p = (struct mpsc_tx_desc *)
-                               (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-                       mpsc_sdma_set_tx_ring(pi, txre_p);
-                       mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
-               }
-       }
-}
-
-static void mpsc_sdma_stop(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
-
-       /* Abort any SDMA transfers */
-       mpsc_sdma_cmd(pi, 0);
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
-
-       /* Clear the SDMA current and first TX and RX pointers */
-       mpsc_sdma_set_tx_ring(pi, NULL);
-       mpsc_sdma_set_rx_ring(pi, NULL);
-
-       /* Disable interrupts */
-       mpsc_sdma_intr_mask(pi, 0xf);
-       mpsc_sdma_intr_ack(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Multi-Protocol Serial Controller Routines (MPSC)
- *
- ******************************************************************************
- */
-
-static void mpsc_hw_init(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
-
-       /* Set up clock routing */
-       if (pi->mirror_regs) {
-               v = pi->shared_regs->MPSC_MRR_m;
-               v &= ~0x1c7;
-               pi->shared_regs->MPSC_MRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = pi->shared_regs->MPSC_RCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_RCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = pi->shared_regs->MPSC_TCRR_m;
-               v = (v & ~0xf0f) | 0x100;
-               pi->shared_regs->MPSC_TCRR_m = v;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       } else {
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-               v &= ~0x1c7;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
-               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-               v = (v & ~0xf0f) | 0x100;
-               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-       }
-
-       /* Put MPSC in UART mode & enabel Tx/Rx egines */
-       writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
-
-       /* No preamble, 16x divider, low-latency, */
-       writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
-       mpsc_set_baudrate(pi, pi->default_baud);
-
-       if (pi->mirror_regs) {
-               pi->MPSC_CHR_1_m = 0;
-               pi->MPSC_CHR_2_m = 0;
-       }
-       writel(0, pi->mpsc_base + MPSC_CHR_1);
-       writel(0, pi->mpsc_base + MPSC_CHR_2);
-       writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
-       writel(0, pi->mpsc_base + MPSC_CHR_4);
-       writel(0, pi->mpsc_base + MPSC_CHR_5);
-       writel(0, pi->mpsc_base + MPSC_CHR_6);
-       writel(0, pi->mpsc_base + MPSC_CHR_7);
-       writel(0, pi->mpsc_base + MPSC_CHR_8);
-       writel(0, pi->mpsc_base + MPSC_CHR_9);
-       writel(0, pi->mpsc_base + MPSC_CHR_10);
-}
-
-static void mpsc_enter_hunt(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
-                       pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
-                       udelay(10);
-       }
-}
-
-static void mpsc_freeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v |= MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_unfreeze(struct mpsc_port_info *pi)
-{
-       u32     v;
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v &= ~MPSC_MPCR_FRZ;
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-
-       pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
-}
-
-static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-       v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
-               pi->port.line, len);
-
-       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
-               readl(pi->mpsc_base + MPSC_MPCR);
-
-       v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
-
-       if (pi->mirror_regs)
-               pi->MPSC_MPCR_m = v;
-       writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
-{
-       u32     v;
-
-       pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
-
-       v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
-               readl(pi->mpsc_base + MPSC_CHR_2);
-
-       p &= 0x3;
-       v = (v & ~0xc000c) | (p << 18) | (p << 2);
-
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_2_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_2);
-}
-
-/*
- ******************************************************************************
- *
- * Driver Init Routines
- *
- ******************************************************************************
- */
-
-static void mpsc_init_hw(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
-
-       mpsc_brg_init(pi, pi->brg_clk_src);
-       mpsc_brg_enable(pi);
-       mpsc_sdma_init(pi, dma_get_cache_alignment());  /* burst a cacheline */
-       mpsc_sdma_stop(pi);
-       mpsc_hw_init(pi);
-}
-
-static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
-{
-       int rc = 0;
-
-       pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
-               pi->port.line);
-
-       if (!pi->dma_region) {
-               if (!dma_supported(pi->port.dev, 0xffffffff)) {
-                       printk(KERN_ERR "MPSC: Inadequate DMA support\n");
-                       rc = -ENXIO;
-               } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
-                                               MPSC_DMA_ALLOC_SIZE,
-                                               &pi->dma_region_p, GFP_KERNEL))
-                               == NULL) {
-                       printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
-                       rc = -ENOMEM;
-               }
-       }
-
-       return rc;
-}
-
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
-
-       if (pi->dma_region) {
-               dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
-                               pi->dma_region, pi->dma_region_p);
-               pi->dma_region = NULL;
-               pi->dma_region_p = (dma_addr_t)NULL;
-       }
-}
-
-static void mpsc_init_rings(struct mpsc_port_info *pi)
-{
-       struct mpsc_rx_desc *rxre;
-       struct mpsc_tx_desc *txre;
-       dma_addr_t dp, dp_p;
-       u8 *bp, *bp_p;
-       int i;
-
-       pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
-
-       /*
-        * Descriptors & buffers are multiples of cacheline size and must be
-        * cacheline aligned.
-        */
-       dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
-       dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
-
-       /*
-        * Partition dma region into rx ring descriptor, rx buffers,
-        * tx ring descriptors, and tx buffers.
-        */
-       pi->rxr = dp;
-       pi->rxr_p = dp_p;
-       dp += MPSC_RXR_SIZE;
-       dp_p += MPSC_RXR_SIZE;
-
-       pi->rxb = (u8 *)dp;
-       pi->rxb_p = (u8 *)dp_p;
-       dp += MPSC_RXB_SIZE;
-       dp_p += MPSC_RXB_SIZE;
-
-       pi->rxr_posn = 0;
-
-       pi->txr = dp;
-       pi->txr_p = dp_p;
-       dp += MPSC_TXR_SIZE;
-       dp_p += MPSC_TXR_SIZE;
-
-       pi->txb = (u8 *)dp;
-       pi->txb_p = (u8 *)dp_p;
-
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-
-       /* Init rx ring descriptors */
-       dp = pi->rxr;
-       dp_p = pi->rxr_p;
-       bp = pi->rxb;
-       bp_p = pi->rxb_p;
-
-       for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
-               rxre = (struct mpsc_rx_desc *)dp;
-
-               rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
-               rxre->bytecnt = cpu_to_be16(0);
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
-               rxre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_RXRE_SIZE;
-               dp_p += MPSC_RXRE_SIZE;
-               bp += MPSC_RXBE_SIZE;
-               bp_p += MPSC_RXBE_SIZE;
-       }
-       rxre->link = cpu_to_be32(pi->rxr_p);    /* Wrap last back to first */
-
-       /* Init tx ring descriptors */
-       dp = pi->txr;
-       dp_p = pi->txr_p;
-       bp = pi->txb;
-       bp_p = pi->txb_p;
-
-       for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
-               txre = (struct mpsc_tx_desc *)dp;
-
-               txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
-               txre->buf_ptr = cpu_to_be32(bp_p);
-
-               dp += MPSC_TXRE_SIZE;
-               dp_p += MPSC_TXRE_SIZE;
-               bp += MPSC_TXBE_SIZE;
-               bp_p += MPSC_TXBE_SIZE;
-       }
-       txre->link = cpu_to_be32(pi->txr_p);    /* Wrap last back to first */
-
-       dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
-                       MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)pi->dma_region,
-                                       (ulong)pi->dma_region
-                                       + MPSC_DMA_ALLOC_SIZE);
-#endif
-
-       return;
-}
-
-static void mpsc_uninit_rings(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
-
-       BUG_ON(pi->dma_region == NULL);
-
-       pi->rxr = 0;
-       pi->rxr_p = 0;
-       pi->rxb = NULL;
-       pi->rxb_p = NULL;
-       pi->rxr_posn = 0;
-
-       pi->txr = 0;
-       pi->txr_p = 0;
-       pi->txb = NULL;
-       pi->txb_p = NULL;
-       pi->txr_head = 0;
-       pi->txr_tail = 0;
-}
-
-static int mpsc_make_ready(struct mpsc_port_info *pi)
-{
-       int rc;
-
-       pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
-
-       if (!pi->ready) {
-               mpsc_init_hw(pi);
-               if ((rc = mpsc_alloc_ring_mem(pi)))
-                       return rc;
-               mpsc_init_rings(pi);
-               pi->ready = 1;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- ******************************************************************************
- *
- * Interrupt Handling Routines
- *
- ******************************************************************************
- */
-
-static int mpsc_rx_intr(struct mpsc_port_info *pi)
-{
-       struct mpsc_rx_desc *rxre;
-       struct tty_struct *tty = pi->port.state->port.tty;
-       u32     cmdstat, bytes_in, i;
-       int     rc = 0;
-       u8      *bp;
-       char    flag = TTY_NORMAL;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
-
-       dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                       DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               invalidate_dcache_range((ulong)rxre,
-                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-       /*
-        * Loop through Rx descriptors handling ones that have been completed.
-        */
-       while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
-                               & SDMA_DESC_CMDSTAT_O)) {
-               bytes_in = be16_to_cpu(rxre->bytecnt);
-#ifdef CONFIG_CONSOLE_POLL
-               if (unlikely(serial_polled)) {
-                       serial_polled = 0;
-                       return 0;
-               }
-#endif
-               /* Following use of tty struct directly is deprecated */
-               if (unlikely(tty_buffer_request_room(tty, bytes_in)
-                                       < bytes_in)) {
-                       if (tty->low_latency)
-                               tty_flip_buffer_push(tty);
-                       /*
-                        * If this failed then we will throw away the bytes
-                        * but must do so to clear interrupts.
-                        */
-               }
-
-               bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-
-               /*
-                * Other than for parity error, the manual provides little
-                * info on what data will be in a frame flagged by any of
-                * these errors.  For parity error, it is the last byte in
-                * the buffer that had the error.  As for the rest, I guess
-                * we'll assume there is no data in the buffer.
-                * If there is...it gets lost.
-                */
-               if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR))) {
-
-                       pi->port.icount.rx++;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR) {   /* Break */
-                               pi->port.icount.brk++;
-
-                               if (uart_handle_break(&pi->port))
-                                       goto next_frame;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
-                               pi->port.icount.frame++;
-                       } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
-                               pi->port.icount.overrun++;
-                       }
-
-                       cmdstat &= pi->port.read_status_mask;
-
-                       if (cmdstat & SDMA_DESC_CMDSTAT_BR)
-                               flag = TTY_BREAK;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
-                               flag = TTY_FRAME;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
-                               flag = TTY_OVERRUN;
-                       else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(&pi->port, *bp)) {
-                       bp++;
-                       bytes_in--;
-#ifdef CONFIG_CONSOLE_POLL
-                       if (unlikely(serial_polled)) {
-                               serial_polled = 0;
-                               return 0;
-                       }
-#endif
-                       goto next_frame;
-               }
-
-               if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
-                                               | SDMA_DESC_CMDSTAT_FR
-                                               | SDMA_DESC_CMDSTAT_OR)))
-                               && !(cmdstat & pi->port.ignore_status_mask)) {
-                       tty_insert_flip_char(tty, *bp, flag);
-               } else {
-                       for (i=0; i<bytes_in; i++)
-                               tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
-
-                       pi->port.icount.rx += bytes_in;
-               }
-
-next_frame:
-               rxre->bytecnt = cpu_to_be16(0);
-               wmb();
-               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
-                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
-                               | SDMA_DESC_CMDSTAT_L);
-               wmb();
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-               /* Advance to next descriptor */
-               pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
-               rxre = (struct mpsc_rx_desc *)
-                       (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               rc = 1;
-       }
-
-       /* Restart rx engine, if its stopped */
-       if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-               mpsc_start_rx(pi);
-
-       tty_flip_buffer_push(tty);
-       return rc;
-}
-
-static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
-{
-       struct mpsc_tx_desc *txre;
-
-       txre = (struct mpsc_tx_desc *)(pi->txr
-                       + (pi->txr_head * MPSC_TXRE_SIZE));
-
-       txre->bytecnt = cpu_to_be16(count);
-       txre->shadow = txre->bytecnt;
-       wmb();                  /* ensure cmdstat is last field updated */
-       txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
-                       | SDMA_DESC_CMDSTAT_L
-                       | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
-       wmb();
-       dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                       DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-               flush_dcache_range((ulong)txre,
-                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-}
-
-static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
-{
-       struct circ_buf *xmit = &pi->port.state->xmit;
-       u8 *bp;
-       u32 i;
-
-       /* Make sure the desc ring isn't full */
-       while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
-                       < (MPSC_TXR_ENTRIES - 1)) {
-               if (pi->port.x_char) {
-                       /*
-                        * Ideally, we should use the TCS field in
-                        * CHR_1 to put the x_char out immediately but
-                        * errata prevents us from being able to read
-                        * CHR_2 to know that its safe to write to
-                        * CHR_1.  Instead, just put it in-band with
-                        * all the other Tx data.
-                        */
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       *bp = pi->port.x_char;
-                       pi->port.x_char = 0;
-                       i = 1;
-               } else if (!uart_circ_empty(xmit)
-                               && !uart_tx_stopped(&pi->port)) {
-                       i = min((u32)MPSC_TXBE_SIZE,
-                               (u32)uart_circ_chars_pending(xmit));
-                       i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
-                               UART_XMIT_SIZE));
-                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-                       memcpy(bp, &xmit->buf[xmit->tail], i);
-                       xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
-
-                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                               uart_write_wakeup(&pi->port);
-               } else { /* All tx data copied into ring bufs */
-                       return;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 1);
-
-               /* Advance to next descriptor */
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-}
-
-static int mpsc_tx_intr(struct mpsc_port_info *pi)
-{
-       struct mpsc_tx_desc *txre;
-       int rc = 0;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       if (!mpsc_sdma_tx_active(pi)) {
-               txre = (struct mpsc_tx_desc *)(pi->txr
-                               + (pi->txr_tail * MPSC_TXRE_SIZE));
-
-               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
-                               DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)txre,
-                                       (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
-               while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
-                       rc = 1;
-                       pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
-                       pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
-
-                       /* If no more data to tx, fall out of loop */
-                       if (pi->txr_head == pi->txr_tail)
-                               break;
-
-                       txre = (struct mpsc_tx_desc *)(pi->txr
-                                       + (pi->txr_tail * MPSC_TXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)txre,
-                                       MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)txre,
-                                               (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-               }
-
-               mpsc_copy_tx_data(pi);
-               mpsc_sdma_start_tx(pi); /* start next desc if ready */
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-       return rc;
-}
-
-/*
- * This is the driver's interrupt handler.  To avoid a race, we first clear
- * the interrupt, then handle any completed Rx/Tx descriptors.  When done
- * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
- */
-static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
-{
-       struct mpsc_port_info *pi = dev_id;
-       ulong iflags;
-       int rc = IRQ_NONE;
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       mpsc_sdma_intr_ack(pi);
-       if (mpsc_rx_intr(pi))
-               rc = IRQ_HANDLED;
-       if (mpsc_tx_intr(pi))
-               rc = IRQ_HANDLED;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
-       return rc;
-}
-
-/*
- ******************************************************************************
- *
- * serial_core.c Interface routines
- *
- ******************************************************************************
- */
-static uint mpsc_tx_empty(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       ulong iflags;
-       uint rc;
-
-       spin_lock_irqsave(&pi->port.lock, iflags);
-       rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
-       spin_unlock_irqrestore(&pi->port.lock, iflags);
-
-       return rc;
-}
-
-static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
-{
-       /* Have no way to set modem control lines AFAICT */
-}
-
-static uint mpsc_get_mctrl(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 mflags, status;
-
-       status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
-               : readl(pi->mpsc_base + MPSC_CHR_10);
-
-       mflags = 0;
-       if (status & 0x1)
-               mflags |= TIOCM_CTS;
-       if (status & 0x2)
-               mflags |= TIOCM_CAR;
-
-       return mflags | TIOCM_DSR;      /* No way to tell if DSR asserted */
-}
-
-static void mpsc_stop_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_stop_tx[%d]\n", port->line);
-
-       mpsc_freeze(pi);
-}
-
-static void mpsc_start_tx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       mpsc_unfreeze(pi);
-       mpsc_copy_tx_data(pi);
-       mpsc_sdma_start_tx(pi);
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-
-       pr_debug("mpsc_start_tx[%d]\n", port->line);
-}
-
-static void mpsc_start_rx(struct mpsc_port_info *pi)
-{
-       pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
-
-       if (pi->rcv_data) {
-               mpsc_enter_hunt(pi);
-               mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
-       }
-}
-
-static void mpsc_stop_rx(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
-
-       if (pi->mirror_regs) {
-               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-               /* Erratum prevents reading CHR_2 so just delay for a while */
-               udelay(100);
-       } else {
-               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
-                               pi->mpsc_base + MPSC_CHR_2);
-
-               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
-                       udelay(10);
-       }
-
-       mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
-}
-
-static void mpsc_enable_ms(struct uart_port *port)
-{
-}
-
-static void mpsc_break_ctl(struct uart_port *port, int ctl)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       ulong   flags;
-       u32     v;
-
-       v = ctl ? 0x00ff0000 : 0;
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-       if (pi->mirror_regs)
-               pi->MPSC_CHR_1_m = v;
-       writel(v, pi->mpsc_base + MPSC_CHR_1);
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static int mpsc_startup(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 flag = 0;
-       int rc;
-
-       pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
-               port->line, pi->port.irq);
-
-       if ((rc = mpsc_make_ready(pi)) == 0) {
-               /* Setup IRQ handler */
-               mpsc_sdma_intr_ack(pi);
-
-               /* If irq's are shared, need to set flag */
-               if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
-                       flag = IRQF_SHARED;
-
-               if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
-                                       "mpsc-sdma", pi))
-                       printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
-                                       pi->port.irq);
-
-               mpsc_sdma_intr_unmask(pi, 0xf);
-               mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
-                                       + (pi->rxr_posn * MPSC_RXRE_SIZE)));
-       }
-
-       return rc;
-}
-
-static void mpsc_shutdown(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
-
-       mpsc_sdma_stop(pi);
-       free_irq(pi->port.irq, pi);
-}
-
-static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
-                struct ktermios *old)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 baud;
-       ulong flags;
-       u32 chr_bits, stop_bits, par;
-
-       pi->c_iflag = termios->c_iflag;
-       pi->c_cflag = termios->c_cflag;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               chr_bits = MPSC_MPCR_CL_5;
-               break;
-       case CS6:
-               chr_bits = MPSC_MPCR_CL_6;
-               break;
-       case CS7:
-               chr_bits = MPSC_MPCR_CL_7;
-               break;
-       case CS8:
-       default:
-               chr_bits = MPSC_MPCR_CL_8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               stop_bits = MPSC_MPCR_SBL_2;
-       else
-               stop_bits = MPSC_MPCR_SBL_1;
-
-       par = MPSC_CHR_2_PAR_EVEN;
-       if (termios->c_cflag & PARENB)
-               if (termios->c_cflag & PARODD)
-                       par = MPSC_CHR_2_PAR_ODD;
-#ifdef CMSPAR
-               if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               par = MPSC_CHR_2_PAR_MARK;
-                       else
-                               par = MPSC_CHR_2_PAR_SPACE;
-               }
-#endif
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
-
-       spin_lock_irqsave(&pi->port.lock, flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       mpsc_set_char_length(pi, chr_bits);
-       mpsc_set_stop_bit_length(pi, stop_bits);
-       mpsc_set_parity(pi, par);
-       mpsc_set_baudrate(pi, baud);
-
-       /* Characters/events to read */
-       pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
-
-       if (termios->c_iflag & INPCK)
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-       /* Characters/events to ignore */
-       pi->port.ignore_status_mask = 0;
-
-       if (termios->c_iflag & IGNPAR)
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
-                       | SDMA_DESC_CMDSTAT_FR;
-
-       if (termios->c_iflag & IGNBRK) {
-               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
-               if (termios->c_iflag & IGNPAR)
-                       pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
-       }
-
-       if ((termios->c_cflag & CREAD)) {
-               if (!pi->rcv_data) {
-                       pi->rcv_data = 1;
-                       mpsc_start_rx(pi);
-               }
-       } else if (pi->rcv_data) {
-               mpsc_stop_rx(port);
-               pi->rcv_data = 0;
-       }
-
-       spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static const char *mpsc_type(struct uart_port *port)
-{
-       pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
-       return MPSC_DRIVER_NAME;
-}
-
-static int mpsc_request_port(struct uart_port *port)
-{
-       /* Should make chip/platform specific call */
-       return 0;
-}
-
-static void mpsc_release_port(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-
-       if (pi->ready) {
-               mpsc_uninit_rings(pi);
-               mpsc_free_ring_mem(pi);
-               pi->ready = 0;
-       }
-}
-
-static void mpsc_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       int rc = 0;
-
-       pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
-               rc = -EINVAL;
-       else if (pi->port.irq != ser->irq)
-               rc = -EINVAL;
-       else if (ser->io_type != SERIAL_IO_MEM)
-               rc = -EINVAL;
-       else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
-               rc = -EINVAL;
-       else if ((void *)pi->port.mapbase != ser->iomem_base)
-               rc = -EINVAL;
-       else if (pi->port.iobase != ser->port)
-               rc = -EINVAL;
-       else if (ser->hub6 != 0)
-               rc = -EINVAL;
-
-       return rc;
-}
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static char poll_buf[2048];
-static int poll_ptr;
-static int poll_cnt;
-static void mpsc_put_poll_char(struct uart_port *port,
-                                                          unsigned char c);
-
-static int mpsc_get_poll_char(struct uart_port *port)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       struct mpsc_rx_desc *rxre;
-       u32     cmdstat, bytes_in, i;
-       u8      *bp;
-
-       if (!serial_polled)
-               serial_polled = 1;
-
-       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-       poll_ptr = 0;
-       poll_cnt = 0;
-
-       while (poll_cnt == 0) {
-               rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                      (pi->rxr_posn*MPSC_RXRE_SIZE));
-               dma_cache_sync(pi->port.dev, (void *)rxre,
-                              MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       invalidate_dcache_range((ulong)rxre,
-                       (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               /*
-                * Loop through Rx descriptors handling ones that have
-                * been completed.
-                */
-               while (poll_cnt == 0 &&
-                      !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
-                        SDMA_DESC_CMDSTAT_O)){
-                       bytes_in = be16_to_cpu(rxre->bytecnt);
-                       bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-                       dma_cache_sync(pi->port.dev, (void *) bp,
-                                      MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-                       if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
-                        SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
-                               !(cmdstat & pi->port.ignore_status_mask)) {
-                               poll_buf[poll_cnt] = *bp;
-                               poll_cnt++;
-                       } else {
-                               for (i = 0; i < bytes_in; i++) {
-                                       poll_buf[poll_cnt] = *bp++;
-                                       poll_cnt++;
-                               }
-                               pi->port.icount.rx += bytes_in;
-                       }
-                       rxre->bytecnt = cpu_to_be16(0);
-                       wmb();
-                       rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
-                                                   SDMA_DESC_CMDSTAT_EI |
-                                                   SDMA_DESC_CMDSTAT_F |
-                                                   SDMA_DESC_CMDSTAT_L);
-                       wmb();
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               flush_dcache_range((ulong)rxre,
-                                          (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
-                       /* Advance to next descriptor */
-                       pi->rxr_posn = (pi->rxr_posn + 1) &
-                               (MPSC_RXR_ENTRIES - 1);
-                       rxre = (struct mpsc_rx_desc *)(pi->rxr +
-                                      (pi->rxr_posn * MPSC_RXRE_SIZE));
-                       dma_cache_sync(pi->port.dev, (void *)rxre,
-                                      MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                               invalidate_dcache_range((ulong)rxre,
-                                               (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-               }
-
-               /* Restart rx engine, if its stopped */
-               if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
-                       mpsc_start_rx(pi);
-       }
-       if (poll_cnt) {
-               poll_cnt--;
-               return poll_buf[poll_ptr++];
-       }
-
-       return 0;
-}
-
-
-static void mpsc_put_poll_char(struct uart_port *port,
-                        unsigned char c)
-{
-       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
-       u32 data;
-
-       data = readl(pi->mpsc_base + MPSC_MPCR);
-       writeb(c, pi->mpsc_base + MPSC_CHR_1);
-       mb();
-       data = readl(pi->mpsc_base + MPSC_CHR_2);
-       data |= MPSC_CHR_2_TTCS;
-       writel(data, pi->mpsc_base + MPSC_CHR_2);
-       mb();
-
-       while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
-}
-#endif
-
-static struct uart_ops mpsc_pops = {
-       .tx_empty       = mpsc_tx_empty,
-       .set_mctrl      = mpsc_set_mctrl,
-       .get_mctrl      = mpsc_get_mctrl,
-       .stop_tx        = mpsc_stop_tx,
-       .start_tx       = mpsc_start_tx,
-       .stop_rx        = mpsc_stop_rx,
-       .enable_ms      = mpsc_enable_ms,
-       .break_ctl      = mpsc_break_ctl,
-       .startup        = mpsc_startup,
-       .shutdown       = mpsc_shutdown,
-       .set_termios    = mpsc_set_termios,
-       .type           = mpsc_type,
-       .release_port   = mpsc_release_port,
-       .request_port   = mpsc_request_port,
-       .config_port    = mpsc_config_port,
-       .verify_port    = mpsc_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = mpsc_get_poll_char,
-       .poll_put_char = mpsc_put_poll_char,
-#endif
-};
-
-/*
- ******************************************************************************
- *
- * Console Interface Routines
- *
- ******************************************************************************
- */
-
-#ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void mpsc_console_write(struct console *co, const char *s, uint count)
-{
-       struct mpsc_port_info *pi = &mpsc_ports[co->index];
-       u8 *bp, *dp, add_cr = 0;
-       int i;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&pi->tx_lock, iflags);
-
-       while (pi->txr_head != pi->txr_tail) {
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-               mpsc_sdma_intr_ack(pi);
-               mpsc_tx_intr(pi);
-       }
-
-       while (mpsc_sdma_tx_active(pi))
-               udelay(100);
-
-       while (count > 0) {
-               bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-
-               for (i = 0; i < MPSC_TXBE_SIZE; i++) {
-                       if (count == 0)
-                               break;
-
-                       if (add_cr) {
-                               *(dp++) = '\r';
-                               add_cr = 0;
-                       } else {
-                               *(dp++) = *s;
-
-                               if (*(s++) == '\n') { /* add '\r' after '\n' */
-                                       add_cr = 1;
-                                       count++;
-                               }
-                       }
-
-                       count--;
-               }
-
-               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
-                               DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
-               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
-                       flush_dcache_range((ulong)bp,
-                                       (ulong)bp + MPSC_TXBE_SIZE);
-#endif
-               mpsc_setup_tx_desc(pi, i, 0);
-               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
-               mpsc_sdma_start_tx(pi);
-
-               while (mpsc_sdma_tx_active(pi))
-                       udelay(100);
-
-               pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
-       }
-
-       spin_unlock_irqrestore(&pi->tx_lock, iflags);
-}
-
-static int __init mpsc_console_setup(struct console *co, char *options)
-{
-       struct mpsc_port_info *pi;
-       int baud, bits, parity, flow;
-
-       pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
-
-       if (co->index >= MPSC_NUM_CTLRS)
-               co->index = 0;
-
-       pi = &mpsc_ports[co->index];
-
-       baud = pi->default_baud;
-       bits = pi->default_bits;
-       parity = pi->default_parity;
-       flow = pi->default_flow;
-
-       if (!pi->port.ops)
-               return -ENODEV;
-
-       spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&pi->port, co, baud, parity, bits, flow);
-}
-
-static struct console mpsc_console = {
-       .name   = MPSC_DEV_NAME,
-       .write  = mpsc_console_write,
-       .device = uart_console_device,
-       .setup  = mpsc_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &mpsc_reg,
-};
-
-static int __init mpsc_late_console_init(void)
-{
-       pr_debug("mpsc_late_console_init: Enter\n");
-
-       if (!(mpsc_console.flags & CON_ENABLED))
-               register_console(&mpsc_console);
-       return 0;
-}
-
-late_initcall(mpsc_late_console_init);
-
-#define MPSC_CONSOLE   &mpsc_console
-#else
-#define MPSC_CONSOLE   NULL
-#endif
-/*
- ******************************************************************************
- *
- * Dummy Platform Driver to extract & map shared register regions
- *
- ******************************************************************************
- */
-static void mpsc_resource_err(char *s)
-{
-       printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
-}
-
-static int mpsc_shared_map_regs(struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_ROUTING_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE,
-                               "mpsc_routing_regs")) {
-               mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_shared_regs.mpsc_routing_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC routing base");
-               return -ENOMEM;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_INTR_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE,
-                               "sdma_intr_regs")) {
-               mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
-                       MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-               mpsc_shared_regs.sdma_intr_base_p = r->start;
-       } else {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-               mpsc_resource_err("SDMA intr base");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void mpsc_shared_unmap_regs(void)
-{
-       if (!mpsc_shared_regs.mpsc_routing_base) {
-               iounmap(mpsc_shared_regs.mpsc_routing_base);
-               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-                               MPSC_ROUTING_REG_BLOCK_SIZE);
-       }
-       if (!mpsc_shared_regs.sdma_intr_base) {
-               iounmap(mpsc_shared_regs.sdma_intr_base);
-               release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
-                               MPSC_SDMA_INTR_REG_BLOCK_SIZE);
-       }
-
-       mpsc_shared_regs.mpsc_routing_base = NULL;
-       mpsc_shared_regs.sdma_intr_base = NULL;
-
-       mpsc_shared_regs.mpsc_routing_base_p = 0;
-       mpsc_shared_regs.sdma_intr_base_p = 0;
-}
-
-static int mpsc_shared_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_shared_pdata        *pdata;
-       int                              rc = -ENODEV;
-
-       if (dev->id == 0) {
-               if (!(rc = mpsc_shared_map_regs(dev))) {
-                       pdata = (struct mpsc_shared_pdata *)
-                               dev->dev.platform_data;
-
-                       mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
-                       mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
-                       mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
-                       mpsc_shared_regs.SDMA_INTR_CAUSE_m =
-                               pdata->intr_cause_val;
-                       mpsc_shared_regs.SDMA_INTR_MASK_m =
-                               pdata->intr_mask_val;
-
-                       rc = 0;
-               }
-       }
-
-       return rc;
-}
-
-static int mpsc_shared_drv_remove(struct platform_device *dev)
-{
-       int     rc = -ENODEV;
-
-       if (dev->id == 0) {
-               mpsc_shared_unmap_regs();
-               mpsc_shared_regs.MPSC_MRR_m = 0;
-               mpsc_shared_regs.MPSC_RCRR_m = 0;
-               mpsc_shared_regs.MPSC_TCRR_m = 0;
-               mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
-               mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
-               rc = 0;
-       }
-
-       return rc;
-}
-
-static struct platform_driver mpsc_shared_driver = {
-       .probe  = mpsc_shared_drv_probe,
-       .remove = mpsc_shared_drv_remove,
-       .driver = {
-               .name   = MPSC_SHARED_NAME,
-       },
-};
-
-/*
- ******************************************************************************
- *
- * Driver Interface Routines
- *
- ******************************************************************************
- */
-static struct uart_driver mpsc_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = MPSC_DRIVER_NAME,
-       .dev_name       = MPSC_DEV_NAME,
-       .major          = MPSC_MAJOR,
-       .minor          = MPSC_MINOR_START,
-       .nr             = MPSC_NUM_CTLRS,
-       .cons           = MPSC_CONSOLE,
-};
-
-static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
-               struct platform_device *pd)
-{
-       struct resource *r;
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
-                       && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
-                       "mpsc_regs")) {
-               pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
-               pi->mpsc_base_p = r->start;
-       } else {
-               mpsc_resource_err("MPSC base");
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-                                       MPSC_SDMA_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
-               pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
-               pi->sdma_base_p = r->start;
-       } else {
-               mpsc_resource_err("SDMA base");
-               if (pi->mpsc_base) {
-                       iounmap(pi->mpsc_base);
-                       pi->mpsc_base = NULL;
-               }
-               goto err;
-       }
-
-       if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
-                       && request_mem_region(r->start,
-                               MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
-               pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
-               pi->brg_base_p = r->start;
-       } else {
-               mpsc_resource_err("BRG base");
-               if (pi->mpsc_base) {
-                       iounmap(pi->mpsc_base);
-                       pi->mpsc_base = NULL;
-               }
-               if (pi->sdma_base) {
-                       iounmap(pi->sdma_base);
-                       pi->sdma_base = NULL;
-               }
-               goto err;
-       }
-       return 0;
-
-err:
-       return -ENOMEM;
-}
-
-static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
-{
-       if (!pi->mpsc_base) {
-               iounmap(pi->mpsc_base);
-               release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
-       }
-       if (!pi->sdma_base) {
-               iounmap(pi->sdma_base);
-               release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
-       }
-       if (!pi->brg_base) {
-               iounmap(pi->brg_base);
-               release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
-       }
-
-       pi->mpsc_base = NULL;
-       pi->sdma_base = NULL;
-       pi->brg_base = NULL;
-
-       pi->mpsc_base_p = 0;
-       pi->sdma_base_p = 0;
-       pi->brg_base_p = 0;
-}
-
-static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
-               struct platform_device *pd, int num)
-{
-       struct mpsc_pdata       *pdata;
-
-       pdata = (struct mpsc_pdata *)pd->dev.platform_data;
-
-       pi->port.uartclk = pdata->brg_clk_freq;
-       pi->port.iotype = UPIO_MEM;
-       pi->port.line = num;
-       pi->port.type = PORT_MPSC;
-       pi->port.fifosize = MPSC_TXBE_SIZE;
-       pi->port.membase = pi->mpsc_base;
-       pi->port.mapbase = (ulong)pi->mpsc_base;
-       pi->port.ops = &mpsc_pops;
-
-       pi->mirror_regs = pdata->mirror_regs;
-       pi->cache_mgmt = pdata->cache_mgmt;
-       pi->brg_can_tune = pdata->brg_can_tune;
-       pi->brg_clk_src = pdata->brg_clk_src;
-       pi->mpsc_max_idle = pdata->max_idle;
-       pi->default_baud = pdata->default_baud;
-       pi->default_bits = pdata->default_bits;
-       pi->default_parity = pdata->default_parity;
-       pi->default_flow = pdata->default_flow;
-
-       /* Initial values of mirrored regs */
-       pi->MPSC_CHR_1_m = pdata->chr_1_val;
-       pi->MPSC_CHR_2_m = pdata->chr_2_val;
-       pi->MPSC_CHR_10_m = pdata->chr_10_val;
-       pi->MPSC_MPCR_m = pdata->mpcr_val;
-       pi->BRG_BCR_m = pdata->bcr_val;
-
-       pi->shared_regs = &mpsc_shared_regs;
-
-       pi->port.irq = platform_get_irq(pd, 0);
-}
-
-static int mpsc_drv_probe(struct platform_device *dev)
-{
-       struct mpsc_port_info   *pi;
-       int                     rc = -ENODEV;
-
-       pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               pi = &mpsc_ports[dev->id];
-
-               if (!(rc = mpsc_drv_map_regs(pi, dev))) {
-                       mpsc_drv_get_platform_data(pi, dev, dev->id);
-                       pi->port.dev = &dev->dev;
-
-                       if (!(rc = mpsc_make_ready(pi))) {
-                               spin_lock_init(&pi->tx_lock);
-                               if (!(rc = uart_add_one_port(&mpsc_reg,
-                                                               &pi->port))) {
-                                       rc = 0;
-                               } else {
-                                       mpsc_release_port((struct uart_port *)
-                                                       pi);
-                                       mpsc_drv_unmap_regs(pi);
-                               }
-                       } else {
-                               mpsc_drv_unmap_regs(pi);
-                       }
-               }
-       }
-
-       return rc;
-}
-
-static int mpsc_drv_remove(struct platform_device *dev)
-{
-       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
-               mpsc_release_port((struct uart_port *)
-                               &mpsc_ports[dev->id].port);
-               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
-               return 0;
-       } else {
-               return -ENODEV;
-       }
-}
-
-static struct platform_driver mpsc_driver = {
-       .probe  = mpsc_drv_probe,
-       .remove = mpsc_drv_remove,
-       .driver = {
-               .name   = MPSC_CTLR_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init mpsc_drv_init(void)
-{
-       int     rc;
-
-       printk(KERN_INFO "Serial: MPSC driver\n");
-
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-
-       if (!(rc = uart_register_driver(&mpsc_reg))) {
-               if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
-                       if ((rc = platform_driver_register(&mpsc_driver))) {
-                               platform_driver_unregister(&mpsc_shared_driver);
-                               uart_unregister_driver(&mpsc_reg);
-                       }
-               } else {
-                       uart_unregister_driver(&mpsc_reg);
-               }
-       }
-
-       return rc;
-}
-
-static void __exit mpsc_drv_exit(void)
-{
-       platform_driver_unregister(&mpsc_driver);
-       platform_driver_unregister(&mpsc_shared_driver);
-       uart_unregister_driver(&mpsc_reg);
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-}
-
-module_init(mpsc_drv_init);
-module_exit(mpsc_drv_exit);
-
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_VERSION(MPSC_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
-MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
diff --git a/drivers/serial/mrst_max3110.c b/drivers/serial/mrst_max3110.c
deleted file mode 100644 (file)
index b62857b..0000000
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- *  mrst_max3110.c - spi uart protocol driver for Maxim 3110
- *
- * Copyright (c) 2008-2010, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Note:
- * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
- *    1 word. If SPI master controller doesn't support sclk frequency change,
- *    then the char need be sent out one by one with some delay
- *
- * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE
- *    interrupt for a low speed UART device
- */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-#include <linux/kthread.h>
-#include <linux/spi/spi.h>
-
-#include "mrst_max3110.h"
-
-#define PR_FMT "mrst_max3110: "
-
-#define UART_TX_NEEDED 1
-#define CON_TX_NEEDED  2
-#define BIT_IRQ_PENDING    3
-
-struct uart_max3110 {
-       struct uart_port port;
-       struct spi_device *spi;
-       char name[24];
-
-       wait_queue_head_t wq;
-       struct task_struct *main_thread;
-       struct task_struct *read_thread;
-       struct mutex thread_mutex;;
-
-       u32 baud;
-       u16 cur_conf;
-       u8 clock;
-       u8 parity, word_7bits;
-       u16 irq;
-
-       unsigned long uart_flags;
-
-       /* console related */
-       struct circ_buf con_xmit;
-};
-
-/* global data structure, may need be removed */
-static struct uart_max3110 *pmax;
-
-static void receive_chars(struct uart_max3110 *max,
-                               unsigned char *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
-static void max3110_con_receive(struct uart_max3110 *max);
-
-static int max3110_write_then_read(struct uart_max3110 *max,
-               const void *txbuf, void *rxbuf, unsigned len, int always_fast)
-{
-       struct spi_device *spi = max->spi;
-       struct spi_message      message;
-       struct spi_transfer     x;
-       int ret;
-
-       spi_message_init(&message);
-       memset(&x, 0, sizeof x);
-       x.len = len;
-       x.tx_buf = txbuf;
-       x.rx_buf = rxbuf;
-       spi_message_add_tail(&x, &message);
-
-       if (always_fast)
-               x.speed_hz = spi->max_speed_hz;
-       else if (max->baud)
-               x.speed_hz = max->baud;
-
-       /* Do the i/o */
-       ret = spi_sync(spi, &message);
-       return ret;
-}
-
-/* Write a 16b word to the device */
-static int max3110_out(struct uart_max3110 *max, const u16 out)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8  ch;
-       int ret;
-
-       buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
-       if (!buf)
-               return -ENOMEM;
-
-       obuf = buf;
-       ibuf = buf + 4;
-       *obuf = out;
-       ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
-       if (ret) {
-               pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n",
-                               __func__, ret, out);
-               goto exit;
-       }
-
-       /* If some valid data is read back */
-       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
-               ch = *ibuf & 0xff;
-               receive_chars(max, &ch, 1);
-       }
-
-exit:
-       kfree(buf);
-       return ret;
-}
-
-/*
- * This is usually used to read data from SPIC RX FIFO, which doesn't
- * need any delay like flushing character out.
- *
- * Return how many valide bytes are read back
- */
-static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
-       int i, j, blen;
-
-       blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
-       buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
-       if (!buf) {
-               pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__);
-               return 0;
-       }
-
-       /* tx/rx always have the same length */
-       obuf = buf;
-       ibuf = buf + blen;
-
-       if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
-               kfree(buf);
-               return 0;
-       }
-
-       /* If caller doesn't provide a buffer, then handle received char */
-       pbuf = rxbuf ? rxbuf : valid_str;
-
-       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
-               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                       pbuf[j++] = ibuf[i] & 0xff;
-       }
-
-       if (j && (pbuf == valid_str))
-               receive_chars(max, valid_str, j);
-
-       kfree(buf);
-       return j;
-}
-
-static void serial_m3110_con_putchar(struct uart_port *port, int ch)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       struct circ_buf *xmit = &max->con_xmit;
-
-       if (uart_circ_chars_free(xmit)) {
-               xmit->buf[xmit->head] = (char)ch;
-               xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
-       }
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void serial_m3110_con_write(struct console *co,
-                               const char *s, unsigned int count)
-{
-       if (!pmax)
-               return;
-
-       uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
-
-       if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-               wake_up_process(pmax->main_thread);
-}
-
-static int __init
-serial_m3110_con_setup(struct console *co, char *options)
-{
-       struct uart_max3110 *max = pmax;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       pr_info(PR_FMT "setting up console\n");
-
-       if (co->index == -1)
-               co->index = 0;
-
-       if (!max) {
-               pr_err(PR_FMT "pmax is NULL, return");
-               return -ENODEV;
-       }
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&max->port, co, baud, parity, bits, flow);
-}
-
-static struct tty_driver *serial_m3110_con_device(struct console *co,
-                                                       int *index)
-{
-       struct uart_driver *p = co->data;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-static struct uart_driver serial_m3110_reg;
-static struct console serial_m3110_console = {
-       .name           = "ttyS",
-       .write          = serial_m3110_con_write,
-       .device         = serial_m3110_con_device,
-       .setup          = serial_m3110_con_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_m3110_reg,
-};
-
-static unsigned int serial_m3110_tx_empty(struct uart_port *port)
-{
-       return 1;
-}
-
-static void serial_m3110_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* stop_rx will be called in spin_lock env */
-static void serial_m3110_stop_rx(struct uart_port *port)
-{
-       return;
-}
-
-#define WORDS_PER_XFER 128
-static void send_circ_buf(struct uart_max3110 *max,
-                               struct circ_buf *xmit)
-{
-       void *buf;
-       u16 *obuf, *ibuf;
-       u8 valid_str[WORDS_PER_XFER];
-       int i, j, len, blen, dma_size, left, ret = 0;
-
-
-       dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
-       buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
-       if (!buf)
-               return;
-       obuf = buf;
-       ibuf = buf + dma_size/2;
-
-       while (!uart_circ_empty(xmit)) {
-               left = uart_circ_chars_pending(xmit);
-               while (left) {
-                       len = min(left, WORDS_PER_XFER);
-                       blen = len * sizeof(u16);
-                       memset(ibuf, 0, blen);
-
-                       for (i = 0; i < len; i++) {
-                               obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
-                               xmit->tail = (xmit->tail + 1) &
-                                               (UART_XMIT_SIZE - 1);
-                       }
-
-                       /* Fail to send msg to console is not very critical */
-                       ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
-                       if (ret)
-                               pr_warning(PR_FMT "%s(): get err msg %d\n",
-                                               __func__, ret);
-
-                       for (i = 0, j = 0; i < len; i++) {
-                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                                       valid_str[j++] = ibuf[i] & 0xff;
-                       }
-
-                       if (j)
-                               receive_chars(max, valid_str, j);
-
-                       max->port.icount.tx += len;
-                       left -= len;
-               }
-       }
-
-       kfree(buf);
-}
-
-static void transmit_char(struct uart_max3110 *max)
-{
-       struct uart_port *port = &max->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       send_circ_buf(max, xmit);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               serial_m3110_stop_tx(port);
-}
-
-/*
- * This will be called by uart_write() and tty_write, can't
- * go to sleep
- */
-static void serial_m3110_start_tx(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-
-       if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-               wake_up_process(max->main_thread);
-}
-
-static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
-{
-       struct uart_port *port = &max->port;
-       struct tty_struct *tty;
-       int usable;
-
-       /* If uart is not opened, just return */
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       while (len) {
-               usable = tty_buffer_request_room(tty, len);
-               if (usable) {
-                       tty_insert_flip_string(tty, str, usable);
-                       str += usable;
-                       port->icount.rx += usable;
-               }
-               len -= usable;
-       }
-       tty_flip_buffer_push(tty);
-}
-
-/*
- * This routine will be used in read_thread or RX IRQ handling,
- * it will first do one round buffer read(8 words), if there is some
- * valid RX data, will try to read 5 more rounds till all data
- * is read out.
- *
- * Use stack space as data buffer to save some system load, and chose
- * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
- * receiving bulk data, a much bigger buffer may cause stack overflow
- */
-static void max3110_con_receive(struct uart_max3110 *max)
-{
-       int loop = 1, num, total = 0;
-       u8 recv_buf[512], *pbuf;
-
-       pbuf = recv_buf;
-       do {
-               num = max3110_read_multi(max, pbuf);
-
-               if (num) {
-                       loop = 5;
-                       pbuf += num;
-                       total += num;
-
-                       if (total >= 504) {
-                               receive_chars(max, recv_buf, total);
-                               pbuf = recv_buf;
-                               total = 0;
-                       }
-               }
-       } while (--loop);
-
-       if (total)
-               receive_chars(max, recv_buf, total);
-}
-
-static int max3110_main_thread(void *_max)
-{
-       struct uart_max3110 *max = _max;
-       wait_queue_head_t *wq = &max->wq;
-       int ret = 0;
-       struct circ_buf *xmit = &max->con_xmit;
-
-       init_waitqueue_head(wq);
-       pr_info(PR_FMT "start main thread\n");
-
-       do {
-               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
-
-               mutex_lock(&max->thread_mutex);
-
-               if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
-                       max3110_con_receive(max);
-
-               /* first handle console output */
-               if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
-                       send_circ_buf(max, xmit);
-
-               /* handle uart output */
-               if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
-                       transmit_char(max);
-
-               mutex_unlock(&max->thread_mutex);
-
-       } while (!kthread_should_stop());
-
-       return ret;
-}
-
-static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
-{
-       struct uart_max3110 *max = dev_id;
-
-       /* max3110's irq is a falling edge, not level triggered,
-        * so no need to disable the irq */
-       if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-               wake_up_process(max->main_thread);
-
-       return IRQ_HANDLED;
-}
-
-/* if don't use RX IRQ, then need a thread to polling read */
-static int max3110_read_thread(void *_max)
-{
-       struct uart_max3110 *max = _max;
-
-       pr_info(PR_FMT "start read thread\n");
-       do {
-               /*
-                * If can't acquire the mutex, it means the main thread
-                * is running which will also perform the rx job
-                */
-               if (mutex_trylock(&max->thread_mutex)) {
-                       max3110_con_receive(max);
-                       mutex_unlock(&max->thread_mutex);
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 20);
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-static int serial_m3110_startup(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       u16 config = 0;
-       int ret = 0;
-
-       if (port->line != 0) {
-               pr_err(PR_FMT "uart port startup failed\n");
-               return -1;
-       }
-
-       /* Disable all IRQ and config it to 115200, 8n1 */
-       config = WC_TAG | WC_FIFO_ENABLE
-                       | WC_1_STOPBITS
-                       | WC_8BIT_WORD
-                       | WC_BAUD_DR2;
-
-       /* as we use thread to handle tx/rx, need set low latency */
-       port->state->port.tty->low_latency = 1;
-
-       if (max->irq) {
-               max->read_thread = NULL;
-               ret = request_irq(max->irq, serial_m3110_irq,
-                               IRQ_TYPE_EDGE_FALLING, "max3110", max);
-               if (ret) {
-                       max->irq = 0;
-                       pr_err(PR_FMT "unable to allocate IRQ, polling\n");
-               }  else {
-                       /* Enable RX IRQ only */
-                       config |= WC_RXA_IRQ_ENABLE;
-               }
-       }
-
-       if (max->irq == 0) {
-               /* If IRQ is disabled, start a read thread for input data */
-               max->read_thread =
-                       kthread_run(max3110_read_thread, max, "max3110_read");
-               if (IS_ERR(max->read_thread)) {
-                       ret = PTR_ERR(max->read_thread);
-                       max->read_thread = NULL;
-                       pr_err(PR_FMT "Can't create read thread!\n");
-                       return ret;
-               }
-       }
-
-       ret = max3110_out(max, config);
-       if (ret) {
-               if (max->irq)
-                       free_irq(max->irq, max);
-               if (max->read_thread)
-                       kthread_stop(max->read_thread);
-               max->read_thread = NULL;
-               return ret;
-       }
-
-       max->cur_conf = config;
-       return 0;
-}
-
-static void serial_m3110_shutdown(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       u16 config;
-
-       if (max->read_thread) {
-               kthread_stop(max->read_thread);
-               max->read_thread = NULL;
-       }
-
-       if (max->irq)
-               free_irq(max->irq, max);
-
-       /* Disable interrupts from this port */
-       config = WC_TAG | WC_SW_SHDI;
-       max3110_out(max, config);
-}
-
-static void serial_m3110_release_port(struct uart_port *port)
-{
-}
-
-static int serial_m3110_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_m3110_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_MAX3100;
-}
-
-static int
-serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-
-static const char *serial_m3110_type(struct uart_port *port)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       return max->name;
-}
-
-static void
-serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_max3110 *max =
-               container_of(port, struct uart_max3110, port);
-       unsigned char cval;
-       unsigned int baud, parity = 0;
-       int clk_div = -1;
-       u16 new_conf = max->cur_conf;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               new_conf |= WC_7BIT_WORD;
-               break;
-       default:
-               /* We only support CS7 & CS8 */
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= CS8;
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               new_conf |= WC_8BIT_WORD;
-               break;
-       }
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-
-       /* First calc the div for 1.8MHZ clock case */
-       switch (baud) {
-       case 300:
-               clk_div = WC_BAUD_DR384;
-               break;
-       case 600:
-               clk_div = WC_BAUD_DR192;
-               break;
-       case 1200:
-               clk_div = WC_BAUD_DR96;
-               break;
-       case 2400:
-               clk_div = WC_BAUD_DR48;
-               break;
-       case 4800:
-               clk_div = WC_BAUD_DR24;
-               break;
-       case 9600:
-               clk_div = WC_BAUD_DR12;
-               break;
-       case 19200:
-               clk_div = WC_BAUD_DR6;
-               break;
-       case 38400:
-               clk_div = WC_BAUD_DR3;
-               break;
-       case 57600:
-               clk_div = WC_BAUD_DR2;
-               break;
-       case 115200:
-               clk_div = WC_BAUD_DR1;
-               break;
-       case 230400:
-               if (max->clock & MAX3110_HIGH_CLK)
-                       break;
-       default:
-               /* Pick the previous baud rate */
-               baud = max->baud;
-               clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-
-       if (max->clock & MAX3110_HIGH_CLK) {
-               clk_div += 1;
-               /* High clk version max3110 doesn't support B300 */
-               if (baud == 300) {
-                       baud = 600;
-                       clk_div = WC_BAUD_DR384;
-               }
-               if (baud == 230400)
-                       clk_div = WC_BAUD_DR1;
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       }
-
-       new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
-
-       if (unlikely(termios->c_cflag & CMSPAR))
-               termios->c_cflag &= ~CMSPAR;
-
-       if (termios->c_cflag & CSTOPB)
-               new_conf |= WC_2_STOPBITS;
-       else
-               new_conf &= ~WC_2_STOPBITS;
-
-       if (termios->c_cflag & PARENB) {
-               new_conf |= WC_PARITY_ENABLE;
-               parity |= UART_LCR_PARITY;
-       } else
-               new_conf &= ~WC_PARITY_ENABLE;
-
-       if (!(termios->c_cflag & PARODD))
-               parity |= UART_LCR_EPAR;
-       max->parity = parity;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       new_conf |= WC_TAG;
-       if (new_conf != max->cur_conf) {
-               if (!max3110_out(max, new_conf)) {
-                       max->cur_conf = new_conf;
-                       max->baud = baud;
-               }
-       }
-}
-
-/* Don't handle hw handshaking */
-static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
-}
-
-static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void serial_m3110_pm(struct uart_port *port, unsigned int state,
-                       unsigned int oldstate)
-{
-}
-
-static void serial_m3110_enable_ms(struct uart_port *port)
-{
-}
-
-struct uart_ops serial_m3110_ops = {
-       .tx_empty       = serial_m3110_tx_empty,
-       .set_mctrl      = serial_m3110_set_mctrl,
-       .get_mctrl      = serial_m3110_get_mctrl,
-       .stop_tx        = serial_m3110_stop_tx,
-       .start_tx       = serial_m3110_start_tx,
-       .stop_rx        = serial_m3110_stop_rx,
-       .enable_ms      = serial_m3110_enable_ms,
-       .break_ctl      = serial_m3110_break_ctl,
-       .startup        = serial_m3110_startup,
-       .shutdown       = serial_m3110_shutdown,
-       .set_termios    = serial_m3110_set_termios,
-       .pm             = serial_m3110_pm,
-       .type           = serial_m3110_type,
-       .release_port   = serial_m3110_release_port,
-       .request_port   = serial_m3110_request_port,
-       .config_port    = serial_m3110_config_port,
-       .verify_port    = serial_m3110_verify_port,
-};
-
-static struct uart_driver serial_m3110_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "MRST serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = 1,
-       .cons           = &serial_m3110_console,
-};
-
-#ifdef CONFIG_PM
-static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
-{
-       struct uart_max3110 *max = spi_get_drvdata(spi);
-
-       disable_irq(max->irq);
-       uart_suspend_port(&serial_m3110_reg, &max->port);
-       max3110_out(max, max->cur_conf | WC_SW_SHDI);
-       return 0;
-}
-
-static int serial_m3110_resume(struct spi_device *spi)
-{
-       struct uart_max3110 *max = spi_get_drvdata(spi);
-
-       max3110_out(max, max->cur_conf);
-       uart_resume_port(&serial_m3110_reg, &max->port);
-       enable_irq(max->irq);
-       return 0;
-}
-#else
-#define serial_m3110_suspend   NULL
-#define serial_m3110_resume    NULL
-#endif
-
-static int __devinit serial_m3110_probe(struct spi_device *spi)
-{
-       struct uart_max3110 *max;
-       void *buffer;
-       u16 res;
-       int ret = 0;
-
-       max = kzalloc(sizeof(*max), GFP_KERNEL);
-       if (!max)
-               return -ENOMEM;
-
-       /* Set spi info */
-       spi->bits_per_word = 16;
-       max->clock = MAX3110_HIGH_CLK;
-
-       spi_setup(spi);
-
-       max->port.type = PORT_MAX3100;
-       max->port.fifosize = 2;         /* Only have 16b buffer */
-       max->port.ops = &serial_m3110_ops;
-       max->port.line = 0;
-       max->port.dev = &spi->dev;
-       max->port.uartclk = 115200;
-
-       max->spi = spi;
-       strcpy(max->name, spi->modalias);
-       max->irq = (u16)spi->irq;
-
-       mutex_init(&max->thread_mutex);
-
-       max->word_7bits = 0;
-       max->parity = 0;
-       max->baud = 0;
-
-       max->cur_conf = 0;
-       max->uart_flags = 0;
-
-       /* Check if reading configuration register returns something sane */
-
-       res = RC_TAG;
-       ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
-       if (ret < 0 || res == 0 || res == 0xffff) {
-               printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
-                                                                       res);
-               ret = -ENODEV;
-               goto err_get_page;
-       }
-
-       buffer = (void *)__get_free_page(GFP_KERNEL);
-       if (!buffer) {
-               ret = -ENOMEM;
-               goto err_get_page;
-       }
-       max->con_xmit.buf = buffer;
-       max->con_xmit.head = 0;
-       max->con_xmit.tail = 0;
-
-       max->main_thread = kthread_run(max3110_main_thread,
-                                       max, "max3110_main");
-       if (IS_ERR(max->main_thread)) {
-               ret = PTR_ERR(max->main_thread);
-               goto err_kthread;
-       }
-
-       spi_set_drvdata(spi, max);
-       pmax = max;
-
-       /* Give membase a psudo value to pass serial_core's check */
-       max->port.membase = (void *)0xff110000;
-       uart_add_one_port(&serial_m3110_reg, &max->port);
-
-       return 0;
-
-err_kthread:
-       free_page((unsigned long)buffer);
-err_get_page:
-       kfree(max);
-       return ret;
-}
-
-static int __devexit serial_m3110_remove(struct spi_device *dev)
-{
-       struct uart_max3110 *max = spi_get_drvdata(dev);
-
-       if (!max)
-               return 0;
-
-       uart_remove_one_port(&serial_m3110_reg, &max->port);
-
-       free_page((unsigned long)max->con_xmit.buf);
-
-       if (max->main_thread)
-               kthread_stop(max->main_thread);
-
-       kfree(max);
-       return 0;
-}
-
-static struct spi_driver uart_max3110_driver = {
-       .driver = {
-                       .name   = "spi_max3111",
-                       .bus    = &spi_bus_type,
-                       .owner  = THIS_MODULE,
-       },
-       .probe          = serial_m3110_probe,
-       .remove         = __devexit_p(serial_m3110_remove),
-       .suspend        = serial_m3110_suspend,
-       .resume         = serial_m3110_resume,
-};
-
-static int __init serial_m3110_init(void)
-{
-       int ret = 0;
-
-       ret = uart_register_driver(&serial_m3110_reg);
-       if (ret)
-               return ret;
-
-       ret = spi_register_driver(&uart_max3110_driver);
-       if (ret)
-               uart_unregister_driver(&serial_m3110_reg);
-
-       return ret;
-}
-
-static void __exit serial_m3110_exit(void)
-{
-       spi_unregister_driver(&uart_max3110_driver);
-       uart_unregister_driver(&serial_m3110_reg);
-}
-
-module_init(serial_m3110_init);
-module_exit(serial_m3110_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("max3110-uart");
diff --git a/drivers/serial/mrst_max3110.h b/drivers/serial/mrst_max3110.h
deleted file mode 100644 (file)
index d1ef43a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _MRST_MAX3110_H
-#define _MRST_MAX3110_H
-
-#define MAX3110_HIGH_CLK       0x1     /* 3.6864 MHZ */
-#define MAX3110_LOW_CLK                0x0     /* 1.8432 MHZ */
-
-/* status bits for all 4 MAX3110 operate modes */
-#define MAX3110_READ_DATA_AVAILABLE    (1 << 15)
-#define MAX3110_WRITE_BUF_EMPTY                (1 << 14)
-
-#define WC_TAG                 (3 << 14)
-#define RC_TAG                 (1 << 14)
-#define WD_TAG                 (2 << 14)
-#define RD_TAG                 (0 << 14)
-
-/* bits def for write configuration */
-#define WC_FIFO_ENABLE_MASK    (1 << 13)
-#define WC_FIFO_ENABLE         (0 << 13)
-
-#define WC_SW_SHDI             (1 << 12)
-
-#define WC_IRQ_MASK            (0xF << 8)
-#define WC_TXE_IRQ_ENABLE      (1 << 11)       /* TX empty irq */
-#define WC_RXA_IRQ_ENABLE      (1 << 10)       /* RX availabe irq */
-#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
-#define WC_REC_ACT_IRQ_ENABLE  (1 << 8)
-
-#define WC_IRDA_ENABLE         (1 << 7)
-
-#define WC_STOPBITS_MASK       (1 << 6)
-#define WC_2_STOPBITS          (1 << 6)
-#define WC_1_STOPBITS          (0 << 6)
-
-#define WC_PARITY_ENABLE_MASK  (1 << 5)
-#define WC_PARITY_ENABLE       (1 << 5)
-
-#define WC_WORDLEN_MASK                (1 << 4)
-#define WC_7BIT_WORD           (1 << 4)
-#define WC_8BIT_WORD           (0 << 4)
-
-#define WC_BAUD_DIV_MASK       (0xF)
-#define WC_BAUD_DR1            (0x0)
-#define WC_BAUD_DR2            (0x1)
-#define WC_BAUD_DR4            (0x2)
-#define WC_BAUD_DR8            (0x3)
-#define WC_BAUD_DR16           (0x4)
-#define WC_BAUD_DR32           (0x5)
-#define WC_BAUD_DR64           (0x6)
-#define WC_BAUD_DR128          (0x7)
-#define WC_BAUD_DR3            (0x8)
-#define WC_BAUD_DR6            (0x9)
-#define WC_BAUD_DR12           (0xA)
-#define WC_BAUD_DR24           (0xB)
-#define WC_BAUD_DR48           (0xC)
-#define WC_BAUD_DR96           (0xD)
-#define WC_BAUD_DR192          (0xE)
-#define WC_BAUD_DR384          (0xF)
-
-#define M3110_RX_FIFO_DEPTH    8
-#endif
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
deleted file mode 100644 (file)
index 8e43a7b..0000000
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * drivers/serial/msm_serial.c - driver for msm7k serial device and console
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-# define SUPPORT_SYSRQ
-#endif
-
-#include <linux/hrtimer.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include "msm_serial.h"
-
-struct msm_port {
-       struct uart_port        uart;
-       char                    name[16];
-       struct clk              *clk;
-       unsigned int            imr;
-};
-
-static void msm_stop_tx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr &= ~UART_IMR_TXLEV;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_start_tx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr |= UART_IMR_TXLEV;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_stop_rx(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void msm_enable_ms(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr |= UART_IMR_DELTA_CTS;
-       msm_write(port, msm_port->imr, UART_IMR);
-}
-
-static void handle_rx(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int sr;
-
-       /*
-        * Handle overrun. My understanding of the hardware is that overrun
-        * is not tied to the RX buffer, so we handle the case out of band.
-        */
-       if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
-               port->icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
-       }
-
-       /* and now the main RX loop */
-       while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
-               unsigned int c;
-               char flag = TTY_NORMAL;
-
-               c = msm_read(port, UART_RF);
-
-               if (sr & UART_SR_RX_BREAK) {
-                       port->icount.brk++;
-                       if (uart_handle_break(port))
-                               continue;
-               } else if (sr & UART_SR_PAR_FRAME_ERR) {
-                       port->icount.frame++;
-               } else {
-                       port->icount.rx++;
-               }
-
-               /* Mask conditions we're ignorning. */
-               sr &= port->read_status_mask;
-
-               if (sr & UART_SR_RX_BREAK) {
-                       flag = TTY_BREAK;
-               } else if (sr & UART_SR_PAR_FRAME_ERR) {
-                       flag = TTY_FRAME;
-               }
-
-               if (!uart_handle_sysrq_char(port, c))
-                       tty_insert_flip_char(tty, c, flag);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
-static void handle_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       int sent_tx;
-
-       if (port->x_char) {
-               msm_write(port, port->x_char, UART_TF);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-
-       while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
-               if (uart_circ_empty(xmit)) {
-                       /* disable tx interrupts */
-                       msm_port->imr &= ~UART_IMR_TXLEV;
-                       msm_write(port, msm_port->imr, UART_IMR);
-                       break;
-               }
-
-               msm_write(port, xmit->buf[xmit->tail], UART_TF);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               sent_tx = 1;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void handle_delta_cts(struct uart_port *port)
-{
-       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-       port->icount.cts++;
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t msm_irq(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int misr;
-
-       spin_lock(&port->lock);
-       misr = msm_read(port, UART_MISR);
-       msm_write(port, 0, UART_IMR); /* disable interrupt */
-
-       if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
-               handle_rx(port);
-       if (misr & UART_IMR_TXLEV)
-               handle_tx(port);
-       if (misr & UART_IMR_DELTA_CTS)
-               handle_delta_cts(port);
-
-       msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int msm_tx_empty(struct uart_port *port)
-{
-       return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int msm_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
-}
-
-static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int mr;
-
-       mr = msm_read(port, UART_MR1);
-
-       if (!(mctrl & TIOCM_RTS)) {
-               mr &= ~UART_MR1_RX_RDY_CTL;
-               msm_write(port, mr, UART_MR1);
-               msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
-       } else {
-               mr |= UART_MR1_RX_RDY_CTL;
-               msm_write(port, mr, UART_MR1);
-       }
-}
-
-static void msm_break_ctl(struct uart_port *port, int break_ctl)
-{
-       if (break_ctl)
-               msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
-       else
-               msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
-}
-
-static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
-{
-       unsigned int baud_code, rxstale, watermark;
-
-       switch (baud) {
-       case 300:
-               baud_code = UART_CSR_300;
-               rxstale = 1;
-               break;
-       case 600:
-               baud_code = UART_CSR_600;
-               rxstale = 1;
-               break;
-       case 1200:
-               baud_code = UART_CSR_1200;
-               rxstale = 1;
-               break;
-       case 2400:
-               baud_code = UART_CSR_2400;
-               rxstale = 1;
-               break;
-       case 4800:
-               baud_code = UART_CSR_4800;
-               rxstale = 1;
-               break;
-       case 9600:
-               baud_code = UART_CSR_9600;
-               rxstale = 2;
-               break;
-       case 14400:
-               baud_code = UART_CSR_14400;
-               rxstale = 3;
-               break;
-       case 19200:
-               baud_code = UART_CSR_19200;
-               rxstale = 4;
-               break;
-       case 28800:
-               baud_code = UART_CSR_28800;
-               rxstale = 6;
-               break;
-       case 38400:
-               baud_code = UART_CSR_38400;
-               rxstale = 8;
-               break;
-       case 57600:
-               baud_code = UART_CSR_57600;
-               rxstale = 16;
-               break;
-       case 115200:
-       default:
-               baud_code = UART_CSR_115200;
-               baud = 115200;
-               rxstale = 31;
-               break;
-       }
-
-       msm_write(port, baud_code, UART_CSR);
-
-       /* RX stale watermark */
-       watermark = UART_IPR_STALE_LSB & rxstale;
-       watermark |= UART_IPR_RXSTALE_LAST;
-       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
-       msm_write(port, watermark, UART_IPR);
-
-       /* set RX watermark */
-       watermark = (port->fifosize * 3) / 4;
-       msm_write(port, watermark, UART_RFWR);
-
-       /* set TX watermark */
-       msm_write(port, 10, UART_TFWR);
-
-       return baud;
-}
-
-static void msm_reset(struct uart_port *port)
-{
-       /* reset everything */
-       msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
-       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
-       msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
-}
-
-static void msm_init_clock(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       clk_enable(msm_port->clk);
-       msm_serial_set_mnd_regs(port);
-}
-
-static int msm_startup(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int data, rfr_level;
-       int ret;
-
-       snprintf(msm_port->name, sizeof(msm_port->name),
-                "msm_serial%d", port->line);
-
-       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
-                         msm_port->name, port);
-       if (unlikely(ret))
-               return ret;
-
-       msm_init_clock(port);
-
-       if (likely(port->fifosize > 12))
-               rfr_level = port->fifosize - 12;
-       else
-               rfr_level = port->fifosize;
-
-       /* set automatic RFR level */
-       data = msm_read(port, UART_MR1);
-       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
-       data &= ~UART_MR1_AUTO_RFR_LEVEL0;
-       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
-       data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
-       msm_write(port, data, UART_MR1);
-
-       /* make sure that RXSTALE count is non-zero */
-       data = msm_read(port, UART_IPR);
-       if (unlikely(!data)) {
-               data |= UART_IPR_RXSTALE_LAST;
-               data |= UART_IPR_STALE_LSB;
-               msm_write(port, data, UART_IPR);
-       }
-
-       msm_reset(port);
-
-       msm_write(port, 0x05, UART_CR); /* enable TX & RX */
-
-       /* turn on RX and CTS interrupts */
-       msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
-                       UART_IMR_CURRENT_CTS;
-       msm_write(port, msm_port->imr, UART_IMR);
-
-       return 0;
-}
-
-static void msm_shutdown(struct uart_port *port)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       msm_port->imr = 0;
-       msm_write(port, 0, UART_IMR); /* disable interrupts */
-
-       clk_disable(msm_port->clk);
-
-       free_irq(port->irq, port);
-}
-
-static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud, mr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
-       baud = msm_set_baud_rate(port, baud);
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-       
-       /* calculate parity */
-       mr = msm_read(port, UART_MR2);
-       mr &= ~UART_MR2_PARITY_MODE;
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & PARODD)
-                       mr |= UART_MR2_PARITY_MODE_ODD;
-               else if (termios->c_cflag & CMSPAR)
-                       mr |= UART_MR2_PARITY_MODE_SPACE;
-               else
-                       mr |= UART_MR2_PARITY_MODE_EVEN;
-       }
-
-       /* calculate bits per char */
-       mr &= ~UART_MR2_BITS_PER_CHAR;
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               mr |= UART_MR2_BITS_PER_CHAR_5;
-               break;
-       case CS6:
-               mr |= UART_MR2_BITS_PER_CHAR_6;
-               break;
-       case CS7:
-               mr |= UART_MR2_BITS_PER_CHAR_7;
-               break;
-       case CS8:
-       default:
-               mr |= UART_MR2_BITS_PER_CHAR_8;
-               break;
-       }
-
-       /* calculate stop bits */
-       mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
-       if (termios->c_cflag & CSTOPB)
-               mr |= UART_MR2_STOP_BIT_LEN_TWO;
-       else
-               mr |= UART_MR2_STOP_BIT_LEN_ONE;
-
-       /* set parity, bits per char, and stop bit */
-       msm_write(port, mr, UART_MR2);
-
-       /* calculate and set hardware flow control */
-       mr = msm_read(port, UART_MR1);
-       mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
-       if (termios->c_cflag & CRTSCTS) {
-               mr |= UART_MR1_CTS_CTL;
-               mr |= UART_MR1_RX_RDY_CTL;
-       }
-       msm_write(port, mr, UART_MR1);
-
-       /* Configure status bits to ignore based on termio flags. */
-       port->read_status_mask = 0;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART_SR_RX_BREAK;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *msm_type(struct uart_port *port)
-{
-       return "MSM";
-}
-
-static void msm_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *resource;
-       resource_size_t size;
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return;
-       size = resource->end - resource->start + 1;
-
-       release_mem_region(port->mapbase, size);
-       iounmap(port->membase);
-       port->membase = NULL;
-}
-
-static int msm_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       struct resource *resource;
-       resource_size_t size;
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return -ENXIO;
-       size = resource->end - resource->start + 1;
-
-       if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
-               return -EBUSY;
-
-       port->membase = ioremap(port->mapbase, size);
-       if (!port->membase) {
-               release_mem_region(port->mapbase, size);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void msm_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_MSM;
-               msm_request_port(port);
-       }
-}
-
-static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
-               return -EINVAL;
-       if (unlikely(port->irq != ser->irq))
-               return -EINVAL;
-       return 0;
-}
-
-static void msm_power(struct uart_port *port, unsigned int state,
-                     unsigned int oldstate)
-{
-       struct msm_port *msm_port = UART_TO_MSM(port);
-
-       switch (state) {
-       case 0:
-               clk_enable(msm_port->clk);
-               break;
-       case 3:
-               clk_disable(msm_port->clk);
-               break;
-       default:
-               printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
-       }
-}
-
-static struct uart_ops msm_uart_pops = {
-       .tx_empty = msm_tx_empty,
-       .set_mctrl = msm_set_mctrl,
-       .get_mctrl = msm_get_mctrl,
-       .stop_tx = msm_stop_tx,
-       .start_tx = msm_start_tx,
-       .stop_rx = msm_stop_rx,
-       .enable_ms = msm_enable_ms,
-       .break_ctl = msm_break_ctl,
-       .startup = msm_startup,
-       .shutdown = msm_shutdown,
-       .set_termios = msm_set_termios,
-       .type = msm_type,
-       .release_port = msm_release_port,
-       .request_port = msm_request_port,
-       .config_port = msm_config_port,
-       .verify_port = msm_verify_port,
-       .pm = msm_power,
-};
-
-static struct msm_port msm_uart_ports[] = {
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 512,
-                       .line = 0,
-               },
-       },
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 512,
-                       .line = 1,
-               },
-       },
-       {
-               .uart = {
-                       .iotype = UPIO_MEM,
-                       .ops = &msm_uart_pops,
-                       .flags = UPF_BOOT_AUTOCONF,
-                       .fifosize = 64,
-                       .line = 2,
-               },
-       },
-};
-
-#define UART_NR        ARRAY_SIZE(msm_uart_ports)
-
-static inline struct uart_port *get_port_from_line(unsigned int line)
-{
-       return &msm_uart_ports[line].uart;
-}
-
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-
-static void msm_console_putchar(struct uart_port *port, int c)
-{
-       while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
-               ;
-       msm_write(port, c, UART_TF);
-}
-
-static void msm_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct uart_port *port;
-       struct msm_port *msm_port;
-
-       BUG_ON(co->index < 0 || co->index >= UART_NR);
-
-       port = get_port_from_line(co->index);
-       msm_port = UART_TO_MSM(port);
-
-       spin_lock(&port->lock);
-       uart_console_write(port, s, count, msm_console_putchar);
-       spin_unlock(&port->lock);
-}
-
-static int __init msm_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud, flow, bits, parity;
-
-       if (unlikely(co->index >= UART_NR || co->index < 0))
-               return -ENXIO;
-
-       port = get_port_from_line(co->index);
-
-       if (unlikely(!port->membase))
-               return -ENXIO;
-
-       port->cons = co;
-
-       msm_init_clock(port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       bits = 8;
-       parity = 'n';
-       flow = 'n';
-       msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
-                 UART_MR2);    /* 8N1 */
-
-       if (baud < 300 || baud > 115200)
-               baud = 115200;
-       msm_set_baud_rate(port, baud);
-
-       msm_reset(port);
-
-       printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver msm_uart_driver;
-
-static struct console msm_console = {
-       .name = "ttyMSM",
-       .write = msm_console_write,
-       .device = uart_console_device,
-       .setup = msm_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &msm_uart_driver,
-};
-
-#define MSM_CONSOLE    (&msm_console)
-
-#else
-#define MSM_CONSOLE    NULL
-#endif
-
-static struct uart_driver msm_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "msm_serial",
-       .dev_name = "ttyMSM",
-       .nr = UART_NR,
-       .cons = MSM_CONSOLE,
-};
-
-static int __init msm_serial_probe(struct platform_device *pdev)
-{
-       struct msm_port *msm_port;
-       struct resource *resource;
-       struct uart_port *port;
-       int irq;
-
-       if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
-               return -ENXIO;
-
-       printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
-
-       port = get_port_from_line(pdev->id);
-       port->dev = &pdev->dev;
-       msm_port = UART_TO_MSM(port);
-
-       msm_port->clk = clk_get(&pdev->dev, "uart_clk");
-       if (IS_ERR(msm_port->clk))
-               return PTR_ERR(msm_port->clk);
-       port->uartclk = clk_get_rate(msm_port->clk);
-       printk(KERN_INFO "uartclk = %d\n", port->uartclk);
-
-
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (unlikely(!resource))
-               return -ENXIO;
-       port->mapbase = resource->start;
-
-       irq = platform_get_irq(pdev, 0);
-       if (unlikely(irq < 0))
-               return -ENXIO;
-       port->irq = irq;
-
-       platform_set_drvdata(pdev, port);
-
-       return uart_add_one_port(&msm_uart_driver, port);
-}
-
-static int __devexit msm_serial_remove(struct platform_device *pdev)
-{
-       struct msm_port *msm_port = platform_get_drvdata(pdev);
-
-       clk_put(msm_port->clk);
-
-       return 0;
-}
-
-static struct platform_driver msm_platform_driver = {
-       .remove = msm_serial_remove,
-       .driver = {
-               .name = "msm_serial",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init msm_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&msm_uart_driver);
-       if (unlikely(ret))
-               return ret;
-
-       ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
-       if (unlikely(ret))
-               uart_unregister_driver(&msm_uart_driver);
-
-       printk(KERN_INFO "msm_serial: driver initialized\n");
-
-       return ret;
-}
-
-static void __exit msm_serial_exit(void)
-{
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-       unregister_console(&msm_console);
-#endif
-       platform_driver_unregister(&msm_platform_driver);
-       uart_unregister_driver(&msm_uart_driver);
-}
-
-module_init(msm_serial_init);
-module_exit(msm_serial_exit);
-
-MODULE_AUTHOR("Robert Love <rlove@google.com>");
-MODULE_DESCRIPTION("Driver for msm7x serial device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
deleted file mode 100644 (file)
index f6ca9ca..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * drivers/serial/msm_serial.h
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
-#define __DRIVERS_SERIAL_MSM_SERIAL_H
-
-#define UART_MR1                       0x0000
-
-#define UART_MR1_AUTO_RFR_LEVEL0       0x3F
-#define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
-#define UART_MR1_RX_RDY_CTL                    (1 << 7)
-#define UART_MR1_CTS_CTL                       (1 << 6)
-
-#define UART_MR2                       0x0004
-#define UART_MR2_ERROR_MODE            (1 << 6)
-#define UART_MR2_BITS_PER_CHAR         0x30
-#define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
-#define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
-#define UART_MR2_BITS_PER_CHAR_7       (0x2 << 4)
-#define UART_MR2_BITS_PER_CHAR_8       (0x3 << 4)
-#define UART_MR2_STOP_BIT_LEN_ONE      (0x1 << 2)
-#define UART_MR2_STOP_BIT_LEN_TWO      (0x3 << 2)
-#define UART_MR2_PARITY_MODE_NONE      0x0
-#define UART_MR2_PARITY_MODE_ODD       0x1
-#define UART_MR2_PARITY_MODE_EVEN      0x2
-#define UART_MR2_PARITY_MODE_SPACE     0x3
-#define UART_MR2_PARITY_MODE           0x3
-
-#define UART_CSR       0x0008
-#define UART_CSR_115200        0xFF
-#define UART_CSR_57600 0xEE
-#define UART_CSR_38400 0xDD
-#define UART_CSR_28800 0xCC
-#define UART_CSR_19200 0xBB
-#define UART_CSR_14400 0xAA
-#define UART_CSR_9600  0x99
-#define UART_CSR_4800  0x77
-#define UART_CSR_2400  0x55
-#define UART_CSR_1200  0x44
-#define UART_CSR_600   0x33
-#define UART_CSR_300   0x22
-
-#define UART_TF                0x000C
-
-#define UART_CR                                0x0010
-#define UART_CR_CMD_NULL               (0 << 4)
-#define UART_CR_CMD_RESET_RX           (1 << 4)
-#define UART_CR_CMD_RESET_TX           (2 << 4)
-#define UART_CR_CMD_RESET_ERR          (3 << 4)
-#define UART_CR_CMD_RESET_BREAK_INT    (4 << 4)
-#define UART_CR_CMD_START_BREAK                (5 << 4)
-#define UART_CR_CMD_STOP_BREAK         (6 << 4)
-#define UART_CR_CMD_RESET_CTS          (7 << 4)
-#define UART_CR_CMD_PACKET_MODE                (9 << 4)
-#define UART_CR_CMD_MODE_RESET         (12 << 4)
-#define UART_CR_CMD_SET_RFR            (13 << 4)
-#define UART_CR_CMD_RESET_RFR          (14 << 4)
-#define UART_CR_TX_DISABLE             (1 << 3)
-#define UART_CR_TX_ENABLE              (1 << 3)
-#define UART_CR_RX_DISABLE             (1 << 3)
-#define UART_CR_RX_ENABLE              (1 << 3)
-
-#define UART_IMR               0x0014
-#define UART_IMR_TXLEV         (1 << 0)
-#define UART_IMR_RXSTALE       (1 << 3)
-#define UART_IMR_RXLEV         (1 << 4)
-#define UART_IMR_DELTA_CTS     (1 << 5)
-#define UART_IMR_CURRENT_CTS   (1 << 6)
-
-#define UART_IPR_RXSTALE_LAST          0x20
-#define UART_IPR_STALE_LSB             0x1F
-#define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
-
-#define UART_IPR       0x0018
-#define UART_TFWR      0x001C
-#define UART_RFWR      0x0020
-#define UART_HCR       0x0024
-
-#define UART_MREG              0x0028
-#define UART_NREG              0x002C
-#define UART_DREG              0x0030
-#define UART_MNDREG            0x0034
-#define UART_IRDA              0x0038
-#define UART_MISR_MODE         0x0040
-#define UART_MISR_RESET                0x0044
-#define UART_MISR_EXPORT       0x0048
-#define UART_MISR_VAL          0x004C
-#define UART_TEST_CTRL         0x0050
-
-#define UART_SR                        0x0008
-#define UART_SR_HUNT_CHAR      (1 << 7)
-#define UART_SR_RX_BREAK       (1 << 6)
-#define UART_SR_PAR_FRAME_ERR  (1 << 5)
-#define UART_SR_OVERRUN                (1 << 4)
-#define UART_SR_TX_EMPTY       (1 << 3)
-#define UART_SR_TX_READY       (1 << 2)
-#define UART_SR_RX_FULL                (1 << 1)
-#define UART_SR_RX_READY       (1 << 0)
-
-#define UART_RF                0x000C
-#define UART_MISR      0x0010
-#define UART_ISR       0x0014
-
-#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
-
-static inline
-void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
-{
-       __raw_writel(val, port->membase + off);
-}
-
-static inline
-unsigned int msm_read(struct uart_port *port, unsigned int off)
-{
-       return __raw_readl(port->membase + off);
-}
-
-/*
- * Setup the MND registers to use the TCXO clock.
- */
-static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
-{
-       msm_write(port, 0x06, UART_MREG);
-       msm_write(port, 0xF1, UART_NREG);
-       msm_write(port, 0x0F, UART_DREG);
-       msm_write(port, 0x1A, UART_MNDREG);
-}
-
-/*
- * Setup the MND registers to use the TCXO clock divided by 4.
- */
-static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
-{
-       msm_write(port, 0x18, UART_MREG);
-       msm_write(port, 0xF6, UART_NREG);
-       msm_write(port, 0x0F, UART_DREG);
-       msm_write(port, 0x0A, UART_MNDREG);
-}
-
-static inline
-void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
-{
-       if (port->uartclk == 19200000)
-               msm_serial_set_mnd_regs_tcxo(port);
-       else
-               msm_serial_set_mnd_regs_tcxoby4(port);
-}
-
-/*
- * TROUT has a specific defect that makes it report it's uartclk
- * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
- * cases TROUT to use the right clock.
- */
-#ifdef CONFIG_MACH_TROUT
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
-#else
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
-#endif
-
-#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
deleted file mode 100644 (file)
index 9711e06..0000000
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
-** mux.c:
-**     serial driver for the Mux console found in some PA-RISC servers.
-**
-**     (c) Copyright 2002 Ryan Bradetich
-**     (c) Copyright 2002 Hewlett-Packard Company
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This Driver currently only supports the console (port 0) on the MUX.
-** Additional work will be needed on this driver to enable the full
-** functionality of the MUX.
-**
-*/
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/delay.h> /* for udelay */
-#include <linux/device.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/parisc-device.h>
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#define MUX_OFFSET 0x800
-#define MUX_LINE_OFFSET 0x80
-
-#define MUX_FIFO_SIZE 255
-#define MUX_POLL_DELAY (30 * HZ / 1000)
-
-#define IO_DATA_REG_OFFSET 0x3c
-#define IO_DCOUNT_REG_OFFSET 0x40
-
-#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
-#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
-#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
-
-#define MUX_NR 256
-static unsigned int port_cnt __read_mostly;
-struct mux_port {
-       struct uart_port port;
-       int enabled;
-};
-static struct mux_port mux_ports[MUX_NR];
-
-static struct uart_driver mux_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "ttyB",
-       .dev_name = "ttyB",
-       .major = MUX_MAJOR,
-       .minor = 0,
-       .nr = MUX_NR,
-};
-
-static struct timer_list mux_timer;
-
-#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
-#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
-
-/**
- * get_mux_port_count - Get the number of available ports on the Mux.
- * @dev: The parisc device.
- *
- * This function is used to determine the number of ports the Mux
- * supports.  The IODC data reports the number of ports the Mux
- * can support, but there are cases where not all the Mux ports
- * are connected.  This function can override the IODC and
- * return the true port count.
- */
-static int __init get_mux_port_count(struct parisc_device *dev)
-{
-       int status;
-       u8 iodc_data[32];
-       unsigned long bytecnt;
-
-       /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
-        * we only need to allocate resources for 1 port since the
-        * other 7 ports are not connected.
-        */
-       if(dev->id.hversion == 0x15)
-               return 1;
-
-       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
-       BUG_ON(status != PDC_OK);
-
-       /* Return the number of ports specified in the iodc data. */
-       return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
-}
-
-/**
- * mux_tx_empty - Check if the transmitter fifo is empty.
- * @port: Ptr to the uart_port.
- *
- * This function test if the transmitter fifo for the port
- * described by 'port' is empty.  If it is empty, this function
- * should return TIOCSER_TEMT, otherwise return 0.
- */
-static unsigned int mux_tx_empty(struct uart_port *port)
-{
-       return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT;
-} 
-
-/**
- * mux_set_mctrl - Set the current state of the modem control inputs.
- * @ports: Ptr to the uart_port.
- * @mctrl: Modem control bits.
- *
- * The Serial MUX does not support CTS, DCD or DSR so this function
- * is ignored.
- */
-static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * mux_get_mctrl - Returns the current state of modem control inputs.
- * @port: Ptr to the uart_port.
- *
- * The Serial MUX does not support CTS, DCD or DSR so these lines are
- * treated as permanently active.
- */
-static unsigned int mux_get_mctrl(struct uart_port *port)
-{ 
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * mux_stop_tx - Stop transmitting characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial MUX does not support this function.
- */
-static void mux_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * mux_start_tx - Start transmitting characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_start_tx(struct uart_port *port)
-{
-}
-
-/**
- * mux_stop_rx - Stop receiving characters.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * mux_enable_ms - Enable modum status interrupts.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_enable_ms(struct uart_port *port)
-{
-}
-
-/**
- * mux_break_ctl - Control the transmitssion of a break signal.
- * @port: Ptr to the uart_port.
- * @break_state: Raise/Lower the break signal.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * mux_write - Write chars to the mux fifo.
- * @port: Ptr to the uart_port.
- *
- * This function writes all the data from the uart buffer to
- * the mux fifo.
- */
-static void mux_write(struct uart_port *port)
-{
-       int count;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if(port->x_char) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               mux_stop_tx(port);
-               return;
-       }
-
-       count = (port->fifosize) - UART_GET_FIFO_CNT(port);
-       do {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if(uart_circ_empty(xmit))
-                       break;
-
-       } while(--count > 0);
-
-       while(UART_GET_FIFO_CNT(port)) 
-               udelay(1);
-
-       if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               mux_stop_tx(port);
-}
-
-/**
- * mux_read - Read chars from the mux fifo.
- * @port: Ptr to the uart_port.
- *
- * This reads all available data from the mux's fifo and pushes
- * the data to the tty layer.
- */
-static void mux_read(struct uart_port *port)
-{
-       int data;
-       struct tty_struct *tty = port->state->port.tty;
-       __u32 start_count = port->icount.rx;
-
-       while(1) {
-               data = __raw_readl(port->membase + IO_DATA_REG_OFFSET);
-
-               if (MUX_STATUS(data))
-                       continue;
-
-               if (MUX_EOFIFO(data))
-                       break;
-
-               port->icount.rx++;
-
-               if (MUX_BREAK(data)) {
-                       port->icount.brk++;
-                       if(uart_handle_break(port))
-                               continue;
-               }
-
-               if (uart_handle_sysrq_char(port, data & 0xffu))
-                       continue;
-
-               tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
-       }
-       
-       if (start_count != port->icount.rx) {
-               tty_flip_buffer_push(tty);
-       }
-}
-
-/**
- * mux_startup - Initialize the port.
- * @port: Ptr to the uart_port.
- *
- * Grab any resources needed for this port and start the
- * mux timer.
- */
-static int mux_startup(struct uart_port *port)
-{
-       mux_ports[port->line].enabled = 1;
-       return 0;
-}
-
-/**
- * mux_shutdown - Disable the port.
- * @port: Ptr to the uart_port.
- *
- * Release any resources needed for the port.
- */
-static void mux_shutdown(struct uart_port *port)
-{
-       mux_ports[port->line].enabled = 0;
-}
-
-/**
- * mux_set_termios - Chane port parameters.
- * @port: Ptr to the uart_port.
- * @termios: new termios settings.
- * @old: old termios settings.
- *
- * The Serial Mux does not support this function.
- */
-static void
-mux_set_termios(struct uart_port *port, struct ktermios *termios,
-               struct ktermios *old)
-{
-}
-
-/**
- * mux_type - Describe the port.
- * @port: Ptr to the uart_port.
- *
- * Return a pointer to a string constant describing the
- * specified port.
- */
-static const char *mux_type(struct uart_port *port)
-{
-       return "Mux";
-}
-
-/**
- * mux_release_port - Release memory and IO regions.
- * @port: Ptr to the uart_port.
- * 
- * Release any memory and IO region resources currently in use by
- * the port.
- */
-static void mux_release_port(struct uart_port *port)
-{
-}
-
-/**
- * mux_request_port - Request memory and IO regions.
- * @port: Ptr to the uart_port.
- *
- * Request any memory and IO region resources required by the port.
- * If any fail, no resources should be registered when this function
- * returns, and it should return -EBUSY on failure.
- */
-static int mux_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * mux_config_port - Perform port autoconfiguration.
- * @port: Ptr to the uart_port.
- * @type: Bitmask of required configurations.
- *
- * Perform any autoconfiguration steps for the port.  This function is
- * called if the UPF_BOOT_AUTOCONF flag is specified for the port.
- * [Note: This is required for now because of a bug in the Serial core.
- *  rmk has already submitted a patch to linus, should be available for
- *  2.5.47.]
- */
-static void mux_config_port(struct uart_port *port, int type)
-{
-       port->type = PORT_MUX;
-}
-
-/**
- * mux_verify_port - Verify the port information.
- * @port: Ptr to the uart_port.
- * @ser: Ptr to the serial information.
- *
- * Verify the new serial port information contained within serinfo is
- * suitable for this port type.
- */
-static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       if(port->membase == NULL)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- * mux_drv_poll - Mux poll function.
- * @unused: Unused variable
- *
- * This function periodically polls the Serial MUX to check for new data.
- */
-static void mux_poll(unsigned long unused)
-{  
-       int i;
-
-       for(i = 0; i < port_cnt; ++i) {
-               if(!mux_ports[i].enabled)
-                       continue;
-
-               mux_read(&mux_ports[i].port);
-               mux_write(&mux_ports[i].port);
-       }
-
-       mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
-}
-
-
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-static void mux_console_write(struct console *co, const char *s, unsigned count)
-{
-       /* Wait until the FIFO drains. */
-       while(UART_GET_FIFO_CNT(&mux_ports[0].port))
-               udelay(1);
-
-       while(count--) {
-               if(*s == '\n') {
-                       UART_PUT_CHAR(&mux_ports[0].port, '\r');
-               }
-               UART_PUT_CHAR(&mux_ports[0].port, *s++);
-       }
-
-}
-
-static int mux_console_setup(struct console *co, char *options)
-{
-        return 0;
-}
-
-struct tty_driver *mux_console_device(struct console *co, int *index)
-{
-        *index = co->index;
-       return mux_driver.tty_driver;
-}
-
-static struct console mux_console = {
-       .name =         "ttyB",
-       .write =        mux_console_write,
-       .device =       mux_console_device,
-       .setup =        mux_console_setup,
-       .flags =        CON_ENABLED | CON_PRINTBUFFER,
-       .index =        0,
-};
-
-#define MUX_CONSOLE    &mux_console
-#else
-#define MUX_CONSOLE    NULL
-#endif
-
-static struct uart_ops mux_pops = {
-       .tx_empty =             mux_tx_empty,
-       .set_mctrl =            mux_set_mctrl,
-       .get_mctrl =            mux_get_mctrl,
-       .stop_tx =              mux_stop_tx,
-       .start_tx =             mux_start_tx,
-       .stop_rx =              mux_stop_rx,
-       .enable_ms =            mux_enable_ms,
-       .break_ctl =            mux_break_ctl,
-       .startup =              mux_startup,
-       .shutdown =             mux_shutdown,
-       .set_termios =          mux_set_termios,
-       .type =                 mux_type,
-       .release_port =         mux_release_port,
-       .request_port =         mux_request_port,
-       .config_port =          mux_config_port,
-       .verify_port =          mux_verify_port,
-};
-
-/**
- * mux_probe - Determine if the Serial Mux should claim this device.
- * @dev: The parisc device.
- *
- * Deterimine if the Serial Mux should claim this chip (return 0)
- * or not (return 1).
- */
-static int __init mux_probe(struct parisc_device *dev)
-{
-       int i, status;
-
-       int port_count = get_mux_port_count(dev);
-       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
-
-       dev_set_drvdata(&dev->dev, (void *)(long)port_count);
-       request_mem_region(dev->hpa.start + MUX_OFFSET,
-                           port_count * MUX_LINE_OFFSET, "Mux");
-
-       if(!port_cnt) {
-               mux_driver.cons = MUX_CONSOLE;
-
-               status = uart_register_driver(&mux_driver);
-               if(status) {
-                       printk(KERN_ERR "Serial mux: Unable to register driver.\n");
-                       return 1;
-               }
-       }
-
-       for(i = 0; i < port_count; ++i, ++port_cnt) {
-               struct uart_port *port = &mux_ports[port_cnt].port;
-               port->iobase    = 0;
-               port->mapbase   = dev->hpa.start + MUX_OFFSET +
-                                               (i * MUX_LINE_OFFSET);
-               port->membase   = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
-               port->iotype    = UPIO_MEM;
-               port->type      = PORT_MUX;
-               port->irq       = NO_IRQ;
-               port->uartclk   = 0;
-               port->fifosize  = MUX_FIFO_SIZE;
-               port->ops       = &mux_pops;
-               port->flags     = UPF_BOOT_AUTOCONF;
-               port->line      = port_cnt;
-
-               /* The port->timeout needs to match what is present in
-                * uart_wait_until_sent in serial_core.c.  Otherwise
-                * the time spent in msleep_interruptable will be very
-                * long, causing the appearance of a console hang.
-                */
-               port->timeout   = HZ / 50;
-               spin_lock_init(&port->lock);
-
-               status = uart_add_one_port(&mux_driver, port);
-               BUG_ON(status);
-       }
-
-       return 0;
-}
-
-static int __devexit mux_remove(struct parisc_device *dev)
-{
-       int i, j;
-       int port_count = (long)dev_get_drvdata(&dev->dev);
-
-       /* Find Port 0 for this card in the mux_ports list. */
-       for(i = 0; i < port_cnt; ++i) {
-               if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
-                       break;
-       }
-       BUG_ON(i + port_count > port_cnt);
-
-       /* Release the resources associated with each port on the device. */
-       for(j = 0; j < port_count; ++j, ++i) {
-               struct uart_port *port = &mux_ports[i].port;
-
-               uart_remove_one_port(&mux_driver, port);
-               if(port->membase)
-                       iounmap(port->membase);
-       }
-
-       release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
-       return 0;
-}
-
-/* Hack.  This idea was taken from the 8250_gsc.c on how to properly order
- * the serial port detection in the proper order.   The idea is we always
- * want the builtin mux to be detected before addin mux cards, so we
- * specifically probe for the builtin mux cards first.
- *
- * This table only contains the parisc_device_id of known builtin mux
- * devices.  All other mux cards will be detected by the generic mux_tbl.
- */
-static struct parisc_device_id builtin_mux_tbl[] = {
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
-       { 0, }
-};
-
-static struct parisc_device_id mux_tbl[] = {
-       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
-MODULE_DEVICE_TABLE(parisc, mux_tbl);
-
-static struct parisc_driver builtin_serial_mux_driver = {
-       .name =         "builtin_serial_mux",
-       .id_table =     builtin_mux_tbl,
-       .probe =        mux_probe,
-       .remove =       __devexit_p(mux_remove),
-};
-
-static struct parisc_driver serial_mux_driver = {
-       .name =         "serial_mux",
-       .id_table =     mux_tbl,
-       .probe =        mux_probe,
-       .remove =       __devexit_p(mux_remove),
-};
-
-/**
- * mux_init - Serial MUX initialization procedure.
- *
- * Register the Serial MUX driver.
- */
-static int __init mux_init(void)
-{
-       register_parisc_driver(&builtin_serial_mux_driver);
-       register_parisc_driver(&serial_mux_driver);
-
-       if(port_cnt > 0) {
-               /* Start the Mux timer */
-               init_timer(&mux_timer);
-               mux_timer.function = mux_poll;
-               mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
-
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-               register_console(&mux_console);
-#endif
-       }
-
-       return 0;
-}
-
-/**
- * mux_exit - Serial MUX cleanup procedure.
- *
- * Unregister the Serial MUX driver from the tty layer.
- */
-static void __exit mux_exit(void)
-{
-       /* Delete the Mux timer. */
-       if(port_cnt > 0) {
-               del_timer(&mux_timer);
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-               unregister_console(&mux_console);
-#endif
-       }
-
-       unregister_parisc_driver(&builtin_serial_mux_driver);
-       unregister_parisc_driver(&serial_mux_driver);
-       uart_unregister_driver(&mux_driver);
-}
-
-module_init(mux_init);
-module_exit(mux_exit);
-
-MODULE_AUTHOR("Ryan Bradetich");
-MODULE_DESCRIPTION("Serial MUX driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
deleted file mode 100644 (file)
index 7735c9f..0000000
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * drivers/serial/netx-serial.c
- *
- * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/netx-regs.h>
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_NX_MAJOR        204
-#define MINOR_START    170
-
-enum uart_regs {
-       UART_DR              = 0x00,
-       UART_SR              = 0x04,
-       UART_LINE_CR         = 0x08,
-       UART_BAUDDIV_MSB     = 0x0c,
-       UART_BAUDDIV_LSB     = 0x10,
-       UART_CR              = 0x14,
-       UART_FR              = 0x18,
-       UART_IIR             = 0x1c,
-       UART_ILPR            = 0x20,
-       UART_RTS_CR          = 0x24,
-       UART_RTS_LEAD        = 0x28,
-       UART_RTS_TRAIL       = 0x2c,
-       UART_DRV_ENABLE      = 0x30,
-       UART_BRM_CR          = 0x34,
-       UART_RXFIFO_IRQLEVEL = 0x38,
-       UART_TXFIFO_IRQLEVEL = 0x3c,
-};
-
-#define SR_FE (1<<0)
-#define SR_PE (1<<1)
-#define SR_BE (1<<2)
-#define SR_OE (1<<3)
-
-#define LINE_CR_BRK       (1<<0)
-#define LINE_CR_PEN       (1<<1)
-#define LINE_CR_EPS       (1<<2)
-#define LINE_CR_STP2      (1<<3)
-#define LINE_CR_FEN       (1<<4)
-#define LINE_CR_5BIT      (0<<5)
-#define LINE_CR_6BIT      (1<<5)
-#define LINE_CR_7BIT      (2<<5)
-#define LINE_CR_8BIT      (3<<5)
-#define LINE_CR_BITS_MASK (3<<5)
-
-#define CR_UART_EN (1<<0)
-#define CR_SIREN   (1<<1)
-#define CR_SIRLP   (1<<2)
-#define CR_MSIE    (1<<3)
-#define CR_RIE     (1<<4)
-#define CR_TIE     (1<<5)
-#define CR_RTIE    (1<<6)
-#define CR_LBE     (1<<7)
-
-#define FR_CTS  (1<<0)
-#define FR_DSR  (1<<1)
-#define FR_DCD  (1<<2)
-#define FR_BUSY (1<<3)
-#define FR_RXFE (1<<4)
-#define FR_TXFF (1<<5)
-#define FR_RXFF (1<<6)
-#define FR_TXFE (1<<7)
-
-#define IIR_MIS (1<<0)
-#define IIR_RIS (1<<1)
-#define IIR_TIS (1<<2)
-#define IIR_RTIS (1<<3)
-#define IIR_MASK 0xf
-
-#define RTS_CR_AUTO (1<<0)
-#define RTS_CR_RTS  (1<<1)
-#define RTS_CR_COUNT (1<<2)
-#define RTS_CR_MOD2  (1<<3)
-#define RTS_CR_RTS_POL (1<<4)
-#define RTS_CR_CTS_CTR (1<<5)
-#define RTS_CR_CTS_POL (1<<6)
-#define RTS_CR_STICK   (1<<7)
-
-#define UART_PORT_SIZE 0x40
-#define DRIVER_NAME "netx-uart"
-
-struct netx_port {
-       struct uart_port        port;
-};
-
-static void netx_stop_tx(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val & ~CR_TIE,  port->membase + UART_CR);
-}
-
-static void netx_stop_rx(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val & ~CR_RIE,  port->membase + UART_CR);
-}
-
-static void netx_enable_ms(struct uart_port *port)
-{
-       unsigned int val;
-       val = readl(port->membase + UART_CR);
-       writel(val | CR_MSIE, port->membase + UART_CR);
-}
-
-static inline void netx_transmit_buffer(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               writel(port->x_char, port->membase + UART_DR);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
-               netx_stop_tx(port);
-               return;
-       }
-
-       do {
-               /* send xmit->buf[xmit->tail]
-                * out the port here */
-               writel(xmit->buf[xmit->tail], port->membase + UART_DR);
-               xmit->tail = (xmit->tail + 1) &
-                        (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (!(readl(port->membase + UART_FR) & FR_TXFF));
-
-       if (uart_circ_empty(xmit))
-               netx_stop_tx(port);
-}
-
-static void netx_start_tx(struct uart_port *port)
-{
-       writel(
-           readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR);
-
-       if (!(readl(port->membase + UART_FR) & FR_TXFF))
-               netx_transmit_buffer(port);
-}
-
-static unsigned int netx_tx_empty(struct uart_port *port)
-{
-       return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;
-}
-
-static void netx_txint(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               netx_stop_tx(port);
-               return;
-       }
-
-       netx_transmit_buffer(port);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static void netx_rxint(struct uart_port *port)
-{
-       unsigned char rx, flg, status;
-       struct tty_struct *tty = port->state->port.tty;
-
-       while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
-               rx = readl(port->membase + UART_DR);
-               flg = TTY_NORMAL;
-               port->icount.rx++;
-               status = readl(port->membase + UART_SR);
-               if (status & SR_BE) {
-                       writel(0, port->membase + UART_SR);
-                       if (uart_handle_break(port))
-                               continue;
-               }
-
-               if (unlikely(status & (SR_FE | SR_PE | SR_OE))) {
-
-                       if (status & SR_PE)
-                               port->icount.parity++;
-                       else if (status & SR_FE)
-                               port->icount.frame++;
-                       if (status & SR_OE)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-
-                       if (status & SR_BE)
-                               flg = TTY_BREAK;
-                       else if (status & SR_PE)
-                               flg = TTY_PARITY;
-                       else if (status & SR_FE)
-                               flg = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, rx))
-                       continue;
-
-               uart_insert_char(port, status, SR_OE, rx, flg);
-       }
-
-       tty_flip_buffer_push(tty);
-       return;
-}
-
-static irqreturn_t netx_int(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned long flags;
-       unsigned char status;
-
-       spin_lock_irqsave(&port->lock,flags);
-
-       status = readl(port->membase + UART_IIR) & IIR_MASK;
-       while (status) {
-               if (status & IIR_RIS)
-                       netx_rxint(port);
-               if (status & IIR_TIS)
-                       netx_txint(port);
-               if (status & IIR_MIS) {
-                       if (readl(port->membase + UART_FR) & FR_CTS)
-                               uart_handle_cts_change(port, 1);
-                       else
-                               uart_handle_cts_change(port, 0);
-               }
-               writel(0, port->membase + UART_IIR);
-               status = readl(port->membase + UART_IIR) & IIR_MASK;
-       }
-
-       spin_unlock_irqrestore(&port->lock,flags);
-       return IRQ_HANDLED;
-}
-
-static unsigned int netx_get_mctrl(struct uart_port *port)
-{
-       unsigned int ret = TIOCM_DSR | TIOCM_CAR;
-
-       if (readl(port->membase + UART_FR) & FR_CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       unsigned int val;
-
-       /* FIXME: Locking needed ? */
-       if (mctrl & TIOCM_RTS) {
-               val = readl(port->membase + UART_RTS_CR);
-               writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
-       }
-}
-
-static void netx_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned int line_cr;
-       spin_lock_irq(&port->lock);
-
-       line_cr = readl(port->membase + UART_LINE_CR);
-       if (break_state != 0)
-               line_cr |= LINE_CR_BRK;
-       else
-               line_cr &= ~LINE_CR_BRK;
-       writel(line_cr, port->membase + UART_LINE_CR);
-
-       spin_unlock_irq(&port->lock);
-}
-
-static int netx_startup(struct uart_port *port)
-{
-       int ret;
-
-       ret = request_irq(port->irq, netx_int, 0,
-                            DRIVER_NAME, port);
-       if (ret) {
-               dev_err(port->dev, "unable to grab irq%d\n",port->irq);
-               goto exit;
-       }
-
-       writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN,
-               port->membase + UART_LINE_CR);
-
-       writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN,
-               port->membase + UART_CR);
-
-exit:
-       return ret;
-}
-
-static void netx_shutdown(struct uart_port *port)
-{
-       writel(0, port->membase + UART_CR) ;
-
-       free_irq(port->irq, port);
-}
-
-static void
-netx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       unsigned int baud, quot;
-       unsigned char old_cr;
-       unsigned char line_cr = LINE_CR_FEN;
-       unsigned char rts_cr = 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               line_cr |= LINE_CR_5BIT;
-               break;
-       case CS6:
-               line_cr |= LINE_CR_6BIT;
-               break;
-       case CS7:
-               line_cr |= LINE_CR_7BIT;
-               break;
-       case CS8:
-               line_cr |= LINE_CR_8BIT;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               line_cr |= LINE_CR_STP2;
-
-       if (termios->c_cflag & PARENB) {
-               line_cr |= LINE_CR_PEN;
-               if (!(termios->c_cflag & PARODD))
-                       line_cr |= LINE_CR_EPS;
-       }
-
-       if (termios->c_cflag & CRTSCTS)
-               rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = baud * 4096;
-       quot /= 1000;
-       quot *= 256;
-       quot /= 100000;
-
-       spin_lock_irq(&port->lock);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       old_cr = readl(port->membase + UART_CR);
-
-       /* disable interrupts */
-       writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE),
-               port->membase + UART_CR);
-
-       /* drain transmitter */
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-
-       /* disable UART */
-       writel(old_cr & ~CR_UART_EN, port->membase + UART_CR);
-
-       /* modem status interrupts */
-       old_cr &= ~CR_MSIE;
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               old_cr |= CR_MSIE;
-
-       writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB);
-       writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB);
-       writel(line_cr, port->membase + UART_LINE_CR);
-
-       writel(rts_cr, port->membase + UART_RTS_CR);
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= SR_PE;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= SR_BE;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= SR_PE;
-       }
-
-       port->read_status_mask = 0;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= SR_BE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= SR_PE | SR_FE;
-
-       writel(old_cr, port->membase + UART_CR);
-
-       spin_unlock_irq(&port->lock);
-}
-
-static const char *netx_type(struct uart_port *port)
-{
-       return port->type == PORT_NETX ? "NETX" : NULL;
-}
-
-static void netx_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, UART_PORT_SIZE);
-}
-
-static int netx_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE,
-                       DRIVER_NAME) != NULL ? 0 : -EBUSY;
-}
-
-static void netx_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0)
-               port->type = PORT_NETX;
-}
-
-static int
-netx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX)
-               ret = -EINVAL;
-
-       return ret;
-}
-
-static struct uart_ops netx_pops = {
-       .tx_empty       = netx_tx_empty,
-       .set_mctrl      = netx_set_mctrl,
-       .get_mctrl      = netx_get_mctrl,
-       .stop_tx        = netx_stop_tx,
-       .start_tx       = netx_start_tx,
-       .stop_rx        = netx_stop_rx,
-       .enable_ms      = netx_enable_ms,
-       .break_ctl      = netx_break_ctl,
-       .startup        = netx_startup,
-       .shutdown       = netx_shutdown,
-       .set_termios    = netx_set_termios,
-       .type           = netx_type,
-       .release_port   = netx_release_port,
-       .request_port   = netx_request_port,
-       .config_port    = netx_config_port,
-       .verify_port    = netx_verify_port,
-};
-
-static struct netx_port netx_ports[] = {
-       {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART0),
-               .mapbase = NETX_PA_UART0,
-               .irq = NETX_IRQ_UART0,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 0,
-       },
-       }, {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART1),
-               .mapbase = NETX_PA_UART1,
-               .irq = NETX_IRQ_UART1,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 1,
-       },
-       }, {
-       .port = {
-               .type = PORT_NETX,
-               .iotype = UPIO_MEM,
-               .membase = (char __iomem *)io_p2v(NETX_PA_UART2),
-               .mapbase = NETX_PA_UART2,
-               .irq = NETX_IRQ_UART2,
-               .uartclk = 100000000,
-               .fifosize = 16,
-               .flags = UPF_BOOT_AUTOCONF,
-               .ops = &netx_pops,
-               .line = 2,
-       },
-       }
-};
-
-#ifdef CONFIG_SERIAL_NETX_CONSOLE
-
-static void netx_console_putchar(struct uart_port *port, int ch)
-{
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-       writel(ch, port->membase + UART_DR);
-}
-
-static void
-netx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_port *port = &netx_ports[co->index].port;
-       unsigned char cr_save;
-
-       cr_save = readl(port->membase + UART_CR);
-       writel(cr_save | CR_UART_EN, port->membase + UART_CR);
-
-       uart_console_write(port, s, count, netx_console_putchar);
-
-       while (readl(port->membase + UART_FR) & FR_BUSY);
-       writel(cr_save, port->membase + UART_CR);
-}
-
-static void __init
-netx_console_get_options(struct uart_port *port, int *baud,
-                       int *parity, int *bits, int *flow)
-{
-       unsigned char line_cr;
-
-       *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) |
-               readl(port->membase + UART_BAUDDIV_LSB);
-       *baud *= 1000;
-       *baud /= 4096;
-       *baud *= 1000;
-       *baud /= 256;
-       *baud *= 100;
-
-       line_cr = readl(port->membase + UART_LINE_CR);
-       *parity = 'n';
-       if (line_cr & LINE_CR_PEN) {
-               if (line_cr & LINE_CR_EPS)
-                       *parity = 'e';
-               else
-                       *parity = 'o';
-       }
-
-       switch (line_cr & LINE_CR_BITS_MASK) {
-       case LINE_CR_8BIT:
-               *bits = 8;
-               break;
-       case LINE_CR_7BIT:
-               *bits = 7;
-               break;
-       case LINE_CR_6BIT:
-               *bits = 6;
-               break;
-       case LINE_CR_5BIT:
-               *bits = 5;
-               break;
-       }
-
-       if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO)
-               *flow = 'r';
-}
-
-static int __init
-netx_console_setup(struct console *co, char *options)
-{
-       struct netx_port *sport;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports))
-               co->index = 0;
-       sport = &netx_ports[co->index];
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       } else {
-               /* if the UART is enabled, assume it has been correctly setup
-                * by the bootloader and get the options
-                */
-               if (readl(sport->port.membase + UART_CR) & CR_UART_EN) {
-                       netx_console_get_options(&sport->port, &baud,
-                       &parity, &bits, &flow);
-               }
-
-       }
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver netx_reg;
-static struct console netx_console = {
-       .name           = "ttyNX",
-       .write          = netx_console_write,
-       .device         = uart_console_device,
-       .setup          = netx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &netx_reg,
-};
-
-static int __init netx_console_init(void)
-{
-       register_console(&netx_console);
-       return 0;
-}
-console_initcall(netx_console_init);
-
-#define NETX_CONSOLE   &netx_console
-#else
-#define NETX_CONSOLE   NULL
-#endif
-
-static struct uart_driver netx_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = DRIVER_NAME,
-       .dev_name       = "ttyNX",
-       .major          = SERIAL_NX_MAJOR,
-       .minor          = MINOR_START,
-       .nr             = ARRAY_SIZE(netx_ports),
-       .cons           = NETX_CONSOLE,
-};
-
-static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       if (sport)
-               uart_suspend_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_netx_resume(struct platform_device *pdev)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       if (sport)
-               uart_resume_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static int serial_netx_probe(struct platform_device *pdev)
-{
-       struct uart_port *port = &netx_ports[pdev->id].port;
-
-       dev_info(&pdev->dev, "initialising\n");
-
-       port->dev = &pdev->dev;
-
-       writel(1, port->membase + UART_RXFIFO_IRQLEVEL);
-       uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port);
-       platform_set_drvdata(pdev, &netx_ports[pdev->id]);
-
-       return 0;
-}
-
-static int serial_netx_remove(struct platform_device *pdev)
-{
-       struct netx_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&netx_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver serial_netx_driver = {
-       .probe          = serial_netx_probe,
-       .remove         = serial_netx_remove,
-
-       .suspend        = serial_netx_suspend,
-       .resume         = serial_netx_resume,
-
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init netx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: NetX driver\n");
-
-       ret = uart_register_driver(&netx_reg);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_register(&serial_netx_driver);
-       if (ret != 0)
-               uart_unregister_driver(&netx_reg);
-
-       return 0;
-}
-
-static void __exit netx_serial_exit(void)
-{
-       platform_driver_unregister(&serial_netx_driver);
-       uart_unregister_driver(&netx_reg);
-}
-
-module_init(netx_serial_init);
-module_exit(netx_serial_exit);
-
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_DESCRIPTION("NetX serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c
deleted file mode 100644 (file)
index de17367..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- *  Serial Port driver for a NWP uart device
- *
- *    Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/irqreturn.h>
-#include <linux/mutex.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/nwpserial.h>
-#include <asm/prom.h>
-#include <asm/dcr.h>
-
-#define NWPSERIAL_NR               2
-
-#define NWPSERIAL_STATUS_RXVALID 0x1
-#define NWPSERIAL_STATUS_TXFULL  0x2
-
-struct nwpserial_port {
-       struct uart_port port;
-       dcr_host_t dcr_host;
-       unsigned int ier;
-       unsigned int mcr;
-};
-
-static DEFINE_MUTEX(nwpserial_mutex);
-static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
-
-static void wait_for_bits(struct nwpserial_port *up, int bits)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = dcr_read(up->dcr_host, UART_LSR);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & bits) != bits);
-}
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static void nwpserial_console_putchar(struct uart_port *port, int c)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-       /* check if tx buffer is full */
-       wait_for_bits(up, UART_LSR_THRE);
-       dcr_write(up->dcr_host, UART_TX, c);
-       up->port.icount.tx++;
-}
-
-static void
-nwpserial_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct nwpserial_port *up = &nwpserial_ports[co->index];
-       unsigned long flags;
-       int locked = 1;
-
-       if (oops_in_progress)
-               locked = spin_trylock_irqsave(&up->port.lock, flags);
-       else
-               spin_lock_irqsave(&up->port.lock, flags);
-
-       /* save and disable interrupt */
-       up->ier = dcr_read(up->dcr_host, UART_IER);
-       dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
-
-       uart_console_write(&up->port, s, count, nwpserial_console_putchar);
-
-       /* wait for transmitter to become empty */
-       while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
-               cpu_relax();
-
-       /* restore interrupt state */
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       if (locked)
-               spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver nwpserial_reg;
-static struct console nwpserial_console = {
-       .name           = "ttySQ",
-       .write          = nwpserial_console_write,
-       .device         = uart_console_device,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &nwpserial_reg,
-};
-#define NWPSERIAL_CONSOLE      (&nwpserial_console)
-#else
-#define NWPSERIAL_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
-
-/**************************************************************************/
-
-static int nwpserial_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void nwpserial_release_port(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void nwpserial_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_NWPSERIAL;
-}
-
-static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
-{
-       struct nwpserial_port *up = dev_id;
-       struct tty_struct *tty = up->port.state->port.tty;
-       irqreturn_t ret;
-       unsigned int iir;
-       unsigned char ch;
-
-       spin_lock(&up->port.lock);
-
-       /* check if the uart was the interrupt source. */
-       iir = dcr_read(up->dcr_host, UART_IIR);
-       if (!iir) {
-               ret = IRQ_NONE;
-               goto out;
-       }
-
-       do {
-               up->port.icount.rx++;
-               ch = dcr_read(up->dcr_host, UART_RX);
-               if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
-                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
-
-       tty_flip_buffer_push(tty);
-       ret = IRQ_HANDLED;
-
-       /* clear interrupt */
-       dcr_write(up->dcr_host, UART_IIR, 1);
-out:
-       spin_unlock(&up->port.lock);
-       return ret;
-}
-
-static int nwpserial_startup(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       int err;
-
-       up = container_of(port, struct nwpserial_port, port);
-
-       /* disable flow control by default */
-       up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
-       dcr_write(up->dcr_host, UART_MCR, up->mcr);
-
-       /* register interrupt handler */
-       err = request_irq(up->port.irq, nwpserial_interrupt,
-                       IRQF_SHARED, "nwpserial", up);
-       if (err)
-               return err;
-
-       /* enable interrupts */
-       up->ier = UART_IER_RDI;
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       /* enable receiving */
-       up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
-
-       return 0;
-}
-
-static void nwpserial_shutdown(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-
-       /* disable receiving */
-       up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
-       /* disable interrupts from this port */
-       up->ier = 0;
-       dcr_write(up->dcr_host, UART_IER, up->ier);
-
-       /* free irq */
-       free_irq(up->port.irq, port);
-}
-
-static int nwpserial_verify_port(struct uart_port *port,
-                       struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static const char *nwpserial_type(struct uart_port *port)
-{
-       return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
-}
-
-static void nwpserial_set_termios(struct uart_port *port,
-                       struct ktermios *termios, struct ktermios *old)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-
-       up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
-                               | NWPSERIAL_STATUS_TXFULL;
-
-       up->port.ignore_status_mask = 0;
-       /* ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
-       /* Copy back the old hardware settings */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-}
-
-static void nwpserial_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static void nwpserial_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void nwpserial_stop_rx(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       up = container_of(port, struct nwpserial_port, port);
-       /* don't forward any more data (like !CREAD) */
-       up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
-}
-
-static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
-{
-       /* check if tx buffer is full */
-       wait_for_bits(up, UART_LSR_THRE);
-       dcr_write(up->dcr_host, UART_TX, c);
-       up->port.icount.tx++;
-}
-
-static void nwpserial_start_tx(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       struct circ_buf *xmit;
-       up = container_of(port, struct nwpserial_port, port);
-       xmit  = &up->port.state->xmit;
-
-       if (port->x_char) {
-               nwpserial_putchar(up, up->port.x_char);
-               port->x_char = 0;
-       }
-
-       while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
-               nwpserial_putchar(up, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-       }
-}
-
-static unsigned int nwpserial_get_mctrl(struct uart_port *port)
-{
-       return 0;
-}
-
-static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* N/A */
-}
-
-static void nwpserial_stop_tx(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static unsigned int nwpserial_tx_empty(struct uart_port *port)
-{
-       struct nwpserial_port *up;
-       unsigned long flags;
-       int ret;
-       up = container_of(port, struct nwpserial_port, port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = dcr_read(up->dcr_host, UART_LSR);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-}
-
-static struct uart_ops nwpserial_pops = {
-       .tx_empty     = nwpserial_tx_empty,
-       .set_mctrl    = nwpserial_set_mctrl,
-       .get_mctrl    = nwpserial_get_mctrl,
-       .stop_tx      = nwpserial_stop_tx,
-       .start_tx     = nwpserial_start_tx,
-       .stop_rx      = nwpserial_stop_rx,
-       .enable_ms    = nwpserial_enable_ms,
-       .break_ctl    = nwpserial_break_ctl,
-       .startup      = nwpserial_startup,
-       .shutdown     = nwpserial_shutdown,
-       .set_termios  = nwpserial_set_termios,
-       .type         = nwpserial_type,
-       .release_port = nwpserial_release_port,
-       .request_port = nwpserial_request_port,
-       .config_port  = nwpserial_config_port,
-       .verify_port  = nwpserial_verify_port,
-};
-
-static struct uart_driver nwpserial_reg = {
-       .owner       = THIS_MODULE,
-       .driver_name = "nwpserial",
-       .dev_name    = "ttySQ",
-       .major       = TTY_MAJOR,
-       .minor       = 68,
-       .nr          = NWPSERIAL_NR,
-       .cons        = NWPSERIAL_CONSOLE,
-};
-
-int nwpserial_register_port(struct uart_port *port)
-{
-       struct nwpserial_port *up = NULL;
-       int ret = -1;
-       int i;
-       static int first = 1;
-       int dcr_len;
-       int dcr_base;
-       struct device_node *dn;
-
-       mutex_lock(&nwpserial_mutex);
-
-       dn = port->dev->of_node;
-       if (dn == NULL)
-               goto out;
-
-       /* get dcr base. */
-       dcr_base = dcr_resource_start(dn, 0);
-
-       /* find matching entry */
-       for (i = 0; i < NWPSERIAL_NR; i++)
-               if (nwpserial_ports[i].port.iobase == dcr_base) {
-                       up = &nwpserial_ports[i];
-                       break;
-               }
-
-       /* we didn't find a mtching entry, search for a free port */
-       if (up == NULL)
-               for (i = 0; i < NWPSERIAL_NR; i++)
-                       if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
-                               nwpserial_ports[i].port.iobase == 0) {
-                               up = &nwpserial_ports[i];
-                               break;
-                       }
-
-       if (up == NULL) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (first)
-               uart_register_driver(&nwpserial_reg);
-       first = 0;
-
-       up->port.membase      = port->membase;
-       up->port.irq          = port->irq;
-       up->port.uartclk      = port->uartclk;
-       up->port.fifosize     = port->fifosize;
-       up->port.regshift     = port->regshift;
-       up->port.iotype       = port->iotype;
-       up->port.flags        = port->flags;
-       up->port.mapbase      = port->mapbase;
-       up->port.private_data = port->private_data;
-
-       if (port->dev)
-               up->port.dev = port->dev;
-
-       if (up->port.iobase != dcr_base) {
-               up->port.ops          = &nwpserial_pops;
-               up->port.fifosize     = 16;
-
-               spin_lock_init(&up->port.lock);
-
-               up->port.iobase = dcr_base;
-               dcr_len = dcr_resource_len(dn, 0);
-
-               up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
-               if (!DCR_MAP_OK(up->dcr_host)) {
-                       printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
-                       goto out;
-               }
-       }
-
-       ret = uart_add_one_port(&nwpserial_reg, &up->port);
-       if (ret == 0)
-               ret = up->port.line;
-
-out:
-       mutex_unlock(&nwpserial_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(nwpserial_register_port);
-
-void nwpserial_unregister_port(int line)
-{
-       struct nwpserial_port *up = &nwpserial_ports[line];
-       mutex_lock(&nwpserial_mutex);
-       uart_remove_one_port(&nwpserial_reg, &up->port);
-
-       up->port.type = PORT_UNKNOWN;
-
-       mutex_unlock(&nwpserial_mutex);
-}
-EXPORT_SYMBOL(nwpserial_unregister_port);
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static int __init nwpserial_console_init(void)
-{
-       struct nwpserial_port *up = NULL;
-       struct device_node *dn;
-       const char *name;
-       int dcr_base;
-       int dcr_len;
-       int i;
-
-       /* search for a free port */
-       for (i = 0; i < NWPSERIAL_NR; i++)
-               if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
-                       up = &nwpserial_ports[i];
-                       break;
-               }
-
-       if (up == NULL)
-               return -1;
-
-       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
-       if (name == NULL)
-               return -1;
-
-       dn = of_find_node_by_path(name);
-       if (!dn)
-               return -1;
-
-       spin_lock_init(&up->port.lock);
-       up->port.ops = &nwpserial_pops;
-       up->port.type = PORT_NWPSERIAL;
-       up->port.fifosize = 16;
-
-       dcr_base = dcr_resource_start(dn, 0);
-       dcr_len = dcr_resource_len(dn, 0);
-       up->port.iobase = dcr_base;
-
-       up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
-       if (!DCR_MAP_OK(up->dcr_host)) {
-               printk("Cannot map DCR resources for SERIAL");
-               return -1;
-       }
-       register_console(&nwpserial_console);
-       return 0;
-}
-console_initcall(nwpserial_console_init);
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
deleted file mode 100644 (file)
index 5c7abe4..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- *  Serial Port driver for Open Firmware platform devices
- *
- *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM 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; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/nwpserial.h>
-
-struct of_serial_info {
-       int type;
-       int line;
-};
-
-/*
- * Fill a struct uart_port for a given device node
- */
-static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
-                                       int type, struct uart_port *port)
-{
-       struct resource resource;
-       struct device_node *np = ofdev->dev.of_node;
-       const __be32 *clk, *spd;
-       const __be32 *prop;
-       int ret, prop_size;
-
-       memset(port, 0, sizeof *port);
-       spd = of_get_property(np, "current-speed", NULL);
-       clk = of_get_property(np, "clock-frequency", NULL);
-       if (!clk) {
-               dev_warn(&ofdev->dev, "no clock-frequency property set\n");
-               return -ENODEV;
-       }
-
-       ret = of_address_to_resource(np, 0, &resource);
-       if (ret) {
-               dev_warn(&ofdev->dev, "invalid address\n");
-               return ret;
-       }
-
-       spin_lock_init(&port->lock);
-       port->mapbase = resource.start;
-
-       /* Check for shifted address mapping */
-       prop = of_get_property(np, "reg-offset", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               port->mapbase += be32_to_cpup(prop);
-
-       /* Check for registers offset within the devices address range */
-       prop = of_get_property(np, "reg-shift", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               port->regshift = be32_to_cpup(prop);
-
-       port->irq = irq_of_parse_and_map(np, 0);
-       port->iotype = UPIO_MEM;
-       port->type = type;
-       port->uartclk = be32_to_cpup(clk);
-       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
-               | UPF_FIXED_PORT | UPF_FIXED_TYPE;
-       port->dev = &ofdev->dev;
-       /* If current-speed was set, then try not to change it. */
-       if (spd)
-               port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
-
-       return 0;
-}
-
-/*
- * Try to register a serial port
- */
-static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
-                                               const struct of_device_id *id)
-{
-       struct of_serial_info *info;
-       struct uart_port port;
-       int port_type;
-       int ret;
-
-       if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
-               return -EBUSY;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (info == NULL)
-               return -ENOMEM;
-
-       port_type = (unsigned long)id->data;
-       ret = of_platform_serial_setup(ofdev, port_type, &port);
-       if (ret)
-               goto out;
-
-       switch (port_type) {
-#ifdef CONFIG_SERIAL_8250
-       case PORT_8250 ... PORT_MAX_8250:
-               ret = serial8250_register_port(&port);
-               break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       case PORT_NWPSERIAL:
-               ret = nwpserial_register_port(&port);
-               break;
-#endif
-       default:
-               /* need to add code for these */
-       case PORT_UNKNOWN:
-               dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
-               ret = -ENODEV;
-               break;
-       }
-       if (ret < 0)
-               goto out;
-
-       info->type = port_type;
-       info->line = ret;
-       dev_set_drvdata(&ofdev->dev, info);
-       return 0;
-out:
-       kfree(info);
-       irq_dispose_mapping(port.irq);
-       return ret;
-}
-
-/*
- * Release a line
- */
-static int of_platform_serial_remove(struct platform_device *ofdev)
-{
-       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
-       switch (info->type) {
-#ifdef CONFIG_SERIAL_8250
-       case PORT_8250 ... PORT_MAX_8250:
-               serial8250_unregister_port(info->line);
-               break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       case PORT_NWPSERIAL:
-               nwpserial_unregister_port(info->line);
-               break;
-#endif
-       default:
-               /* need to add code for these */
-               break;
-       }
-       kfree(info);
-       return 0;
-}
-
-/*
- * A few common types, add more as needed.
- */
-static struct of_device_id __devinitdata of_platform_serial_table[] = {
-       { .type = "serial", .compatible = "ns8250",   .data = (void *)PORT_8250, },
-       { .type = "serial", .compatible = "ns16450",  .data = (void *)PORT_16450, },
-       { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
-       { .type = "serial", .compatible = "ns16550",  .data = (void *)PORT_16550, },
-       { .type = "serial", .compatible = "ns16750",  .data = (void *)PORT_16750, },
-       { .type = "serial", .compatible = "ns16850",  .data = (void *)PORT_16850, },
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
-       { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
-                                       .data = (void *)PORT_NWPSERIAL, },
-#endif
-       { .type = "serial",                           .data = (void *)PORT_UNKNOWN, },
-       { /* end of list */ },
-};
-
-static struct of_platform_driver of_platform_serial_driver = {
-       .driver = {
-               .name = "of_serial",
-               .owner = THIS_MODULE,
-               .of_match_table = of_platform_serial_table,
-       },
-       .probe = of_platform_serial_probe,
-       .remove = of_platform_serial_remove,
-};
-
-static int __init of_platform_serial_init(void)
-{
-       return of_register_platform_driver(&of_platform_serial_driver);
-}
-module_init(of_platform_serial_init);
-
-static void __exit of_platform_serial_exit(void)
-{
-       return of_unregister_platform_driver(&of_platform_serial_driver);
-};
-module_exit(of_platform_serial_exit);
-
-MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
deleted file mode 100644 (file)
index 7f2f010..0000000
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Driver for OMAP-UART controller.
- * Based on drivers/serial/8250.c
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Authors:
- *     Govindraj R     <govindraj.raja@ti.com>
- *     Thara Gopinath  <thara@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Note: This driver is made seperate from 8250 driver as we cannot
- * over load 8250 driver with omap platform specific configuration for
- * features like DMA, it makes easier to implement features like DMA and
- * hardware flow control and software flow control configuration with
- * this driver as required for the omap-platform.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/serial_core.h>
-#include <linux/irq.h>
-
-#include <plat/dma.h>
-#include <plat/dmtimer.h>
-#include <plat/omap-serial.h>
-
-static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
-
-/* Forward declaration of functions */
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_rx_timeout(unsigned long uart_no);
-static int serial_omap_start_rxdma(struct uart_omap_port *up);
-
-static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
-{
-       offset <<= up->port.regshift;
-       return readw(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_omap_port *up, int offset, int value)
-{
-       offset <<= up->port.regshift;
-       writew(value, up->port.membase + offset);
-}
-
-static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
-{
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-/*
- * serial_omap_get_divisor - calculate divisor value
- * @port: uart port info
- * @baud: baudrate for which divisor needs to be calculated.
- *
- * We have written our own function to get the divisor so as to support
- * 13x mode. 3Mbps Baudrate as an different divisor.
- * Reference OMAP TRM Chapter 17:
- * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
- * referring to oversampling - divisor value
- * baudrate 460,800 to 3,686,400 all have divisor 13
- * except 3,000,000 which has divisor value 16
- */
-static unsigned int
-serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int divisor;
-
-       if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
-               divisor = 13;
-       else
-               divisor = 16;
-       return port->uartclk/(baud * divisor);
-}
-
-static void serial_omap_stop_rxdma(struct uart_omap_port *up)
-{
-       if (up->uart_dma.rx_dma_used) {
-               del_timer(&up->uart_dma.rx_timer);
-               omap_stop_dma(up->uart_dma.rx_dma_channel);
-               omap_free_dma(up->uart_dma.rx_dma_channel);
-               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
-               up->uart_dma.rx_dma_used = false;
-       }
-}
-
-static void serial_omap_enable_ms(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_omap_stop_tx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       if (up->use_dma &&
-               up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
-               /*
-                * Check if dma is still active. If yes do nothing,
-                * return. Else stop dma
-                */
-               if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
-                       return;
-               omap_stop_dma(up->uart_dma.tx_dma_channel);
-               omap_free_dma(up->uart_dma.tx_dma_channel);
-               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
-       }
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_omap_stop_rx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       if (up->use_dma)
-               serial_omap_stop_rxdma(up);
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_omap_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int flag;
-       unsigned char ch, lsr = *status;
-       int max_count = 256;
-
-       do {
-               if (likely(lsr & UART_LSR_DR))
-                       ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (lsr & UART_LSR_PE) {
-                               up->port.icount.parity++;
-                       } else if (lsr & UART_LSR_FE) {
-                               up->port.icount.frame++;
-                       }
-
-                       if (lsr & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       lsr &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               lsr |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (lsr & UART_LSR_BI)
-                               flag = TTY_BREAK;
-                       else if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-ignore_char:
-               lsr = serial_in(up, UART_LSR);
-       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-}
-
-static void transmit_chars(struct uart_omap_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_omap_stop_tx(&up->port);
-               return;
-       }
-       count = up->port.fifosize / 4;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_omap_stop_tx(&up->port);
-}
-
-static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
-{
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_omap_start_tx(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       struct circ_buf *xmit;
-       unsigned int start;
-       int ret = 0;
-
-       if (!up->use_dma) {
-               serial_omap_enable_ier_thri(up);
-               return;
-       }
-
-       if (up->uart_dma.tx_dma_used)
-               return;
-
-       xmit = &up->port.state->xmit;
-
-       if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
-               ret = omap_request_dma(up->uart_dma.uart_dma_tx,
-                               "UART Tx DMA",
-                               (void *)uart_tx_dma_callback, up,
-                               &(up->uart_dma.tx_dma_channel));
-
-               if (ret < 0) {
-                       serial_omap_enable_ier_thri(up);
-                       return;
-               }
-       }
-       spin_lock(&(up->uart_dma.tx_lock));
-       up->uart_dma.tx_dma_used = true;
-       spin_unlock(&(up->uart_dma.tx_lock));
-
-       start = up->uart_dma.tx_buf_dma_phys +
-                               (xmit->tail & (UART_XMIT_SIZE - 1));
-
-       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
-       /*
-        * It is a circular buffer. See if the buffer has wounded back.
-        * If yes it will have to be transferred in two separate dma
-        * transfers
-        */
-       if (start + up->uart_dma.tx_buf_size >=
-                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
-               up->uart_dma.tx_buf_size =
-                       (up->uart_dma.tx_buf_dma_phys +
-                       UART_XMIT_SIZE) - start;
-
-       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
-       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.tx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_tx, 0);
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static unsigned int check_modem_status(struct uart_omap_port *up)
-{
-       unsigned int status;
-
-       status = serial_in(up, UART_MSR);
-       status |= up->msr_saved_flags;
-       up->msr_saved_flags = 0;
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return status;
-
-       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
-           up->port.state != NULL) {
-               if (status & UART_MSR_TERI)
-                       up->port.icount.rng++;
-               if (status & UART_MSR_DDSR)
-                       up->port.icount.dsr++;
-               if (status & UART_MSR_DDCD)
-                       uart_handle_dcd_change
-                               (&up->port, status & UART_MSR_DCD);
-               if (status & UART_MSR_DCTS)
-                       uart_handle_cts_change
-                               (&up->port, status & UART_MSR_CTS);
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       return status;
-}
-
-/**
- * serial_omap_irq() - This handles the interrupt from one port
- * @irq: uart port irq number
- * @dev_id: uart port info
- */
-static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
-{
-       struct uart_omap_port *up = dev_id;
-       unsigned int iir, lsr;
-       unsigned long flags;
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       lsr = serial_in(up, UART_LSR);
-       if (iir & UART_IIR_RLSI) {
-               if (!up->use_dma) {
-                       if (lsr & UART_LSR_DR)
-                               receive_chars(up, &lsr);
-               } else {
-                       up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-                       if ((serial_omap_start_rxdma(up) != 0) &&
-                                       (lsr & UART_LSR_DR))
-                               receive_chars(up, &lsr);
-               }
-       }
-
-       check_modem_status(up);
-       if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
-               transmit_chars(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       up->port_activity = jiffies;
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_omap_tx_empty(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-       unsigned int ret = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_omap_get_mctrl(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char status;
-       unsigned int ret = 0;
-
-       status = check_modem_status(up);
-       dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
-
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char mcr = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_omap_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int serial_omap_startup(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
-                               up->name, up);
-       if (retval)
-               return retval;
-
-       dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_omap_clear_fifos(up);
-       /* For Hardware flow control */
-       serial_out(up, UART_MCR, UART_MCR_RTS);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_in(up, UART_LSR);
-       if (serial_in(up, UART_LSR) & UART_LSR_DR)
-               (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-       spin_lock_irqsave(&up->port.lock, flags);
-       /*
-        * Most PC uarts need OUT2 raised to enable interrupts.
-        */
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       up->msr_saved_flags = 0;
-       if (up->use_dma) {
-               free_page((unsigned long)up->port.state->xmit.buf);
-               up->port.state->xmit.buf = dma_alloc_coherent(NULL,
-                       UART_XMIT_SIZE,
-                       (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
-                       0);
-               init_timer(&(up->uart_dma.rx_timer));
-               up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
-               up->uart_dma.rx_timer.data = up->pdev->id;
-               /* Currently the buffer size is 4KB. Can increase it */
-               up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
-                       up->uart_dma.rx_buf_size,
-                       (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
-       }
-       /*
-        * Finally, enable interrupts. Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_out(up, UART_IER, up->ier);
-
-       up->port_activity = jiffies;
-       return 0;
-}
-
-static void serial_omap_shutdown(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned long flags = 0;
-
-       dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_omap_clear_fifos(up);
-
-       /*
-        * Read data port to reset things, and then free the irq
-        */
-       if (serial_in(up, UART_LSR) & UART_LSR_DR)
-               (void) serial_in(up, UART_RX);
-       if (up->use_dma) {
-               dma_free_coherent(up->port.dev,
-                       UART_XMIT_SIZE, up->port.state->xmit.buf,
-                       up->uart_dma.tx_buf_dma_phys);
-               up->port.state->xmit.buf = NULL;
-               serial_omap_stop_rx(port);
-               dma_free_coherent(up->port.dev,
-                       up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
-                       up->uart_dma.rx_buf_dma_phys);
-               up->uart_dma.rx_buf = NULL;
-       }
-       free_irq(up->port.irq, up);
-}
-
-static inline void
-serial_omap_configure_xonxoff
-               (struct uart_omap_port *up, struct ktermios *termios)
-{
-       unsigned char efr = 0;
-
-       up->lcr = serial_in(up, UART_LCR);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
-
-       serial_out(up, UART_XON1, termios->c_cc[VSTART]);
-       serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
-
-       /* clear SW control mode bits */
-       efr = up->efr;
-       efr &= OMAP_UART_SW_CLR;
-
-       /*
-        * IXON Flag:
-        * Enable XON/XOFF flow control on output.
-        * Transmit XON1, XOFF1
-        */
-       if (termios->c_iflag & IXON)
-               efr |= OMAP_UART_SW_TX;
-
-       /*
-        * IXOFF Flag:
-        * Enable XON/XOFF flow control on input.
-        * Receiver compares XON1, XOFF1.
-        */
-       if (termios->c_iflag & IXOFF)
-               efr |= OMAP_UART_SW_RX;
-
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       up->mcr = serial_in(up, UART_MCR);
-
-       /*
-        * IXANY Flag:
-        * Enable any character to restart output.
-        * Operation resumes after receiving any
-        * character after recognition of the XOFF character
-        */
-       if (termios->c_iflag & IXANY)
-               up->mcr |= UART_MCR_XONANY;
-
-       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
-       /* Enable special char function UARTi.EFR_REG[5] and
-        * load the new software flow control mode IXON or IXOFF
-        * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
-        */
-       serial_out(up, UART_EFR, efr | UART_EFR_SCD);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-       serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
-       serial_out(up, UART_LCR, up->lcr);
-}
-
-static void
-serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
-                       struct ktermios *old)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char cval = 0;
-       unsigned char efr = 0;
-       unsigned long flags = 0;
-       unsigned int baud, quot;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
-       quot = serial_omap_get_divisor(port, baud);
-
-       up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
-                       UART_FCR_ENABLE_FIFO;
-       if (up->use_dma)
-               up->fcr |= UART_FCR_DMA_SELECT;
-
-       /*
-        * Ok, we're now changing the port state. Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characters to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * Modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-       serial_out(up, UART_LCR, cval);         /* reset DLAB */
-
-       /* FIFOs and DMA Settings */
-
-       /* FCR can be changed only when the
-        * baud clock is not running
-        * DLL_REG and DLH_REG set to 0.
-        */
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_out(up, UART_DLL, 0);
-       serial_out(up, UART_DLM, 0);
-       serial_out(up, UART_LCR, 0);
-
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       up->mcr = serial_in(up, UART_MCR);
-       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-       /* FIFO ENABLE, DMA MODE */
-       serial_out(up, UART_FCR, up->fcr);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       if (up->use_dma) {
-               serial_out(up, UART_TI752_TLR, 0);
-               serial_out(up, UART_OMAP_SCR,
-                       (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
-       }
-
-       serial_out(up, UART_EFR, up->efr);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-       serial_out(up, UART_MCR, up->mcr);
-
-       /* Protocol, Baud Rate, and Interrupt Settings */
-
-       serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       up->efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-       serial_out(up, UART_LCR, 0);
-       serial_out(up, UART_IER, 0);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-
-       serial_out(up, UART_LCR, 0);
-       serial_out(up, UART_IER, up->ier);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
-       serial_out(up, UART_EFR, up->efr);
-       serial_out(up, UART_LCR, cval);
-
-       if (baud > 230400 && baud != 3000000)
-               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
-       else
-               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
-
-       /* Hardware Flow Control Configuration */
-
-       if (termios->c_cflag & CRTSCTS) {
-               efr |= (UART_EFR_CTS | UART_EFR_RTS);
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
-               up->mcr = serial_in(up, UART_MCR);
-               serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
-
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               up->efr = serial_in(up, UART_EFR);
-               serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
-
-               serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
-               serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
-               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-               serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
-               serial_out(up, UART_LCR, cval);
-       }
-
-       serial_omap_set_mctrl(&up->port, up->port.mctrl);
-       /* Software Flow Control Configuration */
-       if (termios->c_iflag & (IXON | IXOFF))
-               serial_omap_configure_xonxoff(up, termios);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
-}
-
-static void
-serial_omap_pm(struct uart_port *port, unsigned int state,
-              unsigned int oldstate)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char efr;
-
-       dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       efr = serial_in(up, UART_EFR);
-       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
-       serial_out(up, UART_LCR, 0);
-
-       serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
-       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, efr);
-       serial_out(up, UART_LCR, 0);
-       /* Enable module level wake up */
-       serial_out(up, UART_OMAP_WER,
-               (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
-}
-
-static void serial_omap_release_port(struct uart_port *port)
-{
-       dev_dbg(port->dev, "serial_omap_release_port+\n");
-}
-
-static int serial_omap_request_port(struct uart_port *port)
-{
-       dev_dbg(port->dev, "serial_omap_request_port+\n");
-       return 0;
-}
-
-static void serial_omap_config_port(struct uart_port *port, int flags)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
-                                                       up->pdev->id);
-       up->port.type = PORT_OMAP;
-}
-
-static int
-serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       dev_dbg(port->dev, "serial_omap_verify_port+\n");
-       return -EINVAL;
-}
-
-static const char *
-serial_omap_type(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
-       return up->name;
-}
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-static inline void wait_for_xmitr(struct uart_omap_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               for (tmout = 1000000; tmout; tmout--) {
-                       unsigned int msr = serial_in(up, UART_MSR);
-
-                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
-                       if (msr & UART_MSR_CTS)
-                               break;
-
-                       udelay(1);
-               }
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-static int serial_omap_poll_get_char(struct uart_port *port)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned int status = serial_in(up, UART_LSR);
-
-       if (!(status & UART_LSR_DR))
-               return NO_POLL_CHAR;
-
-       return serial_in(up, UART_RX);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
-static struct uart_omap_port *serial_omap_console_ports[4];
-
-static struct uart_driver serial_omap_reg;
-
-static void serial_omap_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-static void
-serial_omap_console_write(struct console *co, const char *s,
-               unsigned int count)
-{
-       struct uart_omap_port *up = serial_omap_console_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = spin_trylock(&up->port.lock);
-       else
-               spin_lock(&up->port.lock);
-
-       /*
-        * First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, serial_omap_console_putchar);
-
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-       /*
-        * The receive handling will happen properly because the
-        * receive ready bit will still be set; it is not cleared
-        * on read.  However, modem control will not, we must
-        * call it if we have saved something in the saved flags
-        * while processing with interrupts off.
-        */
-       if (up->msr_saved_flags)
-               check_modem_status(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init
-serial_omap_console_setup(struct console *co, char *options)
-{
-       struct uart_omap_port *up;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (serial_omap_console_ports[co->index] == NULL)
-               return -ENODEV;
-       up = serial_omap_console_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_omap_console = {
-       .name           = OMAP_SERIAL_NAME,
-       .write          = serial_omap_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_omap_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_omap_reg,
-};
-
-static void serial_omap_add_console_port(struct uart_omap_port *up)
-{
-       serial_omap_console_ports[up->pdev->id] = up;
-}
-
-#define OMAP_CONSOLE   (&serial_omap_console)
-
-#else
-
-#define OMAP_CONSOLE   NULL
-
-static inline void serial_omap_add_console_port(struct uart_omap_port *up)
-{}
-
-#endif
-
-static struct uart_ops serial_omap_pops = {
-       .tx_empty       = serial_omap_tx_empty,
-       .set_mctrl      = serial_omap_set_mctrl,
-       .get_mctrl      = serial_omap_get_mctrl,
-       .stop_tx        = serial_omap_stop_tx,
-       .start_tx       = serial_omap_start_tx,
-       .stop_rx        = serial_omap_stop_rx,
-       .enable_ms      = serial_omap_enable_ms,
-       .break_ctl      = serial_omap_break_ctl,
-       .startup        = serial_omap_startup,
-       .shutdown       = serial_omap_shutdown,
-       .set_termios    = serial_omap_set_termios,
-       .pm             = serial_omap_pm,
-       .type           = serial_omap_type,
-       .release_port   = serial_omap_release_port,
-       .request_port   = serial_omap_request_port,
-       .config_port    = serial_omap_config_port,
-       .verify_port    = serial_omap_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_put_char  = serial_omap_poll_put_char,
-       .poll_get_char  = serial_omap_poll_get_char,
-#endif
-};
-
-static struct uart_driver serial_omap_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "OMAP-SERIAL",
-       .dev_name       = OMAP_SERIAL_NAME,
-       .nr             = OMAP_MAX_HSUART_PORTS,
-       .cons           = OMAP_CONSOLE,
-};
-
-static int
-serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct uart_omap_port *up = platform_get_drvdata(pdev);
-
-       if (up)
-               uart_suspend_port(&serial_omap_reg, &up->port);
-       return 0;
-}
-
-static int serial_omap_resume(struct platform_device *dev)
-{
-       struct uart_omap_port *up = platform_get_drvdata(dev);
-
-       if (up)
-               uart_resume_port(&serial_omap_reg, &up->port);
-       return 0;
-}
-
-static void serial_omap_rx_timeout(unsigned long uart_no)
-{
-       struct uart_omap_port *up = ui[uart_no];
-       unsigned int curr_dma_pos, curr_transmitted_size;
-       int ret = 0;
-
-       curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
-       if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
-                            (curr_dma_pos == 0)) {
-               if (jiffies_to_msecs(jiffies - up->port_activity) <
-                                                       RX_TIMEOUT) {
-                       mod_timer(&up->uart_dma.rx_timer, jiffies +
-                               usecs_to_jiffies(up->uart_dma.rx_timeout));
-               } else {
-                       serial_omap_stop_rxdma(up);
-                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-               }
-               return;
-       }
-
-       curr_transmitted_size = curr_dma_pos -
-                                       up->uart_dma.prev_rx_dma_pos;
-       up->port.icount.rx += curr_transmitted_size;
-       tty_insert_flip_string(up->port.state->port.tty,
-                       up->uart_dma.rx_buf +
-                       (up->uart_dma.prev_rx_dma_pos -
-                       up->uart_dma.rx_buf_dma_phys),
-                       curr_transmitted_size);
-       tty_flip_buffer_push(up->port.state->port.tty);
-       up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
-       if (up->uart_dma.rx_buf_size +
-                       up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
-               ret = serial_omap_start_rxdma(up);
-               if (ret < 0) {
-                       serial_omap_stop_rxdma(up);
-                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
-                       serial_out(up, UART_IER, up->ier);
-               }
-       } else  {
-               mod_timer(&up->uart_dma.rx_timer, jiffies +
-                       usecs_to_jiffies(up->uart_dma.rx_timeout));
-       }
-       up->port_activity = jiffies;
-}
-
-static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
-{
-       return;
-}
-
-static int serial_omap_start_rxdma(struct uart_omap_port *up)
-{
-       int ret = 0;
-
-       if (up->uart_dma.rx_dma_channel == -1) {
-               ret = omap_request_dma(up->uart_dma.uart_dma_rx,
-                               "UART Rx DMA",
-                               (void *)uart_rx_dma_callback, up,
-                               &(up->uart_dma.rx_dma_channel));
-               if (ret < 0)
-                       return ret;
-
-               omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-               omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC,
-                               up->uart_dma.rx_buf_dma_phys, 0, 0);
-               omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.rx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_rx, 0);
-       }
-       up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.rx_dma_channel);
-       mod_timer(&up->uart_dma.rx_timer, jiffies +
-                               usecs_to_jiffies(up->uart_dma.rx_timeout));
-       up->uart_dma.rx_dma_used = true;
-       return ret;
-}
-
-static void serial_omap_continue_tx(struct uart_omap_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       unsigned int start = up->uart_dma.tx_buf_dma_phys
-                       + (xmit->tail & (UART_XMIT_SIZE - 1));
-
-       if (uart_circ_empty(xmit))
-               return;
-
-       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
-       /*
-        * It is a circular buffer. See if the buffer has wounded back.
-        * If yes it will have to be transferred in two separate dma
-        * transfers
-        */
-       if (start + up->uart_dma.tx_buf_size >=
-                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
-               up->uart_dma.tx_buf_size =
-                       (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
-       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               up->uart_dma.uart_base, 0, 0);
-       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
-       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-                               OMAP_DMA_DATA_TYPE_S8,
-                               up->uart_dma.tx_buf_size, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               up->uart_dma.uart_dma_tx, 0);
-       /* FIXME: Cache maintenance needed here? */
-       omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
-{
-       struct uart_omap_port *up = (struct uart_omap_port *)data;
-       struct circ_buf *xmit = &up->port.state->xmit;
-
-       xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
-                       (UART_XMIT_SIZE - 1);
-       up->port.icount.tx += up->uart_dma.tx_buf_size;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit)) {
-               spin_lock(&(up->uart_dma.tx_lock));
-               serial_omap_stop_tx(&up->port);
-               up->uart_dma.tx_dma_used = false;
-               spin_unlock(&(up->uart_dma.tx_lock));
-       } else {
-               omap_stop_dma(up->uart_dma.tx_dma_channel);
-               serial_omap_continue_tx(up);
-       }
-       up->port_activity = jiffies;
-       return;
-}
-
-static int serial_omap_probe(struct platform_device *pdev)
-{
-       struct uart_omap_port   *up;
-       struct resource         *mem, *irq, *dma_tx, *dma_rx;
-       struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
-       int ret = -ENOSPC;
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "no mem resource?\n");
-               return -ENODEV;
-       }
-
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "no irq resource?\n");
-               return -ENODEV;
-       }
-
-       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
-                                    pdev->dev.driver->name)) {
-               dev_err(&pdev->dev, "memory region already claimed\n");
-               return -EBUSY;
-       }
-
-       dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
-       if (!dma_rx) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
-       if (!dma_tx) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       up = kzalloc(sizeof(*up), GFP_KERNEL);
-       if (up == NULL) {
-               ret = -ENOMEM;
-               goto do_release_region;
-       }
-       sprintf(up->name, "OMAP UART%d", pdev->id);
-       up->pdev = pdev;
-       up->port.dev = &pdev->dev;
-       up->port.type = PORT_OMAP;
-       up->port.iotype = UPIO_MEM;
-       up->port.irq = irq->start;
-
-       up->port.regshift = 2;
-       up->port.fifosize = 64;
-       up->port.ops = &serial_omap_pops;
-       up->port.line = pdev->id;
-
-       up->port.membase = omap_up_info->membase;
-       up->port.mapbase = omap_up_info->mapbase;
-       up->port.flags = omap_up_info->flags;
-       up->port.irqflags = omap_up_info->irqflags;
-       up->port.uartclk = omap_up_info->uartclk;
-       up->uart_dma.uart_base = mem->start;
-
-       if (omap_up_info->dma_enabled) {
-               up->uart_dma.uart_dma_tx = dma_tx->start;
-               up->uart_dma.uart_dma_rx = dma_rx->start;
-               up->use_dma = 1;
-               up->uart_dma.rx_buf_size = 4096;
-               up->uart_dma.rx_timeout = 2;
-               spin_lock_init(&(up->uart_dma.tx_lock));
-               spin_lock_init(&(up->uart_dma.rx_lock));
-               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
-               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
-       }
-
-       ui[pdev->id] = up;
-       serial_omap_add_console_port(up);
-
-       ret = uart_add_one_port(&serial_omap_reg, &up->port);
-       if (ret != 0)
-               goto do_release_region;
-
-       platform_set_drvdata(pdev, up);
-       return 0;
-err:
-       dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
-                               pdev->id, __func__, ret);
-do_release_region:
-       release_mem_region(mem->start, (mem->end - mem->start) + 1);
-       return ret;
-}
-
-static int serial_omap_remove(struct platform_device *dev)
-{
-       struct uart_omap_port *up = platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
-       if (up) {
-               uart_remove_one_port(&serial_omap_reg, &up->port);
-               kfree(up);
-       }
-       return 0;
-}
-
-static struct platform_driver serial_omap_driver = {
-       .probe          = serial_omap_probe,
-       .remove         = serial_omap_remove,
-
-       .suspend        = serial_omap_suspend,
-       .resume         = serial_omap_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-static int __init serial_omap_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&serial_omap_reg);
-       if (ret != 0)
-               return ret;
-       ret = platform_driver_register(&serial_omap_driver);
-       if (ret != 0)
-               uart_unregister_driver(&serial_omap_reg);
-       return ret;
-}
-
-static void __exit serial_omap_exit(void)
-{
-       platform_driver_unregister(&serial_omap_driver);
-       uart_unregister_driver(&serial_omap_reg);
-}
-
-module_init(serial_omap_init);
-module_exit(serial_omap_exit);
-
-MODULE_DESCRIPTION("OMAP High Speed UART driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c
deleted file mode 100644 (file)
index 70a6145..0000000
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
- *
- *This program is free software; you can redistribute it and/or modify
- *it under the terms of the GNU General Public License as published by
- *the Free Software Foundation; 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; if not, write to the Free Software
- *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
- */
-#include <linux/serial_reg.h>
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <linux/dmaengine.h>
-#include <linux/pch_dma.h>
-
-enum {
-       PCH_UART_HANDLED_RX_INT_SHIFT,
-       PCH_UART_HANDLED_TX_INT_SHIFT,
-       PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
-       PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
-       PCH_UART_HANDLED_MS_INT_SHIFT,
-};
-
-enum {
-       PCH_UART_8LINE,
-       PCH_UART_2LINE,
-};
-
-#define PCH_UART_DRIVER_DEVICE "ttyPCH"
-
-#define PCH_UART_NR_GE_256FIFO         1
-#define PCH_UART_NR_GE_64FIFO          3
-#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
-#define PCH_UART_NR    PCH_UART_NR_GE
-
-#define PCH_UART_HANDLED_RX_INT        (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_TX_INT        (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_RX_ERR_INT    (1<<((\
-                                       PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_RX_TRG_INT    (1<<((\
-                                       PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
-#define PCH_UART_HANDLED_MS_INT        (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
-
-#define PCH_UART_RBR           0x00
-#define PCH_UART_THR           0x00
-
-#define PCH_UART_IER_MASK      (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
-                               PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
-#define PCH_UART_IER_ERBFI     0x00000001
-#define PCH_UART_IER_ETBEI     0x00000002
-#define PCH_UART_IER_ELSI      0x00000004
-#define PCH_UART_IER_EDSSI     0x00000008
-
-#define PCH_UART_IIR_IP                        0x00000001
-#define PCH_UART_IIR_IID               0x00000006
-#define PCH_UART_IIR_MSI               0x00000000
-#define PCH_UART_IIR_TRI               0x00000002
-#define PCH_UART_IIR_RRI               0x00000004
-#define PCH_UART_IIR_REI               0x00000006
-#define PCH_UART_IIR_TOI               0x00000008
-#define PCH_UART_IIR_FIFO256           0x00000020
-#define PCH_UART_IIR_FIFO64            PCH_UART_IIR_FIFO256
-#define PCH_UART_IIR_FE                        0x000000C0
-
-#define PCH_UART_FCR_FIFOE             0x00000001
-#define PCH_UART_FCR_RFR               0x00000002
-#define PCH_UART_FCR_TFR               0x00000004
-#define PCH_UART_FCR_DMS               0x00000008
-#define PCH_UART_FCR_FIFO256           0x00000020
-#define PCH_UART_FCR_RFTL              0x000000C0
-
-#define PCH_UART_FCR_RFTL1             0x00000000
-#define PCH_UART_FCR_RFTL64            0x00000040
-#define PCH_UART_FCR_RFTL128           0x00000080
-#define PCH_UART_FCR_RFTL224           0x000000C0
-#define PCH_UART_FCR_RFTL16            PCH_UART_FCR_RFTL64
-#define PCH_UART_FCR_RFTL32            PCH_UART_FCR_RFTL128
-#define PCH_UART_FCR_RFTL56            PCH_UART_FCR_RFTL224
-#define PCH_UART_FCR_RFTL4             PCH_UART_FCR_RFTL64
-#define PCH_UART_FCR_RFTL8             PCH_UART_FCR_RFTL128
-#define PCH_UART_FCR_RFTL14            PCH_UART_FCR_RFTL224
-#define PCH_UART_FCR_RFTL_SHIFT                6
-
-#define PCH_UART_LCR_WLS       0x00000003
-#define PCH_UART_LCR_STB       0x00000004
-#define PCH_UART_LCR_PEN       0x00000008
-#define PCH_UART_LCR_EPS       0x00000010
-#define PCH_UART_LCR_SP                0x00000020
-#define PCH_UART_LCR_SB                0x00000040
-#define PCH_UART_LCR_DLAB      0x00000080
-#define PCH_UART_LCR_NP                0x00000000
-#define PCH_UART_LCR_OP                PCH_UART_LCR_PEN
-#define PCH_UART_LCR_EP                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
-#define PCH_UART_LCR_1P                (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
-#define PCH_UART_LCR_0P                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
-                               PCH_UART_LCR_SP)
-
-#define PCH_UART_LCR_5BIT      0x00000000
-#define PCH_UART_LCR_6BIT      0x00000001
-#define PCH_UART_LCR_7BIT      0x00000002
-#define PCH_UART_LCR_8BIT      0x00000003
-
-#define PCH_UART_MCR_DTR       0x00000001
-#define PCH_UART_MCR_RTS       0x00000002
-#define PCH_UART_MCR_OUT       0x0000000C
-#define PCH_UART_MCR_LOOP      0x00000010
-#define PCH_UART_MCR_AFE       0x00000020
-
-#define PCH_UART_LSR_DR                0x00000001
-#define PCH_UART_LSR_ERR       (1<<7)
-
-#define PCH_UART_MSR_DCTS      0x00000001
-#define PCH_UART_MSR_DDSR      0x00000002
-#define PCH_UART_MSR_TERI      0x00000004
-#define PCH_UART_MSR_DDCD      0x00000008
-#define PCH_UART_MSR_CTS       0x00000010
-#define PCH_UART_MSR_DSR       0x00000020
-#define PCH_UART_MSR_RI                0x00000040
-#define PCH_UART_MSR_DCD       0x00000080
-#define PCH_UART_MSR_DELTA     (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
-                               PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
-
-#define PCH_UART_DLL           0x00
-#define PCH_UART_DLM           0x01
-
-#define DIV_ROUND(a, b)        (((a) + ((b)/2)) / (b))
-
-#define PCH_UART_IID_RLS       (PCH_UART_IIR_REI)
-#define PCH_UART_IID_RDR       (PCH_UART_IIR_RRI)
-#define PCH_UART_IID_RDR_TO    (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
-#define PCH_UART_IID_THRE      (PCH_UART_IIR_TRI)
-#define PCH_UART_IID_MS                (PCH_UART_IIR_MSI)
-
-#define PCH_UART_HAL_PARITY_NONE       (PCH_UART_LCR_NP)
-#define PCH_UART_HAL_PARITY_ODD                (PCH_UART_LCR_OP)
-#define PCH_UART_HAL_PARITY_EVEN       (PCH_UART_LCR_EP)
-#define PCH_UART_HAL_PARITY_FIX1       (PCH_UART_LCR_1P)
-#define PCH_UART_HAL_PARITY_FIX0       (PCH_UART_LCR_0P)
-#define PCH_UART_HAL_5BIT              (PCH_UART_LCR_5BIT)
-#define PCH_UART_HAL_6BIT              (PCH_UART_LCR_6BIT)
-#define PCH_UART_HAL_7BIT              (PCH_UART_LCR_7BIT)
-#define PCH_UART_HAL_8BIT              (PCH_UART_LCR_8BIT)
-#define PCH_UART_HAL_STB1              0
-#define PCH_UART_HAL_STB2              (PCH_UART_LCR_STB)
-
-#define PCH_UART_HAL_CLR_TX_FIFO       (PCH_UART_FCR_TFR)
-#define PCH_UART_HAL_CLR_RX_FIFO       (PCH_UART_FCR_RFR)
-#define PCH_UART_HAL_CLR_ALL_FIFO      (PCH_UART_HAL_CLR_TX_FIFO | \
-                                       PCH_UART_HAL_CLR_RX_FIFO)
-
-#define PCH_UART_HAL_DMA_MODE0         0
-#define PCH_UART_HAL_FIFO_DIS          0
-#define PCH_UART_HAL_FIFO16            (PCH_UART_FCR_FIFOE)
-#define PCH_UART_HAL_FIFO256           (PCH_UART_FCR_FIFOE | \
-                                       PCH_UART_FCR_FIFO256)
-#define PCH_UART_HAL_FIFO64            (PCH_UART_HAL_FIFO256)
-#define PCH_UART_HAL_TRIGGER1          (PCH_UART_FCR_RFTL1)
-#define PCH_UART_HAL_TRIGGER64         (PCH_UART_FCR_RFTL64)
-#define PCH_UART_HAL_TRIGGER128                (PCH_UART_FCR_RFTL128)
-#define PCH_UART_HAL_TRIGGER224                (PCH_UART_FCR_RFTL224)
-#define PCH_UART_HAL_TRIGGER16         (PCH_UART_FCR_RFTL16)
-#define PCH_UART_HAL_TRIGGER32         (PCH_UART_FCR_RFTL32)
-#define PCH_UART_HAL_TRIGGER56         (PCH_UART_FCR_RFTL56)
-#define PCH_UART_HAL_TRIGGER4          (PCH_UART_FCR_RFTL4)
-#define PCH_UART_HAL_TRIGGER8          (PCH_UART_FCR_RFTL8)
-#define PCH_UART_HAL_TRIGGER14         (PCH_UART_FCR_RFTL14)
-#define PCH_UART_HAL_TRIGGER_L         (PCH_UART_FCR_RFTL64)
-#define PCH_UART_HAL_TRIGGER_M         (PCH_UART_FCR_RFTL128)
-#define PCH_UART_HAL_TRIGGER_H         (PCH_UART_FCR_RFTL224)
-
-#define PCH_UART_HAL_RX_INT            (PCH_UART_IER_ERBFI)
-#define PCH_UART_HAL_TX_INT            (PCH_UART_IER_ETBEI)
-#define PCH_UART_HAL_RX_ERR_INT                (PCH_UART_IER_ELSI)
-#define PCH_UART_HAL_MS_INT            (PCH_UART_IER_EDSSI)
-#define PCH_UART_HAL_ALL_INT           (PCH_UART_IER_MASK)
-
-#define PCH_UART_HAL_DTR               (PCH_UART_MCR_DTR)
-#define PCH_UART_HAL_RTS               (PCH_UART_MCR_RTS)
-#define PCH_UART_HAL_OUT               (PCH_UART_MCR_OUT)
-#define PCH_UART_HAL_LOOP              (PCH_UART_MCR_LOOP)
-#define PCH_UART_HAL_AFE               (PCH_UART_MCR_AFE)
-
-struct pch_uart_buffer {
-       unsigned char *buf;
-       int size;
-};
-
-struct eg20t_port {
-       struct uart_port port;
-       int port_type;
-       void __iomem *membase;
-       resource_size_t mapbase;
-       unsigned int iobase;
-       struct pci_dev *pdev;
-       int fifo_size;
-       int base_baud;
-       int start_tx;
-       int start_rx;
-       int tx_empty;
-       int int_dis_flag;
-       int trigger;
-       int trigger_level;
-       struct pch_uart_buffer rxbuf;
-       unsigned int dmsr;
-       unsigned int fcr;
-       unsigned int use_dma;
-       unsigned int use_dma_flag;
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx;
-       struct pch_dma_slave            param_tx;
-       struct pch_dma_slave            param_rx;
-       struct dma_chan                 *chan_tx;
-       struct dma_chan                 *chan_rx;
-       struct scatterlist              sg_tx;
-       struct scatterlist              sg_rx;
-       int                             tx_dma_use;
-       void                            *rx_buf_virt;
-       dma_addr_t                      rx_buf_dma;
-};
-
-static unsigned int default_baud = 9600;
-static const int trigger_level_256[4] = { 1, 64, 128, 224 };
-static const int trigger_level_64[4] = { 1, 16, 32, 56 };
-static const int trigger_level_16[4] = { 1, 4, 8, 14 };
-static const int trigger_level_1[4] = { 1, 1, 1, 1 };
-
-static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
-                                int base_baud)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-
-       priv->trigger_level = 1;
-       priv->fcr = 0;
-}
-
-static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
-{
-       unsigned int msr = ioread8(base + UART_MSR);
-       priv->dmsr |= msr & PCH_UART_MSR_DELTA;
-
-       return msr;
-}
-
-static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
-                                         unsigned int flag)
-{
-       u8 ier = ioread8(priv->membase + UART_IER);
-       ier |= flag & PCH_UART_IER_MASK;
-       iowrite8(ier, priv->membase + UART_IER);
-}
-
-static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
-                                          unsigned int flag)
-{
-       u8 ier = ioread8(priv->membase + UART_IER);
-       ier &= ~(flag & PCH_UART_IER_MASK);
-       iowrite8(ier, priv->membase + UART_IER);
-}
-
-static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
-                                unsigned int parity, unsigned int bits,
-                                unsigned int stb)
-{
-       unsigned int dll, dlm, lcr;
-       int div;
-
-       div = DIV_ROUND(priv->base_baud / 16, baud);
-       if (div < 0 || USHRT_MAX <= div) {
-               pr_err("Invalid Baud(div=0x%x)\n", div);
-               return -EINVAL;
-       }
-
-       dll = (unsigned int)div & 0x00FFU;
-       dlm = ((unsigned int)div >> 8) & 0x00FFU;
-
-       if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
-               pr_err("Invalid parity(0x%x)\n", parity);
-               return -EINVAL;
-       }
-
-       if (bits & ~PCH_UART_LCR_WLS) {
-               pr_err("Invalid bits(0x%x)\n", bits);
-               return -EINVAL;
-       }
-
-       if (stb & ~PCH_UART_LCR_STB) {
-               pr_err("Invalid STB(0x%x)\n", stb);
-               return -EINVAL;
-       }
-
-       lcr = parity;
-       lcr |= bits;
-       lcr |= stb;
-
-       pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
-                __func__, baud, div, lcr, jiffies);
-       iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
-       iowrite8(dll, priv->membase + PCH_UART_DLL);
-       iowrite8(dlm, priv->membase + PCH_UART_DLM);
-       iowrite8(lcr, priv->membase + UART_LCR);
-
-       return 0;
-}
-
-static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
-                                   unsigned int flag)
-{
-       if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
-               pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
-               return -EINVAL;
-       }
-
-       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
-       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
-                priv->membase + UART_FCR);
-       iowrite8(priv->fcr, priv->membase + UART_FCR);
-
-       return 0;
-}
-
-static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
-                                unsigned int dmamode,
-                                unsigned int fifo_size, unsigned int trigger)
-{
-       u8 fcr;
-
-       if (dmamode & ~PCH_UART_FCR_DMS) {
-               pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
-               return -EINVAL;
-       }
-
-       if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
-               pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
-               return -EINVAL;
-       }
-
-       if (trigger & ~PCH_UART_FCR_RFTL) {
-               pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
-               return -EINVAL;
-       }
-
-       switch (priv->fifo_size) {
-       case 256:
-               priv->trigger_level =
-                   trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       case 64:
-               priv->trigger_level =
-                   trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       case 16:
-               priv->trigger_level =
-                   trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       default:
-               priv->trigger_level =
-                   trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
-               break;
-       }
-       fcr =
-           dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
-       iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
-       iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
-                priv->membase + UART_FCR);
-       iowrite8(fcr, priv->membase + UART_FCR);
-       priv->fcr = fcr;
-
-       return 0;
-}
-
-static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
-{
-       priv->dmsr = 0;
-       return get_msr(priv, priv->membase);
-}
-
-static int pch_uart_hal_write(struct eg20t_port *priv,
-                             const unsigned char *buf, int tx_size)
-{
-       int i;
-       unsigned int thr;
-
-       for (i = 0; i < tx_size;) {
-               thr = buf[i++];
-               iowrite8(thr, priv->membase + PCH_UART_THR);
-       }
-       return i;
-}
-
-static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
-                            int rx_size)
-{
-       int i;
-       u8 rbr, lsr;
-
-       lsr = ioread8(priv->membase + UART_LSR);
-       for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
-            i < rx_size && lsr & UART_LSR_DR;
-            lsr = ioread8(priv->membase + UART_LSR)) {
-               rbr = ioread8(priv->membase + PCH_UART_RBR);
-               buf[i++] = rbr;
-       }
-       return i;
-}
-
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
-{
-       unsigned int iir;
-       int ret;
-
-       iir = ioread8(priv->membase + UART_IIR);
-       ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
-       return ret;
-}
-
-static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
-{
-       return ioread8(priv->membase + UART_LSR);
-}
-
-static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
-{
-       unsigned int lcr;
-
-       lcr = ioread8(priv->membase + UART_LCR);
-       if (on)
-               lcr |= PCH_UART_LCR_SB;
-       else
-               lcr &= ~PCH_UART_LCR_SB;
-
-       iowrite8(lcr, priv->membase + UART_LCR);
-}
-
-static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
-                  int size)
-{
-       struct uart_port *port;
-       struct tty_struct *tty;
-
-       port = &priv->port;
-       tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return -EBUSY;
-       }
-
-       tty_insert_flip_string(tty, buf, size);
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-
-       return 0;
-}
-
-static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
-{
-       int ret;
-       struct uart_port *port = &priv->port;
-
-       if (port->x_char) {
-               pr_debug("%s:X character send %02x (%lu)\n", __func__,
-                       port->x_char, jiffies);
-               buf[0] = port->x_char;
-               port->x_char = 0;
-               ret = 1;
-       } else {
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int dma_push_rx(struct eg20t_port *priv, int size)
-{
-       struct tty_struct *tty;
-       int room;
-       struct uart_port *port = &priv->port;
-
-       port = &priv->port;
-       tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return 0;
-       }
-
-       room = tty_buffer_request_room(tty, size);
-
-       if (room < size)
-               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
-                        size - room);
-       if (!room)
-               return room;
-
-       tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
-
-       port->icount.rx += room;
-       tty_kref_put(tty);
-
-       return room;
-}
-
-static void pch_free_dma(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-
-       if (priv->chan_tx) {
-               dma_release_channel(priv->chan_tx);
-               priv->chan_tx = NULL;
-       }
-       if (priv->chan_rx) {
-               dma_release_channel(priv->chan_rx);
-               priv->chan_rx = NULL;
-       }
-       if (sg_dma_address(&priv->sg_rx))
-               dma_free_coherent(port->dev, port->fifosize,
-                                 sg_virt(&priv->sg_rx),
-                                 sg_dma_address(&priv->sg_rx));
-
-       return;
-}
-
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct pch_dma_slave *param = slave;
-
-       if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
-                                                 chan->device->dev)) {
-               chan->private = param;
-               return true;
-       } else {
-               return false;
-       }
-}
-
-static void pch_request_dma(struct uart_port *port)
-{
-       dma_cap_mask_t mask;
-       struct dma_chan *chan;
-       struct pci_dev *dma_dev;
-       struct pch_dma_slave *param;
-       struct eg20t_port *priv =
-                               container_of(port, struct eg20t_port, port);
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
-                                                               information */
-       /* Set Tx DMA */
-       param = &priv->param_tx;
-       param->dma_dev = &dma_dev->dev;
-       param->chan_id = priv->port.line;
-       param->tx_reg = port->mapbase + UART_TX;
-       chan = dma_request_channel(mask, filter, param);
-       if (!chan) {
-               pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
-               return;
-       }
-       priv->chan_tx = chan;
-
-       /* Set Rx DMA */
-       param = &priv->param_rx;
-       param->dma_dev = &dma_dev->dev;
-       param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
-       param->rx_reg = port->mapbase + UART_RX;
-       chan = dma_request_channel(mask, filter, param);
-       if (!chan) {
-               pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
-               dma_release_channel(priv->chan_tx);
-               return;
-       }
-
-       /* Get Consistent memory for DMA */
-       priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
-                                   &priv->rx_buf_dma, GFP_KERNEL);
-       priv->chan_rx = chan;
-}
-
-static void pch_dma_rx_complete(void *arg)
-{
-       struct eg20t_port *priv = arg;
-       struct uart_port *port = &priv->port;
-       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-
-       if (!tty) {
-               pr_debug("%s:tty is busy now", __func__);
-               return;
-       }
-
-       if (dma_push_rx(priv, priv->trigger_level))
-               tty_flip_buffer_push(tty);
-
-       tty_kref_put(tty);
-}
-
-static void pch_dma_tx_complete(void *arg)
-{
-       struct eg20t_port *priv = arg;
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       xmit->tail += sg_dma_len(&priv->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
-       port->icount.tx += sg_dma_len(&priv->sg_tx);
-
-       async_tx_ack(priv->desc_tx);
-       priv->tx_dma_use = 0;
-}
-
-static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
-{
-       int count = 0;
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
-               goto pop_tx_end;
-
-       do {
-               int cnt_to_end =
-                   CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-               int sz = min(size - count, cnt_to_end);
-               memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
-               xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
-               count += sz;
-       } while (!uart_circ_empty(xmit) && count < size);
-
-pop_tx_end:
-       pr_debug("%d characters. Remained %d characters. (%lu)\n",
-                count, size - count, jiffies);
-
-       return count;
-}
-
-static int handle_rx_to(struct eg20t_port *priv)
-{
-       struct pch_uart_buffer *buf;
-       int rx_size;
-       int ret;
-       if (!priv->start_rx) {
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-               return 0;
-       }
-       buf = &priv->rxbuf;
-       do {
-               rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
-               ret = push_rx(priv, buf->buf, rx_size);
-               if (ret)
-                       return 0;
-       } while (rx_size == buf->size);
-
-       return PCH_UART_HANDLED_RX_INT;
-}
-
-static int handle_rx(struct eg20t_port *priv)
-{
-       return handle_rx_to(priv);
-}
-
-static int dma_handle_rx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct dma_async_tx_descriptor *desc;
-       struct scatterlist *sg;
-
-       priv = container_of(port, struct eg20t_port, port);
-       sg = &priv->sg_rx;
-
-       sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
-
-       sg_dma_len(sg) = priv->fifo_size;
-
-       sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
-                    sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
-                    ~PAGE_MASK);
-
-       sg_dma_address(sg) = priv->rx_buf_dma;
-
-       desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
-                       sg, 1, DMA_FROM_DEVICE,
-                       DMA_PREP_INTERRUPT);
-       if (!desc)
-               return 0;
-
-       priv->desc_rx = desc;
-       desc->callback = pch_dma_rx_complete;
-       desc->callback_param = priv;
-       desc->tx_submit(desc);
-       dma_async_issue_pending(priv->chan_rx);
-
-       return PCH_UART_HANDLED_RX_INT;
-}
-
-static unsigned int handle_tx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       int ret;
-       int fifo_size;
-       int tx_size;
-       int size;
-       int tx_empty;
-
-       if (!priv->start_tx) {
-               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-               priv->tx_empty = 1;
-               return 0;
-       }
-
-       fifo_size = max(priv->fifo_size, 1);
-       tx_empty = 1;
-       if (pop_tx_x(priv, xmit->buf)) {
-               pch_uart_hal_write(priv, xmit->buf, 1);
-               port->icount.tx++;
-               tx_empty = 0;
-               fifo_size--;
-       }
-       size = min(xmit->head - xmit->tail, fifo_size);
-       tx_size = pop_tx(priv, xmit->buf, size);
-       if (tx_size > 0) {
-               ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
-               port->icount.tx += ret;
-               tx_empty = 0;
-       }
-
-       priv->tx_empty = tx_empty;
-
-       if (tx_empty)
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-
-       return PCH_UART_HANDLED_TX_INT;
-}
-
-static unsigned int dma_handle_tx(struct eg20t_port *priv)
-{
-       struct uart_port *port = &priv->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &priv->sg_tx;
-       int nent;
-       int fifo_size;
-       int tx_empty;
-       struct dma_async_tx_descriptor *desc;
-
-       if (!priv->start_tx) {
-               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
-               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-               priv->tx_empty = 1;
-               return 0;
-       }
-
-       fifo_size = max(priv->fifo_size, 1);
-       tx_empty = 1;
-       if (pop_tx_x(priv, xmit->buf)) {
-               pch_uart_hal_write(priv, xmit->buf, 1);
-               port->icount.tx++;
-               tx_empty = 0;
-               fifo_size--;
-       }
-
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
-
-       priv->tx_dma_use = 1;
-
-       sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
-
-       sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
-                   UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
-
-       nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
-       if (!nent) {
-               pr_err("%s:dma_map_sg Failed\n", __func__);
-               return 0;
-       }
-
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-                             sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
-                            UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
-                            xmit->tail, UART_XMIT_SIZE));
-
-       desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
-               sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("%s:device_prep_slave_sg Failed\n", __func__);
-               return 0;
-       }
-
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
-
-       priv->desc_tx = desc;
-       desc->callback = pch_dma_tx_complete;
-       desc->callback_param = priv;
-
-       desc->tx_submit(desc);
-
-       dma_async_issue_pending(priv->chan_tx);
-
-       return PCH_UART_HANDLED_TX_INT;
-}
-
-static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
-{
-       u8 fcr = ioread8(priv->membase + UART_FCR);
-
-       /* Reset FIFO */
-       fcr |= UART_FCR_CLEAR_RCVR;
-       iowrite8(fcr, priv->membase + UART_FCR);
-
-       if (lsr & PCH_UART_LSR_ERR)
-               dev_err(&priv->pdev->dev, "Error data in FIFO\n");
-
-       if (lsr & UART_LSR_FE)
-               dev_err(&priv->pdev->dev, "Framing Error\n");
-
-       if (lsr & UART_LSR_PE)
-               dev_err(&priv->pdev->dev, "Parity Error\n");
-
-       if (lsr & UART_LSR_OE)
-               dev_err(&priv->pdev->dev, "Overrun Error\n");
-}
-
-static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
-{
-       struct eg20t_port *priv = dev_id;
-       unsigned int handled;
-       u8 lsr;
-       int ret = 0;
-       unsigned int iid;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->port.lock, flags);
-       handled = 0;
-       while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
-               switch (iid) {
-               case PCH_UART_IID_RLS:  /* Receiver Line Status */
-                       lsr = pch_uart_hal_get_line_status(priv);
-                       if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
-                                               UART_LSR_PE | UART_LSR_OE)) {
-                               pch_uart_err_ir(priv, lsr);
-                               ret = PCH_UART_HANDLED_RX_ERR_INT;
-                       }
-                       break;
-               case PCH_UART_IID_RDR:  /* Received Data Ready */
-                       if (priv->use_dma)
-                               ret = dma_handle_rx(priv);
-                       else
-                               ret = handle_rx(priv);
-                       break;
-               case PCH_UART_IID_RDR_TO:       /* Received Data Ready
-                                                  (FIFO Timeout) */
-                       ret = handle_rx_to(priv);
-                       break;
-               case PCH_UART_IID_THRE: /* Transmitter Holding Register
-                                                  Empty */
-                       if (priv->use_dma)
-                               ret = dma_handle_tx(priv);
-                       else
-                               ret = handle_tx(priv);
-                       break;
-               case PCH_UART_IID_MS:   /* Modem Status */
-                       ret = PCH_UART_HANDLED_MS_INT;
-                       break;
-               default:        /* Never junp to this label */
-                       pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
-                       ret = -1;
-                       break;
-               }
-               handled |= (unsigned int)ret;
-       }
-       if (handled == 0 && iid <= 1) {
-               if (priv->int_dis_flag)
-                       priv->int_dis_flag = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->port.lock, flags);
-       return IRQ_RETVAL(handled);
-}
-
-/* This function tests whether the transmitter fifo and shifter for the port
-                                               described by 'port' is empty. */
-static unsigned int pch_uart_tx_empty(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       priv = container_of(port, struct eg20t_port, port);
-       if (priv->tx_empty)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* Returns the current state of modem control inputs. */
-static unsigned int pch_uart_get_mctrl(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       u8 modem;
-       unsigned int ret = 0;
-
-       priv = container_of(port, struct eg20t_port, port);
-       modem = pch_uart_hal_get_modem(priv);
-
-       if (modem & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-
-       if (modem & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-
-       if (modem & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-
-       if (modem & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       u32 mcr = 0;
-       unsigned int dat;
-       struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       if (mctrl) {
-               dat = pch_uart_get_mctrl(port);
-               dat |= mcr;
-               iowrite8(dat, priv->membase + UART_MCR);
-       }
-}
-
-static void pch_uart_stop_tx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       priv->start_tx = 0;
-       priv->tx_dma_use = 0;
-}
-
-static void pch_uart_start_tx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-
-       if (priv->use_dma)
-               if (priv->tx_dma_use)
-                       return;
-
-       priv->start_tx = 1;
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
-}
-
-static void pch_uart_stop_rx(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       priv->start_rx = 0;
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-       priv->int_dis_flag = 1;
-}
-
-/* Enable the modem status interrupts. */
-static void pch_uart_enable_ms(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       priv = container_of(port, struct eg20t_port, port);
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
-}
-
-/* Control the transmission of a break signal. */
-static void pch_uart_break_ctl(struct uart_port *port, int ctl)
-{
-       struct eg20t_port *priv;
-       unsigned long flags;
-
-       priv = container_of(port, struct eg20t_port, port);
-       spin_lock_irqsave(&port->lock, flags);
-       pch_uart_hal_set_break(priv, ctl);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Grab any interrupt resources and initialise any low level driver state. */
-static int pch_uart_startup(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       int fifo_size;
-       int trigger_level;
-
-       priv = container_of(port, struct eg20t_port, port);
-       priv->tx_empty = 1;
-       port->uartclk = priv->base_baud;
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
-       ret = pch_uart_hal_set_line(priv, default_baud,
-                             PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
-                             PCH_UART_HAL_STB1);
-       if (ret)
-               return ret;
-
-       switch (priv->fifo_size) {
-       case 256:
-               fifo_size = PCH_UART_HAL_FIFO256;
-               break;
-       case 64:
-               fifo_size = PCH_UART_HAL_FIFO64;
-               break;
-       case 16:
-               fifo_size = PCH_UART_HAL_FIFO16;
-       case 1:
-       default:
-               fifo_size = PCH_UART_HAL_FIFO_DIS;
-               break;
-       }
-
-       switch (priv->trigger) {
-       case PCH_UART_HAL_TRIGGER1:
-               trigger_level = 1;
-               break;
-       case PCH_UART_HAL_TRIGGER_L:
-               trigger_level = priv->fifo_size / 4;
-               break;
-       case PCH_UART_HAL_TRIGGER_M:
-               trigger_level = priv->fifo_size / 2;
-               break;
-       case PCH_UART_HAL_TRIGGER_H:
-       default:
-               trigger_level = priv->fifo_size - (priv->fifo_size / 8);
-               break;
-       }
-
-       priv->trigger_level = trigger_level;
-       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
-                                   fifo_size, priv->trigger);
-       if (ret < 0)
-               return ret;
-
-       ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, priv);
-       if (ret < 0)
-               return ret;
-
-       if (priv->use_dma)
-               pch_request_dma(port);
-
-       priv->start_rx = 1;
-       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
-       uart_update_timeout(port, CS8, default_baud);
-
-       return 0;
-}
-
-static void pch_uart_shutdown(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-
-       priv = container_of(port, struct eg20t_port, port);
-       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
-       pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
-       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
-                             PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
-       if (ret)
-               pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
-
-       if (priv->use_dma_flag)
-               pch_free_dma(port);
-
-       free_irq(priv->port.irq, priv);
-}
-
-/* Change the port parameters, including word length, parity, stop
- *bits.  Update read_status_mask and ignore_status_mask to indicate
- *the types of events we are interested in receiving.  */
-static void pch_uart_set_termios(struct uart_port *port,
-                                struct ktermios *termios, struct ktermios *old)
-{
-       int baud;
-       int rtn;
-       unsigned int parity, bits, stb;
-       struct eg20t_port *priv;
-       unsigned long flags;
-
-       priv = container_of(port, struct eg20t_port, port);
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               bits = PCH_UART_HAL_5BIT;
-               break;
-       case CS6:
-               bits = PCH_UART_HAL_6BIT;
-               break;
-       case CS7:
-               bits = PCH_UART_HAL_7BIT;
-               break;
-       default:                /* CS8 */
-               bits = PCH_UART_HAL_8BIT;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               stb = PCH_UART_HAL_STB2;
-       else
-               stb = PCH_UART_HAL_STB1;
-
-       if (termios->c_cflag & PARENB) {
-               if (!(termios->c_cflag & PARODD))
-                       parity = PCH_UART_HAL_PARITY_ODD;
-               else
-                       parity = PCH_UART_HAL_PARITY_EVEN;
-
-       } else {
-               parity = PCH_UART_HAL_PARITY_NONE;
-       }
-       termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-       rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
-       if (rtn)
-               goto out;
-
-       /* Don't rewrite B0 */
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-
-out:
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pch_uart_type(struct uart_port *port)
-{
-       return KBUILD_MODNAME;
-}
-
-static void pch_uart_release_port(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       pci_iounmap(priv->pdev, priv->membase);
-       pci_release_regions(priv->pdev);
-}
-
-static int pch_uart_request_port(struct uart_port *port)
-{
-       struct eg20t_port *priv;
-       int ret;
-       void __iomem *membase;
-
-       priv = container_of(port, struct eg20t_port, port);
-       ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
-       if (ret < 0)
-               return -EBUSY;
-
-       membase = pci_iomap(priv->pdev, 1, 0);
-       if (!membase) {
-               pci_release_regions(priv->pdev);
-               return -EBUSY;
-       }
-       priv->membase = port->membase = membase;
-
-       return 0;
-}
-
-static void pch_uart_config_port(struct uart_port *port, int type)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       if (type & UART_CONFIG_TYPE) {
-               port->type = priv->port_type;
-               pch_uart_request_port(port);
-       }
-}
-
-static int pch_uart_verify_port(struct uart_port *port,
-                               struct serial_struct *serinfo)
-{
-       struct eg20t_port *priv;
-
-       priv = container_of(port, struct eg20t_port, port);
-       if (serinfo->flags & UPF_LOW_LATENCY) {
-               pr_info("PCH UART : Use PIO Mode (without DMA)\n");
-               priv->use_dma = 0;
-               serinfo->flags &= ~UPF_LOW_LATENCY;
-       } else {
-#ifndef CONFIG_PCH_DMA
-               pr_err("%s : PCH DMA is not Loaded.\n", __func__);
-               return -EOPNOTSUPP;
-#endif
-               priv->use_dma = 1;
-               priv->use_dma_flag = 1;
-               pr_info("PCH UART : Use DMA Mode\n");
-       }
-
-       return 0;
-}
-
-static struct uart_ops pch_uart_ops = {
-       .tx_empty = pch_uart_tx_empty,
-       .set_mctrl = pch_uart_set_mctrl,
-       .get_mctrl = pch_uart_get_mctrl,
-       .stop_tx = pch_uart_stop_tx,
-       .start_tx = pch_uart_start_tx,
-       .stop_rx = pch_uart_stop_rx,
-       .enable_ms = pch_uart_enable_ms,
-       .break_ctl = pch_uart_break_ctl,
-       .startup = pch_uart_startup,
-       .shutdown = pch_uart_shutdown,
-       .set_termios = pch_uart_set_termios,
-/*     .pm             = pch_uart_pm,          Not supported yet */
-/*     .set_wake       = pch_uart_set_wake,    Not supported yet */
-       .type = pch_uart_type,
-       .release_port = pch_uart_release_port,
-       .request_port = pch_uart_request_port,
-       .config_port = pch_uart_config_port,
-       .verify_port = pch_uart_verify_port
-};
-
-static struct uart_driver pch_uart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = KBUILD_MODNAME,
-       .dev_name = PCH_UART_DRIVER_DEVICE,
-       .major = 0,
-       .minor = 0,
-       .nr = PCH_UART_NR,
-};
-
-static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
-                                               int port_type)
-{
-       struct eg20t_port *priv;
-       int ret;
-       unsigned int iobase;
-       unsigned int mapbase;
-       unsigned char *rxbuf;
-       int fifosize, base_baud;
-       static int num;
-
-       priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
-       if (priv == NULL)
-               goto init_port_alloc_err;
-
-       rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
-       if (!rxbuf)
-               goto init_port_free_txbuf;
-
-       switch (port_type) {
-       case PORT_UNKNOWN:
-               fifosize = 256; /* UART0 */
-               base_baud = 1843200; /* 1.8432MHz */
-               break;
-       case PORT_8250:
-               fifosize = 64; /* UART1~3 */
-               base_baud = 1843200; /* 1.8432MHz */
-               break;
-       default:
-               dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
-               goto init_port_hal_free;
-       }
-
-       iobase = pci_resource_start(pdev, 0);
-       mapbase = pci_resource_start(pdev, 1);
-       priv->mapbase = mapbase;
-       priv->iobase = iobase;
-       priv->pdev = pdev;
-       priv->tx_empty = 1;
-       priv->rxbuf.buf = rxbuf;
-       priv->rxbuf.size = PAGE_SIZE;
-
-       priv->fifo_size = fifosize;
-       priv->base_baud = base_baud;
-       priv->port_type = PORT_MAX_8250 + port_type + 1;
-       priv->port.dev = &pdev->dev;
-       priv->port.iobase = iobase;
-       priv->port.membase = NULL;
-       priv->port.mapbase = mapbase;
-       priv->port.irq = pdev->irq;
-       priv->port.iotype = UPIO_PORT;
-       priv->port.ops = &pch_uart_ops;
-       priv->port.flags = UPF_BOOT_AUTOCONF;
-       priv->port.fifosize = fifosize;
-       priv->port.line = num++;
-       priv->trigger = PCH_UART_HAL_TRIGGER_M;
-
-       pci_set_drvdata(pdev, priv);
-       pch_uart_hal_request(pdev, fifosize, base_baud);
-       ret = uart_add_one_port(&pch_uart_driver, &priv->port);
-       if (ret < 0)
-               goto init_port_hal_free;
-
-       return priv;
-
-init_port_hal_free:
-       free_page((unsigned long)rxbuf);
-init_port_free_txbuf:
-       kfree(priv);
-init_port_alloc_err:
-
-       return NULL;
-}
-
-static void pch_uart_exit_port(struct eg20t_port *priv)
-{
-       uart_remove_one_port(&pch_uart_driver, &priv->port);
-       pci_set_drvdata(priv->pdev, NULL);
-       free_page((unsigned long)priv->rxbuf.buf);
-}
-
-static void pch_uart_pci_remove(struct pci_dev *pdev)
-{
-       struct eg20t_port *priv;
-
-       priv = (struct eg20t_port *)pci_get_drvdata(pdev);
-       pch_uart_exit_port(priv);
-       pci_disable_device(pdev);
-       kfree(priv);
-       return;
-}
-#ifdef CONFIG_PM
-static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-
-       uart_suspend_port(&pch_uart_driver, &priv->port);
-
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-       return 0;
-}
-
-static int pch_uart_pci_resume(struct pci_dev *pdev)
-{
-       struct eg20t_port *priv = pci_get_drvdata(pdev);
-       int ret;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               dev_err(&pdev->dev,
-               "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
-               return ret;
-       }
-
-       uart_resume_port(&pch_uart_driver, &priv->port);
-
-       return 0;
-}
-#else
-#define pch_uart_pci_suspend NULL
-#define pch_uart_pci_resume NULL
-#endif
-
-static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
-        .driver_data = PCH_UART_8LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
-        .driver_data = PCH_UART_2LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
-        .driver_data = PCH_UART_2LINE},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
-        .driver_data = PCH_UART_2LINE},
-       {0,},
-};
-
-static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
-                                       const struct pci_device_id *id)
-{
-       int ret;
-       struct eg20t_port *priv;
-
-       ret = pci_enable_device(pdev);
-       if (ret < 0)
-               goto probe_error;
-
-       priv = pch_uart_init_port(pdev, id->driver_data);
-       if (!priv) {
-               ret = -EBUSY;
-               goto probe_disable_device;
-       }
-       pci_set_drvdata(pdev, priv);
-
-       return ret;
-
-probe_disable_device:
-       pci_disable_device(pdev);
-probe_error:
-       return ret;
-}
-
-static struct pci_driver pch_uart_pci_driver = {
-       .name = "pch_uart",
-       .id_table = pch_uart_pci_id,
-       .probe = pch_uart_pci_probe,
-       .remove = __devexit_p(pch_uart_pci_remove),
-       .suspend = pch_uart_pci_suspend,
-       .resume = pch_uart_pci_resume,
-};
-
-static int __init pch_uart_module_init(void)
-{
-       int ret;
-
-       /* register as UART driver */
-       ret = uart_register_driver(&pch_uart_driver);
-       if (ret < 0)
-               return ret;
-
-       /* register as PCI driver */
-       ret = pci_register_driver(&pch_uart_pci_driver);
-       if (ret < 0)
-               uart_unregister_driver(&pch_uart_driver);
-
-       return ret;
-}
-module_init(pch_uart_module_init);
-
-static void __exit pch_uart_module_exit(void)
-{
-       pci_unregister_driver(&pch_uart_pci_driver);
-       uart_unregister_driver(&pch_uart_driver);
-}
-module_exit(pch_uart_module_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
-module_param(default_baud, uint, S_IRUGO);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
deleted file mode 100644 (file)
index 5b9cde7..0000000
+++ /dev/null
@@ -1,2208 +0,0 @@
-/*
- * linux/drivers/serial/pmac_zilog.c
- * 
- * Driver for PowerMac Z85c30 based ESCC cell found in the
- * "macio" ASICs of various PowerMac models
- * 
- * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- * Derived from drivers/macintosh/macserial.c by Paul Mackerras
- * and drivers/serial/sunzilog.c by David S. Miller
- *
- * Hrm... actually, I ripped most of sunzilog (Thanks David !) and
- * adapted special tweaks needed for us. I don't think it's worth
- * merging back those though. The DMA code still has to get in
- * and once done, I expect that driver to remain fairly stable in
- * the long term, unless we change the driver model again...
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * 2004-08-06 Harald Welte <laforge@gnumonks.org>
- *     - Enable BREAK interrupt
- *     - Add support for sysreq
- *
- * TODO:   - Add DMA support
- *         - Defer port shutdown to a few seconds after close
- *         - maybe put something right into uap->clk_divisor
- */
-
-#undef DEBUG
-#undef DEBUG_HARD
-#undef USE_CTRL_O_SYSRQ
-
-#include <linux/module.h>
-#include <linux/tty.h>
-
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/bitops.h>
-#include <linux/sysrq.h>
-#include <linux/mutex.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-#include <asm/macio.h>
-#else
-#include <linux/platform_device.h>
-#define of_machine_is_compatible(x) (0)
-#endif
-
-#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-
-#include "pmac_zilog.h"
-
-/* Not yet implemented */
-#undef HAS_DBDMA
-
-static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
-#define PMACZILOG_MAJOR                TTY_MAJOR
-#define PMACZILOG_MINOR                64
-#define PMACZILOG_NAME         "ttyS"
-#else
-#define PMACZILOG_MAJOR                204
-#define PMACZILOG_MINOR                192
-#define PMACZILOG_NAME         "ttyPZ"
-#endif
-
-
-/*
- * For the sake of early serial console, we can do a pre-probe
- * (optional) of the ports at rather early boot time.
- */
-static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
-static int                     pmz_ports_count;
-static DEFINE_MUTEX(pmz_irq_mutex);
-
-static struct uart_driver pmz_uart_reg = {
-       .owner          =       THIS_MODULE,
-       .driver_name    =       PMACZILOG_NAME,
-       .dev_name       =       PMACZILOG_NAME,
-       .major          =       PMACZILOG_MAJOR,
-       .minor          =       PMACZILOG_MINOR,
-};
-
-
-/* 
- * Load all registers to reprogram the port
- * This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
-{
-       int i;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(uap, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       ZS_CLEARERR(uap);
-       zssync(uap);
-       ZS_CLEARFIFO(uap);
-       zssync(uap);
-       ZS_CLEARERR(uap);
-
-       /* Disable all interrupts.  */
-       write_zsreg(uap, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(uap, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(uap, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
-       write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
-
-       /* now set R7 "prime" on ESCC */
-       write_zsreg(uap, R15, regs[R15] | EN85C30);
-       write_zsreg(uap, R7, regs[R7P]);
-
-       /* make sure we use R7 "non-prime" on ESCC */
-       write_zsreg(uap, R15, regs[R15] & ~EN85C30);
-
-       /* Synchronous mode config.  */
-       write_zsreg(uap, R6, regs[R6]);
-       write_zsreg(uap, R7, regs[R7]);
-
-       /* Disable baud generator.  */
-       write_zsreg(uap, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(uap, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(uap, R12, regs[R12]);
-       write_zsreg(uap, R13, regs[R13]);
-       
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(uap, R14, regs[R14]);
-
-       /* Reset external status interrupts.  */
-       write_zsreg(uap, R0, RES_EXT_INT);
-       write_zsreg(uap, R0, RES_EXT_INT);
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(uap, R3, regs[R3]);
-       write_zsreg(uap, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(uap, R1, regs[R1]);
-
-       /* Enable interrupts */
-       write_zsreg(uap, R9, regs[R9]);
-}
-
-/* 
- * We do like sunzilog to avoid disrupting pending Tx
- * Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
-{
-       if (!ZS_REGS_HELD(uap)) {
-               if (ZS_TX_ACTIVE(uap)) {
-                       uap->flags |= PMACZILOG_FLAG_REGS_HELD;
-               } else {
-                       pmz_debug("pmz: maybe_update_regs: updating\n");
-                       pmz_load_zsregs(uap, uap->curregs);
-               }
-       }
-}
-
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
-{
-       struct tty_struct *tty = NULL;
-       unsigned char ch, r1, drop, error, flag;
-       int loops = 0;
-
-       /* The interrupt can be enabled when the port isn't open, typically
-        * that happens when using one port is open and the other closed (stale
-        * interrupt) or when one port is used as a console.
-        */
-       if (!ZS_IS_OPEN(uap)) {
-               pmz_debug("pmz: draining input\n");
-               /* Port is closed, drain input data */
-               for (;;) {
-                       if ((++loops) > 1000)
-                               goto flood;
-                       (void)read_zsreg(uap, R1);
-                       write_zsreg(uap, R0, ERR_RES);
-                       (void)read_zsdata(uap);
-                       ch = read_zsreg(uap, R0);
-                       if (!(ch & Rx_CH_AV))
-                               break;
-               }
-               return NULL;
-       }
-
-       /* Sanity check, make sure the old bug is no longer happening */
-       if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
-               WARN_ON(1);
-               (void)read_zsdata(uap);
-               return NULL;
-       }
-       tty = uap->port.state->port.tty;
-
-       while (1) {
-               error = 0;
-               drop = 0;
-
-               r1 = read_zsreg(uap, R1);
-               ch = read_zsdata(uap);
-
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       write_zsreg(uap, R0, ERR_RES);
-                       zssync(uap);
-               }
-
-               ch &= uap->parity_mask;
-               if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
-                       uap->flags &= ~PMACZILOG_FLAG_BREAK;
-               }
-
-#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
-#ifdef USE_CTRL_O_SYSRQ
-               /* Handle the SysRq ^O Hack */
-               if (ch == '\x0f') {
-                       uap->port.sysrq = jiffies + HZ*5;
-                       goto next_char;
-               }
-#endif /* USE_CTRL_O_SYSRQ */
-               if (uap->port.sysrq) {
-                       int swallow;
-                       spin_unlock(&uap->port.lock);
-                       swallow = uart_handle_sysrq_char(&uap->port, ch);
-                       spin_lock(&uap->port.lock);
-                       if (swallow)
-                               goto next_char;
-               }
-#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
-
-               /* A real serial line, record the character and status.  */
-               if (drop)
-                       goto next_char;
-
-               flag = TTY_NORMAL;
-               uap->port.icount.rx++;
-
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
-                       error = 1;
-                       if (r1 & BRK_ABRT) {
-                               pmz_debug("pmz: got break !\n");
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                               uap->port.icount.brk++;
-                               if (uart_handle_break(&uap->port))
-                                       goto next_char;
-                       }
-                       else if (r1 & PAR_ERR)
-                               uap->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               uap->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               uap->port.icount.overrun++;
-                       r1 &= uap->port.read_status_mask;
-                       if (r1 & BRK_ABRT)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uap->port.ignore_status_mask == 0xff ||
-                   (r1 & uap->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if (r1 & Rx_OVR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       next_char:
-               /* We can get stuck in an infinite loop getting char 0 when the
-                * line is in a wrong HW state, we break that here.
-                * When that happens, I disable the receive side of the driver.
-                * Note that what I've been experiencing is a real irq loop where
-                * I'm getting flooded regardless of the actual port speed.
-                * Something stange is going on with the HW
-                */
-               if ((++loops) > 1000)
-                       goto flood;
-               ch = read_zsreg(uap, R0);
-               if (!(ch & Rx_CH_AV))
-                       break;
-       }
-
-       return tty;
- flood:
-       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       write_zsreg(uap, R1, uap->curregs[R1]);
-       zssync(uap);
-       pmz_error("pmz: rx irq flood !\n");
-       return tty;
-}
-
-static void pmz_status_handle(struct uart_pmac_port *uap)
-{
-       unsigned char status;
-
-       status = read_zsreg(uap, R0);
-       write_zsreg(uap, R0, RES_EXT_INT);
-       zssync(uap);
-
-       if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) {
-               if (status & SYNC_HUNT)
-                       uap->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                * The CTS input is inverted for some reason.  -- paulus
-                */
-               if ((status ^ uap->prev_status) & DCD)
-                       uart_handle_dcd_change(&uap->port,
-                                              (status & DCD));
-               if ((status ^ uap->prev_status) & CTS)
-                       uart_handle_cts_change(&uap->port,
-                                              !(status & CTS));
-
-               wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
-       }
-
-       if (status & BRK_ABRT)
-               uap->flags |= PMACZILOG_FLAG_BREAK;
-
-       uap->prev_status = status;
-}
-
-static void pmz_transmit_chars(struct uart_pmac_port *uap)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       if (ZS_IS_CONS(uap)) {
-               unsigned char status = read_zsreg(uap, R0);
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(uap)) {
-               pmz_load_zsregs(uap, uap->curregs);
-               uap->flags &= ~PMACZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(uap)) {
-               uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       /* Under some circumstances, we see interrupts reported for
-        * a closed channel. The interrupt mask in R1 is clear, but
-        * R3 still signals the interrupts and we see them when taking
-        * an interrupt for the other channel (this could be a qemu
-        * bug but since the ESCC doc doesn't specify precsiely whether
-        * R3 interrup status bits are masked by R1 interrupt enable
-        * bits, better safe than sorry). --BenH.
-        */
-       if (!ZS_IS_OPEN(uap))
-               goto ack_tx_int;
-
-       if (uap->port.x_char) {
-               uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-               write_zsdata(uap, uap->port.x_char);
-               zssync(uap);
-               uap->port.icount.tx++;
-               uap->port.x_char = 0;
-               return;
-       }
-
-       if (uap->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &uap->port.state->xmit;
-       if (uart_circ_empty(xmit)) {
-               uart_write_wakeup(&uap->port);
-               goto ack_tx_int;
-       }
-       if (uart_tx_stopped(&uap->port))
-               goto ack_tx_int;
-
-       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-       write_zsdata(uap, xmit->buf[xmit->tail]);
-       zssync(uap);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       uap->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&uap->port);
-
-       return;
-
-ack_tx_int:
-       write_zsreg(uap, R0, RES_Tx_P);
-       zssync(uap);
-}
-
-/* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id)
-{
-       struct uart_pmac_port *uap = dev_id;
-       struct uart_pmac_port *uap_a;
-       struct uart_pmac_port *uap_b;
-       int rc = IRQ_NONE;
-       struct tty_struct *tty;
-       u8 r3;
-
-       uap_a = pmz_get_port_A(uap);
-       uap_b = uap_a->mate;
-
-       spin_lock(&uap_a->port.lock);
-       r3 = read_zsreg(uap_a, R3);
-
-#ifdef DEBUG_HARD
-       pmz_debug("irq, r3: %x\n", r3);
-#endif
-       /* Channel A */
-       tty = NULL;
-       if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-               write_zsreg(uap_a, R0, RES_H_IUS);
-               zssync(uap_a);          
-               if (r3 & CHAEXT)
-                       pmz_status_handle(uap_a);
-               if (r3 & CHARxIP)
-                       tty = pmz_receive_chars(uap_a);
-               if (r3 & CHATxIP)
-                       pmz_transmit_chars(uap_a);
-               rc = IRQ_HANDLED;
-       }
-       spin_unlock(&uap_a->port.lock);
-       if (tty != NULL)
-               tty_flip_buffer_push(tty);
-
-       if (uap_b->node == NULL)
-               goto out;
-
-       spin_lock(&uap_b->port.lock);
-       tty = NULL;
-       if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-               write_zsreg(uap_b, R0, RES_H_IUS);
-               zssync(uap_b);
-               if (r3 & CHBEXT)
-                       pmz_status_handle(uap_b);
-               if (r3 & CHBRxIP)
-                       tty = pmz_receive_chars(uap_b);
-               if (r3 & CHBTxIP)
-                       pmz_transmit_chars(uap_b);
-               rc = IRQ_HANDLED;
-       }
-       spin_unlock(&uap_b->port.lock);
-       if (tty != NULL)
-               tty_flip_buffer_push(tty);
-
- out:
-#ifdef DEBUG_HARD
-       pmz_debug("irq done.\n");
-#endif
-       return rc;
-}
-
-/*
- * Peek the status register, lock not held by caller
- */
-static inline u8 pmz_peek_status(struct uart_pmac_port *uap)
-{
-       unsigned long flags;
-       u8 status;
-       
-       spin_lock_irqsave(&uap->port.lock, flags);
-       status = read_zsreg(uap, R0);
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       return status;
-}
-
-/* 
- * Check if transmitter is empty
- * The port lock is not held.
- */
-static unsigned int pmz_tx_empty(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return TIOCSER_TEMT;
-
-       status = pmz_peek_status(to_pmz(port));
-       if (status & Tx_BUF_EMP)
-               return TIOCSER_TEMT;
-       return 0;
-}
-
-/* 
- * Set Modem Control (RTS & DTR) bits
- * The port lock is held and interrupts are disabled.
- * Note: Shall we really filter out RTS on external ports or
- * should that be dealt at higher level only ?
- */
-static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char set_bits, clear_bits;
-
-        /* Do nothing for irda for now... */
-       if (ZS_IS_IRDA(uap))
-               return;
-       /* We get called during boot with a port not up yet */
-       if (ZS_IS_ASLEEP(uap) ||
-           !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
-               return;
-
-       set_bits = clear_bits = 0;
-
-       if (ZS_IS_INTMODEM(uap)) {
-               if (mctrl & TIOCM_RTS)
-                       set_bits |= RTS;
-               else
-                       clear_bits |= RTS;
-       }
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */ 
-       uap->curregs[R5] |= set_bits;
-       uap->curregs[R5] &= ~clear_bits;
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
-                 set_bits, clear_bits, uap->curregs[R5]);
-       zssync(uap);
-}
-
-/* 
- * Get Modem Control bits (only the input ones, the core will
- * or that with a cached value of the control ones)
- * The port lock is held and interrupts are disabled.
- */
-static unsigned int pmz_get_mctrl(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-       unsigned int ret;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return 0;
-
-       status = read_zsreg(uap, R0);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC_HUNT)
-               ret |= TIOCM_DSR;
-       if (!(status & CTS))
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* 
- * Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more.
- * The port lock is held and interrupts are disabled.
- */
-static void pmz_stop_tx(struct uart_port *port)
-{
-       to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
-}
-
-/* 
- * Kick the Tx side.
- * The port lock is held and interrupts are disabled.
- */
-static void pmz_start_tx(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char status;
-
-       pmz_debug("pmz: start_tx()\n");
-
-       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
-       uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return;
-
-       status = read_zsreg(uap, R0);
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               write_zsdata(uap, port->x_char);
-               zssync(uap);
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               write_zsdata(uap, xmit->buf[xmit->tail]);
-               zssync(uap);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&uap->port);
-       }
-       pmz_debug("pmz: start_tx() done.\n");
-}
-
-/* 
- * Stop Rx side, basically disable emitting of
- * Rx interrupts on the port. We don't disable the rx
- * side of the chip proper though
- * The port lock is held.
- */
-static void pmz_stop_rx(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-
-       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
-               return;
-
-       pmz_debug("pmz: stop_rx()()\n");
-
-       /* Disable all RX interrupts.  */
-       uap->curregs[R1] &= ~RxINT_MASK;
-       pmz_maybe_update_regs(uap);
-
-       pmz_debug("pmz: stop_rx() done.\n");
-}
-
-/* 
- * Enable modem status change interrupts
- * The port lock is held.
- */
-static void pmz_enable_ms(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char new_reg;
-
-       if (ZS_IS_IRDA(uap) || uap->node == NULL)
-               return;
-       new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != uap->curregs[R15]) {
-               uap->curregs[R15] = new_reg;
-
-               if (ZS_IS_ASLEEP(uap))
-                       return;
-               /* NOTE: Not subject to 'transmitter active' rule. */
-               write_zsreg(uap, R15, uap->curregs[R15]);
-       }
-}
-
-/* 
- * Control break state emission
- * The port lock is not held.
- */
-static void pmz_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       if (uap->node == NULL)
-               return;
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != uap->curregs[R5]) {
-               uap->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule. */
-               if (ZS_IS_ASLEEP(uap)) {
-                       spin_unlock_irqrestore(&port->lock, flags);
-                       return;
-               }
-               write_zsreg(uap, R5, uap->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
-{
-       int delay = 0;
-       int rc;
-
-       if (state) {
-               rc = pmac_call_feature(
-                       PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1);
-               pmz_debug("port power on result: %d\n", rc);
-               if (ZS_IS_INTMODEM(uap)) {
-                       rc = pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1);
-                       delay = 2500;   /* wait for 2.5s before using */
-                       pmz_debug("modem power result: %d\n", rc);
-               }
-       } else {
-               /* TODO: Make that depend on a timer, don't power down
-                * immediately
-                */
-               if (ZS_IS_INTMODEM(uap)) {
-                       rc = pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0);
-                       pmz_debug("port power off result: %d\n", rc);
-               }
-               pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0);
-       }
-       return delay;
-}
-
-#else
-
-static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
-{
-       return 0;
-}
-
-#endif /* !CONFIG_PPC_PMAC */
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Inspired from Darwin code, 15 Sept. 2000  -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- *     The SCC is initialized (hardware or software).
- *     A framing error is detected.
- *     The clocking option changes from synchronous or X1 asynchronous
- *             clocking to X16, X32, or X64 asynchronous clocking.
- *     The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap)
-{
-       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
-       zssync(uap);
-       udelay(10);
-       write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV);
-       zssync(uap);
-
-       write_zsreg(uap, 4, X1CLK | MONSYNC);
-       write_zsreg(uap, 3, Rx8);
-       write_zsreg(uap, 5, Tx8 | RTS);
-       write_zsreg(uap, 9, NV);        /* Didn't we already do this? */
-       write_zsreg(uap, 11, RCBR | TCBR);
-       write_zsreg(uap, 12, 0);
-       write_zsreg(uap, 13, 0);
-       write_zsreg(uap, 14, (LOOPBAK | BRSRC));
-       write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB));
-       write_zsreg(uap, 3, Rx8 | RxENABLE);
-       write_zsreg(uap, 0, RES_EXT_INT);
-       write_zsreg(uap, 0, RES_EXT_INT);
-       write_zsreg(uap, 0, RES_EXT_INT);       /* to kill some time */
-
-       /* The channel should be OK now, but it is probably receiving
-        * loopback garbage.
-        * Switch to asynchronous mode, disable the receiver,
-        * and discard everything in the receive buffer.
-        */
-       write_zsreg(uap, 9, NV);
-       write_zsreg(uap, 4, X16CLK | SB_MASK);
-       write_zsreg(uap, 3, Rx8);
-
-       while (read_zsreg(uap, 0) & Rx_CH_AV) {
-               (void)read_zsreg(uap, 8);
-               write_zsreg(uap, 0, RES_EXT_INT);
-               write_zsreg(uap, 0, ERR_RES);
-       }
-}
-
-/*
- * Real startup routine, powers up the hardware and sets up
- * the SCC. Returns a delay in ms where you need to wait before
- * actually using the port, this is typically the internal modem
- * powerup delay. This routine expect the lock to be taken.
- */
-static int __pmz_startup(struct uart_pmac_port *uap)
-{
-       int pwr_delay = 0;
-
-       memset(&uap->curregs, 0, sizeof(uap->curregs));
-
-       /* Power up the SCC & underlying hardware (modem/irda) */
-       pwr_delay = pmz_set_scc_power(uap, 1);
-
-       /* Nice buggy HW ... */
-       pmz_fix_zero_bug_scc(uap);
-
-       /* Reset the channel */
-       uap->curregs[R9] = 0;
-       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
-       zssync(uap);
-       udelay(10);
-       write_zsreg(uap, 9, 0);
-       zssync(uap);
-
-       /* Clear the interrupt registers */
-       write_zsreg(uap, R1, 0);
-       write_zsreg(uap, R0, ERR_RES);
-       write_zsreg(uap, R0, ERR_RES);
-       write_zsreg(uap, R0, RES_H_IUS);
-       write_zsreg(uap, R0, RES_H_IUS);
-
-       /* Setup some valid baud rate */
-       uap->curregs[R4] = X16CLK | SB1;
-       uap->curregs[R3] = Rx8;
-       uap->curregs[R5] = Tx8 | RTS;
-       if (!ZS_IS_IRDA(uap))
-               uap->curregs[R5] |= DTR;
-       uap->curregs[R12] = 0;
-       uap->curregs[R13] = 0;
-       uap->curregs[R14] = BRENAB;
-
-       /* Clear handshaking, enable BREAK interrupts */
-       uap->curregs[R15] = BRKIE;
-
-       /* Master interrupt enable */
-       uap->curregs[R9] |= NV | MIE;
-
-       pmz_load_zsregs(uap, uap->curregs);
-
-       /* Enable receiver and transmitter.  */
-       write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE);
-       write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE);
-
-       /* Remember status for DCD/CTS changes */
-       uap->prev_status = read_zsreg(uap, R0);
-
-       return pwr_delay;
-}
-
-static void pmz_irda_reset(struct uart_pmac_port *uap)
-{
-       uap->curregs[R5] |= DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(110);
-       uap->curregs[R5] &= ~DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(10);
-}
-
-/*
- * This is the "normal" startup routine, using the above one
- * wrapped with the lock and doing a schedule delay
- */
-static int pmz_startup(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-       int pwr_delay = 0;
-
-       pmz_debug("pmz: startup()\n");
-
-       if (ZS_IS_ASLEEP(uap))
-               return -EAGAIN;
-       if (uap->node == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pmz_irq_mutex);
-
-       uap->flags |= PMACZILOG_FLAG_IS_OPEN;
-
-       /* A console is never powered down. Else, power up and
-        * initialize the chip
-        */
-       if (!ZS_IS_CONS(uap)) {
-               spin_lock_irqsave(&port->lock, flags);
-               pwr_delay = __pmz_startup(uap);
-               spin_unlock_irqrestore(&port->lock, flags);
-       }       
-
-       pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
-       if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
-                       "SCC", uap)) {
-               pmz_error("Unable to register zs interrupt handler.\n");
-               pmz_set_scc_power(uap, 0);
-               mutex_unlock(&pmz_irq_mutex);
-               return -ENXIO;
-       }
-
-       mutex_unlock(&pmz_irq_mutex);
-
-       /* Right now, we deal with delay by blocking here, I'll be
-        * smarter later on
-        */
-       if (pwr_delay != 0) {
-               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
-               msleep(pwr_delay);
-       }
-
-       /* IrDA reset is done now */
-       if (ZS_IS_IRDA(uap))
-               pmz_irda_reset(uap);
-
-       /* Enable interrupts emission from the chip */
-       spin_lock_irqsave(&port->lock, flags);
-       uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-       if (!ZS_IS_EXTCLK(uap))
-               uap->curregs[R1] |= EXT_INT_ENAB;
-       write_zsreg(uap, R1, uap->curregs[R1]);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       pmz_debug("pmz: startup() done.\n");
-
-       return 0;
-}
-
-static void pmz_shutdown(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-
-       pmz_debug("pmz: shutdown()\n");
-
-       if (uap->node == NULL)
-               return;
-
-       mutex_lock(&pmz_irq_mutex);
-
-       /* Release interrupt handler */
-       free_irq(uap->port.irq, uap);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;
-
-       if (!ZS_IS_OPEN(uap->mate))
-               pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
-
-       /* Disable interrupts */
-       if (!ZS_IS_ASLEEP(uap)) {
-               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-               write_zsreg(uap, R1, uap->curregs[R1]);
-               zssync(uap);
-       }
-
-       if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               mutex_unlock(&pmz_irq_mutex);
-               return;
-       }
-
-       /* Disable receiver and transmitter.  */
-       uap->curregs[R3] &= ~RxENABLE;
-       uap->curregs[R5] &= ~TxENABLE;
-
-       /* Disable all interrupts and BRK assertion.  */
-       uap->curregs[R5] &= ~SND_BRK;
-       pmz_maybe_update_regs(uap);
-
-       /* Shut the chip down */
-       pmz_set_scc_power(uap, 0);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       mutex_unlock(&pmz_irq_mutex);
-
-       pmz_debug("pmz: shutdown() done.\n");
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
-                             unsigned int iflag, unsigned long baud)
-{
-       int brg;
-
-       /* Switch to external clocking for IrDA high clock rates. That
-        * code could be re-used for Midi interfaces with different
-        * multipliers
-        */
-       if (baud >= 115200 && ZS_IS_IRDA(uap)) {
-               uap->curregs[R4] = X1CLK;
-               uap->curregs[R11] = RCTRxCP | TCTRxCP;
-               uap->curregs[R14] = 0; /* BRG off */
-               uap->curregs[R12] = 0;
-               uap->curregs[R13] = 0;
-               uap->flags |= PMACZILOG_FLAG_IS_EXTCLK;
-       } else {
-               switch (baud) {
-               case ZS_CLOCK/16:       /* 230400 */
-                       uap->curregs[R4] = X16CLK;
-                       uap->curregs[R11] = 0;
-                       uap->curregs[R14] = 0;
-                       break;
-               case ZS_CLOCK/32:       /* 115200 */
-                       uap->curregs[R4] = X32CLK;
-                       uap->curregs[R11] = 0;
-                       uap->curregs[R14] = 0;
-                       break;
-               default:
-                       uap->curregs[R4] = X16CLK;
-                       uap->curregs[R11] = TCBR | RCBR;
-                       brg = BPS_TO_BRG(baud, ZS_CLOCK / 16);
-                       uap->curregs[R12] = (brg & 255);
-                       uap->curregs[R13] = ((brg >> 8) & 255);
-                       uap->curregs[R14] = BRENAB;
-               }
-               uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK;
-       }
-
-       /* Character size, stop bits, and parity. */
-       uap->curregs[3] &= ~RxN_MASK;
-       uap->curregs[5] &= ~TxN_MASK;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               uap->curregs[3] |= Rx5;
-               uap->curregs[5] |= Tx5;
-               uap->parity_mask = 0x1f;
-               break;
-       case CS6:
-               uap->curregs[3] |= Rx6;
-               uap->curregs[5] |= Tx6;
-               uap->parity_mask = 0x3f;
-               break;
-       case CS7:
-               uap->curregs[3] |= Rx7;
-               uap->curregs[5] |= Tx7;
-               uap->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               uap->curregs[3] |= Rx8;
-               uap->curregs[5] |= Tx8;
-               uap->parity_mask = 0xff;
-               break;
-       };
-       uap->curregs[4] &= ~(SB_MASK);
-       if (cflag & CSTOPB)
-               uap->curregs[4] |= SB2;
-       else
-               uap->curregs[4] |= SB1;
-       if (cflag & PARENB)
-               uap->curregs[4] |= PAR_ENAB;
-       else
-               uap->curregs[4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               uap->curregs[4] |= PAR_EVEN;
-       else
-               uap->curregs[4] &= ~PAR_EVEN;
-
-       uap->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               uap->port.read_status_mask |= BRK_ABRT;
-
-       uap->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               uap->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       uap->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               uap->port.ignore_status_mask = 0xff;
-}
-
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
-{
-       u8 cmdbyte;
-       int t, version;
-
-       switch (*baud) {
-       /* SIR modes */
-       case 2400:
-               cmdbyte = 0x53;
-               break;
-       case 4800:
-               cmdbyte = 0x52;
-               break;
-       case 9600:
-               cmdbyte = 0x51;
-               break;
-       case 19200:
-               cmdbyte = 0x50;
-               break;
-       case 38400:
-               cmdbyte = 0x4f;
-               break;
-       case 57600:
-               cmdbyte = 0x4e;
-               break;
-       case 115200:
-               cmdbyte = 0x4d;
-               break;
-       /* The FIR modes aren't really supported at this point, how
-        * do we select the speed ? via the FCR on KeyLargo ?
-        */
-       case 1152000:
-               cmdbyte = 0;
-               break;
-       case 4000000:
-               cmdbyte = 0;
-               break;
-       default: /* 9600 */
-               cmdbyte = 0x51;
-               *baud = 9600;
-               break;
-       }
-
-       /* Wait for transmitter to drain */
-       t = 10000;
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
-              || (read_zsreg(uap, R1) & ALL_SNT) == 0) {
-               if (--t <= 0) {
-                       pmz_error("transmitter didn't drain\n");
-                       return;
-               }
-               udelay(10);
-       }
-
-       /* Drain the receiver too */
-       t = 100;
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       mdelay(10);
-       while (read_zsreg(uap, R0) & Rx_CH_AV) {
-               read_zsdata(uap);
-               mdelay(10);
-               if (--t <= 0) {
-                       pmz_error("receiver didn't drain\n");
-                       return;
-               }
-       }
-
-       /* Switch to command mode */
-       uap->curregs[R5] |= DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-       mdelay(1);
-
-       /* Switch SCC to 19200 */
-       pmz_convert_to_zs(uap, CS8, 0, 19200);          
-       pmz_load_zsregs(uap, uap->curregs);
-       mdelay(1);
-
-       /* Write get_version command byte */
-       write_zsdata(uap, 1);
-       t = 5000;
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       pmz_error("irda_setup timed out on get_version byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       version = read_zsdata(uap);
-
-       if (version < 4) {
-               pmz_info("IrDA: dongle version %d not supported\n", version);
-               goto out;
-       }
-
-       /* Send speed mode */
-       write_zsdata(uap, cmdbyte);
-       t = 5000;
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
-               if (--t <= 0) {
-                       pmz_error("irda_setup timed out on speed mode byte\n");
-                       goto out;
-               }
-               udelay(10);
-       }
-       t = read_zsdata(uap);
-       if (t != cmdbyte)
-               pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
-
-       pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
-                *baud, version);
-
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-
- out:
-       /* Switch back to data mode */
-       uap->curregs[R5] &= ~DTR;
-       write_zsreg(uap, R5, uap->curregs[R5]);
-       zssync(uap);
-
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-       (void)read_zsdata(uap);
-}
-
-
-static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long baud;
-
-       pmz_debug("pmz: set_termios()\n");
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-
-       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
-
-       /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
-        * on the IR dongle. Note that the IRTTY driver currently doesn't know
-        * about the FIR mode and high speed modes. So these are unused. For
-        * implementing proper support for these, we should probably add some
-        * DMA as well, at least on the Rx side, which isn't a simple thing
-        * at this point.
-        */
-       if (ZS_IS_IRDA(uap)) {
-               /* Calc baud rate */
-               baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);
-               pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);
-               /* Cet the irda codec to the right rate */
-               pmz_irda_setup(uap, &baud);
-               /* Set final baud rate */
-               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
-               pmz_load_zsregs(uap, uap->curregs);
-               zssync(uap);
-       } else {
-               baud = uart_get_baud_rate(port, termios, old, 1200, 230400);
-               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
-               /* Make sure modem status interrupts are correctly configured */
-               if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {
-                       uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
-                       uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;
-               } else {
-                       uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
-                       uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
-               }
-
-               /* Load registers to the chip */
-               pmz_maybe_update_regs(uap);
-       }
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       pmz_debug("pmz: set_termios() done.\n");
-}
-
-/* The port lock is not held.  */
-static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);  
-
-       /* Disable IRQs on the port */
-       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       write_zsreg(uap, R1, uap->curregs[R1]);
-
-       /* Setup new port configuration */
-       __pmz_set_termios(port, termios, old);
-
-       /* Re-enable IRQs on the port */
-       if (ZS_IS_OPEN(uap)) {
-               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-               if (!ZS_IS_EXTCLK(uap))
-                       uap->curregs[R1] |= EXT_INT_ENAB;
-               write_zsreg(uap, R1, uap->curregs[R1]);
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *pmz_type(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = to_pmz(port);
-
-       if (ZS_IS_IRDA(uap))
-               return "Z85c30 ESCC - Infrared port";
-       else if (ZS_IS_INTMODEM(uap))
-               return "Z85c30 ESCC - Internal modem";
-       return "Z85c30 ESCC - Serial port";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void pmz_release_port(struct uart_port *port)
-{
-}
-
-static int pmz_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void pmz_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static int pmz_poll_get_char(struct uart_port *port)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
-               udelay(5);
-       return read_zsdata(uap);
-}
-
-static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       /* Wait for the transmit buffer to empty. */
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(uap, c);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops pmz_pops = {
-       .tx_empty       =       pmz_tx_empty,
-       .set_mctrl      =       pmz_set_mctrl,
-       .get_mctrl      =       pmz_get_mctrl,
-       .stop_tx        =       pmz_stop_tx,
-       .start_tx       =       pmz_start_tx,
-       .stop_rx        =       pmz_stop_rx,
-       .enable_ms      =       pmz_enable_ms,
-       .break_ctl      =       pmz_break_ctl,
-       .startup        =       pmz_startup,
-       .shutdown       =       pmz_shutdown,
-       .set_termios    =       pmz_set_termios,
-       .type           =       pmz_type,
-       .release_port   =       pmz_release_port,
-       .request_port   =       pmz_request_port,
-       .config_port    =       pmz_config_port,
-       .verify_port    =       pmz_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  =       pmz_poll_get_char,
-       .poll_put_char  =       pmz_poll_put_char,
-#endif
-};
-
-#ifdef CONFIG_PPC_PMAC
-
-/*
- * Setup one port structure after probing, HW is down at this point,
- * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
- * register our console before uart_add_one_port() is called
- */
-static int __init pmz_init_port(struct uart_pmac_port *uap)
-{
-       struct device_node *np = uap->node;
-       const char *conn;
-       const struct slot_names_prop {
-               int     count;
-               char    name[1];
-       } *slots;
-       int len;
-       struct resource r_ports, r_rxdma, r_txdma;
-
-       /*
-        * Request & map chip registers
-        */
-       if (of_address_to_resource(np, 0, &r_ports))
-               return -ENODEV;
-       uap->port.mapbase = r_ports.start;
-       uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
-
-       uap->control_reg = uap->port.membase;
-       uap->data_reg = uap->control_reg + 0x10;
-       
-       /*
-        * Request & map DBDMA registers
-        */
-#ifdef HAS_DBDMA
-       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
-           of_address_to_resource(np, 2, &r_rxdma) == 0)
-               uap->flags |= PMACZILOG_FLAG_HAS_DMA;
-#else
-       memset(&r_txdma, 0, sizeof(struct resource));
-       memset(&r_rxdma, 0, sizeof(struct resource));
-#endif 
-       if (ZS_HAS_DMA(uap)) {
-               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
-               if (uap->tx_dma_regs == NULL) { 
-                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
-                       goto no_dma;
-               }
-               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
-               if (uap->rx_dma_regs == NULL) { 
-                       iounmap(uap->tx_dma_regs);
-                       uap->tx_dma_regs = NULL;
-                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
-                       goto no_dma;
-               }
-               uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
-               uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
-       }
-no_dma:
-
-       /*
-        * Detect port type
-        */
-       if (of_device_is_compatible(np, "cobalt"))
-               uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-       conn = of_get_property(np, "AAPL,connector", &len);
-       if (conn && (strcmp(conn, "infrared") == 0))
-               uap->flags |= PMACZILOG_FLAG_IS_IRDA;
-       uap->port_type = PMAC_SCC_ASYNC;
-       /* 1999 Powerbook G3 has slot-names property instead */
-       slots = of_get_property(np, "slot-names", &len);
-       if (slots && slots->count > 0) {
-               if (strcmp(slots->name, "IrDA") == 0)
-                       uap->flags |= PMACZILOG_FLAG_IS_IRDA;
-               else if (strcmp(slots->name, "Modem") == 0)
-                       uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-       }
-       if (ZS_IS_IRDA(uap))
-               uap->port_type = PMAC_SCC_IRDA;
-       if (ZS_IS_INTMODEM(uap)) {
-               struct device_node* i2c_modem =
-                       of_find_node_by_name(NULL, "i2c-modem");
-               if (i2c_modem) {
-                       const char* mid =
-                               of_get_property(i2c_modem, "modem-id", NULL);
-                       if (mid) switch(*mid) {
-                       case 0x04 :
-                       case 0x05 :
-                       case 0x07 :
-                       case 0x08 :
-                       case 0x0b :
-                       case 0x0c :
-                               uap->port_type = PMAC_SCC_I2S1;
-                       }
-                       printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
-                               mid ? (*mid) : 0);
-                       of_node_put(i2c_modem);
-               } else {
-                       printk(KERN_INFO "pmac_zilog: serial modem detected\n");
-               }
-       }
-
-       /*
-        * Init remaining bits of "port" structure
-        */
-       uap->port.iotype = UPIO_MEM;
-       uap->port.irq = irq_of_parse_and_map(np, 0);
-       uap->port.uartclk = ZS_CLOCK;
-       uap->port.fifosize = 1;
-       uap->port.ops = &pmz_pops;
-       uap->port.type = PORT_PMAC_ZILOG;
-       uap->port.flags = 0;
-
-       /*
-        * Fixup for the port on Gatwick for which the device-tree has
-        * missing interrupts. Normally, the macio_dev would contain
-        * fixed up interrupt info, but we use the device-tree directly
-        * here due to early probing so we need the fixup too.
-        */
-       if (uap->port.irq == NO_IRQ &&
-           np->parent && np->parent->parent &&
-           of_device_is_compatible(np->parent->parent, "gatwick")) {
-               /* IRQs on gatwick are offset by 64 */
-               uap->port.irq = irq_create_mapping(NULL, 64 + 15);
-               uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
-               uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
-       }
-
-       /* Setup some valid baud rate information in the register
-        * shadows so we don't write crap there before baud rate is
-        * first initialized.
-        */
-       pmz_convert_to_zs(uap, CS8, 0, 9600);
-
-       return 0;
-}
-
-/*
- * Get rid of a port on module removal
- */
-static void pmz_dispose_port(struct uart_pmac_port *uap)
-{
-       struct device_node *np;
-
-       np = uap->node;
-       iounmap(uap->rx_dma_regs);
-       iounmap(uap->tx_dma_regs);
-       iounmap(uap->control_reg);
-       uap->node = NULL;
-       of_node_put(np);
-       memset(uap, 0, sizeof(struct uart_pmac_port));
-}
-
-/*
- * Called upon match with an escc node in the device-tree.
- */
-static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
-{
-       int i;
-       
-       /* Iterate the pmz_ports array to find a matching entry
-        */
-       for (i = 0; i < MAX_ZS_PORTS; i++)
-               if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
-                       struct uart_pmac_port *uap = &pmz_ports[i];
-
-                       uap->dev = mdev;
-                       dev_set_drvdata(&mdev->ofdev.dev, uap);
-                       if (macio_request_resources(uap->dev, "pmac_zilog"))
-                               printk(KERN_WARNING "%s: Failed to request resource"
-                                      ", port still active\n",
-                                      uap->node->name);
-                       else
-                               uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;                            
-                       return 0;
-               }
-       return -ENODEV;
-}
-
-/*
- * That one should not be called, macio isn't really a hotswap device,
- * we don't expect one of those serial ports to go away...
- */
-static int pmz_detach(struct macio_dev *mdev)
-{
-       struct uart_pmac_port   *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       
-       if (!uap)
-               return -ENODEV;
-
-       if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
-               macio_release_resources(uap->dev);
-               uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;
-       }
-       dev_set_drvdata(&mdev->ofdev.dev, NULL);
-       uap->dev = NULL;
-       
-       return 0;
-}
-
-
-static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
-{
-       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       struct uart_state *state;
-       unsigned long flags;
-
-       if (uap == NULL) {
-               printk("HRM... pmz_suspend with NULL uap\n");
-               return 0;
-       }
-
-       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
-               return 0;
-
-       pmz_debug("suspend, switching to state %d\n", pm_state.event);
-
-       state = pmz_uart_reg.state + uap->port.line;
-
-       mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->port.mutex);
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
-               /* Disable receiver and transmitter.  */
-               uap->curregs[R3] &= ~RxENABLE;
-               uap->curregs[R5] &= ~TxENABLE;
-
-               /* Disable all interrupts and BRK assertion.  */
-               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-               uap->curregs[R5] &= ~SND_BRK;
-               pmz_load_zsregs(uap, uap->curregs);
-               uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
-               mb();
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))
-               if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
-                       pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
-                       disable_irq(uap->port.irq);
-               }
-
-       if (ZS_IS_CONS(uap))
-               uap->port.cons->flags &= ~CON_ENABLED;
-
-       /* Shut the chip down */
-       pmz_set_scc_power(uap, 0);
-
-       mutex_unlock(&state->port.mutex);
-       mutex_unlock(&pmz_irq_mutex);
-
-       pmz_debug("suspend, switching complete\n");
-
-       mdev->ofdev.dev.power.power_state = pm_state;
-
-       return 0;
-}
-
-
-static int pmz_resume(struct macio_dev *mdev)
-{
-       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-       struct uart_state *state;
-       unsigned long flags;
-       int pwr_delay = 0;
-
-       if (uap == NULL)
-               return 0;
-
-       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
-               return 0;
-       
-       pmz_debug("resume, switching to state 0\n");
-
-       state = pmz_uart_reg.state + uap->port.line;
-
-       mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->port.mutex);
-
-       spin_lock_irqsave(&uap->port.lock, flags);
-       if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
-               spin_unlock_irqrestore(&uap->port.lock, flags);
-               goto bail;
-       }
-       pwr_delay = __pmz_startup(uap);
-
-       /* Take care of config that may have changed while asleep */
-       __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
-
-       if (ZS_IS_OPEN(uap)) {
-               /* Enable interrupts */         
-               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-               if (!ZS_IS_EXTCLK(uap))
-                       uap->curregs[R1] |= EXT_INT_ENAB;
-               write_zsreg(uap, R1, uap->curregs[R1]);
-       }
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-
-       if (ZS_IS_CONS(uap))
-               uap->port.cons->flags |= CON_ENABLED;
-
-       /* Re-enable IRQ on the controller */
-       if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
-               pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
-               enable_irq(uap->port.irq);
-       }
-
- bail:
-       mutex_unlock(&state->port.mutex);
-       mutex_unlock(&pmz_irq_mutex);
-
-       /* Right now, we deal with delay by blocking here, I'll be
-        * smarter later on
-        */
-       if (pwr_delay != 0) {
-               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
-               msleep(pwr_delay);
-       }
-
-       pmz_debug("resume, switching complete\n");
-
-       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
-
-       return 0;
-}
-
-/*
- * Probe all ports in the system and build the ports array, we register
- * with the serial layer at this point, the macio-type probing is only
- * used later to "attach" to the sysfs tree so we get power management
- * events
- */
-static int __init pmz_probe(void)
-{
-       struct device_node      *node_p, *node_a, *node_b, *np;
-       int                     count = 0;
-       int                     rc;
-
-       /*
-        * Find all escc chips in the system
-        */
-       node_p = of_find_node_by_name(NULL, "escc");
-       while (node_p) {
-               /*
-                * First get channel A/B node pointers
-                * 
-                * TODO: Add routines with proper locking to do that...
-                */
-               node_a = node_b = NULL;
-               for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
-                       if (strncmp(np->name, "ch-a", 4) == 0)
-                               node_a = of_node_get(np);
-                       else if (strncmp(np->name, "ch-b", 4) == 0)
-                               node_b = of_node_get(np);
-               }
-               if (!node_a && !node_b) {
-                       of_node_put(node_a);
-                       of_node_put(node_b);
-                       printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",
-                               (!node_a) ? 'a' : 'b', node_p->full_name);
-                       goto next;
-               }
-
-               /*
-                * Fill basic fields in the port structures
-                */
-               pmz_ports[count].mate           = &pmz_ports[count+1];
-               pmz_ports[count+1].mate         = &pmz_ports[count];
-               pmz_ports[count].flags          = PMACZILOG_FLAG_IS_CHANNEL_A;
-               pmz_ports[count].node           = node_a;
-               pmz_ports[count+1].node         = node_b;
-               pmz_ports[count].port.line      = count;
-               pmz_ports[count+1].port.line    = count+1;
-
-               /*
-                * Setup the ports for real
-                */
-               rc = pmz_init_port(&pmz_ports[count]);
-               if (rc == 0 && node_b != NULL)
-                       rc = pmz_init_port(&pmz_ports[count+1]);
-               if (rc != 0) {
-                       of_node_put(node_a);
-                       of_node_put(node_b);
-                       memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));
-                       memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));
-                       goto next;
-               }
-               count += 2;
-next:
-               node_p = of_find_node_by_name(node_p, "escc");
-       }
-       pmz_ports_count = count;
-
-       return 0;
-}
-
-#else
-
-extern struct platform_device scc_a_pdev, scc_b_pdev;
-
-static int __init pmz_init_port(struct uart_pmac_port *uap)
-{
-       struct resource *r_ports;
-       int irq;
-
-       r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(uap->node, 0);
-       if (!r_ports || !irq)
-               return -ENODEV;
-
-       uap->port.mapbase  = r_ports->start;
-       uap->port.membase  = (unsigned char __iomem *) r_ports->start;
-       uap->port.iotype   = UPIO_MEM;
-       uap->port.irq      = irq;
-       uap->port.uartclk  = ZS_CLOCK;
-       uap->port.fifosize = 1;
-       uap->port.ops      = &pmz_pops;
-       uap->port.type     = PORT_PMAC_ZILOG;
-       uap->port.flags    = 0;
-
-       uap->control_reg   = uap->port.membase;
-       uap->data_reg      = uap->control_reg + 4;
-       uap->port_type     = 0;
-
-       pmz_convert_to_zs(uap, CS8, 0, 9600);
-
-       return 0;
-}
-
-static int __init pmz_probe(void)
-{
-       int err;
-
-       pmz_ports_count = 0;
-
-       pmz_ports[0].mate      = &pmz_ports[1];
-       pmz_ports[0].port.line = 0;
-       pmz_ports[0].flags     = PMACZILOG_FLAG_IS_CHANNEL_A;
-       pmz_ports[0].node      = &scc_a_pdev;
-       err = pmz_init_port(&pmz_ports[0]);
-       if (err)
-               return err;
-       pmz_ports_count++;
-
-       pmz_ports[1].mate      = &pmz_ports[0];
-       pmz_ports[1].port.line = 1;
-       pmz_ports[1].flags     = 0;
-       pmz_ports[1].node      = &scc_b_pdev;
-       err = pmz_init_port(&pmz_ports[1]);
-       if (err)
-               return err;
-       pmz_ports_count++;
-
-       return 0;
-}
-
-static void pmz_dispose_port(struct uart_pmac_port *uap)
-{
-       memset(uap, 0, sizeof(struct uart_pmac_port));
-}
-
-static int __init pmz_attach(struct platform_device *pdev)
-{
-       int i;
-
-       for (i = 0; i < pmz_ports_count; i++)
-               if (pmz_ports[i].node == pdev)
-                       return 0;
-       return -ENODEV;
-}
-
-static int __exit pmz_detach(struct platform_device *pdev)
-{
-       return 0;
-}
-
-#endif /* !CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-
-static void pmz_console_write(struct console *con, const char *s, unsigned int count);
-static int __init pmz_console_setup(struct console *co, char *options);
-
-static struct console pmz_console = {
-       .name   =       PMACZILOG_NAME,
-       .write  =       pmz_console_write,
-       .device =       uart_console_device,
-       .setup  =       pmz_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &pmz_uart_reg,
-};
-
-#define PMACZILOG_CONSOLE      &pmz_console
-#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-#define PMACZILOG_CONSOLE      (NULL)
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-
-/*
- * Register the driver, console driver and ports with the serial
- * core
- */
-static int __init pmz_register(void)
-{
-       int i, rc;
-       
-       pmz_uart_reg.nr = pmz_ports_count;
-       pmz_uart_reg.cons = PMACZILOG_CONSOLE;
-
-       /*
-        * Register this driver with the serial core
-        */
-       rc = uart_register_driver(&pmz_uart_reg);
-       if (rc)
-               return rc;
-
-       /*
-        * Register each port with the serial core
-        */
-       for (i = 0; i < pmz_ports_count; i++) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               /* NULL node may happen on wallstreet */
-               if (uport->node != NULL)
-                       rc = uart_add_one_port(&pmz_uart_reg, &uport->port);
-               if (rc)
-                       goto err_out;
-       }
-
-       return 0;
-err_out:
-       while (i-- > 0) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               uart_remove_one_port(&pmz_uart_reg, &uport->port);
-       }
-       uart_unregister_driver(&pmz_uart_reg);
-       return rc;
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-static struct of_device_id pmz_match[] = 
-{
-       {
-       .name           = "ch-a",
-       },
-       {
-       .name           = "ch-b",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE (of, pmz_match);
-
-static struct macio_driver pmz_driver = {
-       .driver = {
-               .name           = "pmac_zilog",
-               .owner          = THIS_MODULE,
-               .of_match_table = pmz_match,
-       },
-       .probe          = pmz_attach,
-       .remove         = pmz_detach,
-       .suspend        = pmz_suspend,
-       .resume         = pmz_resume,
-};
-
-#else
-
-static struct platform_driver pmz_driver = {
-       .remove         = __exit_p(pmz_detach),
-       .driver         = {
-               .name           = "scc",
-               .owner          = THIS_MODULE,
-       },
-};
-
-#endif /* !CONFIG_PPC_PMAC */
-
-static int __init init_pmz(void)
-{
-       int rc, i;
-       printk(KERN_INFO "%s\n", version);
-
-       /* 
-        * First, we need to do a direct OF-based probe pass. We
-        * do that because we want serial console up before the
-        * macio stuffs calls us back, and since that makes it
-        * easier to pass the proper number of channels to
-        * uart_register_driver()
-        */
-       if (pmz_ports_count == 0)
-               pmz_probe();
-
-       /*
-        * Bail early if no port found
-        */
-       if (pmz_ports_count == 0)
-               return -ENODEV;
-
-       /*
-        * Now we register with the serial layer
-        */
-       rc = pmz_register();
-       if (rc) {
-               printk(KERN_ERR 
-                       "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n"
-                       "pmac_zilog: Did another serial driver already claim the minors?\n"); 
-               /* effectively "pmz_unprobe()" */
-               for (i=0; i < pmz_ports_count; i++)
-                       pmz_dispose_port(&pmz_ports[i]);
-               return rc;
-       }
-
-       /*
-        * Then we register the macio driver itself
-        */
-#ifdef CONFIG_PPC_PMAC
-       return macio_register_driver(&pmz_driver);
-#else
-       return platform_driver_probe(&pmz_driver, pmz_attach);
-#endif
-}
-
-static void __exit exit_pmz(void)
-{
-       int i;
-
-#ifdef CONFIG_PPC_PMAC
-       /* Get rid of macio-driver (detach from macio) */
-       macio_unregister_driver(&pmz_driver);
-#else
-       platform_driver_unregister(&pmz_driver);
-#endif
-
-       for (i = 0; i < pmz_ports_count; i++) {
-               struct uart_pmac_port *uport = &pmz_ports[i];
-               if (uport->node != NULL) {
-                       uart_remove_one_port(&pmz_uart_reg, &uport->port);
-                       pmz_dispose_port(uport);
-               }
-       }
-       /* Unregister UART driver */
-       uart_unregister_driver(&pmz_uart_reg);
-}
-
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-
-static void pmz_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
-
-       /* Wait for the transmit buffer to empty. */
-       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(uap, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void pmz_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_pmac_port *uap = &pmz_ports[con->index];
-       unsigned long flags;
-
-       if (ZS_IS_ASLEEP(uap))
-               return;
-       spin_lock_irqsave(&uap->port.lock, flags);
-
-       /* Turn of interrupts and enable the transmitter. */
-       write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
-       write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
-
-       uart_console_write(&uap->port, s, count, pmz_console_putchar);
-
-       /* Restore the values in the registers. */
-       write_zsreg(uap, R1, uap->curregs[1]);
-       /* Don't disable the transmitter. */
-
-       spin_unlock_irqrestore(&uap->port.lock, flags);
-}
-
-/*
- * Setup the serial console
- */
-static int __init pmz_console_setup(struct console *co, char *options)
-{
-       struct uart_pmac_port *uap;
-       struct uart_port *port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       unsigned long pwr_delay;
-
-       /*
-        * XServe's default to 57600 bps
-        */
-       if (of_machine_is_compatible("RackMac1,1")
-           || of_machine_is_compatible("RackMac1,2")
-           || of_machine_is_compatible("MacRISC4"))
-               baud = 57600;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= pmz_ports_count)
-               co->index = 0;
-       uap = &pmz_ports[co->index];
-       if (uap->node == NULL)
-               return -ENODEV;
-       port = &uap->port;
-
-       /*
-        * Mark port as beeing a console
-        */
-       uap->flags |= PMACZILOG_FLAG_IS_CONS;
-
-       /*
-        * Temporary fix for uart layer who didn't setup the spinlock yet
-        */
-       spin_lock_init(&port->lock);
-
-       /*
-        * Enable the hardware
-        */
-       pwr_delay = __pmz_startup(uap);
-       if (pwr_delay)
-               mdelay(pwr_delay);
-       
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static int __init pmz_console_init(void)
-{
-       /* Probe ports */
-       pmz_probe();
-
-       /* TODO: Autoprobe console based on OF */
-       /* pmz_console.index = i; */
-       register_console(&pmz_console);
-
-       return 0;
-
-}
-console_initcall(pmz_console_init);
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-
-module_init(init_pmz);
-module_exit(exit_pmz);
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
deleted file mode 100644 (file)
index cbc34fb..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-#ifndef __PMAC_ZILOG_H__
-#define __PMAC_ZILOG_H__
-
-#ifdef CONFIG_PPC_PMAC
-#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
-#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
-#define pmz_info(fmt, arg...)  dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
-#else
-#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
-#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
-#define pmz_info(fmt, arg...)  dev_info(&uap->node->dev, fmt, ## arg)
-#endif
-
-/*
- * At most 2 ESCCs with 2 ports each
- */
-#define MAX_ZS_PORTS   4
-
-/* 
- * We wrap our port structure around the generic uart_port.
- */
-#define NUM_ZSREGS    17
-
-struct uart_pmac_port {
-       struct uart_port                port;
-       struct uart_pmac_port           *mate;
-
-#ifdef CONFIG_PPC_PMAC
-       /* macio_dev for the escc holding this port (maybe be null on
-        * early inited port)
-        */
-       struct macio_dev                *dev;
-       /* device node to this port, this points to one of 2 childs
-        * of "escc" node (ie. ch-a or ch-b)
-        */
-       struct device_node              *node;
-#else
-       struct platform_device          *node;
-#endif
-
-       /* Port type as obtained from device tree (IRDA, modem, ...) */
-       int                             port_type;
-       u8                              curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define PMACZILOG_FLAG_IS_CONS         0x00000001
-#define PMACZILOG_FLAG_IS_KGDB         0x00000002
-#define PMACZILOG_FLAG_MODEM_STATUS    0x00000004
-#define PMACZILOG_FLAG_IS_CHANNEL_A    0x00000008
-#define PMACZILOG_FLAG_REGS_HELD       0x00000010
-#define PMACZILOG_FLAG_TX_STOPPED      0x00000020
-#define PMACZILOG_FLAG_TX_ACTIVE       0x00000040
-#define PMACZILOG_FLAG_ENABLED          0x00000080
-#define PMACZILOG_FLAG_IS_IRDA         0x00000100
-#define PMACZILOG_FLAG_IS_INTMODEM     0x00000200
-#define PMACZILOG_FLAG_HAS_DMA         0x00000400
-#define PMACZILOG_FLAG_RSRC_REQUESTED  0x00000800
-#define PMACZILOG_FLAG_IS_ASLEEP       0x00001000
-#define PMACZILOG_FLAG_IS_OPEN         0x00002000
-#define PMACZILOG_FLAG_IS_IRQ_ON       0x00004000
-#define PMACZILOG_FLAG_IS_EXTCLK       0x00008000
-#define PMACZILOG_FLAG_BREAK           0x00010000
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-
-       volatile u8                     __iomem *control_reg;
-       volatile u8                     __iomem *data_reg;
-
-#ifdef CONFIG_PPC_PMAC
-       unsigned int                    tx_dma_irq;
-       unsigned int                    rx_dma_irq;
-       volatile struct dbdma_regs      __iomem *tx_dma_regs;
-       volatile struct dbdma_regs      __iomem *rx_dma_regs;
-#endif
-
-       struct ktermios                 termios_cache;
-};
-
-#define to_pmz(p) ((struct uart_pmac_port *)(p))
-
-static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
-{
-       if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
-               return uap;
-       return uap->mate;
-}
-
-/*
- * Register accessors. Note that we don't need to enforce a recovery
- * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
- * though if we try to use this driver on older machines, we might have
- * to add it back
- */
-static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg)
-{
-       if (reg != 0)
-               writeb(reg, port->control_reg);
-       return readb(port->control_reg);
-}
-
-static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value)
-{
-       if (reg != 0)
-               writeb(reg, port->control_reg);
-       writeb(value, port->control_reg);
-}
-
-static inline u8 read_zsdata(struct uart_pmac_port *port)
-{
-       return readb(port->data_reg);
-}
-
-static inline void write_zsdata(struct uart_pmac_port *port, u8 data)
-{
-       writeb(data, port->data_reg);
-}
-
-static inline void zssync(struct uart_pmac_port *port)
-{
-       (void)readb(port->control_reg);
-}
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-#define        R7P     16
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
-#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
-#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENABLE        0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENABLE        0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (Some enhanced feature control) */
-#define        ENEXREAD        0x40    /* Enable read of some write registers */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
-#define        ZCIE    2       /* Zero count IE */
-#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC_HUNT       0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define        CHB_Tx_EMPTY    0x00
-#define        CHB_EXT_STAT    0x02
-#define        CHB_Rx_AVAIL    0x04
-#define        CHB_SPECIAL     0x06
-#define        CHA_Tx_EMPTY    0x08
-#define        CHA_EXT_STAT    0x0a
-#define        CHA_Rx_AVAIL    0x0c
-#define        CHA_SPECIAL     0x0e
-#define        STATUS_MASK     0x06
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(port)    (write_zsreg(port, 0, ERR_RES))
-#define ZS_CLEARFIFO(port)   do { volatile unsigned char garbage; \
-                                    garbage = read_zsdata(port); \
-                                    garbage = read_zsdata(port); \
-                                    garbage = read_zsdata(port); \
-                               } while(0)
-
-#define ZS_IS_CONS(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_KGDB)
-#define ZS_IS_CHANNEL_A(UP)            ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)               ((UP)->flags & PMACZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)              ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)               ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_IRDA(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
-#define ZS_IS_INTMODEM(UP)             ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
-#define ZS_HAS_DMA(UP)                 ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
-#define ZS_IS_ASLEEP(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
-#define ZS_IS_OPEN(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
-#define ZS_IS_IRQ_ON(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
-#define ZS_IS_EXTCLK(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
-
-#endif /* __PMAC_ZILOG_H__ */
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c
deleted file mode 100644 (file)
index 0aa75a9..0000000
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * UART driver for PNX8XXX SoCs
- *
- * Author: Per Hallsmark per.hallsmark@mvista.com
- * Ported to 2.6 kernel by EmbeddedAlley
- * Reworked by Vitaly Wool <vitalywool@gmail.com>
- *
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- * Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of
- * any kind, whether express or implied.
- *
- */
-
-#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_pnx8xxx.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/* We'll be using StrongARM sa1100 serial port major/minor */
-#define SERIAL_PNX8XXX_MAJOR   204
-#define MINOR_START            5
-
-#define NR_PORTS               2
-
-#define PNX8XXX_ISR_PASS_LIMIT 256
-
-/*
- * Convert from ignore_status_mask or read_status_mask to FIFO
- * and interrupt status bits
- */
-#define SM_TO_FIFO(x)  ((x) >> 10)
-#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
-#define FIFO_TO_SM(x)  ((x) << 10)
-#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
-
-/*
- * This is the size of our serial port register set.
- */
-#define UART_PORT_SIZE 0x1000
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-extern struct pnx8xxx_port pnx8xxx_ports[];
-
-static inline int serial_in(struct pnx8xxx_port *sport, int offset)
-{
-       return (__raw_readl(sport->port.membase + offset));
-}
-
-static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
-{
-       __raw_writel(value, sport->port.membase + offset);
-}
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void pnx8xxx_timeout(unsigned long data)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               pnx8xxx_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void pnx8xxx_stop_tx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Disable TX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
-
-       /* Clear all pending TX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
-}
-
-/*
- * interrupts may not be disabled on entry
- */
-static void pnx8xxx_start_tx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Clear all pending TX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
-
-       /* Enable TX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
-}
-
-/*
- * Interrupts enabled
- */
-static void pnx8xxx_stop_rx(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       u32 ien;
-
-       /* Disable RX intr */
-       ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
-
-       /* Clear all pending RX intr */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void pnx8xxx_enable_ms(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
-{
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
-                ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
-       while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
-               ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
-
-               sport->port.icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
-                                       PNX8XXX_UART_FIFO_RXPAR |
-                                       PNX8XXX_UART_FIFO_RXBRK) |
-                             ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
-                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
-                               status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
-                               sport->port.icount.brk++;
-                               if (uart_handle_break(&sport->port))
-                                       goto ignore_char;
-                       } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
-                               sport->port.icount.parity++;
-                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
-                               sport->port.icount.frame++;
-                       if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
-                               sport->port.icount.overrun++;
-
-                       status &= sport->port.read_status_mask;
-
-                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
-                               flg = TTY_PARITY;
-                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&sport->port, status,
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
-
-       ignore_char:
-               serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
-                               PNX8XXX_UART_LCR_RX_NEXT);
-               status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
-                        ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
-       }
-       tty_flip_buffer_push(tty);
-}
-
-static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       if (sport->port.x_char) {
-               serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       pnx8xxx_mctrl_check(sport);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               pnx8xxx_stop_tx(&sport->port);
-               return;
-       }
-
-       /*
-        * TX while bytes available
-        */
-       while (((serial_in(sport, PNX8XXX_FIFO) &
-                                       PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
-               serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               pnx8xxx_stop_tx(&sport->port);
-}
-
-static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
-{
-       struct pnx8xxx_port *sport = dev_id;
-       unsigned int status;
-
-       spin_lock(&sport->port.lock);
-       /* Get the interrupts */
-       status  = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
-
-       /* Byte or break signal received */
-       if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
-               pnx8xxx_rx_chars(sport);
-
-       /* TX holding register empty - transmit a byte */
-       if (status & PNX8XXX_UART_INT_TX)
-               pnx8xxx_tx_chars(sport);
-
-       /* Clear the ISTAT register */
-       serial_out(sport, PNX8XXX_ICLR, status);
-
-       spin_unlock(&sport->port.lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned int mctrl = TIOCM_DSR;
-       unsigned int msr;
-
-       /* REVISIT */
-
-       msr = serial_in(sport, PNX8XXX_MCR);
-
-       mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
-       mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
-
-       return mctrl;
-}
-
-static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-#if    0       /* FIXME */
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned int msr;
-#endif
-}
-
-/*
- * Interrupts always disabled.
- */
-static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned long flags;
-       unsigned int lcr;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-       lcr = serial_in(sport, PNX8XXX_LCR);
-       if (break_state == -1)
-               lcr |= PNX8XXX_UART_LCR_TXBREAK;
-       else
-               lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
-       serial_out(sport, PNX8XXX_LCR, lcr);
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static int pnx8xxx_startup(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
-                            "pnx8xxx-uart", sport);
-       if (retval)
-               return retval;
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
-                            PNX8XXX_UART_INT_ALLTX);
-
-       serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
-                           PNX8XXX_UART_INT_ALLRX |
-                           PNX8XXX_UART_INT_ALLTX);
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irq(&sport->port.lock);
-       pnx8xxx_enable_ms(&sport->port);
-       spin_unlock_irq(&sport->port.lock);
-
-       return 0;
-}
-
-static void pnx8xxx_shutdown(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int lcr;
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Disable all interrupts
-        */
-       serial_out(sport, PNX8XXX_IEN, 0);
-
-       /*
-        * Reset the Tx and Rx FIFOS, disable the break condition
-        */
-       lcr = serial_in(sport, PNX8XXX_LCR);
-       lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
-       lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
-       serial_out(sport, PNX8XXX_LCR, lcr);
-
-       /*
-        * Clear all interrupts
-        */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
-                            PNX8XXX_UART_INT_ALLTX);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(sport->port.irq, sport);
-}
-
-static void
-pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       unsigned long flags;
-       unsigned int lcr_fcr, old_ien, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               lcr_fcr = PNX8XXX_UART_LCR_8BIT;
-       else
-               lcr_fcr = 0;
-
-       if (termios->c_cflag & CSTOPB)
-               lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
-       if (termios->c_cflag & PARENB) {
-               lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
-               if (!(termios->c_cflag & PARODD))
-                       lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |=
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |=
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
-                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |=
-                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               sport->port.ignore_status_mask |=
-                       ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
-                                       PNX8XXX_UART_INT_ALLRX));
-
-       while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
-               barrier();
-
-       /* then, disable everything */
-       serial_out(sport, PNX8XXX_IEN, 0);
-
-       /* Reset the Rx and Tx FIFOs too */
-       lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
-       lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
-
-       /* set the parity, stop bits and data size */
-       serial_out(sport, PNX8XXX_LCR, lcr_fcr);
-
-       /* set the baud rate */
-       quot -= 1;
-       serial_out(sport, PNX8XXX_BAUD, quot);
-
-       serial_out(sport, PNX8XXX_ICLR, -1);
-
-       serial_out(sport, PNX8XXX_IEN, old_ien);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               pnx8xxx_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *pnx8xxx_type(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void pnx8xxx_release_port(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int pnx8xxx_request_port(struct uart_port *port)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
-                       "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void pnx8xxx_config_port(struct uart_port *port, int flags)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           pnx8xxx_request_port(&sport->port) == 0)
-               sport->port.type = PORT_PNX8XXX;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_PNX8XXX and PORT_UNKNOWN
- */
-static int
-pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops pnx8xxx_pops = {
-       .tx_empty       = pnx8xxx_tx_empty,
-       .set_mctrl      = pnx8xxx_set_mctrl,
-       .get_mctrl      = pnx8xxx_get_mctrl,
-       .stop_tx        = pnx8xxx_stop_tx,
-       .start_tx       = pnx8xxx_start_tx,
-       .stop_rx        = pnx8xxx_stop_rx,
-       .enable_ms      = pnx8xxx_enable_ms,
-       .break_ctl      = pnx8xxx_break_ctl,
-       .startup        = pnx8xxx_startup,
-       .shutdown       = pnx8xxx_shutdown,
-       .set_termios    = pnx8xxx_set_termios,
-       .type           = pnx8xxx_type,
-       .release_port   = pnx8xxx_release_port,
-       .request_port   = pnx8xxx_request_port,
-       .config_port    = pnx8xxx_config_port,
-       .verify_port    = pnx8xxx_verify_port,
-};
-
-
-/*
- * Setup the PNX8XXX serial ports.
- *
- * Note also that we support "console=ttySx" where "x" is either 0 or 1.
- */
-static void __init pnx8xxx_init_ports(void)
-{
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < NR_PORTS; i++) {
-               init_timer(&pnx8xxx_ports[i].timer);
-               pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
-               pnx8xxx_ports[i].timer.data     = (unsigned long)&pnx8xxx_ports[i];
-               pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
-       }
-}
-
-#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
-
-static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
-{
-       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
-       int status;
-
-       do {
-               /* Wait for UART_TX register to empty */
-               status = serial_in(sport, PNX8XXX_FIFO);
-       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
-       serial_out(sport, PNX8XXX_FIFO, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */static void
-pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
-       unsigned int old_ien, status;
-
-       /*
-        *      First, save IEN and then disable interrupts
-        */
-       old_ien = serial_in(sport, PNX8XXX_IEN);
-       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
-                                       PNX8XXX_UART_INT_ALLRX));
-
-       uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore IEN
-        */
-       do {
-               /* Wait for UART_TX register to empty */
-               status = serial_in(sport, PNX8XXX_FIFO);
-       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
-
-       /* Clear TX and EMPTY interrupt */
-       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
-                            PNX8XXX_UART_INT_EMPTY);
-
-       serial_out(sport, PNX8XXX_IEN, old_ien);
-}
-
-static int __init
-pnx8xxx_console_setup(struct console *co, char *options)
-{
-       struct pnx8xxx_port *sport;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index == -1 || co->index >= NR_PORTS)
-               co->index = 0;
-       sport = &pnx8xxx_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver pnx8xxx_reg;
-static struct console pnx8xxx_console = {
-       .name           = "ttyS",
-       .write          = pnx8xxx_console_write,
-       .device         = uart_console_device,
-       .setup          = pnx8xxx_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &pnx8xxx_reg,
-};
-
-static int __init pnx8xxx_rs_console_init(void)
-{
-       pnx8xxx_init_ports();
-       register_console(&pnx8xxx_console);
-       return 0;
-}
-console_initcall(pnx8xxx_rs_console_init);
-
-#define PNX8XXX_CONSOLE        &pnx8xxx_console
-#else
-#define PNX8XXX_CONSOLE        NULL
-#endif
-
-static struct uart_driver pnx8xxx_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyS",
-       .dev_name               = "ttyS",
-       .major                  = SERIAL_PNX8XXX_MAJOR,
-       .minor                  = MINOR_START,
-       .nr                     = NR_PORTS,
-       .cons                   = PNX8XXX_CONSOLE,
-};
-
-static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       return uart_suspend_port(&pnx8xxx_reg, &sport->port);
-}
-
-static int pnx8xxx_serial_resume(struct platform_device *pdev)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       return uart_resume_port(&pnx8xxx_reg, &sport->port);
-}
-
-static int pnx8xxx_serial_probe(struct platform_device *pdev)
-{
-       struct resource *res = pdev->resource;
-       int i;
-
-       for (i = 0; i < pdev->num_resources; i++, res++) {
-               if (!(res->flags & IORESOURCE_MEM))
-                       continue;
-
-               for (i = 0; i < NR_PORTS; i++) {
-                       if (pnx8xxx_ports[i].port.mapbase != res->start)
-                               continue;
-
-                       pnx8xxx_ports[i].port.dev = &pdev->dev;
-                       uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
-                       platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int pnx8xxx_serial_remove(struct platform_device *pdev)
-{
-       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&pnx8xxx_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver pnx8xxx_serial_driver = {
-       .driver         = {
-               .name   = "pnx8xxx-uart",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = pnx8xxx_serial_probe,
-       .remove         = pnx8xxx_serial_remove,
-       .suspend        = pnx8xxx_serial_suspend,
-       .resume         = pnx8xxx_serial_resume,
-};
-
-static int __init pnx8xxx_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: PNX8XXX driver\n");
-
-       pnx8xxx_init_ports();
-
-       ret = uart_register_driver(&pnx8xxx_reg);
-       if (ret == 0) {
-               ret = platform_driver_register(&pnx8xxx_serial_driver);
-               if (ret)
-                       uart_unregister_driver(&pnx8xxx_reg);
-       }
-       return ret;
-}
-
-static void __exit pnx8xxx_serial_exit(void)
-{
-       platform_driver_unregister(&pnx8xxx_serial_driver);
-       uart_unregister_driver(&pnx8xxx_reg);
-}
-
-module_init(pnx8xxx_serial_init);
-module_exit(pnx8xxx_serial_exit);
-
-MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
-MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
-MODULE_ALIAS("platform:pnx8xxx-uart");
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
deleted file mode 100644 (file)
index 1102a39..0000000
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- *  linux/drivers/serial/pxa.c
- *
- *  Based on drivers/serial/8250.c by Russell King.
- *
- *  Author:    Nicolas Pitre
- *  Created:   Feb 20, 2003
- *  Copyright: (C) 2003 Monta Vista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Note 1: This driver is made separate from the already too overloaded
- * 8250.c because it needs some kirks of its own and that'll make it
- * easier to add DMA support.
- *
- * Note 2: I'm too sick of device allocation policies for serial ports.
- * If someone else wants to request an "official" allocation of major/minor
- * for this driver please be my guest.  And don't forget that new hardware
- * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
- * hope for a better port registration and dynamic device allocation scheme
- * with the serial core maintainer satisfaction to appear soon.
- */
-
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-struct uart_pxa_port {
-       struct uart_port        port;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned int            lsr_break_flag;
-       struct clk              *clk;
-       char                    *name;
-};
-
-static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
-{
-       offset <<= 2;
-       return readl(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
-{
-       offset <<= 2;
-       writel(value, up->port.membase + offset);
-}
-
-static void serial_pxa_enable_ms(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_pxa_stop_tx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (up->ier & UART_IER_THRI) {
-               up->ier &= ~UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static void serial_pxa_stop_rx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_pxa_port *up, int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned int ch, flag;
-       int max_count = 256;
-
-       do {
-               ch = serial_in(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ignored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-                       if (up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-#endif
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-
-       ignore_char:
-               *status = serial_in(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-       tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct uart_pxa_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_out(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_pxa_stop_tx(&up->port);
-               return;
-       }
-
-       count = up->port.fifosize / 2;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-
-       if (uart_circ_empty(xmit))
-               serial_pxa_stop_tx(&up->port);
-}
-
-static void serial_pxa_start_tx(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-}
-
-static inline void check_modem_status(struct uart_pxa_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
-{
-       struct uart_pxa_port *up = dev_id;
-       unsigned int iir, lsr;
-
-       iir = serial_in(up, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-       lsr = serial_in(up, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(up, &lsr);
-       check_modem_status(up);
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(up);
-       return IRQ_HANDLED;
-}
-
-static unsigned int serial_pxa_tx_empty(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       mcr |= up->mcr;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-#if 0
-static void serial_pxa_dma_init(struct pxa_uart *up)
-{
-       up->rxdma =
-               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
-       if (up->rxdma < 0)
-               goto out;
-       up->txdma =
-               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
-       if (up->txdma < 0)
-               goto err_txdma;
-       up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
-       if (!up->dmadesc)
-               goto err_alloc;
-
-       /* ... */
-err_alloc:
-       pxa_free_dma(up->txdma);
-err_rxdma:
-       pxa_free_dma(up->rxdma);
-out:
-       return;
-}
-#endif
-
-static int serial_pxa_startup(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-       int retval;
-
-       if (port->line == 3) /* HWUART */
-               up->mcr |= UART_MCR_AFE;
-       else
-               up->mcr = 0;
-
-       up->port.uartclk = clk_get_rate(up->clk);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
-       if (retval)
-               return retval;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl |= TIOCM_OUT2;
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
-       serial_out(up, UART_IER, up->ier);
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) serial_in(up, UART_LSR);
-       (void) serial_in(up, UART_RX);
-       (void) serial_in(up, UART_IIR);
-       (void) serial_in(up, UART_MSR);
-
-       return 0;
-}
-
-static void serial_pxa_shutdown(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned long flags;
-
-       free_irq(up->port.irq, up);
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_out(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->port.mctrl &= ~TIOCM_OUT2;
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned int dll;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               cval = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               cval = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               cval = UART_LCR_WLEN7;
-               break;
-       default:
-       case CS8:
-               cval = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (termios->c_cflag & CSTOPB)
-               cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(termios->c_cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       if ((up->port.uartclk / quot) < (2400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
-       else if ((up->port.uartclk / quot) < (230400 * 16))
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
-       else
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Ensure the port will be enabled.
-        * This is required especially for serial console.
-        */
-       up->ier |= UART_IER_UUE;
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characters to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (termios->c_cflag & CRTSCTS)
-               up->mcr |= UART_MCR_AFE;
-       else
-               up->mcr &= ~UART_MCR_AFE;
-
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
-       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
-
-       /*
-        * work around Errata #75 according to Intel(R) PXA27x Processor Family
-        * Specification Update (Nov 2005)
-        */
-       dll = serial_in(up, UART_DLL);
-       WARN_ON(dll != (quot & 0xff));
-
-       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
-       serial_out(up, UART_FCR, fcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_pxa_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       if (!state)
-               clk_enable(up->clk);
-       else
-               clk_disable(up->clk);
-}
-
-static void serial_pxa_release_port(struct uart_port *port)
-{
-}
-
-static int serial_pxa_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void serial_pxa_config_port(struct uart_port *port, int flags)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       up->port.type = PORT_PXA;
-}
-
-static int
-serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static const char *
-serial_pxa_type(struct uart_port *port)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       return up->name;
-}
-
-static struct uart_pxa_port *serial_pxa_ports[4];
-static struct uart_driver serial_pxa_reg;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void serial_pxa_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void
-serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_pxa_port *up = serial_pxa_ports[co->index];
-       unsigned int ier;
-
-       clk_enable(up->clk);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, UART_IER_UUE);
-
-       uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       clk_disable(up->clk);
-}
-
-static int __init
-serial_pxa_console_setup(struct console *co, char *options)
-{
-       struct uart_pxa_port *up;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index == -1 || co->index >= serial_pxa_reg.nr)
-               co->index = 0;
-       up = serial_pxa_ports[co->index];
-       if (!up)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_pxa_console = {
-       .name           = "ttyS",
-       .write          = serial_pxa_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_pxa_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_pxa_reg,
-};
-
-#define PXA_CONSOLE    &serial_pxa_console
-#else
-#define PXA_CONSOLE    NULL
-#endif
-
-struct uart_ops serial_pxa_pops = {
-       .tx_empty       = serial_pxa_tx_empty,
-       .set_mctrl      = serial_pxa_set_mctrl,
-       .get_mctrl      = serial_pxa_get_mctrl,
-       .stop_tx        = serial_pxa_stop_tx,
-       .start_tx       = serial_pxa_start_tx,
-       .stop_rx        = serial_pxa_stop_rx,
-       .enable_ms      = serial_pxa_enable_ms,
-       .break_ctl      = serial_pxa_break_ctl,
-       .startup        = serial_pxa_startup,
-       .shutdown       = serial_pxa_shutdown,
-       .set_termios    = serial_pxa_set_termios,
-       .pm             = serial_pxa_pm,
-       .type           = serial_pxa_type,
-       .release_port   = serial_pxa_release_port,
-       .request_port   = serial_pxa_request_port,
-       .config_port    = serial_pxa_config_port,
-       .verify_port    = serial_pxa_verify_port,
-};
-
-static struct uart_driver serial_pxa_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "PXA serial",
-       .dev_name       = "ttyS",
-       .major          = TTY_MAJOR,
-       .minor          = 64,
-       .nr             = 4,
-       .cons           = PXA_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int serial_pxa_suspend(struct device *dev)
-{
-        struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
-        if (sport)
-                uart_suspend_port(&serial_pxa_reg, &sport->port);
-
-        return 0;
-}
-
-static int serial_pxa_resume(struct device *dev)
-{
-        struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
-        if (sport)
-                uart_resume_port(&serial_pxa_reg, &sport->port);
-
-        return 0;
-}
-
-static const struct dev_pm_ops serial_pxa_pm_ops = {
-       .suspend        = serial_pxa_suspend,
-       .resume         = serial_pxa_resume,
-};
-#endif
-
-static int serial_pxa_probe(struct platform_device *dev)
-{
-       struct uart_pxa_port *sport;
-       struct resource *mmres, *irqres;
-       int ret;
-
-       mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
-       if (!mmres || !irqres)
-               return -ENODEV;
-
-       sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
-       if (!sport)
-               return -ENOMEM;
-
-       sport->clk = clk_get(&dev->dev, NULL);
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               goto err_free;
-       }
-
-       sport->port.type = PORT_PXA;
-       sport->port.iotype = UPIO_MEM;
-       sport->port.mapbase = mmres->start;
-       sport->port.irq = irqres->start;
-       sport->port.fifosize = 64;
-       sport->port.ops = &serial_pxa_pops;
-       sport->port.line = dev->id;
-       sport->port.dev = &dev->dev;
-       sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-       sport->port.uartclk = clk_get_rate(sport->clk);
-
-       switch (dev->id) {
-       case 0: sport->name = "FFUART"; break;
-       case 1: sport->name = "BTUART"; break;
-       case 2: sport->name = "STUART"; break;
-       case 3: sport->name = "HWUART"; break;
-       default:
-               sport->name = "???";
-               break;
-       }
-
-       sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
-       if (!sport->port.membase) {
-               ret = -ENOMEM;
-               goto err_clk;
-       }
-
-       serial_pxa_ports[dev->id] = sport;
-
-       uart_add_one_port(&serial_pxa_reg, &sport->port);
-       platform_set_drvdata(dev, sport);
-
-       return 0;
-
- err_clk:
-       clk_put(sport->clk);
- err_free:
-       kfree(sport);
-       return ret;
-}
-
-static int serial_pxa_remove(struct platform_device *dev)
-{
-       struct uart_pxa_port *sport = platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
-
-       uart_remove_one_port(&serial_pxa_reg, &sport->port);
-       clk_put(sport->clk);
-       kfree(sport);
-
-       return 0;
-}
-
-static struct platform_driver serial_pxa_driver = {
-        .probe          = serial_pxa_probe,
-        .remove         = serial_pxa_remove,
-
-       .driver         = {
-               .name   = "pxa2xx-uart",
-               .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm     = &serial_pxa_pm_ops,
-#endif
-       },
-};
-
-int __init serial_pxa_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&serial_pxa_reg);
-       if (ret != 0)
-               return ret;
-
-       ret = platform_driver_register(&serial_pxa_driver);
-       if (ret != 0)
-               uart_unregister_driver(&serial_pxa_reg);
-
-       return ret;
-}
-
-void __exit serial_pxa_exit(void)
-{
-       platform_driver_unregister(&serial_pxa_driver);
-       uart_unregister_driver(&serial_pxa_reg);
-}
-
-module_init(serial_pxa_init);
-module_exit(serial_pxa_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c
deleted file mode 100644 (file)
index fed1a9a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* linux/drivers/serial/s3c240.c
- *
- * Driver for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2400_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       clk->divisor = 1;
-       clk->name = "pclk";
-
-       return 0;
-}
-
-static int s3c2400_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       return 0;
-}
-
-static int s3c2400_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2400_uart_inf = {
-       .name           = "Samsung S3C2400 UART",
-       .type           = PORT_S3C2400,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2400_serial_getsource,
-       .set_clksrc     = s3c2400_serial_setsource,
-       .reset_port     = s3c2400_serial_resetport,
-};
-
-static int s3c2400_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
-}
-
-static struct platform_driver s3c2400_serial_driver = {
-       .probe          = s3c2400_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2400-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
-
-static inline int s3c2400_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
-}
-
-static inline void s3c2400_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2400_serial_driver);
-}
-
-module_init(s3c2400_serial_init);
-module_exit(s3c2400_serial_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver");
-MODULE_ALIAS("platform:s3c2400-uart");
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
deleted file mode 100644 (file)
index 73f089d..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* linux/drivers/serial/s3c2410.c
- *
- * Driver for Samsung S3C2410 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2410_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2410_UCON_UCLK;
-       else
-               ucon &= ~S3C2410_UCON_UCLK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-static int s3c2410_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
-
-       return 0;
-}
-
-static int s3c2410_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2410_uart_inf = {
-       .name           = "Samsung S3C2410 UART",
-       .type           = PORT_S3C2410,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2410_serial_getsource,
-       .set_clksrc     = s3c2410_serial_setsource,
-       .reset_port     = s3c2410_serial_resetport,
-};
-
-static int s3c2410_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
-}
-
-static struct platform_driver s3c2410_serial_driver = {
-       .probe          = s3c2410_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2410-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
-
-static int __init s3c2410_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
-}
-
-static void __exit s3c2410_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2410_serial_driver);
-}
-
-module_init(s3c2410_serial_init);
-module_exit(s3c2410_serial_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver");
-MODULE_ALIAS("platform:s3c2410-uart");
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
deleted file mode 100644 (file)
index 1700b1a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* linux/drivers/serial/s3c2412.c
- *
- * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c2412_serial_setsource(struct uart_port *port,
-                                    struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       ucon &= ~S3C2412_UCON_CLKMASK;
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2440_UCON_UCLK;
-       else if (strcmp(clk->name, "pclk") == 0)
-               ucon |= S3C2440_UCON_PCLK;
-       else if (strcmp(clk->name, "usysclk") == 0)
-               ucon |= S3C2412_UCON_USYSCLK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c2412_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       switch (ucon & S3C2412_UCON_CLKMASK) {
-       case S3C2412_UCON_UCLK:
-               clk->divisor = 1;
-               clk->name = "uclk";
-               break;
-
-       case S3C2412_UCON_PCLK:
-       case S3C2412_UCON_PCLK2:
-               clk->divisor = 1;
-               clk->name = "pclk";
-               break;
-
-       case S3C2412_UCON_USYSCLK:
-               clk->divisor = 1;
-               clk->name = "usysclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c2412_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("%s: port=%p (%08lx), cfg=%p\n",
-           __func__, port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= S3C2412_UCON_CLKMASK;
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2412_uart_inf = {
-       .name           = "Samsung S3C2412 UART",
-       .type           = PORT_S3C2412,
-       .fifosize       = 64,
-       .has_divslot    = 1,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2412_serial_getsource,
-       .set_clksrc     = s3c2412_serial_setsource,
-       .reset_port     = s3c2412_serial_resetport,
-};
-
-/* device management */
-
-static int s3c2412_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c2440_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
-}
-
-static struct platform_driver s3c2412_serial_driver = {
-       .probe          = s3c2412_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2412-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
-
-static inline int s3c2412_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
-}
-
-static inline void s3c2412_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2412_serial_driver);
-}
-
-module_init(s3c2412_serial_init);
-module_exit(s3c2412_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c2412-uart");
diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c
deleted file mode 100644 (file)
index 094cc39..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* linux/drivers/serial/s3c2440.c
- *
- * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-
-static int s3c2440_serial_setsource(struct uart_port *port,
-                                    struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       /* todo - proper fclk<>nonfclk switch. */
-
-       ucon &= ~S3C2440_UCON_CLKMASK;
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2440_UCON_UCLK;
-       else if (strcmp(clk->name, "pclk") == 0)
-               ucon |= S3C2440_UCON_PCLK;
-       else if (strcmp(clk->name, "fclk") == 0)
-               ucon |= S3C2440_UCON_FCLK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c2440_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-       unsigned long ucon0, ucon1, ucon2;
-
-       switch (ucon & S3C2440_UCON_CLKMASK) {
-       case S3C2440_UCON_UCLK:
-               clk->divisor = 1;
-               clk->name = "uclk";
-               break;
-
-       case S3C2440_UCON_PCLK:
-       case S3C2440_UCON_PCLK2:
-               clk->divisor = 1;
-               clk->name = "pclk";
-               break;
-
-       case S3C2440_UCON_FCLK:
-               /* the fun of calculating the uart divisors on
-                * the s3c2440 */
-
-               ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
-               ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
-               ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
-
-               printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
-
-               ucon0 &= S3C2440_UCON0_DIVMASK;
-               ucon1 &= S3C2440_UCON1_DIVMASK;
-               ucon2 &= S3C2440_UCON2_DIVMASK;
-
-               if (ucon0 != 0) {
-                       clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 6;
-               } else if (ucon1 != 0) {
-                       clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 21;
-               } else if (ucon2 != 0) {
-                       clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
-                       clk->divisor += 36;
-               } else {
-                       /* manual calims 44, seems to be 9 */
-                       clk->divisor = 9;
-               }
-
-               clk->name = "fclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c2440_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c2440_uart_inf = {
-       .name           = "Samsung S3C2440 UART",
-       .type           = PORT_S3C2440,
-       .fifosize       = 64,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c2440_serial_getsource,
-       .set_clksrc     = s3c2440_serial_setsource,
-       .reset_port     = s3c2440_serial_resetport,
-};
-
-/* device management */
-
-static int s3c2440_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c2440_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
-}
-
-static struct platform_driver s3c2440_serial_driver = {
-       .probe          = s3c2440_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c2440-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
-
-static int __init s3c2440_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
-}
-
-static void __exit s3c2440_serial_exit(void)
-{
-       platform_driver_unregister(&s3c2440_serial_driver);
-}
-
-module_init(s3c2440_serial_init);
-module_exit(s3c2440_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c2440-uart");
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
deleted file mode 100644 (file)
index fad6083..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* linux/drivers/serial/s3c24a0.c
- *
- * Driver for Samsung S3C24A0 SoC onboard UARTs.
- *
- * Based on drivers/serial/s3c2410.c
- *
- * Author: Sandeep Patil <sandeep.patil@azingo.com>
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include "samsung.h"
-
-static int s3c24a0_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk") == 0)
-               ucon |= S3C2410_UCON_UCLK;
-       else
-               ucon &= ~S3C2410_UCON_UCLK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-static int s3c24a0_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
-
-       return 0;
-}
-
-static int s3c24a0_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       wr_regl(port, S3C2410_UCON,  cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c24a0_uart_inf = {
-       .name           = "Samsung S3C24A0 UART",
-       .type           = PORT_S3C2410,
-       .fifosize       = 16,
-       .rx_fifomask    = S3C24A0_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C24A0_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C24A0_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C24A0_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C24A0_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C24A0_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c24a0_serial_getsource,
-       .set_clksrc     = s3c24a0_serial_setsource,
-       .reset_port     = s3c24a0_serial_resetport,
-};
-
-static int s3c24a0_serial_probe(struct platform_device *dev)
-{
-       return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
-}
-
-static struct platform_driver s3c24a0_serial_driver = {
-       .probe          = s3c24a0_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c24a0-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
-
-static int __init s3c24a0_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
-}
-
-static void __exit s3c24a0_serial_exit(void)
-{
-       platform_driver_unregister(&s3c24a0_serial_driver);
-}
-
-module_init(s3c24a0_serial_init);
-module_exit(s3c24a0_serial_exit);
-
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
deleted file mode 100644 (file)
index 4be92ab..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* linux/drivers/serial/s3c6400.c
- *
- * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
- *
- * Copyright 2008 Openmoko,  Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-
-#include "samsung.h"
-
-static int s3c6400_serial_setsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if (strcmp(clk->name, "uclk0") == 0) {
-               ucon &= ~S3C6400_UCON_CLKMASK;
-               ucon |= S3C6400_UCON_UCLK0;
-       } else if (strcmp(clk->name, "uclk1") == 0)
-               ucon |= S3C6400_UCON_UCLK1;
-       else if (strcmp(clk->name, "pclk") == 0) {
-               /* See notes about transitioning from UCLK to PCLK */
-               ucon &= ~S3C6400_UCON_UCLK0;
-       } else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s3c6400_serial_getsource(struct uart_port *port,
-                                   struct s3c24xx_uart_clksrc *clk)
-{
-       u32 ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-
-       switch (ucon & S3C6400_UCON_CLKMASK) {
-       case S3C6400_UCON_UCLK0:
-               clk->name = "uclk0";
-               break;
-
-       case S3C6400_UCON_UCLK1:
-               clk->name = "uclk1";
-               break;
-
-       case S3C6400_UCON_PCLK:
-       case S3C6400_UCON_PCLK2:
-               clk->name = "pclk";
-               break;
-       }
-
-       return 0;
-}
-
-static int s3c6400_serial_resetport(struct uart_port *port,
-                                   struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
-           port, port->mapbase, cfg);
-
-       /* ensure we don't change the clock settings... */
-
-       ucon &= S3C6400_UCON_CLKMASK;
-
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-static struct s3c24xx_uart_info s3c6400_uart_inf = {
-       .name           = "Samsung S3C6400 UART",
-       .type           = PORT_S3C6400,
-       .fifosize       = 64,
-       .has_divslot    = 1,
-       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
-       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
-       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
-       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
-       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
-       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
-       .get_clksrc     = s3c6400_serial_getsource,
-       .set_clksrc     = s3c6400_serial_setsource,
-       .reset_port     = s3c6400_serial_resetport,
-};
-
-/* device management */
-
-static int s3c6400_serial_probe(struct platform_device *dev)
-{
-       dbg("s3c6400_serial_probe: dev=%p\n", dev);
-       return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
-}
-
-static struct platform_driver s3c6400_serial_driver = {
-       .probe          = s3c6400_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s3c6400-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
-
-static int __init s3c6400_serial_init(void)
-{
-       return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
-}
-
-static void __exit s3c6400_serial_exit(void)
-{
-       platform_driver_unregister(&s3c6400_serial_driver);
-}
-
-module_init(s3c6400_serial_init);
-module_exit(s3c6400_serial_exit);
-
-MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/serial/s5pv210.c b/drivers/serial/s5pv210.c
deleted file mode 100644 (file)
index 6ebccd7..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* linux/drivers/serial/s5pv210.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Based on drivers/serial/s3c6400.c
- *
- * Driver for Samsung S5PV210 SoC UARTs.
- *
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <plat/regs-serial.h>
-#include "samsung.h"
-
-static int s5pv210_serial_setsource(struct uart_port *port,
-                                       struct s3c24xx_uart_clksrc *clk)
-{
-       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       if ((cfg->clocks_size) == 1)
-               return 0;
-
-       if (strcmp(clk->name, "pclk") == 0)
-               ucon &= ~S5PV210_UCON_CLKMASK;
-       else if (strcmp(clk->name, "uclk1") == 0)
-               ucon |= S5PV210_UCON_CLKMASK;
-       else {
-               printk(KERN_ERR "unknown clock source %s\n", clk->name);
-               return -EINVAL;
-       }
-
-       wr_regl(port, S3C2410_UCON, ucon);
-       return 0;
-}
-
-
-static int s5pv210_serial_getsource(struct uart_port *port,
-                                       struct s3c24xx_uart_clksrc *clk)
-{
-       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
-       u32 ucon = rd_regl(port, S3C2410_UCON);
-
-       clk->divisor = 1;
-
-       if ((cfg->clocks_size) == 1)
-               return 0;
-
-       switch (ucon & S5PV210_UCON_CLKMASK) {
-       case S5PV210_UCON_PCLK:
-               clk->name = "pclk";
-               break;
-       case S5PV210_UCON_UCLK:
-               clk->name = "uclk1";
-               break;
-       }
-
-       return 0;
-}
-
-static int s5pv210_serial_resetport(struct uart_port *port,
-                                       struct s3c2410_uartcfg *cfg)
-{
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
-
-       ucon &= S5PV210_UCON_CLKMASK;
-       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
-
-       /* reset both fifos */
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
-       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
-
-       return 0;
-}
-
-#define S5PV210_UART_DEFAULT_INFO(fifo_size)                   \
-               .name           = "Samsung S5PV210 UART0",      \
-               .type           = PORT_S3C6400,                 \
-               .fifosize       = fifo_size,                    \
-               .has_divslot    = 1,                            \
-               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
-               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
-               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
-               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
-               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
-               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
-               .get_clksrc     = s5pv210_serial_getsource,     \
-               .set_clksrc     = s5pv210_serial_setsource,     \
-               .reset_port     = s5pv210_serial_resetport
-
-static struct s3c24xx_uart_info s5p_port_fifo256 = {
-       S5PV210_UART_DEFAULT_INFO(256),
-};
-
-static struct s3c24xx_uart_info s5p_port_fifo64 = {
-       S5PV210_UART_DEFAULT_INFO(64),
-};
-
-static struct s3c24xx_uart_info s5p_port_fifo16 = {
-       S5PV210_UART_DEFAULT_INFO(16),
-};
-
-static struct s3c24xx_uart_info *s5p_uart_inf[] = {
-       [0] = &s5p_port_fifo256,
-       [1] = &s5p_port_fifo64,
-       [2] = &s5p_port_fifo16,
-       [3] = &s5p_port_fifo16,
-};
-
-/* device management */
-static int s5p_serial_probe(struct platform_device *pdev)
-{
-       return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
-}
-
-static struct platform_driver s5p_serial_driver = {
-       .probe          = s5p_serial_probe,
-       .remove         = __devexit_p(s3c24xx_serial_remove),
-       .driver         = {
-               .name   = "s5pv210-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init s5pv210_serial_console_init(void)
-{
-       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
-}
-
-console_initcall(s5pv210_serial_console_init);
-
-static int __init s5p_serial_init(void)
-{
-       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
-}
-
-static void __exit s5p_serial_exit(void)
-{
-       platform_driver_unregister(&s5p_serial_driver);
-}
-
-module_init(s5p_serial_init);
-module_exit(s5p_serial_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s5pv210-uart");
-MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
-MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
deleted file mode 100644 (file)
index 2199d81..0000000
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/char/sa1100.c
- *
- *  Driver for SA11x0 serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/mach/serial_sa1100.h>
-
-/* We've been assigned a range on the "Low-density serial ports" major */
-#define SERIAL_SA1100_MAJOR    204
-#define MINOR_START            5
-
-#define NR_PORTS               3
-
-#define SA1100_ISR_PASS_LIMIT  256
-
-/*
- * Convert from ignore_status_mask or read_status_mask to UTSR[01]
- */
-#define SM_TO_UTSR0(x) ((x) & 0xff)
-#define SM_TO_UTSR1(x) ((x) >> 8)
-#define UTSR0_TO_SM(x) ((x))
-#define UTSR1_TO_SM(x) ((x) << 8)
-
-#define UART_GET_UTCR0(sport)  __raw_readl((sport)->port.membase + UTCR0)
-#define UART_GET_UTCR1(sport)  __raw_readl((sport)->port.membase + UTCR1)
-#define UART_GET_UTCR2(sport)  __raw_readl((sport)->port.membase + UTCR2)
-#define UART_GET_UTCR3(sport)  __raw_readl((sport)->port.membase + UTCR3)
-#define UART_GET_UTSR0(sport)  __raw_readl((sport)->port.membase + UTSR0)
-#define UART_GET_UTSR1(sport)  __raw_readl((sport)->port.membase + UTSR1)
-#define UART_GET_CHAR(sport)   __raw_readl((sport)->port.membase + UTDR)
-
-#define UART_PUT_UTCR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR0)
-#define UART_PUT_UTCR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR1)
-#define UART_PUT_UTCR2(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR2)
-#define UART_PUT_UTCR3(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR3)
-#define UART_PUT_UTSR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR0)
-#define UART_PUT_UTSR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR1)
-#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
-
-/*
- * This is the size of our serial port register set.
- */
-#define UART_PORT_SIZE 0x24
-
-/*
- * This determines how often we check the modem status signals
- * for any change.  They generally aren't connected to an IRQ
- * so we have to poll them.  We also check immediately before
- * filling the TX fifo incase CTS has been dropped.
- */
-#define MCTRL_TIMEOUT  (250*HZ/1000)
-
-struct sa1100_port {
-       struct uart_port        port;
-       struct timer_list       timer;
-       unsigned int            old_status;
-};
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void sa1100_mctrl_check(struct sa1100_port *sport)
-{
-       unsigned int status, changed;
-
-       status = sport->port.ops->get_mctrl(&sport->port);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void sa1100_timeout(unsigned long data)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)data;
-       unsigned long flags;
-
-       if (sport->port.state) {
-               spin_lock_irqsave(&sport->port.lock, flags);
-               sa1100_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
-
-               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
-       }
-}
-
-/*
- * interrupts disabled on entry
- */
-static void sa1100_stop_tx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
-       sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
-}
-
-/*
- * port locked and interrupts disabled
- */
-static void sa1100_start_tx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
-       UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
-}
-
-/*
- * Interrupts enabled
- */
-static void sa1100_stop_rx(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       u32 utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
-}
-
-/*
- * Set the modem control timer to fire immediately.
- */
-static void sa1100_enable_ms(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       mod_timer(&sport->timer, jiffies);
-}
-
-static void
-sa1100_rx_chars(struct sa1100_port *sport)
-{
-       struct tty_struct *tty = sport->port.state->port.tty;
-       unsigned int status, ch, flg;
-
-       status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
-                UTSR0_TO_SM(UART_GET_UTSR0(sport));
-       while (status & UTSR1_TO_SM(UTSR1_RNE)) {
-               ch = UART_GET_CHAR(sport);
-
-               sport->port.icount.rx++;
-
-               flg = TTY_NORMAL;
-
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-                */
-               if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) {
-                       if (status & UTSR1_TO_SM(UTSR1_PRE))
-                               sport->port.icount.parity++;
-                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
-                               sport->port.icount.frame++;
-                       if (status & UTSR1_TO_SM(UTSR1_ROR))
-                               sport->port.icount.overrun++;
-
-                       status &= sport->port.read_status_mask;
-
-                       if (status & UTSR1_TO_SM(UTSR1_PRE))
-                               flg = TTY_PARITY;
-                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
-                               flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-                       sport->port.sysrq = 0;
-#endif
-               }
-
-               if (uart_handle_sysrq_char(&sport->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
-
-       ignore_char:
-               status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
-                        UTSR0_TO_SM(UART_GET_UTSR0(sport));
-       }
-       tty_flip_buffer_push(tty);
-}
-
-static void sa1100_tx_chars(struct sa1100_port *sport)
-{
-       struct circ_buf *xmit = &sport->port.state->xmit;
-
-       if (sport->port.x_char) {
-               UART_PUT_CHAR(sport, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       sa1100_mctrl_check(sport);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               sa1100_stop_tx(&sport->port);
-               return;
-       }
-
-       /*
-        * Tried using FIFO (not checking TNF) for fifo fill:
-        * still had the '4 bytes repeated' problem.
-        */
-       while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
-               UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-       if (uart_circ_empty(xmit))
-               sa1100_stop_tx(&sport->port);
-}
-
-static irqreturn_t sa1100_int(int irq, void *dev_id)
-{
-       struct sa1100_port *sport = dev_id;
-       unsigned int status, pass_counter = 0;
-
-       spin_lock(&sport->port.lock);
-       status = UART_GET_UTSR0(sport);
-       status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
-       do {
-               if (status & (UTSR0_RFS | UTSR0_RID)) {
-                       /* Clear the receiver idle bit, if set */
-                       if (status & UTSR0_RID)
-                               UART_PUT_UTSR0(sport, UTSR0_RID);
-                       sa1100_rx_chars(sport);
-               }
-
-               /* Clear the relevant break bits */
-               if (status & (UTSR0_RBB | UTSR0_REB))
-                       UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
-
-               if (status & UTSR0_RBB)
-                       sport->port.icount.brk++;
-
-               if (status & UTSR0_REB)
-                       uart_handle_break(&sport->port);
-
-               if (status & UTSR0_TFS)
-                       sa1100_tx_chars(sport);
-               if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
-                       break;
-               status = UART_GET_UTSR0(sport);
-               status &= SM_TO_UTSR0(sport->port.read_status_mask) |
-                         ~UTSR0_TFS;
-       } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
-       spin_unlock(&sport->port.lock);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Return TIOCSER_TEMT when transmitter is not busy.
- */
-static unsigned int sa1100_tx_empty(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
-}
-
-static unsigned int sa1100_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/*
- * Interrupts always disabled.
- */
-static void sa1100_break_ctl(struct uart_port *port, int break_state)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       unsigned long flags;
-       unsigned int utcr3;
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-       utcr3 = UART_GET_UTCR3(sport);
-       if (break_state == -1)
-               utcr3 |= UTCR3_BRK;
-       else
-               utcr3 &= ~UTCR3_BRK;
-       UART_PUT_UTCR3(sport, utcr3);
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static int sa1100_startup(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       int retval;
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(sport->port.irq, sa1100_int, 0,
-                            "sa11x0-uart", sport);
-       if (retval)
-               return retval;
-
-       /*
-        * Finally, clear and enable interrupts
-        */
-       UART_PUT_UTSR0(sport, -1);
-       UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
-
-       /*
-        * Enable modem status interrupts
-        */
-       spin_lock_irq(&sport->port.lock);
-       sa1100_enable_ms(&sport->port);
-       spin_unlock_irq(&sport->port.lock);
-
-       return 0;
-}
-
-static void sa1100_shutdown(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       /*
-        * Stop our timer.
-        */
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Free the interrupt
-        */
-       free_irq(sport->port.irq, sport);
-
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-       UART_PUT_UTCR3(sport, 0);
-}
-
-static void
-sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       unsigned long flags;
-       unsigned int utcr0, old_utcr3, baud, quot;
-       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-
-       /*
-        * We only support CS7 and CS8.
-        */
-       while ((termios->c_cflag & CSIZE) != CS7 &&
-              (termios->c_cflag & CSIZE) != CS8) {
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= old_csize;
-               old_csize = CS8;
-       }
-
-       if ((termios->c_cflag & CSIZE) == CS8)
-               utcr0 = UTCR0_DSS;
-       else
-               utcr0 = 0;
-
-       if (termios->c_cflag & CSTOPB)
-               utcr0 |= UTCR0_SBS;
-       if (termios->c_cflag & PARENB) {
-               utcr0 |= UTCR0_PE;
-               if (!(termios->c_cflag & PARODD))
-                       utcr0 |= UTCR0_OES;
-       }
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&sport->port.lock, flags);
-
-       sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
-       sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
-       if (termios->c_iflag & INPCK)
-               sport->port.read_status_mask |=
-                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               sport->port.read_status_mask |=
-                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
-
-       /*
-        * Characters to ignore
-        */
-       sport->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |=
-                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
-       if (termios->c_iflag & IGNBRK) {
-               sport->port.ignore_status_mask |=
-                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       sport->port.ignore_status_mask |=
-                               UTSR1_TO_SM(UTSR1_ROR);
-       }
-
-       del_timer_sync(&sport->timer);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * disable interrupts and drain transmitter
-        */
-       old_utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
-
-       while (UART_GET_UTSR1(sport) & UTSR1_TBY)
-               barrier();
-
-       /* then, disable everything */
-       UART_PUT_UTCR3(sport, 0);
-
-       /* set the parity, stop bits and data size */
-       UART_PUT_UTCR0(sport, utcr0);
-
-       /* set the baud rate */
-       quot -= 1;
-       UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
-       UART_PUT_UTCR2(sport, (quot & 0xff));
-
-       UART_PUT_UTSR0(sport, -1);
-
-       UART_PUT_UTCR3(sport, old_utcr3);
-
-       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
-               sa1100_enable_ms(&sport->port);
-
-       spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
-static const char *sa1100_type(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void sa1100_release_port(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int sa1100_request_port(struct uart_port *port)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
-                       "sa11x0-uart") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void sa1100_config_port(struct uart_port *port, int flags)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       if (flags & UART_CONFIG_TYPE &&
-           sa1100_request_port(&sport->port) == 0)
-               sport->port.type = PORT_SA1100;
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- * The only change we allow are to the flags and type, and
- * even then only between PORT_SA1100 and PORT_UNKNOWN
- */
-static int
-sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
-               ret = -EINVAL;
-       if (sport->port.irq != ser->irq)
-               ret = -EINVAL;
-       if (ser->io_type != SERIAL_IO_MEM)
-               ret = -EINVAL;
-       if (sport->port.uartclk / 16 != ser->baud_base)
-               ret = -EINVAL;
-       if ((void *)sport->port.mapbase != ser->iomem_base)
-               ret = -EINVAL;
-       if (sport->port.iobase != ser->port)
-               ret = -EINVAL;
-       if (ser->hub6 != 0)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops sa1100_pops = {
-       .tx_empty       = sa1100_tx_empty,
-       .set_mctrl      = sa1100_set_mctrl,
-       .get_mctrl      = sa1100_get_mctrl,
-       .stop_tx        = sa1100_stop_tx,
-       .start_tx       = sa1100_start_tx,
-       .stop_rx        = sa1100_stop_rx,
-       .enable_ms      = sa1100_enable_ms,
-       .break_ctl      = sa1100_break_ctl,
-       .startup        = sa1100_startup,
-       .shutdown       = sa1100_shutdown,
-       .set_termios    = sa1100_set_termios,
-       .type           = sa1100_type,
-       .release_port   = sa1100_release_port,
-       .request_port   = sa1100_request_port,
-       .config_port    = sa1100_config_port,
-       .verify_port    = sa1100_verify_port,
-};
-
-static struct sa1100_port sa1100_ports[NR_PORTS];
-
-/*
- * Setup the SA1100 serial ports.  Note that we don't include the IrDA
- * port here since we have our own SIR/FIR driver (see drivers/net/irda)
- *
- * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
- * Which serial port this ends up being depends on the machine you're
- * running this kernel on.  I'm not convinced that this is a good idea,
- * but that's the way it traditionally works.
- *
- * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
- * used here.
- */
-static void __init sa1100_init_ports(void)
-{
-       static int first = 1;
-       int i;
-
-       if (!first)
-               return;
-       first = 0;
-
-       for (i = 0; i < NR_PORTS; i++) {
-               sa1100_ports[i].port.uartclk   = 3686400;
-               sa1100_ports[i].port.ops       = &sa1100_pops;
-               sa1100_ports[i].port.fifosize  = 8;
-               sa1100_ports[i].port.line      = i;
-               sa1100_ports[i].port.iotype    = UPIO_MEM;
-               init_timer(&sa1100_ports[i].timer);
-               sa1100_ports[i].timer.function = sa1100_timeout;
-               sa1100_ports[i].timer.data     = (unsigned long)&sa1100_ports[i];
-       }
-
-       /*
-        * make transmit lines outputs, so that when the port
-        * is closed, the output is in the MARK state.
-        */
-       PPDR |= PPC_TXD1 | PPC_TXD3;
-       PPSR |= PPC_TXD1 | PPC_TXD3;
-}
-
-void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns)
-{
-       if (fns->get_mctrl)
-               sa1100_pops.get_mctrl = fns->get_mctrl;
-       if (fns->set_mctrl)
-               sa1100_pops.set_mctrl = fns->set_mctrl;
-
-       sa1100_pops.pm       = fns->pm;
-       sa1100_pops.set_wake = fns->set_wake;
-}
-
-void __init sa1100_register_uart(int idx, int port)
-{
-       if (idx >= NR_PORTS) {
-               printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
-               return;
-       }
-
-       switch (port) {
-       case 1:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       case 2:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       case 3:
-               sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
-               sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
-               sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
-               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
-               break;
-
-       default:
-               printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
-       }
-}
-
-
-#ifdef CONFIG_SERIAL_SA1100_CONSOLE
-static void sa1100_console_putchar(struct uart_port *port, int ch)
-{
-       struct sa1100_port *sport = (struct sa1100_port *)port;
-
-       while (!(UART_GET_UTSR1(sport) & UTSR1_TNF))
-               barrier();
-       UART_PUT_CHAR(sport, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-sa1100_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct sa1100_port *sport = &sa1100_ports[co->index];
-       unsigned int old_utcr3, status;
-
-       /*
-        *      First, save UTCR3 and then disable interrupts
-        */
-       old_utcr3 = UART_GET_UTCR3(sport);
-       UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
-                               UTCR3_TXE);
-
-       uart_console_write(&sport->port, s, count, sa1100_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore UTCR3
-        */
-       do {
-               status = UART_GET_UTSR1(sport);
-       } while (status & UTSR1_TBY);
-       UART_PUT_UTCR3(sport, old_utcr3);
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader),
- * try to determine the current setup.
- */
-static void __init
-sa1100_console_get_options(struct sa1100_port *sport, int *baud,
-                          int *parity, int *bits)
-{
-       unsigned int utcr3;
-
-       utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
-       if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
-               /* ok, the port was enabled */
-               unsigned int utcr0, quot;
-
-               utcr0 = UART_GET_UTCR0(sport);
-
-               *parity = 'n';
-               if (utcr0 & UTCR0_PE) {
-                       if (utcr0 & UTCR0_OES)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
-
-               if (utcr0 & UTCR0_DSS)
-                       *bits = 8;
-               else
-                       *bits = 7;
-
-               quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
-               quot &= 0xfff;
-               *baud = sport->port.uartclk / (16 * (quot + 1));
-       }
-}
-
-static int __init
-sa1100_console_setup(struct console *co, char *options)
-{
-       struct sa1100_port *sport;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index == -1 || co->index >= NR_PORTS)
-               co->index = 0;
-       sport = &sa1100_ports[co->index];
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               sa1100_console_get_options(sport, &baud, &parity, &bits);
-
-       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver sa1100_reg;
-static struct console sa1100_console = {
-       .name           = "ttySA",
-       .write          = sa1100_console_write,
-       .device         = uart_console_device,
-       .setup          = sa1100_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &sa1100_reg,
-};
-
-static int __init sa1100_rs_console_init(void)
-{
-       sa1100_init_ports();
-       register_console(&sa1100_console);
-       return 0;
-}
-console_initcall(sa1100_rs_console_init);
-
-#define SA1100_CONSOLE &sa1100_console
-#else
-#define SA1100_CONSOLE NULL
-#endif
-
-static struct uart_driver sa1100_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttySA",
-       .dev_name               = "ttySA",
-       .major                  = SERIAL_SA1100_MAJOR,
-       .minor                  = MINOR_START,
-       .nr                     = NR_PORTS,
-       .cons                   = SA1100_CONSOLE,
-};
-
-static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct sa1100_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_suspend_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static int sa1100_serial_resume(struct platform_device *dev)
-{
-       struct sa1100_port *sport = platform_get_drvdata(dev);
-
-       if (sport)
-               uart_resume_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static int sa1100_serial_probe(struct platform_device *dev)
-{
-       struct resource *res = dev->resource;
-       int i;
-
-       for (i = 0; i < dev->num_resources; i++, res++)
-               if (res->flags & IORESOURCE_MEM)
-                       break;
-
-       if (i < dev->num_resources) {
-               for (i = 0; i < NR_PORTS; i++) {
-                       if (sa1100_ports[i].port.mapbase != res->start)
-                               continue;
-
-                       sa1100_ports[i].port.dev = &dev->dev;
-                       uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
-                       platform_set_drvdata(dev, &sa1100_ports[i]);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int sa1100_serial_remove(struct platform_device *pdev)
-{
-       struct sa1100_port *sport = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (sport)
-               uart_remove_one_port(&sa1100_reg, &sport->port);
-
-       return 0;
-}
-
-static struct platform_driver sa11x0_serial_driver = {
-       .probe          = sa1100_serial_probe,
-       .remove         = sa1100_serial_remove,
-       .suspend        = sa1100_serial_suspend,
-       .resume         = sa1100_serial_resume,
-       .driver         = {
-               .name   = "sa11x0-uart",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sa1100_serial_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Serial: SA11x0 driver\n");
-
-       sa1100_init_ports();
-
-       ret = uart_register_driver(&sa1100_reg);
-       if (ret == 0) {
-               ret = platform_driver_register(&sa11x0_serial_driver);
-               if (ret)
-                       uart_unregister_driver(&sa1100_reg);
-       }
-       return ret;
-}
-
-static void __exit sa1100_serial_exit(void)
-{
-       platform_driver_unregister(&sa11x0_serial_driver);
-       uart_unregister_driver(&sa1100_reg);
-}
-
-module_init(sa1100_serial_init);
-module_exit(sa1100_serial_exit);
-
-MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("SA1100 generic serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
-MODULE_ALIAS("platform:sa11x0-uart");
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
deleted file mode 100644 (file)
index 2335eda..0000000
+++ /dev/null
@@ -1,1487 +0,0 @@
-/* linux/drivers/serial/samsuing.c
- *
- * Driver core for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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.
-*/
-
-/* Hote on 2410 error handling
- *
- * The s3c2410 manual has a love/hate affair with the contents of the
- * UERSTAT register in the UART blocks, and keeps marking some of the
- * error bits as reserved. Having checked with the s3c2410x01,
- * it copes with BREAKs properly, so I am happy to ignore the RESERVED
- * feature from the latter versions of the manual.
- *
- * If it becomes aparrent that latter versions of the 2410 remove these
- * bits, then action will have to be taken to differentiate the versions
- * and change the policy on BREAK
- *
- * BJD, 04-Nov-2004
-*/
-
-#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/regs-serial.h>
-
-#include "samsung.h"
-
-/* UART name and device definitions */
-
-#define S3C24XX_SERIAL_NAME    "ttySAC"
-#define S3C24XX_SERIAL_MAJOR   204
-#define S3C24XX_SERIAL_MINOR   64
-
-/* macros to change one thing to another */
-
-#define tx_enabled(port) ((port)->unused[0])
-#define rx_enabled(port) ((port)->unused[1])
-
-/* flag to ignore all characters comming in */
-#define RXSTAT_DUMMY_READ (0x10000000)
-
-static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
-{
-       return container_of(port, struct s3c24xx_uart_port, port);
-}
-
-/* translate a port to the device name */
-
-static inline const char *s3c24xx_serial_portname(struct uart_port *port)
-{
-       return to_platform_device(port->dev)->name;
-}
-
-static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
-{
-       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
-}
-
-static void s3c24xx_serial_rx_enable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon, ufcon;
-       int count = 10000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (--count && !s3c24xx_serial_txempty_nofifo(port))
-               udelay(100);
-
-       ufcon = rd_regl(port, S3C2410_UFCON);
-       ufcon |= S3C2410_UFCON_RESETRX;
-       wr_regl(port, S3C2410_UFCON, ufcon);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon |= S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_rx_disable(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-       ucon &= ~S3C2410_UCON_RXIRQMODE;
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       rx_enabled(port) = 0;
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_stop_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (tx_enabled(port)) {
-               disable_irq_nosync(ourport->tx_irq);
-               tx_enabled(port) = 0;
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_enable(port);
-       }
-}
-
-static void s3c24xx_serial_start_tx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (!tx_enabled(port)) {
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_disable(port);
-
-               enable_irq(ourport->tx_irq);
-               tx_enabled(port) = 1;
-       }
-}
-
-
-static void s3c24xx_serial_stop_rx(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (rx_enabled(port)) {
-               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               disable_irq_nosync(ourport->rx_irq);
-               rx_enabled(port) = 0;
-       }
-}
-
-static void s3c24xx_serial_enable_ms(struct uart_port *port)
-{
-}
-
-static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
-{
-       return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
-{
-       if (port->dev == NULL)
-               return NULL;
-
-       return (struct s3c2410_uartcfg *)port->dev->platform_data;
-}
-
-static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat)
-{
-       struct s3c24xx_uart_info *info = ourport->info;
-
-       if (ufstat & info->rx_fifofull)
-               return info->fifosize;
-
-       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
-}
-
-
-/* ? - where has parity gone?? */
-#define S3C2410_UERSTAT_PARITY (0x1000)
-
-static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id)
-{
-       struct s3c24xx_uart_port *ourport = dev_id;
-       struct uart_port *port = &ourport->port;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int ufcon, ch, flag, ufstat, uerstat;
-       int max_count = 64;
-
-       while (max_count-- > 0) {
-               ufcon = rd_regl(port, S3C2410_UFCON);
-               ufstat = rd_regl(port, S3C2410_UFSTAT);
-
-               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
-                       break;
-
-               uerstat = rd_regl(port, S3C2410_UERSTAT);
-               ch = rd_regb(port, S3C2410_URXH);
-
-               if (port->flags & UPF_CONS_FLOW) {
-                       int txe = s3c24xx_serial_txempty_nofifo(port);
-
-                       if (rx_enabled(port)) {
-                               if (!txe) {
-                                       rx_enabled(port) = 0;
-                                       continue;
-                               }
-                       } else {
-                               if (txe) {
-                                       ufcon |= S3C2410_UFCON_RESETRX;
-                                       wr_regl(port, S3C2410_UFCON, ufcon);
-                                       rx_enabled(port) = 1;
-                                       goto out;
-                               }
-                               continue;
-                       }
-               }
-
-               /* insert the character into the buffer */
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
-                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
-                           ch, uerstat);
-
-                       /* check for break */
-                       if (uerstat & S3C2410_UERSTAT_BREAK) {
-                               dbg("break!\n");
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                   goto ignore_char;
-                       }
-
-                       if (uerstat & S3C2410_UERSTAT_FRAME)
-                               port->icount.frame++;
-                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
-                               port->icount.overrun++;
-
-                       uerstat &= port->read_status_mask;
-
-                       if (uerstat & S3C2410_UERSTAT_BREAK)
-                               flag = TTY_BREAK;
-                       else if (uerstat & S3C2410_UERSTAT_PARITY)
-                               flag = TTY_PARITY;
-                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
-                                           S3C2410_UERSTAT_OVERRUN))
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
-                                ch, flag);
-
- ignore_char:
-               continue;
-       }
-       tty_flip_buffer_push(tty);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
-{
-       struct s3c24xx_uart_port *ourport = id;
-       struct uart_port *port = &ourport->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       int count = 256;
-
-       if (port->x_char) {
-               wr_regb(port, S3C2410_UTXH, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               goto out;
-       }
-
-       /* if there isnt anything more to transmit, or the uart is now
-        * stopped, disable the uart and exit
-       */
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               s3c24xx_serial_stop_tx(port);
-               goto out;
-       }
-
-       /* try and drain the buffer... */
-
-       while (!uart_circ_empty(xmit) && count-- > 0) {
-               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
-                       break;
-
-               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               s3c24xx_serial_stop_tx(port);
-
- out:
-       return IRQ_HANDLED;
-}
-
-static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
-       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               if ((ufstat & info->tx_fifomask) != 0 ||
-                   (ufstat & info->tx_fifofull))
-                       return 0;
-
-               return 1;
-       }
-
-       return s3c24xx_serial_txempty_nofifo(port);
-}
-
-/* no modem control lines */
-static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
-{
-       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
-
-       if (umstat & S3C2410_UMSTAT_CTS)
-               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-       else
-               return TIOCM_CAR | TIOCM_DSR;
-}
-
-static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* todo - possibly remove AFC and do manual CTS */
-}
-
-static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned long flags;
-       unsigned int ucon;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ucon = rd_regl(port, S3C2410_UCON);
-
-       if (break_state)
-               ucon |= S3C2410_UCON_SBREAK;
-       else
-               ucon &= ~S3C2410_UCON_SBREAK;
-
-       wr_regl(port, S3C2410_UCON, ucon);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void s3c24xx_serial_shutdown(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (ourport->tx_claimed) {
-               free_irq(ourport->tx_irq, ourport);
-               tx_enabled(port) = 0;
-               ourport->tx_claimed = 0;
-       }
-
-       if (ourport->rx_claimed) {
-               free_irq(ourport->rx_irq, ourport);
-               ourport->rx_claimed = 0;
-               rx_enabled(port) = 0;
-       }
-}
-
-
-static int s3c24xx_serial_startup(struct uart_port *port)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       int ret;
-
-       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
-           port->mapbase, port->membase);
-
-       rx_enabled(port) = 1;
-
-       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret != 0) {
-               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
-               return ret;
-       }
-
-       ourport->rx_claimed = 1;
-
-       dbg("requesting tx irq...\n");
-
-       tx_enabled(port) = 1;
-
-       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
-                         s3c24xx_serial_portname(port), ourport);
-
-       if (ret) {
-               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
-               goto err;
-       }
-
-       ourport->tx_claimed = 1;
-
-       dbg("s3c24xx_serial_startup ok\n");
-
-       /* the port reset code should have done the correct
-        * register setup for the port controls */
-
-       return ret;
-
- err:
-       s3c24xx_serial_shutdown(port);
-       return ret;
-}
-
-/* power power management control */
-
-static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
-                             unsigned int old)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       ourport->pm_level = level;
-
-       switch (level) {
-       case 3:
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
-                       clk_disable(ourport->baudclk);
-
-               clk_disable(ourport->clk);
-               break;
-
-       case 0:
-               clk_enable(ourport->clk);
-
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
-                       clk_enable(ourport->baudclk);
-
-               break;
-       default:
-               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
-       }
-}
-
-/* baud rate calculation
- *
- * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
- * of different sources, including the peripheral clock ("pclk") and an
- * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
- * with a programmable extra divisor.
- *
- * The following code goes through the clock sources, and calculates the
- * baud clocks (and the resultant actual baud rates) and then tries to
- * pick the closest one and select that.
- *
-*/
-
-
-#define MAX_CLKS (8)
-
-static struct s3c24xx_uart_clksrc tmp_clksrc = {
-       .name           = "pclk",
-       .min_baud       = 0,
-       .max_baud       = 0,
-       .divisor        = 1,
-};
-
-static inline int
-s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->get_clksrc)(port, c);
-}
-
-static inline int
-s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->set_clksrc)(port, c);
-}
-
-struct baud_calc {
-       struct s3c24xx_uart_clksrc      *clksrc;
-       unsigned int                     calc;
-       unsigned int                     divslot;
-       unsigned int                     quot;
-       struct clk                      *src;
-};
-
-static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
-                                  struct uart_port *port,
-                                  struct s3c24xx_uart_clksrc *clksrc,
-                                  unsigned int baud)
-{
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       unsigned long rate;
-
-       calc->src = clk_get(port->dev, clksrc->name);
-       if (calc->src == NULL || IS_ERR(calc->src))
-               return 0;
-
-       rate = clk_get_rate(calc->src);
-       rate /= clksrc->divisor;
-
-       calc->clksrc = clksrc;
-
-       if (ourport->info->has_divslot) {
-               unsigned long div = rate / baud;
-
-               /* The UDIVSLOT register on the newer UARTs allows us to
-                * get a divisor adjustment of 1/16th on the baud clock.
-                *
-                * We don't keep the UDIVSLOT value (the 16ths we calculated
-                * by not multiplying the baud by 16) as it is easy enough
-                * to recalculate.
-                */
-
-               calc->quot = div / 16;
-               calc->calc = rate / div;
-       } else {
-               calc->quot = (rate + (8 * baud)) / (16 * baud);
-               calc->calc = (rate / (calc->quot * 16));
-       }
-
-       calc->quot--;
-       return 1;
-}
-
-static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
-                                         struct s3c24xx_uart_clksrc **clksrc,
-                                         struct clk **clk,
-                                         unsigned int baud)
-{
-       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
-       struct s3c24xx_uart_clksrc *clkp;
-       struct baud_calc res[MAX_CLKS];
-       struct baud_calc *resptr, *best, *sptr;
-       int i;
-
-       clkp = cfg->clocks;
-       best = NULL;
-
-       if (cfg->clocks_size < 2) {
-               if (cfg->clocks_size == 0)
-                       clkp = &tmp_clksrc;
-
-               /* check to see if we're sourcing fclk, and if so we're
-                * going to have to update the clock source
-                */
-
-               if (strcmp(clkp->name, "fclk") == 0) {
-                       struct s3c24xx_uart_clksrc src;
-
-                       s3c24xx_serial_getsource(port, &src);
-
-                       /* check that the port already using fclk, and if
-                        * not, then re-select fclk
-                        */
-
-                       if (strcmp(src.name, clkp->name) == 0) {
-                               s3c24xx_serial_setsource(port, clkp);
-                               s3c24xx_serial_getsource(port, &src);
-                       }
-
-                       clkp->divisor = src.divisor;
-               }
-
-               s3c24xx_serial_calcbaud(res, port, clkp, baud);
-               best = res;
-               resptr = best + 1;
-       } else {
-               resptr = res;
-
-               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
-                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
-                               resptr++;
-               }
-       }
-
-       /* ok, we now need to select the best clock we found */
-
-       if (!best) {
-               unsigned int deviation = (1<<30)|((1<<30)-1);
-               int calc_deviation;
-
-               for (sptr = res; sptr < resptr; sptr++) {
-                       calc_deviation = baud - sptr->calc;
-                       if (calc_deviation < 0)
-                               calc_deviation = -calc_deviation;
-
-                       if (calc_deviation < deviation) {
-                               best = sptr;
-                               deviation = calc_deviation;
-                       }
-               }
-       }
-
-       /* store results to pass back */
-
-       *clksrc = best->clksrc;
-       *clk    = best->src;
-
-       return best->quot;
-}
-
-/* udivslot_table[]
- *
- * This table takes the fractional value of the baud divisor and gives
- * the recommended setting for the UDIVSLOT register.
- */
-static u16 udivslot_table[16] = {
-       [0] = 0x0000,
-       [1] = 0x0080,
-       [2] = 0x0808,
-       [3] = 0x0888,
-       [4] = 0x2222,
-       [5] = 0x4924,
-       [6] = 0x4A52,
-       [7] = 0x54AA,
-       [8] = 0x5555,
-       [9] = 0xD555,
-       [10] = 0xD5D5,
-       [11] = 0xDDD5,
-       [12] = 0xDDDD,
-       [13] = 0xDFDD,
-       [14] = 0xDFDF,
-       [15] = 0xFFDF,
-};
-
-static void s3c24xx_serial_set_termios(struct uart_port *port,
-                                      struct ktermios *termios,
-                                      struct ktermios *old)
-{
-       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct s3c24xx_uart_clksrc *clksrc = NULL;
-       struct clk *clk = NULL;
-       unsigned long flags;
-       unsigned int baud, quot;
-       unsigned int ulcon;
-       unsigned int umcon;
-       unsigned int udivslot = 0;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
-
-       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-               quot = port->custom_divisor;
-       else
-               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
-
-       /* check to see if we need  to change clock source */
-
-       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
-               dbg("selecting clock %p\n", clk);
-               s3c24xx_serial_setsource(port, clksrc);
-
-               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
-                       clk_disable(ourport->baudclk);
-                       ourport->baudclk  = NULL;
-               }
-
-               clk_enable(clk);
-
-               ourport->clksrc = clksrc;
-               ourport->baudclk = clk;
-               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
-       }
-
-       if (ourport->info->has_divslot) {
-               unsigned int div = ourport->baudclk_rate / baud;
-
-               if (cfg->has_fracval) {
-                       udivslot = (div & 15);
-                       dbg("fracval = %04x\n", udivslot);
-               } else {
-                       udivslot = udivslot_table[div & 15];
-                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
-               }
-       }
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               dbg("config: 5bits/char\n");
-               ulcon = S3C2410_LCON_CS5;
-               break;
-       case CS6:
-               dbg("config: 6bits/char\n");
-               ulcon = S3C2410_LCON_CS6;
-               break;
-       case CS7:
-               dbg("config: 7bits/char\n");
-               ulcon = S3C2410_LCON_CS7;
-               break;
-       case CS8:
-       default:
-               dbg("config: 8bits/char\n");
-               ulcon = S3C2410_LCON_CS8;
-               break;
-       }
-
-       /* preserve original lcon IR settings */
-       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
-
-       if (termios->c_cflag & CSTOPB)
-               ulcon |= S3C2410_LCON_STOPB;
-
-       umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
-
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & PARODD)
-                       ulcon |= S3C2410_LCON_PODD;
-               else
-                       ulcon |= S3C2410_LCON_PEVEN;
-       } else {
-               ulcon |= S3C2410_LCON_PNONE;
-       }
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
-           ulcon, quot, udivslot);
-
-       wr_regl(port, S3C2410_ULCON, ulcon);
-       wr_regl(port, S3C2410_UBRDIV, quot);
-       wr_regl(port, S3C2410_UMCON, umcon);
-
-       if (ourport->info->has_divslot)
-               wr_regl(port, S3C2443_DIVSLOT, udivslot);
-
-       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
-           rd_regl(port, S3C2410_ULCON),
-           rd_regl(port, S3C2410_UCON),
-           rd_regl(port, S3C2410_UFCON));
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /*
-        * Which character status flags are we interested in?
-        */
-       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
-
-       /*
-        * Which character status flags should we ignore?
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
-       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *s3c24xx_serial_type(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_S3C2410:
-               return "S3C2410";
-       case PORT_S3C2440:
-               return "S3C2440";
-       case PORT_S3C2412:
-               return "S3C2412";
-       case PORT_S3C6400:
-               return "S3C6400/10";
-       default:
-               return NULL;
-       }
-}
-
-#define MAP_SIZE (0x100)
-
-static void s3c24xx_serial_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, MAP_SIZE);
-}
-
-static int s3c24xx_serial_request_port(struct uart_port *port)
-{
-       const char *name = s3c24xx_serial_portname(port);
-       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
-}
-
-static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (flags & UART_CONFIG_TYPE &&
-           s3c24xx_serial_request_port(port) == 0)
-               port->type = info->type;
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int
-s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct console s3c24xx_serial_console;
-
-#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
-#else
-#define S3C24XX_SERIAL_CONSOLE NULL
-#endif
-
-static struct uart_ops s3c24xx_serial_ops = {
-       .pm             = s3c24xx_serial_pm,
-       .tx_empty       = s3c24xx_serial_tx_empty,
-       .get_mctrl      = s3c24xx_serial_get_mctrl,
-       .set_mctrl      = s3c24xx_serial_set_mctrl,
-       .stop_tx        = s3c24xx_serial_stop_tx,
-       .start_tx       = s3c24xx_serial_start_tx,
-       .stop_rx        = s3c24xx_serial_stop_rx,
-       .enable_ms      = s3c24xx_serial_enable_ms,
-       .break_ctl      = s3c24xx_serial_break_ctl,
-       .startup        = s3c24xx_serial_startup,
-       .shutdown       = s3c24xx_serial_shutdown,
-       .set_termios    = s3c24xx_serial_set_termios,
-       .type           = s3c24xx_serial_type,
-       .release_port   = s3c24xx_serial_release_port,
-       .request_port   = s3c24xx_serial_request_port,
-       .config_port    = s3c24xx_serial_config_port,
-       .verify_port    = s3c24xx_serial_verify_port,
-};
-
-
-static struct uart_driver s3c24xx_uart_drv = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "s3c2410_serial",
-       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
-       .cons           = S3C24XX_SERIAL_CONSOLE,
-       .dev_name       = S3C24XX_SERIAL_NAME,
-       .major          = S3C24XX_SERIAL_MAJOR,
-       .minor          = S3C24XX_SERIAL_MINOR,
-};
-
-static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
-       [0] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX0,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 0,
-               }
-       },
-       [1] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX1,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 1,
-               }
-       },
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
-
-       [2] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX2,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 2,
-               }
-       },
-#endif
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
-       [3] = {
-               .port = {
-                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX3,
-                       .uartclk        = 0,
-                       .fifosize       = 16,
-                       .ops            = &s3c24xx_serial_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 3,
-               }
-       }
-#endif
-};
-
-/* s3c24xx_serial_resetport
- *
- * wrapper to call the specific reset for this port (reset the fifos
- * and the settings)
-*/
-
-static inline int s3c24xx_serial_resetport(struct uart_port *port,
-                                          struct s3c2410_uartcfg *cfg)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
-       return (info->reset_port)(port, cfg);
-}
-
-
-#ifdef CONFIG_CPU_FREQ
-
-static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
-                                            unsigned long val, void *data)
-{
-       struct s3c24xx_uart_port *port;
-       struct uart_port *uport;
-
-       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
-       uport = &port->port;
-
-       /* check to see if port is enabled */
-
-       if (port->pm_level != 0)
-               return 0;
-
-       /* try and work out if the baudrate is changing, we can detect
-        * a change in rate, but we do not have support for detecting
-        * a disturbance in the clock-rate over the change.
-        */
-
-       if (IS_ERR(port->clk))
-               goto exit;
-
-       if (port->baudclk_rate == clk_get_rate(port->clk))
-               goto exit;
-
-       if (val == CPUFREQ_PRECHANGE) {
-               /* we should really shut the port down whilst the
-                * frequency change is in progress. */
-
-       } else if (val == CPUFREQ_POSTCHANGE) {
-               struct ktermios *termios;
-               struct tty_struct *tty;
-
-               if (uport->state == NULL)
-                       goto exit;
-
-               tty = uport->state->port.tty;
-
-               if (tty == NULL)
-                       goto exit;
-
-               termios = tty->termios;
-
-               if (termios == NULL) {
-                       printk(KERN_WARNING "%s: no termios?\n", __func__);
-                       goto exit;
-               }
-
-               s3c24xx_serial_set_termios(uport, termios, NULL);
-       }
-
- exit:
-       return 0;
-}
-
-static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
-
-       return cpufreq_register_notifier(&port->freq_transition,
-                                        CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-       cpufreq_unregister_notifier(&port->freq_transition,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
-{
-       return 0;
-}
-
-static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
-{
-}
-#endif
-
-/* s3c24xx_serial_init_port
- *
- * initialise a single serial port from the platform device given
- */
-
-static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
-                                   struct s3c24xx_uart_info *info,
-                                   struct platform_device *platdev)
-{
-       struct uart_port *port = &ourport->port;
-       struct s3c2410_uartcfg *cfg;
-       struct resource *res;
-       int ret;
-
-       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
-
-       if (platdev == NULL)
-               return -ENODEV;
-
-       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
-
-       if (port->mapbase != 0)
-               return 0;
-
-       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
-               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
-                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
-               return -ERANGE;
-       }
-
-       /* setup info for port */
-       port->dev       = &platdev->dev;
-       ourport->info   = info;
-
-       /* copy the info in from provided structure */
-       ourport->port.fifosize = info->fifosize;
-
-       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
-
-       port->uartclk = 1;
-
-       if (cfg->uart_flags & UPF_CONS_FLOW) {
-               dbg("s3c24xx_serial_init_port: enabling flow control\n");
-               port->flags |= UPF_CONS_FLOW;
-       }
-
-       /* sort our the physical and virtual addresses for each UART */
-
-       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               printk(KERN_ERR "failed to find memory resource for uart\n");
-               return -EINVAL;
-       }
-
-       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
-
-       port->mapbase = res->start;
-       port->membase = S3C_VA_UART + (res->start & 0xfffff);
-       ret = platform_get_irq(platdev, 0);
-       if (ret < 0)
-               port->irq = 0;
-       else {
-               port->irq = ret;
-               ourport->rx_irq = ret;
-               ourport->tx_irq = ret + 1;
-       }
-       
-       ret = platform_get_irq(platdev, 1);
-       if (ret > 0)
-               ourport->tx_irq = ret;
-
-       ourport->clk    = clk_get(&platdev->dev, "uart");
-
-       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
-           port->mapbase, port->membase, port->irq,
-           ourport->rx_irq, ourport->tx_irq, port->uartclk);
-
-       /* reset the fifos (and setup the uart) */
-       s3c24xx_serial_resetport(port, cfg);
-       return 0;
-}
-
-static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
-                                         struct device_attribute *attr,
-                                         char *buf)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
-}
-
-static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
-
-/* Device driver serial port probe */
-
-static int probe_index;
-
-int s3c24xx_serial_probe(struct platform_device *dev,
-                        struct s3c24xx_uart_info *info)
-{
-       struct s3c24xx_uart_port *ourport;
-       int ret;
-
-       dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
-
-       ourport = &s3c24xx_serial_ports[probe_index];
-       probe_index++;
-
-       dbg("%s: initialising port %p...\n", __func__, ourport);
-
-       ret = s3c24xx_serial_init_port(ourport, info, dev);
-       if (ret < 0)
-               goto probe_err;
-
-       dbg("%s: adding port\n", __func__);
-       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
-       platform_set_drvdata(dev, &ourport->port);
-
-       ret = device_create_file(&dev->dev, &dev_attr_clock_source);
-       if (ret < 0)
-               printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
-
-       ret = s3c24xx_serial_cpufreq_register(ourport);
-       if (ret < 0)
-               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
-
-       return 0;
-
- probe_err:
-       return ret;
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
-
-int __devexit s3c24xx_serial_remove(struct platform_device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-
-       if (port) {
-               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
-               device_remove_file(&dev->dev, &dev_attr_clock_source);
-               uart_remove_one_port(&s3c24xx_uart_drv, port);
-       }
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
-
-/* UART power management code */
-
-#ifdef CONFIG_PM
-
-static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-
-       if (port)
-               uart_suspend_port(&s3c24xx_uart_drv, port);
-
-       return 0;
-}
-
-static int s3c24xx_serial_resume(struct platform_device *dev)
-{
-       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
-       struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-       if (port) {
-               clk_enable(ourport->clk);
-               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
-               clk_disable(ourport->clk);
-
-               uart_resume_port(&s3c24xx_uart_drv, port);
-       }
-
-       return 0;
-}
-#endif
-
-int s3c24xx_serial_init(struct platform_driver *drv,
-                       struct s3c24xx_uart_info *info)
-{
-       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
-
-#ifdef CONFIG_PM
-       drv->suspend = s3c24xx_serial_suspend;
-       drv->resume = s3c24xx_serial_resume;
-#endif
-
-       return platform_driver_register(drv);
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
-
-/* module initialisation code */
-
-static int __init s3c24xx_serial_modinit(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&s3c24xx_uart_drv);
-       if (ret < 0) {
-               printk(KERN_ERR "failed to register UART driver\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void __exit s3c24xx_serial_modexit(void)
-{
-       uart_unregister_driver(&s3c24xx_uart_drv);
-}
-
-module_init(s3c24xx_serial_modinit);
-module_exit(s3c24xx_serial_modexit);
-
-/* Console code */
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-static struct uart_port *cons_uart;
-
-static int
-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
-{
-       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat, utrstat;
-
-       if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               /* fifo mode - check amount of data in fifo registers... */
-
-               ufstat = rd_regl(port, S3C2410_UFSTAT);
-               return (ufstat & info->tx_fifofull) ? 0 : 1;
-       }
-
-       /* in non-fifo mode, we go and use the tx buffer empty */
-
-       utrstat = rd_regl(port, S3C2410_UTRSTAT);
-       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
-}
-
-static void
-s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
-{
-       unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
-       while (!s3c24xx_serial_console_txrdy(port, ufcon))
-               barrier();
-       wr_regb(cons_uart, S3C2410_UTXH, ch);
-}
-
-static void
-s3c24xx_serial_console_write(struct console *co, const char *s,
-                            unsigned int count)
-{
-       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
-}
-
-static void __init
-s3c24xx_serial_get_options(struct uart_port *port, int *baud,
-                          int *parity, int *bits)
-{
-       struct s3c24xx_uart_clksrc clksrc;
-       struct clk *clk;
-       unsigned int ulcon;
-       unsigned int ucon;
-       unsigned int ubrdiv;
-       unsigned long rate;
-
-       ulcon  = rd_regl(port, S3C2410_ULCON);
-       ucon   = rd_regl(port, S3C2410_UCON);
-       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
-
-       dbg("s3c24xx_serial_get_options: port=%p\n"
-           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
-           port, ulcon, ucon, ubrdiv);
-
-       if ((ucon & 0xf) != 0) {
-               /* consider the serial port configured if the tx/rx mode set */
-
-               switch (ulcon & S3C2410_LCON_CSMASK) {
-               case S3C2410_LCON_CS5:
-                       *bits = 5;
-                       break;
-               case S3C2410_LCON_CS6:
-                       *bits = 6;
-                       break;
-               case S3C2410_LCON_CS7:
-                       *bits = 7;
-                       break;
-               default:
-               case S3C2410_LCON_CS8:
-                       *bits = 8;
-                       break;
-               }
-
-               switch (ulcon & S3C2410_LCON_PMASK) {
-               case S3C2410_LCON_PEVEN:
-                       *parity = 'e';
-                       break;
-
-               case S3C2410_LCON_PODD:
-                       *parity = 'o';
-                       break;
-
-               case S3C2410_LCON_PNONE:
-               default:
-                       *parity = 'n';
-               }
-
-               /* now calculate the baud rate */
-
-               s3c24xx_serial_getsource(port, &clksrc);
-
-               clk = clk_get(port->dev, clksrc.name);
-               if (!IS_ERR(clk) && clk != NULL)
-                       rate = clk_get_rate(clk) / clksrc.divisor;
-               else
-                       rate = 1;
-
-
-               *baud = rate / (16 * (ubrdiv + 1));
-               dbg("calculated baud %d\n", *baud);
-       }
-
-}
-
-/* s3c24xx_serial_init_ports
- *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
-
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
-{
-       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
-       struct platform_device **platdev_ptr;
-       int i;
-
-       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
-
-       platdev_ptr = s3c24xx_uart_devs;
-
-       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
-               s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
-       }
-
-       return 0;
-}
-
-static int __init
-s3c24xx_serial_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
-           co, co->index, options);
-
-       /* is this a valid port */
-
-       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
-               co->index = 0;
-
-       port = &s3c24xx_serial_ports[co->index].port;
-
-       /* is the port configured? */
-
-       if (port->mapbase == 0x0) {
-               co->index = 0;
-               port = &s3c24xx_serial_ports[co->index].port;
-       }
-
-       cons_uart = port;
-
-       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
-
-       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-/* s3c24xx_serial_initconsole
- *
- * initialise the console from one of the uart drivers
-*/
-
-static struct console s3c24xx_serial_console = {
-       .name           = S3C24XX_SERIAL_NAME,
-       .device         = uart_console_device,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .write          = s3c24xx_serial_console_write,
-       .setup          = s3c24xx_serial_console_setup
-};
-
-int s3c24xx_serial_initconsole(struct platform_driver *drv,
-                              struct s3c24xx_uart_info **info)
-
-{
-       struct platform_device *dev = s3c24xx_uart_devs[0];
-
-       dbg("s3c24xx_serial_initconsole\n");
-
-       /* select driver based on the cpu */
-
-       if (dev == NULL) {
-               printk(KERN_ERR "s3c24xx: no devices for console init\n");
-               return 0;
-       }
-
-       if (strcmp(dev->name, drv->driver.name) != 0)
-               return 0;
-
-       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
-       s3c24xx_serial_init_ports(info);
-
-       register_console(&s3c24xx_serial_console);
-       return 0;
-}
-
-#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
-
-MODULE_DESCRIPTION("Samsung SoC Serial port driver");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
deleted file mode 100644 (file)
index 0ac06a0..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* linux/drivers/serial/samsung.h
- *
- * Driver for Samsung SoC onboard UARTs.
- *
- * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *
- * 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.
-*/
-
-struct s3c24xx_uart_info {
-       char                    *name;
-       unsigned int            type;
-       unsigned int            fifosize;
-       unsigned long           rx_fifomask;
-       unsigned long           rx_fifoshift;
-       unsigned long           rx_fifofull;
-       unsigned long           tx_fifomask;
-       unsigned long           tx_fifoshift;
-       unsigned long           tx_fifofull;
-
-       /* uart port features */
-
-       unsigned int            has_divslot:1;
-
-       /* clock source control */
-
-       int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
-       int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
-
-       /* uart controls */
-       int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
-};
-
-struct s3c24xx_uart_port {
-       unsigned char                   rx_claimed;
-       unsigned char                   tx_claimed;
-       unsigned int                    pm_level;
-       unsigned long                   baudclk_rate;
-
-       unsigned int                    rx_irq;
-       unsigned int                    tx_irq;
-
-       struct s3c24xx_uart_info        *info;
-       struct s3c24xx_uart_clksrc      *clksrc;
-       struct clk                      *clk;
-       struct clk                      *baudclk;
-       struct uart_port                port;
-
-#ifdef CONFIG_CPU_FREQ
-       struct notifier_block           freq_transition;
-#endif
-};
-
-/* conversion functions */
-
-#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
-#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
-
-/* register access controls */
-
-#define portaddr(port, reg) ((port)->membase + (reg))
-
-#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
-#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
-
-#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
-#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
-
-extern int s3c24xx_serial_probe(struct platform_device *dev,
-                               struct s3c24xx_uart_info *uart);
-
-extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
-
-extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
-                                     struct s3c24xx_uart_info **uart);
-
-extern int s3c24xx_serial_init(struct platform_driver *drv,
-                              struct s3c24xx_uart_info *info);
-
-#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-
-#define s3c24xx_console_init(__drv, __inf)                             \
-static int __init s3c_serial_console_init(void)                                \
-{                                                                      \
-       struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS];   \
-       int i;                                                          \
-                                                                       \
-       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)               \
-               uinfo[i] = __inf;                                       \
-       return s3c24xx_serial_initconsole(__drv, uinfo);                \
-}                                                                      \
-                                                                       \
-console_initcall(s3c_serial_console_init)
-
-#else
-#define s3c24xx_console_init(drv, inf) extern void no_console(void)
-#endif
-
-#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
-
-extern void printascii(const char *);
-
-static void dbg(const char *fmt, ...)
-{
-       va_list va;
-       char buff[256];
-
-       va_start(va, fmt);
-       vsprintf(buff, fmt, va);
-       va_end(va);
-
-       printascii(buff);
-}
-
-#else
-#define dbg(x...) do { } while (0)
-#endif
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
deleted file mode 100644 (file)
index a2f2b32..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- *     drivers/serial/sb1250-duart.c
- *
- *     Support for the asynchronous serial interface (DUART) included
- *     in the BCM1250 and derived System-On-a-Chip (SOC) devices.
- *
- *     Copyright (c) 2007  Maciej W. Rozycki
- *
- *     Derived from drivers/char/sb1250_duart.c for which the following
- *     copyright applies:
- *
- *     Copyright (c) 2000, 2001, 2002, 2003, 2004  Broadcom Corporation
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     References:
- *
- *     "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation
- */
-
-#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/compiler.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/war.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_uart.h>
-#include <asm/sibyte/swarm.h>
-
-
-#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
-#include <asm/sibyte/bcm1480_regs.h>
-#include <asm/sibyte/bcm1480_int.h>
-
-#define SBD_CHANREGS(line)     A_BCM1480_DUART_CHANREG((line), 0)
-#define SBD_CTRLREGS(line)     A_BCM1480_DUART_CTRLREG((line), 0)
-#define SBD_INT(line)          (K_BCM1480_INT_UART_0 + (line))
-
-#define DUART_CHANREG_SPACING  BCM1480_DUART_CHANREG_SPACING
-
-#define R_DUART_IMRREG(line)   R_BCM1480_DUART_IMRREG(line)
-#define R_DUART_INCHREG(line)  R_BCM1480_DUART_INCHREG(line)
-#define R_DUART_ISRREG(line)   R_BCM1480_DUART_ISRREG(line)
-
-#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-
-#define SBD_CHANREGS(line)     A_DUART_CHANREG((line), 0)
-#define SBD_CTRLREGS(line)     A_DUART_CTRLREG(0)
-#define SBD_INT(line)          (K_INT_UART_0 + (line))
-
-#else
-#error invalid SB1250 UART configuration
-
-#endif
-
-
-MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
-MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver");
-MODULE_LICENSE("GPL");
-
-
-#define DUART_MAX_CHIP 2
-#define DUART_MAX_SIDE 2
-
-/*
- * Per-port state.
- */
-struct sbd_port {
-       struct sbd_duart        *duart;
-       struct uart_port        port;
-       unsigned char __iomem   *memctrl;
-       int                     tx_stopped;
-       int                     initialised;
-};
-
-/*
- * Per-DUART state for the shared register space.
- */
-struct sbd_duart {
-       struct sbd_port         sport[2];
-       unsigned long           mapctrl;
-       atomic_t                map_guard;
-};
-
-#define to_sport(uport) container_of(uport, struct sbd_port, port)
-
-static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
-
-
-/*
- * Reading and writing SB1250 DUART registers.
- *
- * There are three register spaces: two per-channel ones and
- * a shared one.  We have to define accessors appropriately.
- * All registers are 64-bit and all but the Baud Rate Clock
- * registers only define 8 least significant bits.  There is
- * also a workaround to take into account.  Raw accessors use
- * the full register width, but cooked ones truncate it
- * intentionally so that the rest of the driver does not care.
- */
-static u64 __read_sbdchn(struct sbd_port *sport, int reg)
-{
-       void __iomem *csr = sport->port.membase + reg;
-
-       return __raw_readq(csr);
-}
-
-static u64 __read_sbdshr(struct sbd_port *sport, int reg)
-{
-       void __iomem *csr = sport->memctrl + reg;
-
-       return __raw_readq(csr);
-}
-
-static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value)
-{
-       void __iomem *csr = sport->port.membase + reg;
-
-       __raw_writeq(value, csr);
-}
-
-static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value)
-{
-       void __iomem *csr = sport->memctrl + reg;
-
-       __raw_writeq(value, csr);
-}
-
-/*
- * In bug 1956, we get glitches that can mess up uart registers.  This
- * "read-mode-reg after any register access" is an accepted workaround.
- */
-static void __war_sbd1956(struct sbd_port *sport)
-{
-       __read_sbdchn(sport, R_DUART_MODE_REG_1);
-       __read_sbdchn(sport, R_DUART_MODE_REG_2);
-}
-
-static unsigned char read_sbdchn(struct sbd_port *sport, int reg)
-{
-       unsigned char retval;
-
-       retval = __read_sbdchn(sport, reg);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-       return retval;
-}
-
-static unsigned char read_sbdshr(struct sbd_port *sport, int reg)
-{
-       unsigned char retval;
-
-       retval = __read_sbdshr(sport, reg);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-       return retval;
-}
-
-static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value)
-{
-       __write_sbdchn(sport, reg, value);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-}
-
-static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value)
-{
-       __write_sbdshr(sport, reg, value);
-       if (SIBYTE_1956_WAR)
-               __war_sbd1956(sport);
-}
-
-
-static int sbd_receive_ready(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY;
-}
-
-static int sbd_receive_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (sbd_receive_ready(sport) && --loops)
-               read_sbdchn(sport, R_DUART_RX_HOLD);
-       return loops;
-}
-
-static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
-}
-
-static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (!sbd_transmit_ready(sport) && --loops)
-               udelay(2);
-       return loops;
-}
-
-static int sbd_transmit_empty(struct sbd_port *sport)
-{
-       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT;
-}
-
-static int sbd_line_drain(struct sbd_port *sport)
-{
-       int loops = 10000;
-
-       while (!sbd_transmit_empty(sport) && --loops)
-               udelay(2);
-       return loops;
-}
-
-
-static unsigned int sbd_tx_empty(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int sbd_get_mctrl(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mctrl, status;
-
-       status = read_sbdshr(sport, R_DUART_IN_PORT);
-       status >>= (uport->line) % 2;
-       mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) |
-               (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) |
-               (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) |
-               (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0);
-       return mctrl;
-}
-
-static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int clr = 0, set = 0, mode2;
-
-       if (mctrl & TIOCM_DTR)
-               set |= M_DUART_SET_OPR2;
-       else
-               clr |= M_DUART_CLR_OPR2;
-       if (mctrl & TIOCM_RTS)
-               set |= M_DUART_SET_OPR0;
-       else
-               clr |= M_DUART_CLR_OPR0;
-       clr <<= (uport->line) % 2;
-       set <<= (uport->line) % 2;
-
-       mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2);
-       mode2 &= ~M_DUART_CHAN_MODE;
-       if (mctrl & TIOCM_LOOP)
-               mode2 |= V_DUART_CHAN_MODE_LCL_LOOP;
-       else
-               mode2 |= V_DUART_CHAN_MODE_NORMAL;
-
-       write_sbdshr(sport, R_DUART_CLEAR_OPR, clr);
-       write_sbdshr(sport, R_DUART_SET_OPR, set);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2);
-}
-
-static void sbd_stop_tx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
-       sport->tx_stopped = 1;
-};
-
-static void sbd_start_tx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mask;
-
-       /* Enable tx interrupts.  */
-       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-       mask |= M_DUART_IMR_TX;
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-
-       /* Go!, go!, go!...  */
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
-       sport->tx_stopped = 0;
-};
-
-static void sbd_stop_rx(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
-};
-
-static void sbd_enable_ms(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_AUXCTL_X,
-                    M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA);
-}
-
-static void sbd_break_ctl(struct uart_port *uport, int break_state)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       if (break_state == -1)
-               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK);
-       else
-               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK);
-}
-
-
-static void sbd_receive_chars(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       struct uart_icount *icount;
-       unsigned int status, ch, flag;
-       int count;
-
-       for (count = 16; count; count--) {
-               status = read_sbdchn(sport, R_DUART_STATUS);
-               if (!(status & M_DUART_RX_RDY))
-                       break;
-
-               ch = read_sbdchn(sport, R_DUART_RX_HOLD);
-
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               if (unlikely(status &
-                            (M_DUART_RCVD_BRK | M_DUART_FRM_ERR |
-                             M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) {
-                       if (status & M_DUART_RCVD_BRK) {
-                               icount->brk++;
-                               if (uart_handle_break(uport))
-                                       continue;
-                       } else if (status & M_DUART_FRM_ERR)
-                               icount->frame++;
-                       else if (status & M_DUART_PARITY_ERR)
-                               icount->parity++;
-                       if (status & M_DUART_OVRUN_ERR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & M_DUART_RCVD_BRK)
-                               flag = TTY_BREAK;
-                       else if (status & M_DUART_FRM_ERR)
-                               flag = TTY_FRAME;
-                       else if (status & M_DUART_PARITY_ERR)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
-       }
-
-       tty_flip_buffer_push(uport->state->port.tty);
-}
-
-static void sbd_transmit_chars(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       struct circ_buf *xmit = &sport->port.state->xmit;
-       unsigned int mask;
-       int stop_tx;
-
-       /* XON/XOFF chars.  */
-       if (sport->port.x_char) {
-               write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char);
-               sport->port.icount.tx++;
-               sport->port.x_char = 0;
-               return;
-       }
-
-       /* If nothing to do or stopped or hardware stopped.  */
-       stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
-
-       /* Send char.  */
-       if (!stop_tx) {
-               write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               sport->port.icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&sport->port);
-       }
-
-       /* Are we are done?  */
-       if (stop_tx || uart_circ_empty(xmit)) {
-               /* Disable tx interrupts.  */
-               mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-               mask &= ~M_DUART_IMR_TX;
-               write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-       }
-}
-
-static void sbd_status_handle(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-       unsigned int delta;
-
-       delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
-       delta >>= (uport->line) % 2;
-
-       if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
-               uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));
-
-       if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
-               uport->icount.dsr++;
-
-       if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
-                    S_DUART_IN_PIN_CHNG))
-               wake_up_interruptible(&uport->state->port.delta_msr_wait);
-}
-
-static irqreturn_t sbd_interrupt(int irq, void *dev_id)
-{
-       struct sbd_port *sport = dev_id;
-       struct uart_port *uport = &sport->port;
-       irqreturn_t status = IRQ_NONE;
-       unsigned int intstat;
-       int count;
-
-       for (count = 16; count; count--) {
-               intstat = read_sbdshr(sport,
-                                     R_DUART_ISRREG((uport->line) % 2));
-               intstat &= read_sbdshr(sport,
-                                      R_DUART_IMRREG((uport->line) % 2));
-               intstat &= M_DUART_ISR_ALL;
-               if (!intstat)
-                       break;
-
-               if (intstat & M_DUART_ISR_RX)
-                       sbd_receive_chars(sport);
-               if (intstat & M_DUART_ISR_IN)
-                       sbd_status_handle(sport);
-               if (intstat & M_DUART_ISR_TX)
-                       sbd_transmit_chars(sport);
-
-               status = IRQ_HANDLED;
-       }
-
-       return status;
-}
-
-
-static int sbd_startup(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mode1;
-       int ret;
-
-       ret = request_irq(sport->port.irq, sbd_interrupt,
-                         IRQF_SHARED, "sb1250-duart", sport);
-       if (ret)
-               return ret;
-
-       /* Clear the receive FIFO.  */
-       sbd_receive_drain(sport);
-
-       /* Clear the interrupt registers.  */
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);
-       read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
-
-       /* Set rx/tx interrupt to FIFO available.  */
-       mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);
-       mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);
-       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);
-
-       /* Disable tx, enable rx.  */
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);
-       sport->tx_stopped = 1;
-
-       /* Enable interrupts.  */
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
-                    M_DUART_IMR_IN | M_DUART_IMR_RX);
-
-       return 0;
-}
-
-static void sbd_shutdown(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
-       sport->tx_stopped = 1;
-       free_irq(sport->port.irq, sport);
-}
-
-
-static void sbd_init_port(struct sbd_port *sport)
-{
-       struct uart_port *uport = &sport->port;
-
-       if (sport->initialised)
-               return;
-
-       /* There is no DUART reset feature, so just set some sane defaults.  */
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);
-       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);
-       write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, 0);
-       write_sbdchn(sport, R_DUART_FULL_CTL,
-                    V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));
-       write_sbdchn(sport, R_DUART_OPCR_X, 0);
-       write_sbdchn(sport, R_DUART_AUXCTL_X, 0);
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
-
-       sport->initialised = 1;
-}
-
-static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
-                           struct ktermios *old_termios)
-{
-       struct sbd_port *sport = to_sport(uport);
-       unsigned int mode1 = 0, mode2 = 0, aux = 0;
-       unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;
-       unsigned int oldmode1, oldmode2, oldaux;
-       unsigned int baud, brg;
-       unsigned int command;
-
-       mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |
-                      M_DUART_BITS_PER_CHAR);
-       mode2mask |= ~M_DUART_STOP_BIT_LEN_2;
-       auxmask |= ~M_DUART_CTS_CHNG_ENA;
-
-       /* Byte size.  */
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-       case CS6:
-               /* Unsupported, leave unchanged.  */
-               mode1mask |= M_DUART_PARITY_MODE;
-               break;
-       case CS7:
-               mode1 |= V_DUART_BITS_PER_CHAR_7;
-               break;
-       case CS8:
-       default:
-               mode1 |= V_DUART_BITS_PER_CHAR_8;
-               break;
-       }
-
-       /* Parity and stop bits.  */
-       if (termios->c_cflag & CSTOPB)
-               mode2 |= M_DUART_STOP_BIT_LEN_2;
-       else
-               mode2 |= M_DUART_STOP_BIT_LEN_1;
-       if (termios->c_cflag & PARENB)
-               mode1 |= V_DUART_PARITY_MODE_ADD;
-       else
-               mode1 |= V_DUART_PARITY_MODE_NONE;
-       if (termios->c_cflag & PARODD)
-               mode1 |= M_DUART_PARITY_TYPE_ODD;
-       else
-               mode1 |= M_DUART_PARITY_TYPE_EVEN;
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);
-       brg = V_DUART_BAUD_RATE(baud);
-       /* The actual lower bound is 1221bps, so compensate.  */
-       if (brg > M_DUART_CLK_COUNTER)
-               brg = M_DUART_CLK_COUNTER;
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       uport->read_status_mask = M_DUART_OVRUN_ERR;
-       if (termios->c_iflag & INPCK)
-               uport->read_status_mask |= M_DUART_FRM_ERR |
-                                          M_DUART_PARITY_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uport->read_status_mask |= M_DUART_RCVD_BRK;
-
-       uport->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uport->ignore_status_mask |= M_DUART_FRM_ERR |
-                                            M_DUART_PARITY_ERR;
-       if (termios->c_iflag & IGNBRK) {
-               uport->ignore_status_mask |= M_DUART_RCVD_BRK;
-               if (termios->c_iflag & IGNPAR)
-                       uport->ignore_status_mask |= M_DUART_OVRUN_ERR;
-       }
-
-       if (termios->c_cflag & CREAD)
-               command = M_DUART_RX_EN;
-       else
-               command = M_DUART_RX_DIS;
-
-       if (termios->c_cflag & CRTSCTS)
-               aux |= M_DUART_CTS_CHNG_ENA;
-       else
-               aux &= ~M_DUART_CTS_CHNG_ENA;
-
-       spin_lock(&uport->lock);
-
-       if (sport->tx_stopped)
-               command |= M_DUART_TX_DIS;
-       else
-               command |= M_DUART_TX_EN;
-
-       oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;
-       oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;
-       oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;
-
-       if (!sport->tx_stopped)
-               sbd_line_drain(sport);
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
-
-       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);
-       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);
-       write_sbdchn(sport, R_DUART_CLK_SEL, brg);
-       write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);
-
-       write_sbdchn(sport, R_DUART_CMD, command);
-
-       spin_unlock(&uport->lock);
-}
-
-
-static const char *sbd_type(struct uart_port *uport)
-{
-       return "SB1250 DUART";
-}
-
-static void sbd_release_port(struct uart_port *uport)
-{
-       struct sbd_port *sport = to_sport(uport);
-       struct sbd_duart *duart = sport->duart;
-       int map_guard;
-
-       iounmap(sport->memctrl);
-       sport->memctrl = NULL;
-       iounmap(uport->membase);
-       uport->membase = NULL;
-
-       map_guard = atomic_add_return(-1, &duart->map_guard);
-       if (!map_guard)
-               release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
-       release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
-}
-
-static int sbd_map_port(struct uart_port *uport)
-{
-       const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
-       struct sbd_port *sport = to_sport(uport);
-       struct sbd_duart *duart = sport->duart;
-
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                DUART_CHANREG_SPACING);
-       if (!uport->membase) {
-               printk(err);
-               return -ENOMEM;
-       }
-
-       if (!sport->memctrl)
-               sport->memctrl = ioremap_nocache(duart->mapctrl,
-                                                DUART_CHANREG_SPACING);
-       if (!sport->memctrl) {
-               printk(err);
-               iounmap(uport->membase);
-               uport->membase = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int sbd_request_port(struct uart_port *uport)
-{
-       const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
-       struct sbd_duart *duart = to_sport(uport)->duart;
-       int map_guard;
-       int ret = 0;
-
-       if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
-                               "sb1250-duart")) {
-               printk(err);
-               return -EBUSY;
-       }
-       map_guard = atomic_add_return(1, &duart->map_guard);
-       if (map_guard == 1) {
-               if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
-                                       "sb1250-duart")) {
-                       atomic_add(-1, &duart->map_guard);
-                       printk(err);
-                       ret = -EBUSY;
-               }
-       }
-       if (!ret) {
-               ret = sbd_map_port(uport);
-               if (ret) {
-                       map_guard = atomic_add_return(-1, &duart->map_guard);
-                       if (!map_guard)
-                               release_mem_region(duart->mapctrl,
-                                                  DUART_CHANREG_SPACING);
-               }
-       }
-       if (ret) {
-               release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
-               return ret;
-       }
-       return 0;
-}
-
-static void sbd_config_port(struct uart_port *uport, int flags)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (sbd_request_port(uport))
-                       return;
-
-               uport->type = PORT_SB1250_DUART;
-
-               sbd_init_port(sport);
-       }
-}
-
-static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       if (ser->baud_base != uport->uartclk / 16)
-               ret = -EINVAL;
-       return ret;
-}
-
-
-static const struct uart_ops sbd_ops = {
-       .tx_empty       = sbd_tx_empty,
-       .set_mctrl      = sbd_set_mctrl,
-       .get_mctrl      = sbd_get_mctrl,
-       .stop_tx        = sbd_stop_tx,
-       .start_tx       = sbd_start_tx,
-       .stop_rx        = sbd_stop_rx,
-       .enable_ms      = sbd_enable_ms,
-       .break_ctl      = sbd_break_ctl,
-       .startup        = sbd_startup,
-       .shutdown       = sbd_shutdown,
-       .set_termios    = sbd_set_termios,
-       .type           = sbd_type,
-       .release_port   = sbd_release_port,
-       .request_port   = sbd_request_port,
-       .config_port    = sbd_config_port,
-       .verify_port    = sbd_verify_port,
-};
-
-/* Initialize SB1250 DUART port structures.  */
-static void __init sbd_probe_duarts(void)
-{
-       static int probed;
-       int chip, side;
-       int max_lines, line;
-
-       if (probed)
-               return;
-
-       /* Set the number of available units based on the SOC type.  */
-       switch (soc_type) {
-       case K_SYS_SOC_TYPE_BCM1x55:
-       case K_SYS_SOC_TYPE_BCM1x80:
-               max_lines = 4;
-               break;
-       default:
-               /* Assume at least two serial ports at the normal address.  */
-               max_lines = 2;
-               break;
-       }
-
-       probed = 1;
-
-       for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;
-            chip++) {
-               sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);
-
-               for (side = 0; side < DUART_MAX_SIDE && line < max_lines;
-                    side++, line++) {
-                       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-                       struct uart_port *uport = &sport->port;
-
-                       sport->duart    = &sbd_duarts[chip];
-
-                       uport->irq      = SBD_INT(line);
-                       uport->uartclk  = 100000000 / 20 * 16;
-                       uport->fifosize = 16;
-                       uport->iotype   = UPIO_MEM;
-                       uport->flags    = UPF_BOOT_AUTOCONF;
-                       uport->ops      = &sbd_ops;
-                       uport->line     = line;
-                       uport->mapbase  = SBD_CHANREGS(line);
-               }
-       }
-}
-
-
-#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
-/*
- * Serial console stuff.  Very basic, polling driver for doing serial
- * console output.  The console_sem is held by the caller, so we
- * shouldn't be interrupted for more console activity.
- */
-static void sbd_console_putchar(struct uart_port *uport, int ch)
-{
-       struct sbd_port *sport = to_sport(uport);
-
-       sbd_transmit_drain(sport);
-       write_sbdchn(sport, R_DUART_TX_HOLD, ch);
-}
-
-static void sbd_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       int chip = co->index / DUART_MAX_SIDE;
-       int side = co->index % DUART_MAX_SIDE;
-       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-       struct uart_port *uport = &sport->port;
-       unsigned long flags;
-       unsigned int mask;
-
-       /* Disable transmit interrupts and enable the transmitter. */
-       spin_lock_irqsave(&uport->lock, flags);
-       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
-                    mask & ~M_DUART_IMR_TX);
-       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
-       spin_unlock_irqrestore(&uport->lock, flags);
-
-       uart_console_write(&sport->port, s, count, sbd_console_putchar);
-
-       /* Restore transmit interrupts and the transmitter enable. */
-       spin_lock_irqsave(&uport->lock, flags);
-       sbd_line_drain(sport);
-       if (sport->tx_stopped)
-               write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
-       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
-       spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-static int __init sbd_console_setup(struct console *co, char *options)
-{
-       int chip = co->index / DUART_MAX_SIDE;
-       int side = co->index % DUART_MAX_SIDE;
-       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
-       struct uart_port *uport = &sport->port;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       if (!sport->duart)
-               return -ENXIO;
-
-       ret = sbd_map_port(uport);
-       if (ret)
-               return ret;
-
-       sbd_init_port(sport);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(uport, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver sbd_reg;
-static struct console sbd_console = {
-       .name   = "duart",
-       .write  = sbd_console_write,
-       .device = uart_console_device,
-       .setup  = sbd_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &sbd_reg
-};
-
-static int __init sbd_serial_console_init(void)
-{
-       sbd_probe_duarts();
-       register_console(&sbd_console);
-
-       return 0;
-}
-
-console_initcall(sbd_serial_console_init);
-
-#define SERIAL_SB1250_DUART_CONSOLE    &sbd_console
-#else
-#define SERIAL_SB1250_DUART_CONSOLE    NULL
-#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */
-
-
-static struct uart_driver sbd_reg = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "sb1250_duart",
-       .dev_name       = "duart",
-       .major          = TTY_MAJOR,
-       .minor          = SB1250_DUART_MINOR_BASE,
-       .nr             = DUART_MAX_CHIP * DUART_MAX_SIDE,
-       .cons           = SERIAL_SB1250_DUART_CONSOLE,
-};
-
-/* Set up the driver and register it.  */
-static int __init sbd_init(void)
-{
-       int i, ret;
-
-       sbd_probe_duarts();
-
-       ret = uart_register_driver(&sbd_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {
-               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
-               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
-               struct uart_port *uport = &sport->port;
-
-               if (sport->duart)
-                       uart_add_one_port(&sbd_reg, uport);
-       }
-
-       return 0;
-}
-
-/* Unload the driver.  Unregister stuff, get ready to go away.  */
-static void __exit sbd_exit(void)
-{
-       int i;
-
-       for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {
-               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
-               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
-               struct uart_port *uport = &sport->port;
-
-               if (sport->duart)
-                       uart_remove_one_port(&sbd_reg, uport);
-       }
-
-       uart_unregister_driver(&sbd_reg);
-}
-
-module_init(sbd_init);
-module_exit(sbd_exit);
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
deleted file mode 100644 (file)
index 75038ad..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
- *
- * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#define SC26XX_MAJOR         204
-#define SC26XX_MINOR_START   205
-#define SC26XX_NR            2
-
-struct uart_sc26xx_port {
-       struct uart_port      port[2];
-       u8     dsr_mask[2];
-       u8     cts_mask[2];
-       u8     dcd_mask[2];
-       u8     ri_mask[2];
-       u8     dtr_mask[2];
-       u8     rts_mask[2];
-       u8     imr;
-};
-
-/* register common to both ports */
-#define RD_ISR      0x14
-#define RD_IPR      0x34
-
-#define WR_ACR      0x10
-#define WR_IMR      0x14
-#define WR_OPCR     0x34
-#define WR_OPR_SET  0x38
-#define WR_OPR_CLR  0x3C
-
-/* access common register */
-#define READ_SC(p, r)        readb((p)->membase + RD_##r)
-#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
-
-/* register per port */
-#define RD_PORT_MRx 0x00
-#define RD_PORT_SR  0x04
-#define RD_PORT_RHR 0x0c
-
-#define WR_PORT_MRx 0x00
-#define WR_PORT_CSR 0x04
-#define WR_PORT_CR  0x08
-#define WR_PORT_THR 0x0c
-
-/* SR bits */
-#define SR_BREAK    (1 << 7)
-#define SR_FRAME    (1 << 6)
-#define SR_PARITY   (1 << 5)
-#define SR_OVERRUN  (1 << 4)
-#define SR_TXRDY    (1 << 2)
-#define SR_RXRDY    (1 << 0)
-
-#define CR_RES_MR   (1 << 4)
-#define CR_RES_RX   (2 << 4)
-#define CR_RES_TX   (3 << 4)
-#define CR_STRT_BRK (6 << 4)
-#define CR_STOP_BRK (7 << 4)
-#define CR_DIS_TX   (1 << 3)
-#define CR_ENA_TX   (1 << 2)
-#define CR_DIS_RX   (1 << 1)
-#define CR_ENA_RX   (1 << 0)
-
-/* ISR bits */
-#define ISR_RXRDYB  (1 << 5)
-#define ISR_TXRDYB  (1 << 4)
-#define ISR_RXRDYA  (1 << 1)
-#define ISR_TXRDYA  (1 << 0)
-
-/* IMR bits */
-#define IMR_RXRDY   (1 << 1)
-#define IMR_TXRDY   (1 << 0)
-
-/* access port register */
-static inline u8 read_sc_port(struct uart_port *p, u8 reg)
-{
-       return readb(p->membase + p->line * 0x20 + reg);
-}
-
-static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
-{
-       writeb(val, p->membase + p->line * 0x20 + reg);
-}
-
-#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
-#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
-
-static void sc26xx_enable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr |= mask << (line * 4);
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static void sc26xx_disable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr &= ~(mask << (line * 4));
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static struct tty_struct *receive_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = NULL;
-       int limit = 10000;
-       unsigned char ch;
-       char flag;
-       u8 status;
-
-       if (port->state != NULL)                /* Unopened serial console */
-               tty = port->state->port.tty;
-
-       while (limit-- > 0) {
-               status = READ_SC_PORT(port, SR);
-               if (!(status & SR_RXRDY))
-                       break;
-               ch = READ_SC_PORT(port, RHR);
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(status & (SR_BREAK | SR_FRAME |
-                                      SR_PARITY | SR_OVERRUN))) {
-                       if (status & SR_BREAK) {
-                               status &= ~(SR_PARITY | SR_FRAME);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & SR_PARITY)
-                               port->icount.parity++;
-                       else if (status & SR_FRAME)
-                               port->icount.frame++;
-                       if (status & SR_OVERRUN)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-                       if (status & SR_BREAK)
-                               flag = TTY_BREAK;
-                       else if (status & SR_PARITY)
-                               flag = TTY_PARITY;
-                       else if (status & SR_FRAME)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-
-               if (status & port->ignore_status_mask)
-                       continue;
-
-               tty_insert_flip_char(tty, ch, flag);
-       }
-       return tty;
-}
-
-static void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-
-       if (!port->state)
-               return;
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               sc26xx_disable_irq(port, IMR_TXRDY);
-               return;
-       }
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
-                       break;
-
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
-{
-       struct uart_sc26xx_port *up = dev_id;
-       struct tty_struct *tty;
-       unsigned long flags;
-       u8 isr;
-
-       spin_lock_irqsave(&up->port[0].lock, flags);
-
-       tty = NULL;
-       isr = READ_SC(&up->port[0], ISR);
-       if (isr & ISR_TXRDYA)
-           transmit_chars(&up->port[0]);
-       if (isr & ISR_RXRDYA)
-           tty = receive_chars(&up->port[0]);
-
-       spin_unlock(&up->port[0].lock);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       spin_lock(&up->port[1].lock);
-
-       tty = NULL;
-       if (isr & ISR_TXRDYB)
-           transmit_chars(&up->port[1]);
-       if (isr & ISR_RXRDYB)
-           tty = receive_chars(&up->port[1]);
-
-       spin_unlock_irqrestore(&up->port[1].lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sc26xx_tx_empty(struct uart_port *port)
-{
-       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       if (up->dtr_mask[line]) {
-               if (mctrl & TIOCM_DTR)
-                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
-       }
-       if (up->rts_mask[line]) {
-               if (mctrl & TIOCM_RTS)
-                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
-       }
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sc26xx_get_mctrl(struct uart_port *port)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
-       u8 ipr;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-       ipr = READ_SC(port, IPR) ^ 0xff;
-
-       if (up->dsr_mask[line]) {
-               mctrl &= ~TIOCM_DSR;
-               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
-       }
-       if (up->cts_mask[line]) {
-               mctrl &= ~TIOCM_CTS;
-               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
-       }
-       if (up->dcd_mask[line]) {
-               mctrl &= ~TIOCM_CAR;
-               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
-       }
-       if (up->ri_mask[line]) {
-               mctrl &= ~TIOCM_RNG;
-               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
-       }
-       return mctrl;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_start_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
-                       sc26xx_enable_irq(port, IMR_TXRDY);
-                       break;
-               }
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_rx(struct uart_port *port)
-{
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_enable_ms(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sc26xx_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state == -1)
-               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
-       else
-               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
-}
-
-/* port->lock is not held.  */
-static int sc26xx_startup(struct uart_port *port)
-{
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-       WRITE_SC(port, OPCR, 0);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       /* start rx/tx */
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-
-       /* enable irqs */
-       sc26xx_enable_irq(port, IMR_RXRDY);
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sc26xx_shutdown(struct uart_port *port)
-{
-       /* disable interrupst */
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-
-       /* stop tx/rx */
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-}
-
-/* port->lock is not held.  */
-static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-       unsigned int iflag, cflag;
-       unsigned long flags;
-       u8 mr1, mr2, csr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-
-       iflag = termios->c_iflag;
-       cflag = termios->c_cflag;
-
-       port->read_status_mask = SR_OVERRUN;
-       if (iflag & INPCK)
-               port->read_status_mask |= SR_PARITY | SR_FRAME;
-       if (iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= SR_BREAK;
-
-       port->ignore_status_mask = 0;
-       if (iflag & IGNBRK)
-               port->ignore_status_mask |= SR_BREAK;
-       if ((cflag & CREAD) == 0)
-               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
-                                           SR_PARITY | SR_OVERRUN;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               mr1 = 0x00;
-               break;
-       case CS6:
-               mr1 = 0x01;
-               break;
-       case CS7:
-               mr1 = 0x02;
-               break;
-       default:
-       case CS8:
-               mr1 = 0x03;
-               break;
-       }
-       mr2 = 0x07;
-       if (cflag & CSTOPB)
-               mr2 = 0x0f;
-       if (cflag & PARENB) {
-               if (cflag & PARODD)
-                       mr1 |= (1 << 2);
-       } else
-               mr1 |= (2 << 3);
-
-       switch (baud) {
-       case 50:
-               csr = 0x00;
-               break;
-       case 110:
-               csr = 0x11;
-               break;
-       case 134:
-               csr = 0x22;
-               break;
-       case 200:
-               csr = 0x33;
-               break;
-       case 300:
-               csr = 0x44;
-               break;
-       case 600:
-               csr = 0x55;
-               break;
-       case 1200:
-               csr = 0x66;
-               break;
-       case 2400:
-               csr = 0x88;
-               break;
-       case 4800:
-               csr = 0x99;
-               break;
-       default:
-       case 9600:
-               csr = 0xbb;
-               break;
-       case 19200:
-               csr = 0xcc;
-               break;
-       }
-
-       WRITE_SC_PORT(port, CR, CR_RES_MR);
-       WRITE_SC_PORT(port, MRx, mr1);
-       WRITE_SC_PORT(port, MRx, mr2);
-
-       WRITE_SC(port, ACR, 0x80);
-       WRITE_SC_PORT(port, CSR, csr);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       /* XXX */
-       uart_update_timeout(port, cflag,
-                           (port->uartclk / (16 * quot)));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *sc26xx_type(struct uart_port *port)
-{
-       return "SC26XX";
-}
-
-static void sc26xx_release_port(struct uart_port *port)
-{
-}
-
-static int sc26xx_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sc26xx_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sc26xx_ops = {
-       .tx_empty       = sc26xx_tx_empty,
-       .set_mctrl      = sc26xx_set_mctrl,
-       .get_mctrl      = sc26xx_get_mctrl,
-       .stop_tx        = sc26xx_stop_tx,
-       .start_tx       = sc26xx_start_tx,
-       .stop_rx        = sc26xx_stop_rx,
-       .enable_ms      = sc26xx_enable_ms,
-       .break_ctl      = sc26xx_break_ctl,
-       .startup        = sc26xx_startup,
-       .shutdown       = sc26xx_shutdown,
-       .set_termios    = sc26xx_set_termios,
-       .type           = sc26xx_type,
-       .release_port   = sc26xx_release_port,
-       .request_port   = sc26xx_request_port,
-       .config_port    = sc26xx_config_port,
-       .verify_port    = sc26xx_verify_port,
-};
-
-static struct uart_port *sc26xx_port;
-
-#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
-static void sc26xx_console_putchar(struct uart_port *port, char c)
-{
-       unsigned long flags;
-       int limit = 1000000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (limit-- > 0) {
-               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
-                       WRITE_SC_PORT(port, THR, c);
-                       break;
-               }
-               udelay(2);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sc26xx_port;
-       int i;
-
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sc26xx_console_putchar(port, '\r');
-               sc26xx_console_putchar(port, *s++);
-       }
-}
-
-static int __init sc26xx_console_setup(struct console *con, char *options)
-{
-       struct uart_port *port = sc26xx_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (port->type != PORT_SC26XX)
-               return -1;
-
-       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver sc26xx_reg;
-static struct console sc26xx_console = {
-       .name   =       "ttySC",
-       .write  =       sc26xx_console_write,
-       .device =       uart_console_device,
-       .setup  =       sc26xx_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sc26xx_reg,
-};
-#define SC26XX_CONSOLE   &sc26xx_console
-#else
-#define SC26XX_CONSOLE   NULL
-#endif
-
-static struct uart_driver sc26xx_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "SC26xx",
-       .dev_name               = "ttySC",
-       .major                  = SC26XX_MAJOR,
-       .minor                  = SC26XX_MINOR_START,
-       .nr                     = SC26XX_NR,
-       .cons                   = SC26XX_CONSOLE,
-};
-
-static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
-{
-       unsigned int bit = (flags >> bitpos) & 15;
-
-       return bit ? (1 << (bit - 1)) : 0;
-}
-
-static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
-                                       int line, unsigned int data)
-{
-       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
-       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
-       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
-       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
-       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
-       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
-}
-
-static int __devinit sc26xx_probe(struct platform_device *dev)
-{
-       struct resource *res;
-       struct uart_sc26xx_port *up;
-       unsigned int *sc26xx_data = dev->dev.platform_data;
-       int err;
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       up = kzalloc(sizeof *up, GFP_KERNEL);
-       if (unlikely(!up))
-               return -ENOMEM;
-
-       up->port[0].line = 0;
-       up->port[0].ops = &sc26xx_ops;
-       up->port[0].type = PORT_SC26XX;
-       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[0].mapbase = res->start;
-       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
-       up->port[0].iotype = UPIO_MEM;
-       up->port[0].irq = platform_get_irq(dev, 0);
-
-       up->port[0].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 0, sc26xx_data[0]);
-
-       sc26xx_port = &up->port[0];
-
-       up->port[1].line = 1;
-       up->port[1].ops = &sc26xx_ops;
-       up->port[1].type = PORT_SC26XX;
-       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[1].mapbase = up->port[0].mapbase;
-       up->port[1].membase = up->port[0].membase;
-       up->port[1].iotype = UPIO_MEM;
-       up->port[1].irq = up->port[0].irq;
-
-       up->port[1].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 1, sc26xx_data[1]);
-
-       err = uart_register_driver(&sc26xx_reg);
-       if (err)
-               goto out_free_port;
-
-       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
-       if (err)
-               goto out_unregister_driver;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
-       if (err)
-               goto out_remove_port0;
-
-       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
-       if (err)
-               goto out_remove_ports;
-
-       dev_set_drvdata(&dev->dev, up);
-       return 0;
-
-out_remove_ports:
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-out_remove_port0:
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-
-out_unregister_driver:
-       uart_unregister_driver(&sc26xx_reg);
-
-out_free_port:
-       kfree(up);
-       sc26xx_port = NULL;
-       return err;
-}
-
-
-static int __exit sc26xx_driver_remove(struct platform_device *dev)
-{
-       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
-
-       free_irq(up->port[0].irq, up);
-
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-
-       uart_unregister_driver(&sc26xx_reg);
-
-       kfree(up);
-       sc26xx_port = NULL;
-
-       dev_set_drvdata(&dev->dev, NULL);
-       return 0;
-}
-
-static struct platform_driver sc26xx_driver = {
-       .probe  = sc26xx_probe,
-       .remove = __devexit_p(sc26xx_driver_remove),
-       .driver = {
-               .name   = "SC26xx",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init sc26xx_init(void)
-{
-       return platform_driver_register(&sc26xx_driver);
-}
-
-static void __exit sc26xx_exit(void)
-{
-       platform_driver_unregister(&sc26xx_driver);
-}
-
-module_init(sc26xx_init);
-module_exit(sc26xx_exit);
-
-
-MODULE_AUTHOR("Thomas Bogendörfer");
-MODULE_DESCRIPTION("SC681/SC2692 serial driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:SC26xx");
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
deleted file mode 100644 (file)
index 460a72d..0000000
+++ /dev/null
@@ -1,2578 +0,0 @@
-/*
- *  linux/drivers/char/core.c
- *
- *  Driver core for serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright 1999 ARM Limited
- *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-/*
- * This is used to lock changes in serial line configuration.
- */
-static DEFINE_MUTEX(port_mutex);
-
-/*
- * lockdep: port->lock is initialized in two places, but we
- *          want only one lock-class:
- */
-static struct lock_class_key port_lock_key;
-
-#define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
-
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port)     (0)
-#endif
-
-static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
-                                       struct ktermios *old_termios);
-static void __uart_wait_until_sent(struct uart_port *port, int timeout);
-static void uart_change_pm(struct uart_state *state, int pm_state);
-
-/*
- * This routine is used by the interrupt handler to schedule processing in
- * the software interrupt portion of the driver.
- */
-void uart_write_wakeup(struct uart_port *port)
-{
-       struct uart_state *state = port->state;
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       BUG_ON(!state);
-       tasklet_schedule(&state->tlet);
-}
-
-static void uart_stop(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->ops->stop_tx(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __uart_start(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
-           !tty->stopped && !tty->hw_stopped)
-               port->ops->start_tx(port);
-}
-
-static void uart_start(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __uart_start(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void uart_tasklet_action(unsigned long data)
-{
-       struct uart_state *state = (struct uart_state *)data;
-       tty_wakeup(state->port.tty);
-}
-
-static inline void
-uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
-{
-       unsigned long flags;
-       unsigned int old;
-
-       spin_lock_irqsave(&port->lock, flags);
-       old = port->mctrl;
-       port->mctrl = (old & ~clear) | set;
-       if (old != port->mctrl)
-               port->ops->set_mctrl(port, port->mctrl);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-#define uart_set_mctrl(port, set)      uart_update_mctrl(port, set, 0)
-#define uart_clear_mctrl(port, clear)  uart_update_mctrl(port, 0, clear)
-
-/*
- * Startup the port.  This will be called once per open.  All calls
- * will be serialised by the per-port mutex.
- */
-static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       unsigned long page;
-       int retval = 0;
-
-       if (port->flags & ASYNC_INITIALIZED)
-               return 0;
-
-       /*
-        * Set the TTY IO error marker - we will only clear this
-        * once we have successfully opened the port.  Also set
-        * up the tty->alt_speed kludge
-        */
-       set_bit(TTY_IO_ERROR, &tty->flags);
-
-       if (uport->type == PORT_UNKNOWN)
-               return 0;
-
-       /*
-        * Initialise and allocate the transmit and temporary
-        * buffer.
-        */
-       if (!state->xmit.buf) {
-               /* This is protected by the per port mutex */
-               page = get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-
-               state->xmit.buf = (unsigned char *) page;
-               uart_circ_clear(&state->xmit);
-       }
-
-       retval = uport->ops->startup(uport);
-       if (retval == 0) {
-               if (init_hw) {
-                       /*
-                        * Initialise the hardware port settings.
-                        */
-                       uart_change_speed(tty, state, NULL);
-
-                       /*
-                        * Setup the RTS and DTR signals once the
-                        * port is open and ready to respond.
-                        */
-                       if (tty->termios->c_cflag & CBAUD)
-                               uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
-               }
-
-               if (port->flags & ASYNC_CTS_FLOW) {
-                       spin_lock_irq(&uport->lock);
-                       if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
-                               tty->hw_stopped = 1;
-                       spin_unlock_irq(&uport->lock);
-               }
-
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-       }
-
-       if (retval && capable(CAP_SYS_ADMIN))
-               retval = 0;
-
-       return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.  Calls to
- * uart_shutdown are serialised by the per-port semaphore.
- */
-static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-
-       /*
-        * Set the TTY IO error marker
-        */
-       if (tty)
-               set_bit(TTY_IO_ERROR, &tty->flags);
-
-       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               /*
-                * Turn off DTR and RTS early.
-                */
-               if (!tty || (tty->termios->c_cflag & HUPCL))
-                       uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-
-               /*
-                * clear delta_msr_wait queue to avoid mem leaks: we may free
-                * the irq here so the queue might never be woken up.  Note
-                * that we won't end up waiting on delta_msr_wait again since
-                * any outstanding file descriptors should be pointing at
-                * hung_up_tty_fops now.
-                */
-               wake_up_interruptible(&port->delta_msr_wait);
-
-               /*
-                * Free the IRQ and disable the port.
-                */
-               uport->ops->shutdown(uport);
-
-               /*
-                * Ensure that the IRQ handler isn't running on another CPU.
-                */
-               synchronize_irq(uport->irq);
-       }
-
-       /*
-        * kill off our tasklet
-        */
-       tasklet_kill(&state->tlet);
-
-       /*
-        * Free the transmit buffer page.
-        */
-       if (state->xmit.buf) {
-               free_page((unsigned long)state->xmit.buf);
-               state->xmit.buf = NULL;
-       }
-}
-
-/**
- *     uart_update_timeout - update per-port FIFO timeout.
- *     @port:  uart_port structure describing the port
- *     @cflag: termios cflag value
- *     @baud:  speed of the port
- *
- *     Set the port FIFO timeout value.  The @cflag value should
- *     reflect the actual hardware settings.
- */
-void
-uart_update_timeout(struct uart_port *port, unsigned int cflag,
-                   unsigned int baud)
-{
-       unsigned int bits;
-
-       /* byte size and parity */
-       switch (cflag & CSIZE) {
-       case CS5:
-               bits = 7;
-               break;
-       case CS6:
-               bits = 8;
-               break;
-       case CS7:
-               bits = 9;
-               break;
-       default:
-               bits = 10;
-               break; /* CS8 */
-       }
-
-       if (cflag & CSTOPB)
-               bits++;
-       if (cflag & PARENB)
-               bits++;
-
-       /*
-        * The total number of bits to be transmitted in the fifo.
-        */
-       bits = bits * port->fifosize;
-
-       /*
-        * Figure the timeout to send the above number of bits.
-        * Add .02 seconds of slop
-        */
-       port->timeout = (HZ * bits) / baud + HZ/50;
-}
-
-EXPORT_SYMBOL(uart_update_timeout);
-
-/**
- *     uart_get_baud_rate - return baud rate for a particular port
- *     @port: uart_port structure describing the port in question.
- *     @termios: desired termios settings.
- *     @old: old termios (or NULL)
- *     @min: minimum acceptable baud rate
- *     @max: maximum acceptable baud rate
- *
- *     Decode the termios structure into a numeric baud rate,
- *     taking account of the magic 38400 baud rate (with spd_*
- *     flags), and mapping the %B0 rate to 9600 baud.
- *
- *     If the new baud rate is invalid, try the old termios setting.
- *     If it's still invalid, we try 9600 baud.
- *
- *     Update the @termios structure to reflect the baud rate
- *     we're actually going to be using. Don't do this for the case
- *     where B0 is requested ("hang up").
- */
-unsigned int
-uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
-                  struct ktermios *old, unsigned int min, unsigned int max)
-{
-       unsigned int try, baud, altbaud = 38400;
-       int hung_up = 0;
-       upf_t flags = port->flags & UPF_SPD_MASK;
-
-       if (flags == UPF_SPD_HI)
-               altbaud = 57600;
-       else if (flags == UPF_SPD_VHI)
-               altbaud = 115200;
-       else if (flags == UPF_SPD_SHI)
-               altbaud = 230400;
-       else if (flags == UPF_SPD_WARP)
-               altbaud = 460800;
-
-       for (try = 0; try < 2; try++) {
-               baud = tty_termios_baud_rate(termios);
-
-               /*
-                * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
-                * Die! Die! Die!
-                */
-               if (baud == 38400)
-                       baud = altbaud;
-
-               /*
-                * Special case: B0 rate.
-                */
-               if (baud == 0) {
-                       hung_up = 1;
-                       baud = 9600;
-               }
-
-               if (baud >= min && baud <= max)
-                       return baud;
-
-               /*
-                * Oops, the quotient was zero.  Try again with
-                * the old baud rate if possible.
-                */
-               termios->c_cflag &= ~CBAUD;
-               if (old) {
-                       baud = tty_termios_baud_rate(old);
-                       if (!hung_up)
-                               tty_termios_encode_baud_rate(termios,
-                                                               baud, baud);
-                       old = NULL;
-                       continue;
-               }
-
-               /*
-                * As a last resort, if the range cannot be met then clip to
-                * the nearest chip supported rate.
-                */
-               if (!hung_up) {
-                       if (baud <= min)
-                               tty_termios_encode_baud_rate(termios,
-                                                       min + 1, min + 1);
-                       else
-                               tty_termios_encode_baud_rate(termios,
-                                                       max - 1, max - 1);
-               }
-       }
-       /* Should never happen */
-       WARN_ON(1);
-       return 0;
-}
-
-EXPORT_SYMBOL(uart_get_baud_rate);
-
-/**
- *     uart_get_divisor - return uart clock divisor
- *     @port: uart_port structure describing the port.
- *     @baud: desired baud rate
- *
- *     Calculate the uart clock divisor for the port.
- */
-unsigned int
-uart_get_divisor(struct uart_port *port, unsigned int baud)
-{
-       unsigned int quot;
-
-       /*
-        * Old custom speed handling.
-        */
-       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-               quot = port->custom_divisor;
-       else
-               quot = (port->uartclk + (8 * baud)) / (16 * baud);
-
-       return quot;
-}
-
-EXPORT_SYMBOL(uart_get_divisor);
-
-/* FIXME: Consistent locking policy */
-static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
-                                       struct ktermios *old_termios)
-{
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-       struct ktermios *termios;
-
-       /*
-        * If we have no tty, termios, or the port does not exist,
-        * then we can't set the parameters for this port.
-        */
-       if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
-               return;
-
-       termios = tty->termios;
-
-       /*
-        * Set flags based on termios cflag
-        */
-       if (termios->c_cflag & CRTSCTS)
-               set_bit(ASYNCB_CTS_FLOW, &port->flags);
-       else
-               clear_bit(ASYNCB_CTS_FLOW, &port->flags);
-
-       if (termios->c_cflag & CLOCAL)
-               clear_bit(ASYNCB_CHECK_CD, &port->flags);
-       else
-               set_bit(ASYNCB_CHECK_CD, &port->flags);
-
-       uport->ops->set_termios(uport, termios, old_termios);
-}
-
-static inline int __uart_put_char(struct uart_port *port,
-                               struct circ_buf *circ, unsigned char c)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (!circ->buf)
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (uart_circ_chars_free(circ) != 0) {
-               circ->buf[circ->head] = c;
-               circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
-               ret = 1;
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-       return ret;
-}
-
-static int uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct uart_state *state = tty->driver_data;
-
-       return __uart_put_char(state->uart_port, &state->xmit, ch);
-}
-
-static void uart_flush_chars(struct tty_struct *tty)
-{
-       uart_start(tty);
-}
-
-static int uart_write(struct tty_struct *tty,
-                                       const unsigned char *buf, int count)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port;
-       struct circ_buf *circ;
-       unsigned long flags;
-       int c, ret = 0;
-
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       if (!state) {
-               WARN_ON(1);
-               return -EL3HLT;
-       }
-
-       port = state->uart_port;
-       circ = &state->xmit;
-
-       if (!circ->buf)
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       while (1) {
-               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
-               if (count < c)
-                       c = count;
-               if (c <= 0)
-                       break;
-               memcpy(circ->buf + circ->head, buf, c);
-               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       uart_start(tty);
-       return ret;
-}
-
-static int uart_write_room(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&state->uart_port->lock, flags);
-       ret = uart_circ_chars_free(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       return ret;
-}
-
-static int uart_chars_in_buffer(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&state->uart_port->lock, flags);
-       ret = uart_circ_chars_pending(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       return ret;
-}
-
-static void uart_flush_buffer(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port;
-       unsigned long flags;
-
-       /*
-        * This means you called this function _after_ the port was
-        * closed.  No cookie for you.
-        */
-       if (!state) {
-               WARN_ON(1);
-               return;
-       }
-
-       port = state->uart_port;
-       pr_debug("uart_flush_buffer(%d) called\n", tty->index);
-
-       spin_lock_irqsave(&port->lock, flags);
-       uart_circ_clear(&state->xmit);
-       if (port->ops->flush_buffer)
-               port->ops->flush_buffer(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-       tty_wakeup(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void uart_send_xchar(struct tty_struct *tty, char ch)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       unsigned long flags;
-
-       if (port->ops->send_xchar)
-               port->ops->send_xchar(port, ch);
-       else {
-               port->x_char = ch;
-               if (ch) {
-                       spin_lock_irqsave(&port->lock, flags);
-                       port->ops->start_tx(port);
-                       spin_unlock_irqrestore(&port->lock, flags);
-               }
-       }
-}
-
-static void uart_throttle(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-
-       if (I_IXOFF(tty))
-               uart_send_xchar(tty, STOP_CHAR(tty));
-
-       if (tty->termios->c_cflag & CRTSCTS)
-               uart_clear_mctrl(state->uart_port, TIOCM_RTS);
-}
-
-static void uart_unthrottle(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       if (I_IXOFF(tty)) {
-               if (port->x_char)
-                       port->x_char = 0;
-               else
-                       uart_send_xchar(tty, START_CHAR(tty));
-       }
-
-       if (tty->termios->c_cflag & CRTSCTS)
-               uart_set_mctrl(port, TIOCM_RTS);
-}
-
-static int uart_get_info(struct uart_state *state,
-                        struct serial_struct __user *retinfo)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       struct serial_struct tmp;
-
-       memset(&tmp, 0, sizeof(tmp));
-
-       /* Ensure the state we copy is consistent and no hardware changes
-          occur as we go */
-       mutex_lock(&port->mutex);
-
-       tmp.type            = uport->type;
-       tmp.line            = uport->line;
-       tmp.port            = uport->iobase;
-       if (HIGH_BITS_OFFSET)
-               tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
-       tmp.irq             = uport->irq;
-       tmp.flags           = uport->flags;
-       tmp.xmit_fifo_size  = uport->fifosize;
-       tmp.baud_base       = uport->uartclk / 16;
-       tmp.close_delay     = port->close_delay / 10;
-       tmp.closing_wait    = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                               ASYNC_CLOSING_WAIT_NONE :
-                               port->closing_wait / 10;
-       tmp.custom_divisor  = uport->custom_divisor;
-       tmp.hub6            = uport->hub6;
-       tmp.io_type         = uport->iotype;
-       tmp.iomem_reg_shift = uport->regshift;
-       tmp.iomem_base      = (void *)(unsigned long)uport->mapbase;
-
-       mutex_unlock(&port->mutex);
-
-       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
-                        struct serial_struct __user *newinfo)
-{
-       struct serial_struct new_serial;
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       unsigned long new_port;
-       unsigned int change_irq, change_port, closing_wait;
-       unsigned int old_custom_divisor, close_delay;
-       upf_t old_flags, new_flags;
-       int retval = 0;
-
-       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
-               return -EFAULT;
-
-       new_port = new_serial.port;
-       if (HIGH_BITS_OFFSET)
-               new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
-
-       new_serial.irq = irq_canonicalize(new_serial.irq);
-       close_delay = new_serial.close_delay * 10;
-       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
-
-       /*
-        * This semaphore protects port->count.  It is also
-        * very useful to prevent opens.  Also, take the
-        * port configuration semaphore to make sure that a
-        * module insertion/removal doesn't change anything
-        * under us.
-        */
-       mutex_lock(&port->mutex);
-
-       change_irq  = !(uport->flags & UPF_FIXED_PORT)
-               && new_serial.irq != uport->irq;
-
-       /*
-        * Since changing the 'type' of the port changes its resource
-        * allocations, we should treat type changes the same as
-        * IO port changes.
-        */
-       change_port = !(uport->flags & UPF_FIXED_PORT)
-               && (new_port != uport->iobase ||
-                   (unsigned long)new_serial.iomem_base != uport->mapbase ||
-                   new_serial.hub6 != uport->hub6 ||
-                   new_serial.io_type != uport->iotype ||
-                   new_serial.iomem_reg_shift != uport->regshift ||
-                   new_serial.type != uport->type);
-
-       old_flags = uport->flags;
-       new_flags = new_serial.flags;
-       old_custom_divisor = uport->custom_divisor;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               retval = -EPERM;
-               if (change_irq || change_port ||
-                   (new_serial.baud_base != uport->uartclk / 16) ||
-                   (close_delay != port->close_delay) ||
-                   (closing_wait != port->closing_wait) ||
-                   (new_serial.xmit_fifo_size &&
-                    new_serial.xmit_fifo_size != uport->fifosize) ||
-                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
-                       goto exit;
-               uport->flags = ((uport->flags & ~UPF_USR_MASK) |
-                              (new_flags & UPF_USR_MASK));
-               uport->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       /*
-        * Ask the low level driver to verify the settings.
-        */
-       if (uport->ops->verify_port)
-               retval = uport->ops->verify_port(uport, &new_serial);
-
-       if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
-           (new_serial.baud_base < 9600))
-               retval = -EINVAL;
-
-       if (retval)
-               goto exit;
-
-       if (change_port || change_irq) {
-               retval = -EBUSY;
-
-               /*
-                * Make sure that we are the sole user of this port.
-                */
-               if (tty_port_users(port) > 1)
-                       goto exit;
-
-               /*
-                * We need to shutdown the serial port at the old
-                * port/type/irq combination.
-                */
-               uart_shutdown(tty, state);
-       }
-
-       if (change_port) {
-               unsigned long old_iobase, old_mapbase;
-               unsigned int old_type, old_iotype, old_hub6, old_shift;
-
-               old_iobase = uport->iobase;
-               old_mapbase = uport->mapbase;
-               old_type = uport->type;
-               old_hub6 = uport->hub6;
-               old_iotype = uport->iotype;
-               old_shift = uport->regshift;
-
-               /*
-                * Free and release old regions
-                */
-               if (old_type != PORT_UNKNOWN)
-                       uport->ops->release_port(uport);
-
-               uport->iobase = new_port;
-               uport->type = new_serial.type;
-               uport->hub6 = new_serial.hub6;
-               uport->iotype = new_serial.io_type;
-               uport->regshift = new_serial.iomem_reg_shift;
-               uport->mapbase = (unsigned long)new_serial.iomem_base;
-
-               /*
-                * Claim and map the new regions
-                */
-               if (uport->type != PORT_UNKNOWN) {
-                       retval = uport->ops->request_port(uport);
-               } else {
-                       /* Always success - Jean II */
-                       retval = 0;
-               }
-
-               /*
-                * If we fail to request resources for the
-                * new port, try to restore the old settings.
-                */
-               if (retval && old_type != PORT_UNKNOWN) {
-                       uport->iobase = old_iobase;
-                       uport->type = old_type;
-                       uport->hub6 = old_hub6;
-                       uport->iotype = old_iotype;
-                       uport->regshift = old_shift;
-                       uport->mapbase = old_mapbase;
-                       retval = uport->ops->request_port(uport);
-                       /*
-                        * If we failed to restore the old settings,
-                        * we fail like this.
-                        */
-                       if (retval)
-                               uport->type = PORT_UNKNOWN;
-
-                       /*
-                        * We failed anyway.
-                        */
-                       retval = -EBUSY;
-                       /* Added to return the correct error -Ram Gupta */
-                       goto exit;
-               }
-       }
-
-       if (change_irq)
-               uport->irq      = new_serial.irq;
-       if (!(uport->flags & UPF_FIXED_PORT))
-               uport->uartclk  = new_serial.baud_base * 16;
-       uport->flags            = (uport->flags & ~UPF_CHANGE_MASK) |
-                                (new_flags & UPF_CHANGE_MASK);
-       uport->custom_divisor   = new_serial.custom_divisor;
-       port->close_delay     = close_delay;
-       port->closing_wait    = closing_wait;
-       if (new_serial.xmit_fifo_size)
-               uport->fifosize = new_serial.xmit_fifo_size;
-       if (port->tty)
-               port->tty->low_latency =
-                       (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-       retval = 0;
-       if (uport->type == PORT_UNKNOWN)
-               goto exit;
-       if (port->flags & ASYNC_INITIALIZED) {
-               if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
-                   old_custom_divisor != uport->custom_divisor) {
-                       /*
-                        * If they're setting up a custom divisor or speed,
-                        * instead of clearing it, then bitch about it. No
-                        * need to rate-limit; it's CAP_SYS_ADMIN only.
-                        */
-                       if (uport->flags & UPF_SPD_MASK) {
-                               char buf[64];
-                               printk(KERN_NOTICE
-                                      "%s sets custom speed on %s. This "
-                                      "is deprecated.\n", current->comm,
-                                      tty_name(port->tty, buf));
-                       }
-                       uart_change_speed(tty, state, NULL);
-               }
-       } else
-               retval = uart_startup(tty, state, 1);
- exit:
-       mutex_unlock(&port->mutex);
-       return retval;
-}
-
-/**
- *     uart_get_lsr_info       -       get line status register info
- *     @tty: tty associated with the UART
- *     @state: UART being queried
- *     @value: returned modem value
- *
- *     Note: uart_ioctl protects us against hangups.
- */
-static int uart_get_lsr_info(struct tty_struct *tty,
-                       struct uart_state *state, unsigned int __user *value)
-{
-       struct uart_port *uport = state->uart_port;
-       unsigned int result;
-
-       result = uport->ops->tx_empty(uport);
-
-       /*
-        * If we're about to load something into the transmit
-        * register, we'll pretend the transmitter isn't empty to
-        * avoid a race condition (depending on when the transmit
-        * interrupt happens).
-        */
-       if (uport->x_char ||
-           ((uart_circ_chars_pending(&state->xmit) > 0) &&
-            !tty->stopped && !tty->hw_stopped))
-               result &= ~TIOCSER_TEMT;
-
-       return put_user(result, value);
-}
-
-static int uart_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-       int result = -EIO;
-
-       mutex_lock(&port->mutex);
-       if ((!file || !tty_hung_up_p(file)) &&
-           !(tty->flags & (1 << TTY_IO_ERROR))) {
-               result = uport->mctrl;
-
-               spin_lock_irq(&uport->lock);
-               result |= uport->ops->get_mctrl(uport);
-               spin_unlock_irq(&uport->lock);
-       }
-       mutex_unlock(&port->mutex);
-
-       return result;
-}
-
-static int
-uart_tiocmset(struct tty_struct *tty, struct file *file,
-             unsigned int set, unsigned int clear)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       int ret = -EIO;
-
-       mutex_lock(&port->mutex);
-       if ((!file || !tty_hung_up_p(file)) &&
-           !(tty->flags & (1 << TTY_IO_ERROR))) {
-               uart_update_mctrl(uport, set, clear);
-               ret = 0;
-       }
-       mutex_unlock(&port->mutex);
-       return ret;
-}
-
-static int uart_break_ctl(struct tty_struct *tty, int break_state)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
-
-       mutex_lock(&port->mutex);
-
-       if (uport->type != PORT_UNKNOWN)
-               uport->ops->break_ctl(uport, break_state);
-
-       mutex_unlock(&port->mutex);
-       return 0;
-}
-
-static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       int flags, ret;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       /*
-        * Take the per-port semaphore.  This prevents count from
-        * changing, and hence any extra opens of the port while
-        * we're auto-configuring.
-        */
-       if (mutex_lock_interruptible(&port->mutex))
-               return -ERESTARTSYS;
-
-       ret = -EBUSY;
-       if (tty_port_users(port) == 1) {
-               uart_shutdown(tty, state);
-
-               /*
-                * If we already have a port type configured,
-                * we must release its resources.
-                */
-               if (uport->type != PORT_UNKNOWN)
-                       uport->ops->release_port(uport);
-
-               flags = UART_CONFIG_TYPE;
-               if (uport->flags & UPF_AUTO_IRQ)
-                       flags |= UART_CONFIG_IRQ;
-
-               /*
-                * This will claim the ports resources if
-                * a port is found.
-                */
-               uport->ops->config_port(uport, flags);
-
-               ret = uart_startup(tty, state, 1);
-       }
-       mutex_unlock(&port->mutex);
-       return ret;
-}
-
-/*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- *
- * FIXME: This wants extracting into a common all driver implementation
- * of TIOCMWAIT using tty_port.
- */
-static int
-uart_wait_modem_status(struct uart_state *state, unsigned long arg)
-{
-       struct uart_port *uport = state->uart_port;
-       struct tty_port *port = &state->port;
-       DECLARE_WAITQUEUE(wait, current);
-       struct uart_icount cprev, cnow;
-       int ret;
-
-       /*
-        * note the counters on entry
-        */
-       spin_lock_irq(&uport->lock);
-       memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
-
-       /*
-        * Force modem status interrupts on
-        */
-       uport->ops->enable_ms(uport);
-       spin_unlock_irq(&uport->lock);
-
-       add_wait_queue(&port->delta_msr_wait, &wait);
-       for (;;) {
-               spin_lock_irq(&uport->lock);
-               memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
-               spin_unlock_irq(&uport->lock);
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                   ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                   ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                   ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                       ret = 0;
-                       break;
-               }
-
-               schedule();
-
-               /* see if a signal did it */
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-
-               cprev = cnow;
-       }
-
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&port->delta_msr_wait, &wait);
-
-       return ret;
-}
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- *     RI where only 0->1 is counted.
- */
-static int uart_get_icount(struct tty_struct *tty,
-                         struct serial_icounter_struct *icount)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_icount cnow;
-       struct uart_port *uport = state->uart_port;
-
-       spin_lock_irq(&uport->lock);
-       memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
-       spin_unlock_irq(&uport->lock);
-
-       icount->cts         = cnow.cts;
-       icount->dsr         = cnow.dsr;
-       icount->rng         = cnow.rng;
-       icount->dcd         = cnow.dcd;
-       icount->rx          = cnow.rx;
-       icount->tx          = cnow.tx;
-       icount->frame       = cnow.frame;
-       icount->overrun     = cnow.overrun;
-       icount->parity      = cnow.parity;
-       icount->brk         = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       return 0;
-}
-
-/*
- * Called via sys_ioctl.  We can use spin_lock_irq() here.
- */
-static int
-uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
-          unsigned long arg)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       void __user *uarg = (void __user *)arg;
-       int ret = -ENOIOCTLCMD;
-
-
-       /*
-        * These ioctls don't rely on the hardware to be present.
-        */
-       switch (cmd) {
-       case TIOCGSERIAL:
-               ret = uart_get_info(state, uarg);
-               break;
-
-       case TIOCSSERIAL:
-               ret = uart_set_info(tty, state, uarg);
-               break;
-
-       case TIOCSERCONFIG:
-               ret = uart_do_autoconfig(tty, state);
-               break;
-
-       case TIOCSERGWILD: /* obsolete */
-       case TIOCSERSWILD: /* obsolete */
-               ret = 0;
-               break;
-       }
-
-       if (ret != -ENOIOCTLCMD)
-               goto out;
-
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               ret = -EIO;
-               goto out;
-       }
-
-       /*
-        * The following should only be used when hardware is present.
-        */
-       switch (cmd) {
-       case TIOCMIWAIT:
-               ret = uart_wait_modem_status(state, arg);
-               break;
-       }
-
-       if (ret != -ENOIOCTLCMD)
-               goto out;
-
-       mutex_lock(&port->mutex);
-
-       if (tty_hung_up_p(filp)) {
-               ret = -EIO;
-               goto out_up;
-       }
-
-       /*
-        * All these rely on hardware being present and need to be
-        * protected against the tty being hung up.
-        */
-       switch (cmd) {
-       case TIOCSERGETLSR: /* Get line status register */
-               ret = uart_get_lsr_info(tty, state, uarg);
-               break;
-
-       default: {
-               struct uart_port *uport = state->uart_port;
-               if (uport->ops->ioctl)
-                       ret = uport->ops->ioctl(uport, cmd, arg);
-               break;
-       }
-       }
-out_up:
-       mutex_unlock(&port->mutex);
-out:
-       return ret;
-}
-
-static void uart_set_ldisc(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
-
-       if (uport->ops->set_ldisc)
-               uport->ops->set_ldisc(uport, tty->termios->c_line);
-}
-
-static void uart_set_termios(struct tty_struct *tty,
-                                               struct ktermios *old_termios)
-{
-       struct uart_state *state = tty->driver_data;
-       unsigned long flags;
-       unsigned int cflag = tty->termios->c_cflag;
-
-
-       /*
-        * These are the bits that are used to setup various
-        * flags in the low level driver. We can ignore the Bfoo
-        * bits in c_cflag; c_[io]speed will always be set
-        * appropriately by set_termios() in tty_ioctl.c
-        */
-#define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-       if ((cflag ^ old_termios->c_cflag) == 0 &&
-           tty->termios->c_ospeed == old_termios->c_ospeed &&
-           tty->termios->c_ispeed == old_termios->c_ispeed &&
-           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
-               return;
-       }
-
-       uart_change_speed(tty, state, old_termios);
-
-       /* Handle transition to B0 status */
-       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
-               uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
-       /* Handle transition away from B0 status */
-       else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
-               unsigned int mask = TIOCM_DTR;
-               if (!(cflag & CRTSCTS) ||
-                   !test_bit(TTY_THROTTLED, &tty->flags))
-                       mask |= TIOCM_RTS;
-               uart_set_mctrl(state->uart_port, mask);
-       }
-
-       /* Handle turning off CRTSCTS */
-       if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
-               spin_lock_irqsave(&state->uart_port->lock, flags);
-               tty->hw_stopped = 0;
-               __uart_start(tty);
-               spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       }
-       /* Handle turning on CRTSCTS */
-       else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
-               spin_lock_irqsave(&state->uart_port->lock, flags);
-               if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
-                       tty->hw_stopped = 1;
-                       state->uart_port->ops->stop_tx(state->uart_port);
-               }
-               spin_unlock_irqrestore(&state->uart_port->lock, flags);
-       }
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&state->uart_port.open_wait);
-#endif
-}
-
-/*
- * In 2.4.5, calls to this will be serialized via the BKL in
- *  linux/drivers/char/tty_io.c:tty_release()
- *  linux/drivers/char/tty_io.c:do_tty_handup()
- */
-static void uart_close(struct tty_struct *tty, struct file *filp)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port;
-       struct uart_port *uport;
-       unsigned long flags;
-
-       BUG_ON(!tty_locked());
-
-       if (!state)
-               return;
-
-       uport = state->uart_port;
-       port = &state->port;
-
-       pr_debug("uart_close(%d) called\n", uport->line);
-
-       mutex_lock(&port->mutex);
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
-       }
-
-       if ((tty->count == 1) && (port->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  port->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
-                      "port->count is %d\n", port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
-                      tty->name, port->count);
-               port->count = 0;
-       }
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
-       }
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters by
-        * setting tty->closing.
-        */
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               /*
-                * hack: open-coded tty_wait_until_sent to avoid
-                * recursive tty_lock
-                */
-               long timeout = msecs_to_jiffies(port->closing_wait);
-               if (wait_event_interruptible_timeout(tty->write_wait,
-                               !tty_chars_in_buffer(tty), timeout) >= 0)
-                       __uart_wait_until_sent(uport, timeout);
-       }
-
-       /*
-        * At this point, we stop accepting input.  To do this, we
-        * disable the receive line status interrupts.
-        */
-       if (port->flags & ASYNC_INITIALIZED) {
-               unsigned long flags;
-               spin_lock_irqsave(&uport->lock, flags);
-               uport->ops->stop_rx(uport);
-               spin_unlock_irqrestore(&uport->lock, flags);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               __uart_wait_until_sent(uport, uport->timeout);
-       }
-
-       uart_shutdown(tty, state);
-       uart_flush_buffer(tty);
-
-       tty_ldisc_flush(tty);
-
-       tty_port_tty_set(port, NULL);
-       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(port->close_delay);
-               spin_lock_irqsave(&port->lock, flags);
-       } else if (!uart_console(uport)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               uart_change_pm(state, 3);
-               spin_lock_irqsave(&port->lock, flags);
-       }
-
-       /*
-        * Wake up anyone trying to open this port.
-        */
-       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-       spin_unlock_irqrestore(&port->lock, flags);
-       wake_up_interruptible(&port->open_wait);
-
-done:
-       mutex_unlock(&port->mutex);
-}
-
-static void __uart_wait_until_sent(struct uart_port *port, int timeout)
-{
-       unsigned long char_time, expire;
-
-       if (port->type == PORT_UNKNOWN || port->fifosize == 0)
-               return;
-
-       /*
-        * Set the check interval to be 1/5 of the estimated time to
-        * send a single character, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        *
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       char_time = (port->timeout - HZ/50) / port->fifosize;
-       char_time = char_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout && timeout < char_time)
-               char_time = timeout;
-
-       /*
-        * If the transmitter hasn't cleared in twice the approximate
-        * amount of time to send the entire FIFO, it probably won't
-        * ever clear.  This assumes the UART isn't doing flow
-        * control, which is currently the case.  Hence, if it ever
-        * takes longer than port->timeout, this is probably due to a
-        * UART bug of some kind.  So, we clamp the timeout parameter at
-        * 2*port->timeout.
-        */
-       if (timeout == 0 || timeout > 2 * port->timeout)
-               timeout = 2 * port->timeout;
-
-       expire = jiffies + timeout;
-
-       pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
-               port->line, jiffies, expire);
-
-       /*
-        * Check whether the transmitter is empty every 'char_time'.
-        * 'timeout' / 'expire' give us the maximum amount of time
-        * we wait.
-        */
-       while (!port->ops->tx_empty(port)) {
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (time_after(jiffies, expire))
-                       break;
-       }
-       set_current_state(TASK_RUNNING); /* might not be needed */
-}
-
-static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       tty_lock();
-       __uart_wait_until_sent(port, timeout);
-       tty_unlock();
-}
-
-/*
- * This is called with the BKL held in
- *  linux/drivers/char/tty_io.c:do_tty_hangup()
- * We're called from the eventd thread, so we can sleep for
- * a _short_ time only.
- */
-static void uart_hangup(struct tty_struct *tty)
-{
-       struct uart_state *state = tty->driver_data;
-       struct tty_port *port = &state->port;
-       unsigned long flags;
-
-       BUG_ON(!tty_locked());
-       pr_debug("uart_hangup(%d)\n", state->uart_port->line);
-
-       mutex_lock(&port->mutex);
-       if (port->flags & ASYNC_NORMAL_ACTIVE) {
-               uart_flush_buffer(tty);
-               uart_shutdown(tty, state);
-               spin_lock_irqsave(&port->lock, flags);
-               port->count = 0;
-               clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-               spin_unlock_irqrestore(&port->lock, flags);
-               tty_port_tty_set(port, NULL);
-               wake_up_interruptible(&port->open_wait);
-               wake_up_interruptible(&port->delta_msr_wait);
-       }
-       mutex_unlock(&port->mutex);
-}
-
-/**
- *     uart_update_termios     -       update the terminal hw settings
- *     @tty: tty associated with UART
- *     @state: UART to update
- *
- *     Copy across the serial console cflag setting into the termios settings
- *     for the initial open of the port.  This allows continuity between the
- *     kernel settings, and the settings init adopts when it opens the port
- *     for the first time.
- */
-static void uart_update_termios(struct tty_struct *tty,
-                                               struct uart_state *state)
-{
-       struct uart_port *port = state->uart_port;
-
-       if (uart_console(port) && port->cons->cflag) {
-               tty->termios->c_cflag = port->cons->cflag;
-               port->cons->cflag = 0;
-       }
-
-       /*
-        * If the device failed to grab its irq resources,
-        * or some other error occurred, don't try to talk
-        * to the port hardware.
-        */
-       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
-               /*
-                * Make termios settings take effect.
-                */
-               uart_change_speed(tty, state, NULL);
-
-               /*
-                * And finally enable the RTS and DTR signals.
-                */
-               if (tty->termios->c_cflag & CBAUD)
-                       uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-       }
-}
-
-static int uart_carrier_raised(struct tty_port *port)
-{
-       struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
-       int mctrl;
-       spin_lock_irq(&uport->lock);
-       uport->ops->enable_ms(uport);
-       mctrl = uport->ops->get_mctrl(uport);
-       spin_unlock_irq(&uport->lock);
-       if (mctrl & TIOCM_CAR)
-               return 1;
-       return 0;
-}
-
-static void uart_dtr_rts(struct tty_port *port, int onoff)
-{
-       struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
-
-       if (onoff) {
-               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-
-               /*
-                * If this is the first open to succeed,
-                * adjust things to suit.
-                */
-               if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
-                       uart_update_termios(port->tty, state);
-       }
-       else
-               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-}
-
-static struct uart_state *uart_get(struct uart_driver *drv, int line)
-{
-       struct uart_state *state;
-       struct tty_port *port;
-       int ret = 0;
-
-       state = drv->state + line;
-       port = &state->port;
-       if (mutex_lock_interruptible(&port->mutex)) {
-               ret = -ERESTARTSYS;
-               goto err;
-       }
-
-       port->count++;
-       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
-               ret = -ENXIO;
-               goto err_unlock;
-       }
-       return state;
-
- err_unlock:
-       port->count--;
-       mutex_unlock(&port->mutex);
- err:
-       return ERR_PTR(ret);
-}
-
-/*
- * calls to uart_open are serialised by the BKL in
- *   fs/char_dev.c:chrdev_open()
- * Note that if this fails, then uart_close() _will_ be called.
- *
- * In time, we want to scrap the "opening nonpresent ports"
- * behaviour and implement an alternative way for setserial
- * to set base addresses/ports/types.  This will allow us to
- * get rid of a certain amount of extra tests.
- */
-static int uart_open(struct tty_struct *tty, struct file *filp)
-{
-       struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
-       struct uart_state *state;
-       struct tty_port *port;
-       int retval, line = tty->index;
-
-       BUG_ON(!tty_locked());
-       pr_debug("uart_open(%d) called\n", line);
-
-       /*
-        * tty->driver->num won't change, so we won't fail here with
-        * tty->driver_data set to something non-NULL (and therefore
-        * we won't get caught by uart_close()).
-        */
-       retval = -ENODEV;
-       if (line >= tty->driver->num)
-               goto fail;
-
-       /*
-        * We take the semaphore inside uart_get to guarantee that we won't
-        * be re-entered while allocating the state structure, or while we
-        * request any IRQs that the driver may need.  This also has the nice
-        * side-effect that it delays the action of uart_hangup, so we can
-        * guarantee that state->port.tty will always contain something
-        * reasonable.
-        */
-       state = uart_get(drv, line);
-       if (IS_ERR(state)) {
-               retval = PTR_ERR(state);
-               goto fail;
-       }
-       port = &state->port;
-
-       /*
-        * Once we set tty->driver_data here, we are guaranteed that
-        * uart_close() will decrement the driver module use count.
-        * Any failures from here onwards should not touch the count.
-        */
-       tty->driver_data = state;
-       state->uart_port->state = state;
-       tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
-       tty->alt_speed = 0;
-       tty_port_tty_set(port, tty);
-
-       /*
-        * If the port is in the middle of closing, bail out now.
-        */
-       if (tty_hung_up_p(filp)) {
-               retval = -EAGAIN;
-               port->count--;
-               mutex_unlock(&port->mutex);
-               goto fail;
-       }
-
-       /*
-        * Make sure the device is in D0 state.
-        */
-       if (port->count == 1)
-               uart_change_pm(state, 0);
-
-       /*
-        * Start up the serial port.
-        */
-       retval = uart_startup(tty, state, 0);
-
-       /*
-        * If we succeeded, wait until the port is ready.
-        */
-       mutex_unlock(&port->mutex);
-       if (retval == 0)
-               retval = tty_port_block_til_ready(port, tty, filp);
-
-fail:
-       return retval;
-}
-
-static const char *uart_type(struct uart_port *port)
-{
-       const char *str = NULL;
-
-       if (port->ops->type)
-               str = port->ops->type(port);
-
-       if (!str)
-               str = "unknown";
-
-       return str;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
-{
-       struct uart_state *state = drv->state + i;
-       struct tty_port *port = &state->port;
-       int pm_state;
-       struct uart_port *uport = state->uart_port;
-       char stat_buf[32];
-       unsigned int status;
-       int mmio;
-
-       if (!uport)
-               return;
-
-       mmio = uport->iotype >= UPIO_MEM;
-       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
-                       uport->line, uart_type(uport),
-                       mmio ? "mmio:0x" : "port:",
-                       mmio ? (unsigned long long)uport->mapbase
-                            : (unsigned long long)uport->iobase,
-                       uport->irq);
-
-       if (uport->type == PORT_UNKNOWN) {
-               seq_putc(m, '\n');
-               return;
-       }
-
-       if (capable(CAP_SYS_ADMIN)) {
-               mutex_lock(&port->mutex);
-               pm_state = state->pm_state;
-               if (pm_state)
-                       uart_change_pm(state, 0);
-               spin_lock_irq(&uport->lock);
-               status = uport->ops->get_mctrl(uport);
-               spin_unlock_irq(&uport->lock);
-               if (pm_state)
-                       uart_change_pm(state, pm_state);
-               mutex_unlock(&port->mutex);
-
-               seq_printf(m, " tx:%d rx:%d",
-                               uport->icount.tx, uport->icount.rx);
-               if (uport->icount.frame)
-                       seq_printf(m, " fe:%d",
-                               uport->icount.frame);
-               if (uport->icount.parity)
-                       seq_printf(m, " pe:%d",
-                               uport->icount.parity);
-               if (uport->icount.brk)
-                       seq_printf(m, " brk:%d",
-                               uport->icount.brk);
-               if (uport->icount.overrun)
-                       seq_printf(m, " oe:%d",
-                               uport->icount.overrun);
-
-#define INFOBIT(bit, str) \
-       if (uport->mctrl & (bit)) \
-               strncat(stat_buf, (str), sizeof(stat_buf) - \
-                       strlen(stat_buf) - 2)
-#define STATBIT(bit, str) \
-       if (status & (bit)) \
-               strncat(stat_buf, (str), sizeof(stat_buf) - \
-                      strlen(stat_buf) - 2)
-
-               stat_buf[0] = '\0';
-               stat_buf[1] = '\0';
-               INFOBIT(TIOCM_RTS, "|RTS");
-               STATBIT(TIOCM_CTS, "|CTS");
-               INFOBIT(TIOCM_DTR, "|DTR");
-               STATBIT(TIOCM_DSR, "|DSR");
-               STATBIT(TIOCM_CAR, "|CD");
-               STATBIT(TIOCM_RNG, "|RI");
-               if (stat_buf[0])
-                       stat_buf[0] = ' ';
-
-               seq_puts(m, stat_buf);
-       }
-       seq_putc(m, '\n');
-#undef STATBIT
-#undef INFOBIT
-}
-
-static int uart_proc_show(struct seq_file *m, void *v)
-{
-       struct tty_driver *ttydrv = m->private;
-       struct uart_driver *drv = ttydrv->driver_state;
-       int i;
-
-       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
-                       "", "", "");
-       for (i = 0; i < drv->nr; i++)
-               uart_line_info(m, drv, i);
-       return 0;
-}
-
-static int uart_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, uart_proc_show, PDE(inode)->data);
-}
-
-static const struct file_operations uart_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = uart_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-#endif
-
-#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
-/*
- *     uart_console_write - write a console message to a serial port
- *     @port: the port to write the message
- *     @s: array of characters
- *     @count: number of characters in string to write
- *     @write: function to write character to port
- */
-void uart_console_write(struct uart_port *port, const char *s,
-                       unsigned int count,
-                       void (*putchar)(struct uart_port *, int))
-{
-       unsigned int i;
-
-       for (i = 0; i < count; i++, s++) {
-               if (*s == '\n')
-                       putchar(port, '\r');
-               putchar(port, *s);
-       }
-}
-EXPORT_SYMBOL_GPL(uart_console_write);
-
-/*
- *     Check whether an invalid uart number has been specified, and
- *     if so, search for the first available port that does have
- *     console support.
- */
-struct uart_port * __init
-uart_get_console(struct uart_port *ports, int nr, struct console *co)
-{
-       int idx = co->index;
-
-       if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
-                                    ports[idx].membase == NULL))
-               for (idx = 0; idx < nr; idx++)
-                       if (ports[idx].iobase != 0 ||
-                           ports[idx].membase != NULL)
-                               break;
-
-       co->index = idx;
-
-       return ports + idx;
-}
-
-/**
- *     uart_parse_options - Parse serial port baud/parity/bits/flow contro.
- *     @options: pointer to option string
- *     @baud: pointer to an 'int' variable for the baud rate.
- *     @parity: pointer to an 'int' variable for the parity.
- *     @bits: pointer to an 'int' variable for the number of data bits.
- *     @flow: pointer to an 'int' variable for the flow control character.
- *
- *     uart_parse_options decodes a string containing the serial console
- *     options.  The format of the string is <baud><parity><bits><flow>,
- *     eg: 115200n8r
- */
-void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
-{
-       char *s = options;
-
-       *baud = simple_strtoul(s, NULL, 10);
-       while (*s >= '0' && *s <= '9')
-               s++;
-       if (*s)
-               *parity = *s++;
-       if (*s)
-               *bits = *s++ - '0';
-       if (*s)
-               *flow = *s;
-}
-EXPORT_SYMBOL_GPL(uart_parse_options);
-
-struct baud_rates {
-       unsigned int rate;
-       unsigned int cflag;
-};
-
-static const struct baud_rates baud_rates[] = {
-       { 921600, B921600 },
-       { 460800, B460800 },
-       { 230400, B230400 },
-       { 115200, B115200 },
-       {  57600, B57600  },
-       {  38400, B38400  },
-       {  19200, B19200  },
-       {   9600, B9600   },
-       {   4800, B4800   },
-       {   2400, B2400   },
-       {   1200, B1200   },
-       {      0, B38400  }
-};
-
-/**
- *     uart_set_options - setup the serial console parameters
- *     @port: pointer to the serial ports uart_port structure
- *     @co: console pointer
- *     @baud: baud rate
- *     @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
- *     @bits: number of data bits
- *     @flow: flow control character - 'r' (rts)
- */
-int
-uart_set_options(struct uart_port *port, struct console *co,
-                int baud, int parity, int bits, int flow)
-{
-       struct ktermios termios;
-       static struct ktermios dummy;
-       int i;
-
-       /*
-        * Ensure that the serial console lock is initialised
-        * early.
-        */
-       spin_lock_init(&port->lock);
-       lockdep_set_class(&port->lock, &port_lock_key);
-
-       memset(&termios, 0, sizeof(struct ktermios));
-
-       termios.c_cflag = CREAD | HUPCL | CLOCAL;
-
-       /*
-        * Construct a cflag setting.
-        */
-       for (i = 0; baud_rates[i].rate; i++)
-               if (baud_rates[i].rate <= baud)
-                       break;
-
-       termios.c_cflag |= baud_rates[i].cflag;
-
-       if (bits == 7)
-               termios.c_cflag |= CS7;
-       else
-               termios.c_cflag |= CS8;
-
-       switch (parity) {
-       case 'o': case 'O':
-               termios.c_cflag |= PARODD;
-               /*fall through*/
-       case 'e': case 'E':
-               termios.c_cflag |= PARENB;
-               break;
-       }
-
-       if (flow == 'r')
-               termios.c_cflag |= CRTSCTS;
-
-       /*
-        * some uarts on other side don't support no flow control.
-        * So we set * DTR in host uart to make them happy
-        */
-       port->mctrl |= TIOCM_DTR;
-
-       port->ops->set_termios(port, &termios, &dummy);
-       /*
-        * Allow the setting of the UART parameters with a NULL console
-        * too:
-        */
-       if (co)
-               co->cflag = termios.c_cflag;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uart_set_options);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-
-static void uart_change_pm(struct uart_state *state, int pm_state)
-{
-       struct uart_port *port = state->uart_port;
-
-       if (state->pm_state != pm_state) {
-               if (port->ops->pm)
-                       port->ops->pm(port, pm_state, state->pm_state);
-               state->pm_state = pm_state;
-       }
-}
-
-struct uart_match {
-       struct uart_port *port;
-       struct uart_driver *driver;
-};
-
-static int serial_match_port(struct device *dev, void *data)
-{
-       struct uart_match *match = data;
-       struct tty_driver *tty_drv = match->driver->tty_driver;
-       dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
-               match->port->line;
-
-       return dev->devt == devt; /* Actually, only one tty per port */
-}
-
-int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-       struct device *tty_dev;
-       struct uart_match match = {uport, drv};
-       struct tty_struct *tty;
-
-       mutex_lock(&port->mutex);
-
-       /* Must be inside the mutex lock until we convert to tty_port */
-       tty = port->tty;
-
-       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
-       if (device_may_wakeup(tty_dev)) {
-               if (!enable_irq_wake(uport->irq))
-                       uport->irq_wake = 1;
-               put_device(tty_dev);
-               mutex_unlock(&port->mutex);
-               return 0;
-       }
-       if (console_suspend_enabled || !uart_console(uport))
-               uport->suspended = 1;
-
-       if (port->flags & ASYNC_INITIALIZED) {
-               const struct uart_ops *ops = uport->ops;
-               int tries;
-
-               if (console_suspend_enabled || !uart_console(uport)) {
-                       set_bit(ASYNCB_SUSPENDED, &port->flags);
-                       clear_bit(ASYNCB_INITIALIZED, &port->flags);
-
-                       spin_lock_irq(&uport->lock);
-                       ops->stop_tx(uport);
-                       ops->set_mctrl(uport, 0);
-                       ops->stop_rx(uport);
-                       spin_unlock_irq(&uport->lock);
-               }
-
-               /*
-                * Wait for the transmitter to empty.
-                */
-               for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
-                       msleep(10);
-               if (!tries)
-                       printk(KERN_ERR "%s%s%s%d: Unable to drain "
-                                       "transmitter\n",
-                              uport->dev ? dev_name(uport->dev) : "",
-                              uport->dev ? ": " : "",
-                              drv->dev_name,
-                              drv->tty_driver->name_base + uport->line);
-
-               if (console_suspend_enabled || !uart_console(uport))
-                       ops->shutdown(uport);
-       }
-
-       /*
-        * Disable the console device before suspending.
-        */
-       if (console_suspend_enabled && uart_console(uport))
-               console_stop(uport->cons);
-
-       if (console_suspend_enabled || !uart_console(uport))
-               uart_change_pm(state, 3);
-
-       mutex_unlock(&port->mutex);
-
-       return 0;
-}
-
-int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-       struct device *tty_dev;
-       struct uart_match match = {uport, drv};
-       struct ktermios termios;
-
-       mutex_lock(&port->mutex);
-
-       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
-       if (!uport->suspended && device_may_wakeup(tty_dev)) {
-               if (uport->irq_wake) {
-                       disable_irq_wake(uport->irq);
-                       uport->irq_wake = 0;
-               }
-               mutex_unlock(&port->mutex);
-               return 0;
-       }
-       uport->suspended = 0;
-
-       /*
-        * Re-enable the console device after suspending.
-        */
-       if (console_suspend_enabled && uart_console(uport)) {
-               /*
-                * First try to use the console cflag setting.
-                */
-               memset(&termios, 0, sizeof(struct ktermios));
-               termios.c_cflag = uport->cons->cflag;
-
-               /*
-                * If that's unset, use the tty termios setting.
-                */
-               if (port->tty && port->tty->termios && termios.c_cflag == 0)
-                       termios = *(port->tty->termios);
-
-               uart_change_pm(state, 0);
-               uport->ops->set_termios(uport, &termios, NULL);
-               console_start(uport->cons);
-       }
-
-       if (port->flags & ASYNC_SUSPENDED) {
-               const struct uart_ops *ops = uport->ops;
-               int ret;
-
-               uart_change_pm(state, 0);
-               spin_lock_irq(&uport->lock);
-               ops->set_mctrl(uport, 0);
-               spin_unlock_irq(&uport->lock);
-               if (console_suspend_enabled || !uart_console(uport)) {
-                       /* Protected by port mutex for now */
-                       struct tty_struct *tty = port->tty;
-                       ret = ops->startup(uport);
-                       if (ret == 0) {
-                               if (tty)
-                                       uart_change_speed(tty, state, NULL);
-                               spin_lock_irq(&uport->lock);
-                               ops->set_mctrl(uport, uport->mctrl);
-                               ops->start_tx(uport);
-                               spin_unlock_irq(&uport->lock);
-                               set_bit(ASYNCB_INITIALIZED, &port->flags);
-                       } else {
-                               /*
-                                * Failed to resume - maybe hardware went away?
-                                * Clear the "initialized" flag so we won't try
-                                * to call the low level drivers shutdown method.
-                                */
-                               uart_shutdown(tty, state);
-                       }
-               }
-
-               clear_bit(ASYNCB_SUSPENDED, &port->flags);
-       }
-
-       mutex_unlock(&port->mutex);
-
-       return 0;
-}
-
-static inline void
-uart_report_port(struct uart_driver *drv, struct uart_port *port)
-{
-       char address[64];
-
-       switch (port->iotype) {
-       case UPIO_PORT:
-               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
-               break;
-       case UPIO_HUB6:
-               snprintf(address, sizeof(address),
-                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
-               break;
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               snprintf(address, sizeof(address),
-                        "MMIO 0x%llx", (unsigned long long)port->mapbase);
-               break;
-       default:
-               strlcpy(address, "*unknown*", sizeof(address));
-               break;
-       }
-
-       printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
-              port->dev ? dev_name(port->dev) : "",
-              port->dev ? ": " : "",
-              drv->dev_name,
-              drv->tty_driver->name_base + port->line,
-              address, port->irq, uart_type(port));
-}
-
-static void
-uart_configure_port(struct uart_driver *drv, struct uart_state *state,
-                   struct uart_port *port)
-{
-       unsigned int flags;
-
-       /*
-        * If there isn't a port here, don't do anything further.
-        */
-       if (!port->iobase && !port->mapbase && !port->membase)
-               return;
-
-       /*
-        * Now do the auto configuration stuff.  Note that config_port
-        * is expected to claim the resources and map the port for us.
-        */
-       flags = 0;
-       if (port->flags & UPF_AUTO_IRQ)
-               flags |= UART_CONFIG_IRQ;
-       if (port->flags & UPF_BOOT_AUTOCONF) {
-               if (!(port->flags & UPF_FIXED_TYPE)) {
-                       port->type = PORT_UNKNOWN;
-                       flags |= UART_CONFIG_TYPE;
-               }
-               port->ops->config_port(port, flags);
-       }
-
-       if (port->type != PORT_UNKNOWN) {
-               unsigned long flags;
-
-               uart_report_port(drv, port);
-
-               /* Power up port for set_mctrl() */
-               uart_change_pm(state, 0);
-
-               /*
-                * Ensure that the modem control lines are de-activated.
-                * keep the DTR setting that is set in uart_set_options()
-                * We probably don't need a spinlock around this, but
-                */
-               spin_lock_irqsave(&port->lock, flags);
-               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
-               spin_unlock_irqrestore(&port->lock, flags);
-
-               /*
-                * If this driver supports console, and it hasn't been
-                * successfully registered yet, try to re-register it.
-                * It may be that the port was not available.
-                */
-               if (port->cons && !(port->cons->flags & CON_ENABLED))
-                       register_console(port->cons);
-
-               /*
-                * Power down all ports by default, except the
-                * console if we have one.
-                */
-               if (!uart_console(port))
-                       uart_change_pm(state, 3);
-       }
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-static int uart_poll_init(struct tty_driver *driver, int line, char *options)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (!state || !state->uart_port)
-               return -1;
-
-       port = state->uart_port;
-       if (!(port->ops->poll_get_char && port->ops->poll_put_char))
-               return -1;
-
-       if (options) {
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-               return uart_set_options(port, NULL, baud, parity, bits, flow);
-       }
-
-       return 0;
-}
-
-static int uart_poll_get_char(struct tty_driver *driver, int line)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-
-       if (!state || !state->uart_port)
-               return -1;
-
-       port = state->uart_port;
-       return port->ops->poll_get_char(port);
-}
-
-static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
-{
-       struct uart_driver *drv = driver->driver_state;
-       struct uart_state *state = drv->state + line;
-       struct uart_port *port;
-
-       if (!state || !state->uart_port)
-               return;
-
-       port = state->uart_port;
-       port->ops->poll_put_char(port, ch);
-}
-#endif
-
-static const struct tty_operations uart_ops = {
-       .open           = uart_open,
-       .close          = uart_close,
-       .write          = uart_write,
-       .put_char       = uart_put_char,
-       .flush_chars    = uart_flush_chars,
-       .write_room     = uart_write_room,
-       .chars_in_buffer= uart_chars_in_buffer,
-       .flush_buffer   = uart_flush_buffer,
-       .ioctl          = uart_ioctl,
-       .throttle       = uart_throttle,
-       .unthrottle     = uart_unthrottle,
-       .send_xchar     = uart_send_xchar,
-       .set_termios    = uart_set_termios,
-       .set_ldisc      = uart_set_ldisc,
-       .stop           = uart_stop,
-       .start          = uart_start,
-       .hangup         = uart_hangup,
-       .break_ctl      = uart_break_ctl,
-       .wait_until_sent= uart_wait_until_sent,
-#ifdef CONFIG_PROC_FS
-       .proc_fops      = &uart_proc_fops,
-#endif
-       .tiocmget       = uart_tiocmget,
-       .tiocmset       = uart_tiocmset,
-       .get_icount     = uart_get_icount,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_init      = uart_poll_init,
-       .poll_get_char  = uart_poll_get_char,
-       .poll_put_char  = uart_poll_put_char,
-#endif
-};
-
-static const struct tty_port_operations uart_port_ops = {
-       .carrier_raised = uart_carrier_raised,
-       .dtr_rts        = uart_dtr_rts,
-};
-
-/**
- *     uart_register_driver - register a driver with the uart core layer
- *     @drv: low level driver structure
- *
- *     Register a uart driver with the core driver.  We in turn register
- *     with the tty layer, and initialise the core driver per-port state.
- *
- *     We have a proc file in /proc/tty/driver which is named after the
- *     normal driver.
- *
- *     drv->port should be NULL, and the per-port structures should be
- *     registered using uart_add_one_port after this call has succeeded.
- */
-int uart_register_driver(struct uart_driver *drv)
-{
-       struct tty_driver *normal;
-       int i, retval;
-
-       BUG_ON(drv->state);
-
-       /*
-        * Maybe we should be using a slab cache for this, especially if
-        * we have a large number of ports to handle.
-        */
-       drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
-       if (!drv->state)
-               goto out;
-
-       normal = alloc_tty_driver(drv->nr);
-       if (!normal)
-               goto out_kfree;
-
-       drv->tty_driver = normal;
-
-       normal->owner           = drv->owner;
-       normal->driver_name     = drv->driver_name;
-       normal->name            = drv->dev_name;
-       normal->major           = drv->major;
-       normal->minor_start     = drv->minor;
-       normal->type            = TTY_DRIVER_TYPE_SERIAL;
-       normal->subtype         = SERIAL_TYPE_NORMAL;
-       normal->init_termios    = tty_std_termios;
-       normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
-       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       normal->driver_state    = drv;
-       tty_set_operations(normal, &uart_ops);
-
-       /*
-        * Initialise the UART state(s).
-        */
-       for (i = 0; i < drv->nr; i++) {
-               struct uart_state *state = drv->state + i;
-               struct tty_port *port = &state->port;
-
-               tty_port_init(port);
-               port->ops = &uart_port_ops;
-               port->close_delay     = 500;    /* .5 seconds */
-               port->closing_wait    = 30000;  /* 30 seconds */
-               tasklet_init(&state->tlet, uart_tasklet_action,
-                            (unsigned long)state);
-       }
-
-       retval = tty_register_driver(normal);
-       if (retval >= 0)
-               return retval;
-
-       put_tty_driver(normal);
-out_kfree:
-       kfree(drv->state);
-out:
-       return -ENOMEM;
-}
-
-/**
- *     uart_unregister_driver - remove a driver from the uart core layer
- *     @drv: low level driver structure
- *
- *     Remove all references to a driver from the core driver.  The low
- *     level driver must have removed all its ports via the
- *     uart_remove_one_port() if it registered them with uart_add_one_port().
- *     (ie, drv->port == NULL)
- */
-void uart_unregister_driver(struct uart_driver *drv)
-{
-       struct tty_driver *p = drv->tty_driver;
-       tty_unregister_driver(p);
-       put_tty_driver(p);
-       kfree(drv->state);
-       drv->tty_driver = NULL;
-}
-
-struct tty_driver *uart_console_device(struct console *co, int *index)
-{
-       struct uart_driver *p = co->data;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-/**
- *     uart_add_one_port - attach a driver-defined port structure
- *     @drv: pointer to the uart low level driver structure for this port
- *     @uport: uart port structure to use for this port.
- *
- *     This allows the driver to register its own uart_port structure
- *     with the core driver.  The main purpose is to allow the low
- *     level uart drivers to expand uart_port, rather than having yet
- *     more levels of structures.
- */
-int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state;
-       struct tty_port *port;
-       int ret = 0;
-       struct device *tty_dev;
-
-       BUG_ON(in_interrupt());
-
-       if (uport->line >= drv->nr)
-               return -EINVAL;
-
-       state = drv->state + uport->line;
-       port = &state->port;
-
-       mutex_lock(&port_mutex);
-       mutex_lock(&port->mutex);
-       if (state->uart_port) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       state->uart_port = uport;
-       state->pm_state = -1;
-
-       uport->cons = drv->cons;
-       uport->state = state;
-
-       /*
-        * If this port is a console, then the spinlock is already
-        * initialised.
-        */
-       if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
-               spin_lock_init(&uport->lock);
-               lockdep_set_class(&uport->lock, &port_lock_key);
-       }
-
-       uart_configure_port(drv, state, uport);
-
-       /*
-        * Register the port whether it's detected or not.  This allows
-        * setserial to be used to alter this ports parameters.
-        */
-       tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
-       if (likely(!IS_ERR(tty_dev))) {
-               device_init_wakeup(tty_dev, 1);
-               device_set_wakeup_enable(tty_dev, 0);
-       } else
-               printk(KERN_ERR "Cannot register tty device on line %d\n",
-                      uport->line);
-
-       /*
-        * Ensure UPF_DEAD is not set.
-        */
-       uport->flags &= ~UPF_DEAD;
-
- out:
-       mutex_unlock(&port->mutex);
-       mutex_unlock(&port_mutex);
-
-       return ret;
-}
-
-/**
- *     uart_remove_one_port - detach a driver defined port structure
- *     @drv: pointer to the uart low level driver structure for this port
- *     @uport: uart port structure for this port
- *
- *     This unhooks (and hangs up) the specified port structure from the
- *     core driver.  No further calls will be made to the low-level code
- *     for this port.
- */
-int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
-{
-       struct uart_state *state = drv->state + uport->line;
-       struct tty_port *port = &state->port;
-
-       BUG_ON(in_interrupt());
-
-       if (state->uart_port != uport)
-               printk(KERN_ALERT "Removing wrong port: %p != %p\n",
-                       state->uart_port, uport);
-
-       mutex_lock(&port_mutex);
-
-       /*
-        * Mark the port "dead" - this prevents any opens from
-        * succeeding while we shut down the port.
-        */
-       mutex_lock(&port->mutex);
-       uport->flags |= UPF_DEAD;
-       mutex_unlock(&port->mutex);
-
-       /*
-        * Remove the devices from the tty layer
-        */
-       tty_unregister_device(drv->tty_driver, uport->line);
-
-       if (port->tty)
-               tty_vhangup(port->tty);
-
-       /*
-        * Free the port IO and memory resources, if any.
-        */
-       if (uport->type != PORT_UNKNOWN)
-               uport->ops->release_port(uport);
-
-       /*
-        * Indicate that there isn't a port here anymore.
-        */
-       uport->type = PORT_UNKNOWN;
-
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       tasklet_kill(&state->tlet);
-
-       state->uart_port = NULL;
-       mutex_unlock(&port_mutex);
-
-       return 0;
-}
-
-/*
- *     Are the two ports equivalent?
- */
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
-{
-       if (port1->iotype != port2->iotype)
-               return 0;
-
-       switch (port1->iotype) {
-       case UPIO_PORT:
-               return (port1->iobase == port2->iobase);
-       case UPIO_HUB6:
-               return (port1->iobase == port2->iobase) &&
-                      (port1->hub6   == port2->hub6);
-       case UPIO_MEM:
-       case UPIO_MEM32:
-       case UPIO_AU:
-       case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
-               return (port1->mapbase == port2->mapbase);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(uart_match_port);
-
-EXPORT_SYMBOL(uart_write_wakeup);
-EXPORT_SYMBOL(uart_register_driver);
-EXPORT_SYMBOL(uart_unregister_driver);
-EXPORT_SYMBOL(uart_suspend_port);
-EXPORT_SYMBOL(uart_resume_port);
-EXPORT_SYMBOL(uart_add_one_port);
-EXPORT_SYMBOL(uart_remove_one_port);
-
-MODULE_DESCRIPTION("Serial driver core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
deleted file mode 100644 (file)
index 93760b2..0000000
+++ /dev/null
@@ -1,869 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA serial devices
-
-    serial_cs.c 1.134 2002/05/04 05:48:53
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include "8250.h"
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Enable the speaker? */
-static int do_sound = 1;
-/* Skip strict UART tests? */
-static int buggy_uart;
-
-module_param(do_sound, int, 0444);
-module_param(buggy_uart, int, 0444);
-
-/*====================================================================*/
-
-/* Table of multi-port card ID's */
-
-struct serial_quirk {
-       unsigned int manfid;
-       unsigned int prodid;
-       int multi;              /* 1 = multifunction, > 1 = # ports */
-       void (*config)(struct pcmcia_device *);
-       void (*setup)(struct pcmcia_device *, struct uart_port *);
-       void (*wakeup)(struct pcmcia_device *);
-       int (*post)(struct pcmcia_device *);
-};
-
-struct serial_info {
-       struct pcmcia_device    *p_dev;
-       int                     ndev;
-       int                     multi;
-       int                     slave;
-       int                     manfid;
-       int                     prodid;
-       int                     c950ctrl;
-       int                     line[4];
-       const struct serial_quirk *quirk;
-};
-
-struct serial_cfg_mem {
-       tuple_t tuple;
-       cisparse_t parse;
-       u_char buf[256];
-};
-
-/*
- * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
- * manfid 0x0160, 0x0104
- * This card appears to have a 14.7456MHz clock.
- */
-/* Generic Modem: MD55x (GPRS/EDGE) have
- * Elan VPU16551 UART with 14.7456MHz oscillator
- * manfid 0x015D, 0x4C45
- */
-static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
-{
-       port->uartclk = 14745600;
-}
-
-static int quirk_post_ibm(struct pcmcia_device *link)
-{
-       u8 val;
-       int ret;
-
-       ret = pcmcia_read_config_byte(link, 0x800, &val);
-       if (ret)
-               goto failed;
-
-       ret = pcmcia_write_config_byte(link, 0x800, val | 1);
-       if (ret)
-               goto failed;
-       return 0;
-
- failed:
-       return -ENODEV;
-}
-
-/*
- * Nokia cards are not really multiport cards.  Shouldn't this
- * be handled by setting the quirk entry .multi = 0 | 1 ?
- */
-static void quirk_config_nokia(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->multi > 1)
-               info->multi = 1;
-}
-
-static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->c950ctrl)
-               outb(12, info->c950ctrl + 1);
-}
-
-/* request_region? oxsemi branch does no request_region too... */
-/*
- * This sequence is needed to properly initialize MC45 attached to OXCF950.
- * I tried decreasing these msleep()s, but it worked properly (survived
- * 1000 stop/start operations) with these timeouts (or bigger).
- */
-static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       unsigned int ctrl = info->c950ctrl;
-
-       outb(0xA, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(300);
-       outb(0xC, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(200);
-       outb(0xF, ctrl + 1);
-       msleep(100);
-       outb(0xE, ctrl + 1);
-       msleep(100);
-       outb(0xC, ctrl + 1);
-}
-
-/*
- * Socket Dual IO: this enables irq's for second port
- */
-static void quirk_config_socket(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       if (info->multi)
-               link->config_flags |= CONF_ENABLE_ESR;
-}
-
-static const struct serial_quirk quirks[] = {
-       {
-               .manfid = 0x0160,
-               .prodid = 0x0104,
-               .multi  = -1,
-               .setup  = quirk_setup_brainboxes_0104,
-       }, {
-               .manfid = 0x015D,
-               .prodid = 0x4C45,
-               .multi  = -1,
-               .setup  = quirk_setup_brainboxes_0104,
-       }, {
-               .manfid = MANFID_IBM,
-               .prodid = ~0,
-               .multi  = -1,
-               .post   = quirk_post_ibm,
-       }, {
-               .manfid = MANFID_INTEL,
-               .prodid = PRODID_INTEL_DUAL_RS232,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_NATINST,
-               .prodid = PRODID_NATINST_QUAD_RS232,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_NOKIA,
-               .prodid = ~0,
-               .multi  = -1,
-               .config = quirk_config_nokia,
-       }, {
-               .manfid = MANFID_OMEGA,
-               .prodid = PRODID_OMEGA_QSP_100,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_OXSEMI,
-               .prodid = ~0,
-               .multi  = -1,
-               .wakeup = quirk_wakeup_oxsemi,
-       }, {
-               .manfid = MANFID_POSSIO,
-               .prodid = PRODID_POSSIO_GCC,
-               .multi  = -1,
-               .wakeup = quirk_wakeup_possio_gcc,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232_D1,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_DUAL_RS232_G,
-               .multi  = 2,
-       }, {
-               .manfid = MANFID_QUATECH,
-               .prodid = PRODID_QUATECH_QUAD_RS232,
-               .multi  = 4,
-       }, {
-               .manfid = MANFID_SOCKET,
-               .prodid = PRODID_SOCKET_DUAL_RS232,
-               .multi  = 2,
-               .config = quirk_config_socket,
-       }, {
-               .manfid = MANFID_SOCKET,
-               .prodid = ~0,
-               .multi  = -1,
-               .config = quirk_config_socket,
-       }
-};
-
-
-static int serial_config(struct pcmcia_device * link);
-
-
-static void serial_remove(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       dev_dbg(&link->dev, "serial_release\n");
-
-       /*
-        * Recheck to see if the device is still configured.
-        */
-       for (i = 0; i < info->ndev; i++)
-               serial8250_unregister_port(info->line[i]);
-
-       if (!info->slave)
-               pcmcia_disable_device(link);
-}
-
-static int serial_suspend(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       for (i = 0; i < info->ndev; i++)
-               serial8250_suspend_port(info->line[i]);
-
-       return 0;
-}
-
-static int serial_resume(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       for (i = 0; i < info->ndev; i++)
-               serial8250_resume_port(info->line[i]);
-
-       if (info->quirk && info->quirk->wakeup)
-               info->quirk->wakeup(link);
-
-       return 0;
-}
-
-static int serial_probe(struct pcmcia_device *link)
-{
-       struct serial_info *info;
-
-       dev_dbg(&link->dev, "serial_attach()\n");
-
-       /* Create new serial device */
-       info = kzalloc(sizeof (*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       info->p_dev = link;
-       link->priv = info;
-
-       link->config_flags |= CONF_ENABLE_IRQ;
-       if (do_sound)
-               link->config_flags |= CONF_ENABLE_SPKR;
-
-       return serial_config(link);
-}
-
-static void serial_detach(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-
-       dev_dbg(&link->dev, "serial_detach\n");
-
-       /*
-        * Ensure that the ports have been released.
-        */
-       serial_remove(link);
-
-       /* free bits */
-       kfree(info);
-}
-
-/*====================================================================*/
-
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
-                       unsigned int iobase, int irq)
-{
-       struct uart_port port;
-       int line;
-
-       memset(&port, 0, sizeof (struct uart_port));
-       port.iobase = iobase;
-       port.irq = irq;
-       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &handle->dev;
-       if (buggy_uart)
-               port.flags |= UPF_BUGGY_UART;
-
-       if (info->quirk && info->quirk->setup)
-               info->quirk->setup(handle, &port);
-
-       line = serial8250_register_port(&port);
-       if (line < 0) {
-               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
-                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
-               return -EINVAL;
-       }
-
-       info->line[info->ndev] = line;
-       info->ndev++;
-
-       return 0;
-}
-
-/*====================================================================*/
-
-static int pfc_config(struct pcmcia_device *p_dev)
-{
-       unsigned int port = 0;
-       struct serial_info *info = p_dev->priv;
-
-       if ((p_dev->resource[1]->end != 0) &&
-               (resource_size(p_dev->resource[1]) == 8)) {
-               port = p_dev->resource[1]->start;
-               info->slave = 1;
-       } else if ((info->manfid == MANFID_OSITECH) &&
-               (resource_size(p_dev->resource[0]) == 0x40)) {
-               port = p_dev->resource[0]->start + 0x28;
-               info->slave = 1;
-       }
-       if (info->slave)
-               return setup_serial(p_dev, info, port, p_dev->irq);
-
-       dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
-       return -ENODEV;
-}
-
-static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-       static const int size_table[2] = { 8, 16 };
-       int *try = priv_data;
-
-       if (p_dev->resource[0]->start == 0)
-               return -ENODEV;
-
-       if ((*try & 0x1) == 0)
-               p_dev->io_lines = 16;
-
-       if (p_dev->resource[0]->end != size_table[(*try >> 1)])
-               return -ENODEV;
-
-       p_dev->resource[0]->end = 8;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
-       return pcmcia_request_io(p_dev);
-}
-
-static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
-                                       void *priv_data)
-{
-       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-       int j;
-
-       if (p_dev->io_lines > 3)
-               return -ENODEV;
-
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[0]->end = 8;
-
-       for (j = 0; j < 5; j++) {
-               p_dev->resource[0]->start = base[j];
-               p_dev->io_lines = base[j] ? 16 : 3;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
-}
-
-static int simple_config(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i = -ENODEV, try;
-
-       /* First pass: look for a config entry that looks normal.
-        * Two tries: without IO aliases, then with aliases */
-       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
-       for (try = 0; try < 4; try++)
-               if (!pcmcia_loop_config(link, simple_config_check, &try))
-                       goto found_port;
-
-       /* Second pass: try to find an entry that isn't picky about
-          its base address, then try to grab any standard serial port
-          address, and finally try to get any free port. */
-       if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
-               goto found_port;
-
-       dev_warn(&link->dev, "no usable port range found, giving up\n");
-       return -1;
-
-found_port:
-       if (info->multi && (info->manfid == MANFID_3COM))
-               link->config_index &= ~(0x08);
-
-       /*
-        * Apply any configuration quirks.
-        */
-       if (info->quirk && info->quirk->config)
-               info->quirk->config(link);
-
-       i = pcmcia_enable_device(link);
-       if (i != 0)
-               return -1;
-       return setup_serial(link, info, link->resource[0]->start, link->irq);
-}
-
-static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-       int *multi = priv_data;
-
-       if (p_dev->resource[1]->end)
-               return -EINVAL;
-
-       /* The quad port cards have bad CIS's, so just look for a
-          window larger than 8 ports and assume it will be right */
-       if (p_dev->resource[0]->end <= 8)
-               return -EINVAL;
-
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[0]->end = *multi * 8;
-
-       if (pcmcia_request_io(p_dev))
-               return -ENODEV;
-       return 0;
-}
-
-static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
-                                      void *priv_data)
-{
-       int *base2 = priv_data;
-
-       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
-               return -ENODEV;
-
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
-       if (pcmcia_request_io(p_dev))
-               return -ENODEV;
-
-       *base2 = p_dev->resource[0]->start + 8;
-       return 0;
-}
-
-static int multi_config(struct pcmcia_device *link)
-{
-       struct serial_info *info = link->priv;
-       int i, base2 = 0;
-
-       link->config_flags |= CONF_AUTO_SET_IO;
-       /* First, look for a generic full-sized window */
-       if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
-               base2 = link->resource[0]->start + 8;
-       else {
-               /* If that didn't work, look for two windows */
-               info->multi = 2;
-               if (pcmcia_loop_config(link, multi_config_check_notpicky,
-                                      &base2)) {
-                       dev_warn(&link->dev, "no usable port range "
-                              "found, giving up\n");
-                       return -ENODEV;
-               }
-       }
-
-       if (!link->irq)
-               dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
-
-       /*
-        * Apply any configuration quirks.
-        */
-       if (info->quirk && info->quirk->config)
-               info->quirk->config(link);
-
-       i = pcmcia_enable_device(link);
-       if (i != 0)
-               return -ENODEV;
-
-       /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-        * 8 registers are for the UART, the others are extra registers.
-        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
-        */
-       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
-                               info->prodid == PRODID_POSSIO_GCC)) {
-               int err;
-
-               if (link->config_index == 1 ||
-                   link->config_index == 3) {
-                       err = setup_serial(link, info, base2,
-                                       link->irq);
-                       base2 = link->resource[0]->start;
-               } else {
-                       err = setup_serial(link, info, link->resource[0]->start,
-                                       link->irq);
-               }
-               info->c950ctrl = base2;
-
-               /*
-                * FIXME: We really should wake up the port prior to
-                * handing it over to the serial layer.
-                */
-               if (info->quirk && info->quirk->wakeup)
-                       info->quirk->wakeup(link);
-
-               return 0;
-       }
-
-       setup_serial(link, info, link->resource[0]->start, link->irq);
-       for (i = 0; i < info->multi - 1; i++)
-               setup_serial(link, info, base2 + (8 * i),
-                               link->irq);
-       return 0;
-}
-
-static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)
-{
-       struct serial_info *info = p_dev->priv;
-
-       if (!p_dev->resource[0]->end)
-               return -EINVAL;
-
-       if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
-               info->multi = p_dev->resource[0]->end >> 3;
-
-       if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
-               && (p_dev->resource[1]->end == 8))
-               info->multi = 2;
-
-       return 0; /* break */
-}
-
-
-static int serial_config(struct pcmcia_device * link)
-{
-       struct serial_info *info = link->priv;
-       int i;
-
-       dev_dbg(&link->dev, "serial_config\n");
-
-       /* Is this a compliant multifunction card? */
-       info->multi = (link->socket->functions > 1);
-
-       /* Is this a multiport card? */
-       info->manfid = link->manf_id;
-       info->prodid = link->card_id;
-
-       for (i = 0; i < ARRAY_SIZE(quirks); i++)
-               if ((quirks[i].manfid == ~0 ||
-                    quirks[i].manfid == info->manfid) &&
-                   (quirks[i].prodid == ~0 ||
-                    quirks[i].prodid == info->prodid)) {
-                       info->quirk = &quirks[i];
-                       break;
-               }
-
-       /* Another check for dual-serial cards: look for either serial or
-          multifunction cards that ask for appropriate IO port ranges */
-       if ((info->multi == 0) &&
-           (link->has_func_id) &&
-           (link->socket->pcmcia_pfc == 0) &&
-           ((link->func_id == CISTPL_FUNCID_MULTI) ||
-            (link->func_id == CISTPL_FUNCID_SERIAL)))
-               pcmcia_loop_config(link, serial_check_for_multi, info);
-
-       /*
-        * Apply any multi-port quirk.
-        */
-       if (info->quirk && info->quirk->multi != -1)
-               info->multi = info->quirk->multi;
-
-       dev_info(&link->dev,
-               "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
-               link->manf_id, link->card_id,
-               link->socket->pcmcia_pfc, info->multi, info->quirk);
-       if (link->socket->pcmcia_pfc)
-               i = pfc_config(link);
-       else if (info->multi > 1)
-               i = multi_config(link);
-       else
-               i = simple_config(link);
-
-       if (i || info->ndev == 0)
-               goto failed;
-
-       /*
-        * Apply any post-init quirk.  FIXME: This should really happen
-        * before we register the port, since it might already be in use.
-        */
-       if (info->quirk && info->quirk->post)
-               if (info->quirk->post(link))
-                       goto failed;
-
-       return 0;
-
-failed:
-       dev_warn(&link->dev, "failed to initialize\n");
-       serial_remove(link);
-       return -ENODEV;
-}
-
-static struct pcmcia_device_id serial_ids[] = {
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
-       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
-       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
-       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
-       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
-       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
-       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
-       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
-       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
-       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
-       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
-       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
-       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
-       PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
-       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
-       PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
-       PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
-       PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
-       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
-       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
-       PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
-       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
-       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
-       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
-       PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
-       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
-       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
-       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
-       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
-       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
-       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
-       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
-       PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
-       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
-       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
-       PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
-       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
-       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
-       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
-       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
-       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
-       PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
-       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
-       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
-       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
-       PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
-       PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
-       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
-       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
-       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"),  /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
-       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
-       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
-       PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100  1.00.",0x19ca78af,0xf964f42b),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232  1.00.",0x19ca78af,0x69fb7490),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
-       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
-       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
-       PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
-       /* too generic */
-       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
-       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
-       PCMCIA_DEVICE_FUNC_ID(2),
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, serial_ids);
-
-MODULE_FIRMWARE("cis/PCMLM28.cis");
-MODULE_FIRMWARE("cis/DP83903.cis");
-MODULE_FIRMWARE("cis/3CCFEM556.cis");
-MODULE_FIRMWARE("cis/3CXEM556.cis");
-MODULE_FIRMWARE("cis/SW_8xx_SER.cis");
-MODULE_FIRMWARE("cis/SW_7xx_SER.cis");
-MODULE_FIRMWARE("cis/SW_555_SER.cis");
-MODULE_FIRMWARE("cis/MT5634ZLX.cis");
-MODULE_FIRMWARE("cis/COMpad2.cis");
-MODULE_FIRMWARE("cis/COMpad4.cis");
-MODULE_FIRMWARE("cis/RS-COM-2P.cis");
-
-static struct pcmcia_driver serial_cs_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "serial_cs",
-       .probe          = serial_probe,
-       .remove         = serial_detach,
-       .id_table       = serial_ids,
-       .suspend        = serial_suspend,
-       .resume         = serial_resume,
-};
-
-static int __init init_serial_cs(void)
-{
-       return pcmcia_register_driver(&serial_cs_driver);
-}
-
-static void __exit exit_serial_cs(void)
-{
-       pcmcia_unregister_driver(&serial_cs_driver);
-}
-
-module_init(init_serial_cs);
-module_exit(exit_serial_cs);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
deleted file mode 100644 (file)
index b196202..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- *  drivers/serial/serial_ks8695.c
- *
- *  Driver for KS8695 serial ports
- *
- *  Based on drivers/serial/serial_amba.c, by Kam Lee.
- *
- *  Copyright 2002-2005 Micrel Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
-
-#include <mach/regs-uart.h>
-#include <mach/regs-irq.h>
-
-#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-
-#define SERIAL_KS8695_MAJOR    204
-#define SERIAL_KS8695_MINOR    16
-#define SERIAL_KS8695_DEVNAME  "ttyAM"
-
-#define SERIAL_KS8695_NR       1
-
-/*
- * Access macros for the KS8695 UART
- */
-#define UART_GET_CHAR(p)       (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
-#define UART_PUT_CHAR(p, c)    __raw_writel((c), (p)->membase + KS8695_URTH)
-#define UART_GET_FCR(p)                __raw_readl((p)->membase + KS8695_URFC)
-#define UART_PUT_FCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URFC)
-#define UART_GET_MSR(p)                __raw_readl((p)->membase + KS8695_URMS)
-#define UART_GET_LSR(p)                __raw_readl((p)->membase + KS8695_URLS)
-#define UART_GET_LCR(p)                __raw_readl((p)->membase + KS8695_URLC)
-#define UART_PUT_LCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URLC)
-#define UART_GET_MCR(p)                __raw_readl((p)->membase + KS8695_URMC)
-#define UART_PUT_MCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URMC)
-#define UART_GET_BRDR(p)       __raw_readl((p)->membase + KS8695_URBD)
-#define UART_PUT_BRDR(p, c)    __raw_writel((c), (p)->membase + KS8695_URBD)
-
-#define KS8695_CLR_TX_INT()    __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
-
-#define UART_DUMMY_LSR_RX      0x100
-#define UART_PORT_SIZE         (KS8695_USR - KS8695_URRB + 4)
-
-static inline int tx_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 1;
-}
-
-static inline int rx_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 2;
-}
-
-static inline int ms_enabled(struct uart_port *port)
-{
-       return port->unused[0] & 4;
-}
-
-static inline void ms_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 4;
-       else
-               port->unused[0] &= ~4;
-}
-
-static inline void rx_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 2;
-       else
-               port->unused[0] &= ~2;
-}
-
-static inline void tx_enable(struct uart_port *port, int enabled)
-{
-       if(enabled)
-               port->unused[0] |= 1;
-       else
-               port->unused[0] &= ~1;
-}
-
-
-#ifdef SUPPORT_SYSRQ
-static struct console ks8695_console;
-#endif
-
-static void ks8695uart_stop_tx(struct uart_port *port)
-{
-       if (tx_enabled(port)) {
-               /* use disable_irq_nosync() and not disable_irq() to avoid self
-                * imposed deadlock by not waiting for irq handler to end,
-                * since this ks8695uart_stop_tx() is called from interrupt context.
-                */
-               disable_irq_nosync(KS8695_IRQ_UART_TX);
-               tx_enable(port, 0);
-       }
-}
-
-static void ks8695uart_start_tx(struct uart_port *port)
-{
-       if (!tx_enabled(port)) {
-               enable_irq(KS8695_IRQ_UART_TX);
-               tx_enable(port, 1);
-       }
-}
-
-static void ks8695uart_stop_rx(struct uart_port *port)
-{
-       if (rx_enabled(port)) {
-               disable_irq(KS8695_IRQ_UART_RX);
-               rx_enable(port, 0);
-       }
-}
-
-static void ks8695uart_enable_ms(struct uart_port *port)
-{
-       if (!ms_enabled(port)) {
-               enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
-               ms_enable(port,1);
-       }
-}
-
-static void ks8695uart_disable_ms(struct uart_port *port)
-{
-       if (ms_enabled(port)) {
-               disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
-               ms_enable(port,0);
-       }
-}
-
-static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned int status, ch, lsr, flg, max_count = 256;
-
-       status = UART_GET_LSR(port);            /* clears pending LSR interrupts */
-       while ((status & URLS_URDR) && max_count--) {
-               ch = UART_GET_CHAR(port);
-               flg = TTY_NORMAL;
-
-               port->icount.rx++;
-
-               /*
-                * Note that the error handling code is
-                * out of the main execution path
-                */
-               lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
-               if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
-                       if (lsr & URLS_URBI) {
-                               lsr &= ~(URLS_URFE | URLS_URPE);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       }
-                       if (lsr & URLS_URPE)
-                               port->icount.parity++;
-                       if (lsr & URLS_URFE)
-                               port->icount.frame++;
-                       if (lsr & URLS_URROE)
-                               port->icount.overrun++;
-
-                       lsr &= port->read_status_mask;
-
-                       if (lsr & URLS_URBI)
-                               flg = TTY_BREAK;
-                       else if (lsr & URLS_URPE)
-                               flg = TTY_PARITY;
-                       else if (lsr & URLS_URFE)
-                               flg = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, lsr, URLS_URROE, ch, flg);
-
-ignore_char:
-               status = UART_GET_LSR(port);
-       }
-       tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-
-static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int count;
-
-       if (port->x_char) {
-               KS8695_CLR_TX_INT();
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return IRQ_HANDLED;
-       }
-
-       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
-               ks8695uart_stop_tx(port);
-               return IRQ_HANDLED;
-       }
-
-       count = 16;     /* fifo size */
-       while (!uart_circ_empty(xmit) && (count-- > 0)) {
-               KS8695_CLR_TX_INT();
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               ks8695uart_stop_tx(port);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned int status;
-
-       /*
-        * clear modem interrupt by reading MSR
-        */
-       status = UART_GET_MSR(port);
-
-       if (status & URMS_URDDCD)
-               uart_handle_dcd_change(port, status & URMS_URDDCD);
-
-       if (status & URMS_URDDST)
-               port->icount.dsr++;
-
-       if (status & URMS_URDCTS)
-               uart_handle_cts_change(port, status & URMS_URDCTS);
-
-       if (status & URMS_URTERI)
-               port->icount.rng++;
-
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int ks8695uart_tx_empty(struct uart_port *port)
-{
-       return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
-{
-       unsigned int result = 0;
-       unsigned int status;
-
-       status = UART_GET_MSR(port);
-       if (status & URMS_URDCD)
-               result |= TIOCM_CAR;
-       if (status & URMS_URDSR)
-               result |= TIOCM_DSR;
-       if (status & URMS_URCTS)
-               result |= TIOCM_CTS;
-       if (status & URMS_URRI)
-               result |= TIOCM_RI;
-
-       return result;
-}
-
-static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       unsigned int mcr;
-
-       mcr = UART_GET_MCR(port);
-       if (mctrl & TIOCM_RTS)
-               mcr |= URMC_URRTS;
-       else
-               mcr &= ~URMC_URRTS;
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= URMC_URDTR;
-       else
-               mcr &= ~URMC_URDTR;
-
-       UART_PUT_MCR(port, mcr);
-}
-
-static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
-{
-       unsigned int lcr;
-
-       lcr = UART_GET_LCR(port);
-
-       if (break_state == -1)
-               lcr |= URLC_URSBC;
-       else
-               lcr &= ~URLC_URSBC;
-
-       UART_PUT_LCR(port, lcr);
-}
-
-static int ks8695uart_startup(struct uart_port *port)
-{
-       int retval;
-
-       set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
-       tx_enable(port, 0);
-       rx_enable(port, 1);
-       ms_enable(port, 1);
-
-       /*
-        * Allocate the IRQ
-        */
-       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
-       if (retval)
-               goto err_tx;
-
-       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
-       if (retval)
-               goto err_rx;
-
-       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
-       if (retval)
-               goto err_ls;
-
-       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
-       if (retval)
-               goto err_ms;
-
-       return 0;
-
-err_ms:
-       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
-err_ls:
-       free_irq(KS8695_IRQ_UART_RX, port);
-err_rx:
-       free_irq(KS8695_IRQ_UART_TX, port);
-err_tx:
-       return retval;
-}
-
-static void ks8695uart_shutdown(struct uart_port *port)
-{
-       /*
-        * Free the interrupt
-        */
-       free_irq(KS8695_IRQ_UART_RX, port);
-       free_irq(KS8695_IRQ_UART_TX, port);
-       free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
-       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
-
-       /* disable break condition and fifos */
-       UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
-       UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
-}
-
-static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
-{
-       unsigned int lcr, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               lcr = URCL_5;
-               break;
-       case CS6:
-               lcr = URCL_6;
-               break;
-       case CS7:
-               lcr = URCL_7;
-               break;
-       default:
-               lcr = URCL_8;
-               break;
-       }
-
-       /* stop bits */
-       if (termios->c_cflag & CSTOPB)
-               lcr |= URLC_URSB;
-
-       /* parity */
-       if (termios->c_cflag & PARENB) {
-               if (termios->c_cflag & CMSPAR) {        /* Mark or Space parity */
-                       if (termios->c_cflag & PARODD)
-                               lcr |= URPE_MARK;
-                       else
-                               lcr |= URPE_SPACE;
-               }
-               else if (termios->c_cflag & PARODD)
-                       lcr |= URPE_ODD;
-               else
-                       lcr |= URPE_EVEN;
-       }
-
-       if (port->fifosize > 1)
-               fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       port->read_status_mask = URLS_URROE;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= (URLS_URFE | URLS_URPE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= URLS_URBI;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= URLS_URBI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= URLS_URROE;
-       }
-
-       /*
-        * Ignore all characters if CREAD is not set.
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_DUMMY_LSR_RX;
-
-       /* first, disable everything */
-       if (UART_ENABLE_MS(port, termios->c_cflag))
-               ks8695uart_enable_ms(port);
-       else
-               ks8695uart_disable_ms(port);
-
-       /* Set baud rate */
-       UART_PUT_BRDR(port, quot);
-
-       UART_PUT_LCR(port, lcr);
-       UART_PUT_FCR(port, fcr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *ks8695uart_type(struct uart_port *port)
-{
-       return port->type == PORT_KS8695 ? "KS8695" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'
- */
-static void ks8695uart_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, UART_PORT_SIZE);
-}
-
-/*
- * Request the memory region(s) being used by 'port'
- */
-static int ks8695uart_request_port(struct uart_port *port)
-{
-       return request_mem_region(port->mapbase, UART_PORT_SIZE,
-                       "serial_ks8695") != NULL ? 0 : -EBUSY;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void ks8695uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_KS8695;
-               ks8695uart_request_port(port);
-       }
-}
-
-/*
- * verify the new serial_struct (for TIOCSSERIAL).
- */
-static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
-               ret = -EINVAL;
-       if (ser->irq != port->irq)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600)
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops ks8695uart_pops = {
-       .tx_empty       = ks8695uart_tx_empty,
-       .set_mctrl      = ks8695uart_set_mctrl,
-       .get_mctrl      = ks8695uart_get_mctrl,
-       .stop_tx        = ks8695uart_stop_tx,
-       .start_tx       = ks8695uart_start_tx,
-       .stop_rx        = ks8695uart_stop_rx,
-       .enable_ms      = ks8695uart_enable_ms,
-       .break_ctl      = ks8695uart_break_ctl,
-       .startup        = ks8695uart_startup,
-       .shutdown       = ks8695uart_shutdown,
-       .set_termios    = ks8695uart_set_termios,
-       .type           = ks8695uart_type,
-       .release_port   = ks8695uart_release_port,
-       .request_port   = ks8695uart_request_port,
-       .config_port    = ks8695uart_config_port,
-       .verify_port    = ks8695uart_verify_port,
-};
-
-static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
-       {
-               .membase        = (void *) KS8695_UART_VA,
-               .mapbase        = KS8695_UART_VA,
-               .iotype         = SERIAL_IO_MEM,
-               .irq            = KS8695_IRQ_UART_TX,
-               .uartclk        = KS8695_CLOCK_RATE * 16,
-               .fifosize       = 16,
-               .ops            = &ks8695uart_pops,
-               .flags          = ASYNC_BOOT_AUTOCONF,
-               .line           = 0,
-       }
-};
-
-#ifdef CONFIG_SERIAL_KS8695_CONSOLE
-static void ks8695_console_putchar(struct uart_port *port, int ch)
-{
-       while (!(UART_GET_LSR(port) & URLS_URTHRE))
-               barrier();
-
-       UART_PUT_CHAR(port, ch);
-}
-
-static void ks8695_console_write(struct console *co, const char *s, u_int count)
-{
-       struct uart_port *port = ks8695uart_ports + co->index;
-
-       uart_console_write(port, s, count, ks8695_console_putchar);
-}
-
-static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-{
-       unsigned int lcr;
-
-       lcr = UART_GET_LCR(port);
-
-       switch (lcr & URLC_PARITY) {
-               case URPE_ODD:
-                       *parity = 'o';
-                       break;
-               case URPE_EVEN:
-                       *parity = 'e';
-                       break;
-               default:
-                       *parity = 'n';
-       }
-
-       switch (lcr & URLC_URCL) {
-               case URCL_5:
-                       *bits = 5;
-                       break;
-               case URCL_6:
-                       *bits = 6;
-                       break;
-               case URCL_7:
-                       *bits = 7;
-                       break;
-               default:
-                       *bits = 8;
-       }
-
-       *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
-       *baud /= 16;
-       *baud &= 0xFFFFFFF0;
-}
-
-static int __init ks8695_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               ks8695_console_get_options(port, &baud, &parity, &bits);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver ks8695_reg;
-
-static struct console ks8695_console = {
-       .name           = SERIAL_KS8695_DEVNAME,
-       .write          = ks8695_console_write,
-       .device         = uart_console_device,
-       .setup          = ks8695_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &ks8695_reg,
-};
-
-static int __init ks8695_console_init(void)
-{
-       add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL);
-       register_console(&ks8695_console);
-       return 0;
-}
-
-console_initcall(ks8695_console_init);
-
-#define KS8695_CONSOLE &ks8695_console
-#else
-#define KS8695_CONSOLE NULL
-#endif
-
-static struct uart_driver ks8695_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial_ks8695",
-       .dev_name               = SERIAL_KS8695_DEVNAME,
-       .major                  = SERIAL_KS8695_MAJOR,
-       .minor                  = SERIAL_KS8695_MINOR,
-       .nr                     = SERIAL_KS8695_NR,
-       .cons                   = KS8695_CONSOLE,
-};
-
-static int __init ks8695uart_init(void)
-{
-       int i, ret;
-
-       printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
-
-       ret = uart_register_driver(&ks8695_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < SERIAL_KS8695_NR; i++)
-               uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
-
-       return 0;
-}
-
-static void __exit ks8695uart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < SERIAL_KS8695_NR; i++)
-               uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
-       uart_unregister_driver(&ks8695_reg);
-}
-
-module_init(ks8695uart_init);
-module_exit(ks8695uart_exit);
-
-MODULE_DESCRIPTION("KS8695 serial port driver");
-MODULE_AUTHOR("Micrel Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
deleted file mode 100644 (file)
index ea74470..0000000
+++ /dev/null
@@ -1,682 +0,0 @@
-/* drivers/serial/serial_lh7a40x.c
- *
- *  Copyright (C) 2004 Coastal Environmental Systems
- *
- *  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.
- *
- */
-
-/* Driver for Sharp LH7A40X embedded serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
- *
- *  ---
- *
- * This driver supports the embedded UARTs of the Sharp LH7A40X series
- * CPUs.  While similar to the 16550 and other UART chips, there is
- * nothing close to register compatibility.  Moreover, some of the
- * modem control lines are not available, either in the chip or they
- * are lacking in the board-level implementation.
- *
- * - Use of SIRDIS
- *   For simplicity, we disable the IR functions of any UART whenever
- *   we enable it.
- *
- */
-
-
-#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#define DEV_MAJOR      204
-#define DEV_MINOR      16
-#define DEV_NR         3
-
-#define ISR_LOOP_LIMIT 256
-
-#define UR(p,o)        _UR ((p)->membase, o)
-#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
-#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
-#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
-
-#define UART_REG_SIZE  32
-
-#define UART_R_DATA    (0x00)
-#define UART_R_FCON    (0x04)
-#define UART_R_BRCON   (0x08)
-#define UART_R_CON     (0x0c)
-#define UART_R_STATUS  (0x10)
-#define UART_R_RAWISR  (0x14)
-#define UART_R_INTEN   (0x18)
-#define UART_R_ISR     (0x1c)
-
-#define UARTEN         (0x01)          /* UART enable */
-#define SIRDIS         (0x02)          /* Serial IR disable (UART1 only) */
-
-#define RxEmpty                (0x10)
-#define TxEmpty                (0x80)
-#define TxFull         (0x20)
-#define nRxRdy         RxEmpty
-#define nTxRdy         TxFull
-#define TxBusy         (0x08)
-
-#define RxBreak                (0x0800)
-#define RxOverrunError (0x0400)
-#define RxParityError  (0x0200)
-#define RxFramingError (0x0100)
-#define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError)
-
-#define DCD            (0x04)
-#define DSR            (0x02)
-#define CTS            (0x01)
-
-#define RxInt          (0x01)
-#define TxInt          (0x02)
-#define ModemInt       (0x04)
-#define RxTimeoutInt   (0x08)
-
-#define MSEOI          (0x10)
-
-#define WLEN_8         (0x60)
-#define WLEN_7         (0x40)
-#define WLEN_6         (0x20)
-#define WLEN_5         (0x00)
-#define WLEN           (0x60)  /* Mask for all word-length bits */
-#define STP2           (0x08)
-#define PEN            (0x02)  /* Parity Enable */
-#define EPS            (0x04)  /* Even Parity Set */
-#define FEN            (0x10)  /* FIFO Enable */
-#define BRK            (0x01)  /* Send Break */
-
-
-struct uart_port_lh7a40x {
-       struct uart_port port;
-       unsigned int statusPrev; /* Most recently read modem status */
-};
-
-static void lh7a40xuart_stop_tx (struct uart_port* port)
-{
-       BIT_CLR (port, UART_R_INTEN, TxInt);
-}
-
-static void lh7a40xuart_start_tx (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, TxInt);
-
-       /* *** FIXME: do I need to check for startup of the
-                     transmitter?  The old driver did, but AMBA
-                     doesn't . */
-}
-
-static void lh7a40xuart_stop_rx (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
-}
-
-static void lh7a40xuart_enable_ms (struct uart_port* port)
-{
-       BIT_SET (port, UART_R_INTEN, ModemInt);
-}
-
-static void lh7a40xuart_rx_chars (struct uart_port* port)
-{
-       struct tty_struct* tty = port->state->port.tty;
-       int cbRxMax = 256;      /* (Gross) limit on receive */
-       unsigned int data;      /* Received data and status */
-       unsigned int flag;
-
-       while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
-               data = UR (port, UART_R_DATA);
-               flag = TTY_NORMAL;
-               ++port->icount.rx;
-
-               if (unlikely(data & RxError)) {
-                       if (data & RxBreak) {
-                               data &= ~(RxFramingError | RxParityError);
-                               ++port->icount.brk;
-                               if (uart_handle_break (port))
-                                       continue;
-                       }
-                       else if (data & RxParityError)
-                               ++port->icount.parity;
-                       else if (data & RxFramingError)
-                               ++port->icount.frame;
-                       if (data & RxOverrunError)
-                               ++port->icount.overrun;
-
-                               /* Mask by termios, leave Rx'd byte */
-                       data &= port->read_status_mask | 0xff;
-
-                       if (data & RxBreak)
-                               flag = TTY_BREAK;
-                       else if (data & RxParityError)
-                               flag = TTY_PARITY;
-                       else if (data & RxFramingError)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char (port, (unsigned char) data))
-                       continue;
-
-               uart_insert_char(port, data, RxOverrunError, data, flag);
-       }
-       tty_flip_buffer_push (tty);
-       return;
-}
-
-static void lh7a40xuart_tx_chars (struct uart_port* port)
-{
-       struct circ_buf* xmit = &port->state->xmit;
-       int cbTxMax = port->fifosize;
-
-       if (port->x_char) {
-               UR (port, UART_R_DATA) = port->x_char;
-               ++port->icount.tx;
-               port->x_char = 0;
-               return;
-       }
-       if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
-               lh7a40xuart_stop_tx (port);
-               return;
-       }
-
-       /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
-          that at least half of the FIFO is empty.  Instead, we check
-          status for every character.  Using the AMBA method causes
-          the transmitter to drop characters. */
-
-       do {
-               UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               ++port->icount.tx;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (!(UR (port, UART_R_STATUS) & nTxRdy)
-                && cbTxMax--);
-
-       if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
-               uart_write_wakeup (port);
-
-       if (uart_circ_empty (xmit))
-               lh7a40xuart_stop_tx (port);
-}
-
-static void lh7a40xuart_modem_status (struct uart_port* port)
-{
-       unsigned int status = UR (port, UART_R_STATUS);
-       unsigned int delta
-               = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
-
-       BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
-
-       if (!delta)             /* Only happens if we missed 2 transitions */
-               return;
-
-       ((struct uart_port_lh7a40x*) port)->statusPrev = status;
-
-       if (delta & DCD)
-               uart_handle_dcd_change (port, status & DCD);
-
-       if (delta & DSR)
-               ++port->icount.dsr;
-
-       if (delta & CTS)
-               uart_handle_cts_change (port, status & CTS);
-
-       wake_up_interruptible (&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
-{
-       struct uart_port* port = dev_id;
-       unsigned int cLoopLimit = ISR_LOOP_LIMIT;
-       unsigned int isr = UR (port, UART_R_ISR);
-
-
-       do {
-               if (isr & (RxInt | RxTimeoutInt))
-                       lh7a40xuart_rx_chars(port);
-               if (isr & ModemInt)
-                       lh7a40xuart_modem_status (port);
-               if (isr & TxInt)
-                       lh7a40xuart_tx_chars (port);
-
-               if (--cLoopLimit == 0)
-                       break;
-
-               isr = UR (port, UART_R_ISR);
-       } while (isr & (RxInt | TxInt | RxTimeoutInt));
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
-{
-       return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
-{
-       unsigned int result = 0;
-       unsigned int status = UR (port, UART_R_STATUS);
-
-       if (status & DCD)
-               result |= TIOCM_CAR;
-       if (status & DSR)
-               result |= TIOCM_DSR;
-       if (status & CTS)
-               result |= TIOCM_CTS;
-
-       return result;
-}
-
-static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
-{
-       /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
-       /* Note, kernel appears to be setting DTR and RTS on console. */
-
-       /* *** FIXME: this deserves more work.  There's some work in
-              tracing all of the IO pins. */
-#if 0
-       if( port->mapbase == UART1_PHYS) {
-               gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
-
-               if (mctrl & TIOCM_RTS)
-                       gpio->pbdr &= ~GPIOB_UART1_RTS;
-               else
-                       gpio->pbdr |= GPIOB_UART1_RTS;
-       }
-#endif
-}
-
-static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (break_state == -1)
-               BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
-       else
-               BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int lh7a40xuart_startup (struct uart_port* port)
-{
-       int retval;
-
-       retval = request_irq (port->irq, lh7a40xuart_int, 0,
-                             "serial_lh7a40x", port);
-       if (retval)
-               return retval;
-
-                               /* Initial modem control-line settings */
-       ((struct uart_port_lh7a40x*) port)->statusPrev
-               = UR (port, UART_R_STATUS);
-
-       /* There is presently no configuration option to enable IR.
-          Thus, we always disable it. */
-
-       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
-       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
-
-       return 0;
-}
-
-static void lh7a40xuart_shutdown (struct uart_port* port)
-{
-       free_irq (port->irq, port);
-       BIT_CLR (port, UART_R_FCON, BRK | FEN);
-       BIT_CLR (port, UART_R_CON, UARTEN);
-}
-
-static void lh7a40xuart_set_termios (struct uart_port* port,
-                                    struct ktermios* termios,
-                                    struct ktermios* old)
-{
-       unsigned int con;
-       unsigned int inten;
-       unsigned int fcon;
-       unsigned long flags;
-       unsigned int baud;
-       unsigned int quot;
-
-       baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
-       quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               fcon = WLEN_5;
-               break;
-       case CS6:
-               fcon = WLEN_6;
-               break;
-       case CS7:
-               fcon = WLEN_7;
-               break;
-       case CS8:
-       default:
-               fcon = WLEN_8;
-               break;
-       }
-       if (termios->c_cflag & CSTOPB)
-               fcon |= STP2;
-       if (termios->c_cflag & PARENB) {
-               fcon |= PEN;
-               if (!(termios->c_cflag & PARODD))
-                       fcon |= EPS;
-       }
-       if (port->fifosize > 1)
-               fcon |= FEN;
-
-       spin_lock_irqsave (&port->lock, flags);
-
-       uart_update_timeout (port, termios->c_cflag, baud);
-
-       port->read_status_mask = RxOverrunError;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= RxFramingError | RxParityError;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= RxBreak;
-
-               /* Figure mask for status we ignore */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= RxFramingError | RxParityError;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= RxBreak;
-               /* Ignore overrun when ignorning parity */
-               /* *** FIXME: is this in the right place? */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= RxOverrunError;
-       }
-
-               /* Ignore all receive errors when receive disabled */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= RxError;
-
-       con   = UR (port, UART_R_CON);
-       inten = (UR (port, UART_R_INTEN) & ~ModemInt);
-
-       if (UART_ENABLE_MS (port, termios->c_cflag))
-               inten |= ModemInt;
-
-       BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
-       UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
-       UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
-       UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
-       UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
-       UR (port, UART_R_CON)   = con;          /* Restore UART mode */
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char* lh7a40xuart_type (struct uart_port* port)
-{
-       return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
-}
-
-static void lh7a40xuart_release_port (struct uart_port* port)
-{
-       release_mem_region (port->mapbase, UART_REG_SIZE);
-}
-
-static int lh7a40xuart_request_port (struct uart_port* port)
-{
-       return request_mem_region (port->mapbase, UART_REG_SIZE,
-                                  "serial_lh7a40x") != NULL
-               ? 0 : -EBUSY;
-}
-
-static void lh7a40xuart_config_port (struct uart_port* port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_LH7A40X;
-               lh7a40xuart_request_port (port);
-       }
-}
-
-static int lh7a40xuart_verify_port (struct uart_port* port,
-                                   struct serial_struct* ser)
-{
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
-               ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               ret = -EINVAL;
-       if (ser->baud_base < 9600) /* *** FIXME: is this true? */
-               ret = -EINVAL;
-       return ret;
-}
-
-static struct uart_ops lh7a40x_uart_ops = {
-       .tx_empty       = lh7a40xuart_tx_empty,
-       .set_mctrl      = lh7a40xuart_set_mctrl,
-       .get_mctrl      = lh7a40xuart_get_mctrl,
-       .stop_tx        = lh7a40xuart_stop_tx,
-       .start_tx       = lh7a40xuart_start_tx,
-       .stop_rx        = lh7a40xuart_stop_rx,
-       .enable_ms      = lh7a40xuart_enable_ms,
-       .break_ctl      = lh7a40xuart_break_ctl,
-       .startup        = lh7a40xuart_startup,
-       .shutdown       = lh7a40xuart_shutdown,
-       .set_termios    = lh7a40xuart_set_termios,
-       .type           = lh7a40xuart_type,
-       .release_port   = lh7a40xuart_release_port,
-       .request_port   = lh7a40xuart_request_port,
-       .config_port    = lh7a40xuart_config_port,
-       .verify_port    = lh7a40xuart_verify_port,
-};
-
-static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART1_PHYS),
-                       .mapbase        = UART1_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART1INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 0,
-               },
-       },
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART2_PHYS),
-                       .mapbase        = UART2_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART2INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 1,
-               },
-       },
-       {
-               .port = {
-                       .membase        = (void*) io_p2v (UART3_PHYS),
-                       .mapbase        = UART3_PHYS,
-                       .iotype         = UPIO_MEM,
-                       .irq            = IRQ_UART3INTR,
-                       .uartclk        = 14745600/2,
-                       .fifosize       = 16,
-                       .ops            = &lh7a40x_uart_ops,
-                       .flags          = UPF_BOOT_AUTOCONF,
-                       .line           = 2,
-               },
-       },
-};
-
-#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
-# define LH7A40X_CONSOLE NULL
-#else
-# define LH7A40X_CONSOLE &lh7a40x_console
-
-static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
-{
-       while (UR(port, UART_R_STATUS) & nTxRdy)
-               ;
-       UR(port, UART_R_DATA) = ch;
-}
-
-static void lh7a40xuart_console_write (struct console* co,
-                                      const char* s,
-                                      unsigned int count)
-{
-       struct uart_port* port = &lh7a40x_ports[co->index].port;
-       unsigned int con = UR (port, UART_R_CON);
-       unsigned int inten = UR (port, UART_R_INTEN);
-
-
-       UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
-       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
-
-       uart_console_write(port, s, count, lh7a40xuart_console_putchar);
-
-                               /* Wait until all characters are sent */
-       while (UR (port, UART_R_STATUS) & TxBusy)
-               ;
-
-                               /* Restore control and interrupt mask */
-       UR (port, UART_R_CON) = con;
-       UR (port, UART_R_INTEN) = inten;
-}
-
-static void __init lh7a40xuart_console_get_options (struct uart_port* port,
-                                                   int* baud,
-                                                   int* parity,
-                                                   int* bits)
-{
-       if (UR (port, UART_R_CON) & UARTEN) {
-               unsigned int fcon = UR (port, UART_R_FCON);
-               unsigned int quot = UR (port, UART_R_BRCON) + 1;
-
-               switch (fcon & (PEN | EPS)) {
-               default:        *parity = 'n'; break;
-               case PEN:       *parity = 'o'; break;
-               case PEN | EPS: *parity = 'e'; break;
-               }
-
-               switch (fcon & WLEN) {
-               default:
-               case WLEN_8: *bits = 8; break;
-               case WLEN_7: *bits = 7; break;
-               case WLEN_6: *bits = 6; break;
-               case WLEN_5: *bits = 5; break;
-               }
-
-               *baud = port->uartclk/(16*quot);
-       }
-}
-
-static int __init lh7a40xuart_console_setup (struct console* co, char* options)
-{
-       struct uart_port* port;
-       int baud = 38400;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index >= DEV_NR) /* Bounds check on device number */
-               co->index = 0;
-       port = &lh7a40x_ports[co->index].port;
-
-       if (options)
-               uart_parse_options (options, &baud, &parity, &bits, &flow);
-       else
-               lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
-
-       return uart_set_options (port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver lh7a40x_reg;
-static struct console lh7a40x_console = {
-       .name           = "ttyAM",
-       .write          = lh7a40xuart_console_write,
-       .device         = uart_console_device,
-       .setup          = lh7a40xuart_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &lh7a40x_reg,
-};
-
-static int __init lh7a40xuart_console_init(void)
-{
-       register_console (&lh7a40x_console);
-       return 0;
-}
-
-console_initcall (lh7a40xuart_console_init);
-
-#endif
-
-static struct uart_driver lh7a40x_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "ttyAM",
-       .dev_name               = "ttyAM",
-       .major                  = DEV_MAJOR,
-       .minor                  = DEV_MINOR,
-       .nr                     = DEV_NR,
-       .cons                   = LH7A40X_CONSOLE,
-};
-
-static int __init lh7a40xuart_init(void)
-{
-       int ret;
-
-       printk (KERN_INFO "serial: LH7A40X serial driver\n");
-
-       ret = uart_register_driver (&lh7a40x_reg);
-
-       if (ret == 0) {
-               int i;
-
-               for (i = 0; i < DEV_NR; i++) {
-                       /* UART3, when used, requires GPIO pin reallocation */
-                       if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
-                               GPIO_PINMUX |= 1<<3;
-                       uart_add_one_port (&lh7a40x_reg,
-                                          &lh7a40x_ports[i].port);
-               }
-       }
-       return ret;
-}
-
-static void __exit lh7a40xuart_exit(void)
-{
-       int i;
-
-       for (i = 0; i < DEV_NR; i++)
-               uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
-
-       uart_unregister_driver (&lh7a40x_reg);
-}
-
-module_init (lh7a40xuart_init);
-module_exit (lh7a40xuart_exit);
-
-MODULE_AUTHOR ("Marc Singer");
-MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
-MODULE_LICENSE ("GPL");
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
deleted file mode 100644 (file)
index c50e9fb..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- *  drivers/serial/serial_txx9.c
- *
- * Derived from many drivers using generic_serial interface,
- * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c
- * (was in Linux/VR tree) by Jim Pick.
- *
- *  Copyright (C) 1999 Harald Koerfgen
- *  Copyright (C) 2000 Jim Pick <jim@jimpick.com>
- *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
- *  Copyright (C) 2000-2002 Toshiba 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.
- *
- *  Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
- */
-
-#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-
-#include <asm/io.h>
-
-static char *serial_version = "1.11";
-static char *serial_name = "TX39/49 Serial driver";
-
-#define PASS_LIMIT     256
-
-#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
-/* "ttyS" is used for standard serial driver */
-#define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_MINOR_START   196
-#define TXX9_TTY_MAJOR 204
-#else
-/* acts like standard serial driver */
-#define TXX9_TTY_NAME "ttyS"
-#define TXX9_TTY_MINOR_START   64
-#define TXX9_TTY_MAJOR TTY_MAJOR
-#endif
-
-/* flag aliases */
-#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
-#define UPF_TXX9_USE_SCLK      UPF_MAGIC_MULTIPLIER
-
-#ifdef CONFIG_PCI
-/* support for Toshiba TC86C001 SIO */
-#define ENABLE_SERIAL_TXX9_PCI
-#endif
-
-/*
- * Number of serial ports
- */
-#define UART_NR  CONFIG_SERIAL_TXX9_NR_UARTS
-
-struct uart_txx9_port {
-       struct uart_port        port;
-       /* No additional info for now */
-};
-
-#define TXX9_REGION_SIZE       0x24
-
-/* TXX9 Serial Registers */
-#define TXX9_SILCR     0x00
-#define TXX9_SIDICR    0x04
-#define TXX9_SIDISR    0x08
-#define TXX9_SICISR    0x0c
-#define TXX9_SIFCR     0x10
-#define TXX9_SIFLCR    0x14
-#define TXX9_SIBGR     0x18
-#define TXX9_SITFIFO   0x1c
-#define TXX9_SIRFIFO   0x20
-
-/* SILCR : Line Control */
-#define TXX9_SILCR_SCS_MASK    0x00000060
-#define TXX9_SILCR_SCS_IMCLK   0x00000000
-#define TXX9_SILCR_SCS_IMCLK_BG        0x00000020
-#define TXX9_SILCR_SCS_SCLK    0x00000040
-#define TXX9_SILCR_SCS_SCLK_BG 0x00000060
-#define TXX9_SILCR_UEPS        0x00000010
-#define TXX9_SILCR_UPEN        0x00000008
-#define TXX9_SILCR_USBL_MASK   0x00000004
-#define TXX9_SILCR_USBL_1BIT   0x00000000
-#define TXX9_SILCR_USBL_2BIT   0x00000004
-#define TXX9_SILCR_UMODE_MASK  0x00000003
-#define TXX9_SILCR_UMODE_8BIT  0x00000000
-#define TXX9_SILCR_UMODE_7BIT  0x00000001
-
-/* SIDICR : DMA/Int. Control */
-#define TXX9_SIDICR_TDE        0x00008000
-#define TXX9_SIDICR_RDE        0x00004000
-#define TXX9_SIDICR_TIE        0x00002000
-#define TXX9_SIDICR_RIE        0x00001000
-#define TXX9_SIDICR_SPIE       0x00000800
-#define TXX9_SIDICR_CTSAC      0x00000600
-#define TXX9_SIDICR_STIE_MASK  0x0000003f
-#define TXX9_SIDICR_STIE_OERS          0x00000020
-#define TXX9_SIDICR_STIE_CTSS          0x00000010
-#define TXX9_SIDICR_STIE_RBRKD 0x00000008
-#define TXX9_SIDICR_STIE_TRDY          0x00000004
-#define TXX9_SIDICR_STIE_TXALS 0x00000002
-#define TXX9_SIDICR_STIE_UBRKD 0x00000001
-
-/* SIDISR : DMA/Int. Status */
-#define TXX9_SIDISR_UBRK       0x00008000
-#define TXX9_SIDISR_UVALID     0x00004000
-#define TXX9_SIDISR_UFER       0x00002000
-#define TXX9_SIDISR_UPER       0x00001000
-#define TXX9_SIDISR_UOER       0x00000800
-#define TXX9_SIDISR_ERI        0x00000400
-#define TXX9_SIDISR_TOUT       0x00000200
-#define TXX9_SIDISR_TDIS       0x00000100
-#define TXX9_SIDISR_RDIS       0x00000080
-#define TXX9_SIDISR_STIS       0x00000040
-#define TXX9_SIDISR_RFDN_MASK  0x0000001f
-
-/* SICISR : Change Int. Status */
-#define TXX9_SICISR_OERS       0x00000020
-#define TXX9_SICISR_CTSS       0x00000010
-#define TXX9_SICISR_RBRKD      0x00000008
-#define TXX9_SICISR_TRDY       0x00000004
-#define TXX9_SICISR_TXALS      0x00000002
-#define TXX9_SICISR_UBRKD      0x00000001
-
-/* SIFCR : FIFO Control */
-#define TXX9_SIFCR_SWRST       0x00008000
-#define TXX9_SIFCR_RDIL_MASK   0x00000180
-#define TXX9_SIFCR_RDIL_1      0x00000000
-#define TXX9_SIFCR_RDIL_4      0x00000080
-#define TXX9_SIFCR_RDIL_8      0x00000100
-#define TXX9_SIFCR_RDIL_12     0x00000180
-#define TXX9_SIFCR_RDIL_MAX    0x00000180
-#define TXX9_SIFCR_TDIL_MASK   0x00000018
-#define TXX9_SIFCR_TDIL_MASK   0x00000018
-#define TXX9_SIFCR_TDIL_1      0x00000000
-#define TXX9_SIFCR_TDIL_4      0x00000001
-#define TXX9_SIFCR_TDIL_8      0x00000010
-#define TXX9_SIFCR_TDIL_MAX    0x00000010
-#define TXX9_SIFCR_TFRST       0x00000004
-#define TXX9_SIFCR_RFRST       0x00000002
-#define TXX9_SIFCR_FRSTE       0x00000001
-#define TXX9_SIO_TX_FIFO       8
-#define TXX9_SIO_RX_FIFO       16
-
-/* SIFLCR : Flow Control */
-#define TXX9_SIFLCR_RCS        0x00001000
-#define TXX9_SIFLCR_TES        0x00000800
-#define TXX9_SIFLCR_RTSSC      0x00000200
-#define TXX9_SIFLCR_RSDE       0x00000100
-#define TXX9_SIFLCR_TSDE       0x00000080
-#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e
-#define TXX9_SIFLCR_RTSTL_MAX  0x0000001e
-#define TXX9_SIFLCR_TBRK       0x00000001
-
-/* SIBGR : Baudrate Control */
-#define TXX9_SIBGR_BCLK_MASK   0x00000300
-#define TXX9_SIBGR_BCLK_T0     0x00000000
-#define TXX9_SIBGR_BCLK_T2     0x00000100
-#define TXX9_SIBGR_BCLK_T4     0x00000200
-#define TXX9_SIBGR_BCLK_T6     0x00000300
-#define TXX9_SIBGR_BRD_MASK    0x000000ff
-
-static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
-{
-       switch (up->port.iotype) {
-       default:
-               return __raw_readl(up->port.membase + offset);
-       case UPIO_PORT:
-               return inl(up->port.iobase + offset);
-       }
-}
-
-static inline void
-sio_out(struct uart_txx9_port *up, int offset, int value)
-{
-       switch (up->port.iotype) {
-       default:
-               __raw_writel(value, up->port.membase + offset);
-               break;
-       case UPIO_PORT:
-               outl(value, up->port.iobase + offset);
-               break;
-       }
-}
-
-static inline void
-sio_mask(struct uart_txx9_port *up, int offset, unsigned int value)
-{
-       sio_out(up, offset, sio_in(up, offset) & ~value);
-}
-static inline void
-sio_set(struct uart_txx9_port *up, int offset, unsigned int value)
-{
-       sio_out(up, offset, sio_in(up, offset) | value);
-}
-
-static inline void
-sio_quot_set(struct uart_txx9_port *up, int quot)
-{
-       quot >>= 1;
-       if (quot < 256)
-               sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0);
-       else if (quot < (256 << 2))
-               sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2);
-       else if (quot < (256 << 4))
-               sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4);
-       else if (quot < (256 << 6))
-               sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6);
-       else
-               sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
-}
-
-static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
-{
-       return container_of(port, struct uart_txx9_port, port);
-}
-
-static void serial_txx9_stop_tx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
-}
-
-static void serial_txx9_start_tx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
-}
-
-static void serial_txx9_stop_rx(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
-}
-
-static void serial_txx9_enable_ms(struct uart_port *port)
-{
-       /* TXX9-SIO can not control DTR... */
-}
-
-static void serial_txx9_initialize(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int tmout = 10000;
-
-       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
-       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
-        * immediately after soft reset causes bus error. */
-       mmiowb();
-       udelay(1);
-       while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
-               udelay(1);
-       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
-       /* initial settings */
-       sio_out(up, TXX9_SILCR,
-               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
-               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
-                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
-       sio_quot_set(up, uart_get_divisor(port, 9600));
-       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
-       sio_out(up, TXX9_SIDICR, 0);
-}
-
-static inline void
-receive_chars(struct uart_txx9_port *up, unsigned int *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch;
-       unsigned int disr = *status;
-       int max_count = 256;
-       char flag;
-       unsigned int next_ignore_status_mask;
-
-       do {
-               ch = sio_in(up, TXX9_SIRFIFO);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               /* mask out RFDN_MASK bit added by previous overrun */
-               next_ignore_status_mask =
-                       up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
-               if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
-                                    TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (disr & TXX9_SIDISR_UBRK) {
-                               disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (disr & TXX9_SIDISR_UPER)
-                               up->port.icount.parity++;
-                       else if (disr & TXX9_SIDISR_UFER)
-                               up->port.icount.frame++;
-                       if (disr & TXX9_SIDISR_UOER) {
-                               up->port.icount.overrun++;
-                               /*
-                                * The receiver read buffer still hold
-                                * a char which caused overrun.
-                                * Ignore next char by adding RFDN_MASK
-                                * to ignore_status_mask temporarily.
-                                */
-                               next_ignore_status_mask |=
-                                       TXX9_SIDISR_RFDN_MASK;
-                       }
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       disr &= up->port.read_status_mask;
-
-                       if (disr & TXX9_SIDISR_UBRK) {
-                               flag = TTY_BREAK;
-                       } else if (disr & TXX9_SIDISR_UPER)
-                               flag = TTY_PARITY;
-                       else if (disr & TXX9_SIDISR_UFER)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
-
-       ignore_char:
-               up->port.ignore_status_mask = next_ignore_status_mask;
-               disr = sio_in(up, TXX9_SIDISR);
-       } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
-       spin_unlock(&up->port.lock);
-       tty_flip_buffer_push(tty);
-       spin_lock(&up->port.lock);
-       *status = disr;
-}
-
-static inline void transmit_chars(struct uart_txx9_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               sio_out(up, TXX9_SITFIFO, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               serial_txx9_stop_tx(&up->port);
-               return;
-       }
-
-       count = TXX9_SIO_TX_FIFO;
-       do {
-               sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               serial_txx9_stop_tx(&up->port);
-}
-
-static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
-{
-       int pass_counter = 0;
-       struct uart_txx9_port *up = dev_id;
-       unsigned int status;
-
-       while (1) {
-               spin_lock(&up->port.lock);
-               status = sio_in(up, TXX9_SIDISR);
-               if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
-                       status &= ~TXX9_SIDISR_TDIS;
-               if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
-                               TXX9_SIDISR_TOUT))) {
-                       spin_unlock(&up->port.lock);
-                       break;
-               }
-
-               if (status & TXX9_SIDISR_RDIS)
-                       receive_chars(up, &status);
-               if (status & TXX9_SIDISR_TDIS)
-                       transmit_chars(up);
-               /* Clear TX/RX Int. Status */
-               sio_mask(up, TXX9_SIDISR,
-                        TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
-                        TXX9_SIDISR_TOUT);
-               spin_unlock(&up->port.lock);
-
-               if (pass_counter++ > PASS_LIMIT)
-                       break;
-       }
-
-       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static unsigned int serial_txx9_tx_empty(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int ret;
-
-       /* no modem control lines */
-       ret = TIOCM_CAR | TIOCM_DSR;
-       ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
-       ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
-
-       return ret;
-}
-
-static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       if (mctrl & TIOCM_RTS)
-               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
-       else
-               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
-}
-
-static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-       else
-               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_txx9_port *up)
-{
-       unsigned int tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       while (--tmout &&
-              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
-               udelay(1);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
-                       udelay(1);
-       }
-}
-#endif
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial_txx9_get_poll_char(struct uart_port *port)
-{
-       unsigned int ier;
-       unsigned char c;
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
-               ;
-
-       c = sio_in(up, TXX9_SIRFIFO);
-
-       /*
-        *      Finally, clear RX interrupt status
-        *      and restore the IER
-        */
-       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
-       sio_out(up, TXX9_SIDICR, ier);
-       return c;
-}
-
-
-static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
-{
-       unsigned int ier;
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       /*
-        *      First save the IER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       wait_for_xmitr(up);
-       /*
-        *      Send the character out.
-        *      If a LF, also do CR...
-        */
-       sio_out(up, TXX9_SITFIFO, c);
-       if (c == 10) {
-               wait_for_xmitr(up);
-               sio_out(up, TXX9_SITFIFO, 13);
-       }
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SIDICR, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int serial_txx9_startup(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-       int retval;
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       /* clear reset */
-       sio_mask(up, TXX9_SIFCR,
-                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       sio_out(up, TXX9_SIDICR, 0);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       sio_out(up, TXX9_SIDISR, 0);
-
-       retval = request_irq(up->port.irq, serial_txx9_interrupt,
-                            IRQF_SHARED, "serial_txx9", up);
-       if (retval)
-               return retval;
-
-       /*
-        * Now, initialize the UART
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /* Enable RX/TX */
-       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
-
-       /*
-        * Finally, enable interrupts.
-        */
-       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
-
-       return 0;
-}
-
-static void serial_txx9_shutdown(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       sio_out(up, TXX9_SIDICR, 0);    /* disable all intrs */
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition
-        */
-       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-       if (up->port.cons && up->port.line == up->port.cons->index) {
-               free_irq(up->port.irq, up);
-               return;
-       }
-#endif
-       /* reset FIFOs */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-       /* clear reset */
-       sio_mask(up, TXX9_SIFCR,
-                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
-
-       /* Disable RX/TX */
-       sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
-
-       free_irq(up->port.irq, up);
-}
-
-static void
-serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
-                      struct ktermios *old)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       unsigned int cval, fcr = 0;
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * We don't support modem control lines.
-        */
-       termios->c_cflag &= ~(HUPCL | CMSPAR);
-       termios->c_cflag |= CLOCAL;
-
-       cval = sio_in(up, TXX9_SILCR);
-       /* byte size and parity */
-       cval &= ~TXX9_SILCR_UMODE_MASK;
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               cval |= TXX9_SILCR_UMODE_7BIT;
-               break;
-       default:
-       case CS5:       /* not supported */
-       case CS6:       /* not supported */
-       case CS8:
-               cval |= TXX9_SILCR_UMODE_8BIT;
-               break;
-       }
-
-       cval &= ~TXX9_SILCR_USBL_MASK;
-       if (termios->c_cflag & CSTOPB)
-               cval |= TXX9_SILCR_USBL_2BIT;
-       else
-               cval |= TXX9_SILCR_USBL_1BIT;
-       cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS);
-       if (termios->c_cflag & PARENB)
-               cval |= TXX9_SILCR_UPEN;
-       if (!(termios->c_cflag & PARODD))
-               cval |= TXX9_SILCR_UEPS;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2);
-       quot = uart_get_divisor(port, baud);
-
-       /* Set up FIFOs */
-       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
-       fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       up->port.read_status_mask = TXX9_SIDISR_UOER |
-               TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
-       if (termios->c_iflag & INPCK)
-               up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= TXX9_SIDISR_UBRK;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
-       if (termios->c_iflag & IGNBRK) {
-               up->port.ignore_status_mask |= TXX9_SIDISR_UBRK;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       up->port.ignore_status_mask |= TXX9_SIDISR_UOER;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= TXX9_SIDISR_RDIS;
-
-       /* CTS flow control flag */
-       if ((termios->c_cflag & CRTSCTS) &&
-           (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) {
-               sio_set(up, TXX9_SIFLCR,
-                       TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
-       } else {
-               sio_mask(up, TXX9_SIFLCR,
-                        TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
-       }
-
-       sio_out(up, TXX9_SILCR, cval);
-       sio_quot_set(up, quot);
-       sio_out(up, TXX9_SIFCR, fcr);
-
-       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_txx9_pm(struct uart_port *port, unsigned int state,
-             unsigned int oldstate)
-{
-       /*
-        * If oldstate was -1 this is called from
-        * uart_configure_port().  In this case do not initialize the
-        * port now, because the port was already initialized (for
-        * non-console port) or should not be initialized here (for
-        * console port).  If we initialized the port here we lose
-        * serial console settings.
-        */
-       if (state == 0 && oldstate != -1)
-               serial_txx9_initialize(port);
-}
-
-static int serial_txx9_request_resource(struct uart_txx9_port *up)
-{
-       unsigned int size = TXX9_REGION_SIZE;
-       int ret = 0;
-
-       switch (up->port.iotype) {
-       default:
-               if (!up->port.mapbase)
-                       break;
-
-               if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) {
-                       ret = -EBUSY;
-                       break;
-               }
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap(up->port.mapbase, size);
-                       if (!up->port.membase) {
-                               release_mem_region(up->port.mapbase, size);
-                               ret = -ENOMEM;
-                       }
-               }
-               break;
-
-       case UPIO_PORT:
-               if (!request_region(up->port.iobase, size, "serial_txx9"))
-                       ret = -EBUSY;
-               break;
-       }
-       return ret;
-}
-
-static void serial_txx9_release_resource(struct uart_txx9_port *up)
-{
-       unsigned int size = TXX9_REGION_SIZE;
-
-       switch (up->port.iotype) {
-       default:
-               if (!up->port.mapbase)
-                       break;
-
-               if (up->port.flags & UPF_IOREMAP) {
-                       iounmap(up->port.membase);
-                       up->port.membase = NULL;
-               }
-
-               release_mem_region(up->port.mapbase, size);
-               break;
-
-       case UPIO_PORT:
-               release_region(up->port.iobase, size);
-               break;
-       }
-}
-
-static void serial_txx9_release_port(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       serial_txx9_release_resource(up);
-}
-
-static int serial_txx9_request_port(struct uart_port *port)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       return serial_txx9_request_resource(up);
-}
-
-static void serial_txx9_config_port(struct uart_port *port, int uflags)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-       int ret;
-
-       /*
-        * Find the region that we can probe for.  This in turn
-        * tells us whether we can probe for the type of port.
-        */
-       ret = serial_txx9_request_resource(up);
-       if (ret < 0)
-               return;
-       port->type = PORT_TXX9;
-       up->port.fifosize = TXX9_SIO_TX_FIFO;
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-       if (up->port.line == up->port.cons->index)
-               return;
-#endif
-       serial_txx9_initialize(port);
-}
-
-static const char *
-serial_txx9_type(struct uart_port *port)
-{
-       return "txx9";
-}
-
-static struct uart_ops serial_txx9_pops = {
-       .tx_empty       = serial_txx9_tx_empty,
-       .set_mctrl      = serial_txx9_set_mctrl,
-       .get_mctrl      = serial_txx9_get_mctrl,
-       .stop_tx        = serial_txx9_stop_tx,
-       .start_tx       = serial_txx9_start_tx,
-       .stop_rx        = serial_txx9_stop_rx,
-       .enable_ms      = serial_txx9_enable_ms,
-       .break_ctl      = serial_txx9_break_ctl,
-       .startup        = serial_txx9_startup,
-       .shutdown       = serial_txx9_shutdown,
-       .set_termios    = serial_txx9_set_termios,
-       .pm             = serial_txx9_pm,
-       .type           = serial_txx9_type,
-       .release_port   = serial_txx9_release_port,
-       .request_port   = serial_txx9_request_port,
-       .config_port    = serial_txx9_config_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = serial_txx9_get_poll_char,
-       .poll_put_char  = serial_txx9_put_poll_char,
-#endif
-};
-
-static struct uart_txx9_port serial_txx9_ports[UART_NR];
-
-static void __init serial_txx9_register_ports(struct uart_driver *drv,
-                                             struct device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               up->port.line = i;
-               up->port.ops = &serial_txx9_pops;
-               up->port.dev = dev;
-               if (up->port.iobase || up->port.mapbase)
-                       uart_add_one_port(drv, &up->port);
-       }
-}
-
-#ifdef CONFIG_SERIAL_TXX9_CONSOLE
-
-static void serial_txx9_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_txx9_port *up = to_uart_txx9_port(port);
-
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SITFIFO, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- *
- *     The console_lock must be held when we get here.
- */
-static void
-serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
-{
-       struct uart_txx9_port *up = &serial_txx9_ports[co->index];
-       unsigned int ier, flcr;
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = sio_in(up, TXX9_SIDICR);
-       sio_out(up, TXX9_SIDICR, 0);
-       /*
-        *      Disable flow-control if enabled (and unnecessary)
-        */
-       flcr = sio_in(up, TXX9_SIFLCR);
-       if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
-               sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
-
-       uart_console_write(&up->port, s, count, serial_txx9_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       sio_out(up, TXX9_SIFLCR, flcr);
-       sio_out(up, TXX9_SIDICR, ier);
-}
-
-static int __init serial_txx9_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       struct uart_txx9_port *up;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       up = &serial_txx9_ports[co->index];
-       port = &up->port;
-       if (!port->ops)
-               return -ENODEV;
-
-       serial_txx9_initialize(&up->port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver serial_txx9_reg;
-static struct console serial_txx9_console = {
-       .name           = TXX9_TTY_NAME,
-       .write          = serial_txx9_console_write,
-       .device         = uart_console_device,
-       .setup          = serial_txx9_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-       .data           = &serial_txx9_reg,
-};
-
-static int __init serial_txx9_console_init(void)
-{
-       register_console(&serial_txx9_console);
-       return 0;
-}
-console_initcall(serial_txx9_console_init);
-
-#define SERIAL_TXX9_CONSOLE    &serial_txx9_console
-#else
-#define SERIAL_TXX9_CONSOLE    NULL
-#endif
-
-static struct uart_driver serial_txx9_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial_txx9",
-       .dev_name               = TXX9_TTY_NAME,
-       .major                  = TXX9_TTY_MAJOR,
-       .minor                  = TXX9_TTY_MINOR_START,
-       .nr                     = UART_NR,
-       .cons                   = SERIAL_TXX9_CONSOLE,
-};
-
-int __init early_serial_txx9_setup(struct uart_port *port)
-{
-       if (port->line >= ARRAY_SIZE(serial_txx9_ports))
-               return -ENODEV;
-
-       serial_txx9_ports[port->line].port = *port;
-       serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
-       serial_txx9_ports[port->line].port.flags |=
-               UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-       return 0;
-}
-
-static DEFINE_MUTEX(serial_txx9_mutex);
-
-/**
- *     serial_txx9_register_port - register a serial port
- *     @port: serial port template
- *
- *     Configure the serial port specified by the request.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- */
-static int __devinit serial_txx9_register_port(struct uart_port *port)
-{
-       int i;
-       struct uart_txx9_port *uart;
-       int ret = -ENOSPC;
-
-       mutex_lock(&serial_txx9_mutex);
-       for (i = 0; i < UART_NR; i++) {
-               uart = &serial_txx9_ports[i];
-               if (uart_match_port(&uart->port, port)) {
-                       uart_remove_one_port(&serial_txx9_reg, &uart->port);
-                       break;
-               }
-       }
-       if (i == UART_NR) {
-               /* Find unused port */
-               for (i = 0; i < UART_NR; i++) {
-                       uart = &serial_txx9_ports[i];
-                       if (!(uart->port.iobase || uart->port.mapbase))
-                               break;
-               }
-       }
-       if (i < UART_NR) {
-               uart->port.iobase = port->iobase;
-               uart->port.membase = port->membase;
-               uart->port.irq      = port->irq;
-               uart->port.uartclk  = port->uartclk;
-               uart->port.iotype   = port->iotype;
-               uart->port.flags    = port->flags
-                       | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-               uart->port.mapbase  = port->mapbase;
-               if (port->dev)
-                       uart->port.dev = port->dev;
-               ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
-       }
-       mutex_unlock(&serial_txx9_mutex);
-       return ret;
-}
-
-/**
- *     serial_txx9_unregister_port - remove a txx9 serial port at runtime
- *     @line: serial line number
- *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to the our control.
- */
-static void __devexit serial_txx9_unregister_port(int line)
-{
-       struct uart_txx9_port *uart = &serial_txx9_ports[line];
-
-       mutex_lock(&serial_txx9_mutex);
-       uart_remove_one_port(&serial_txx9_reg, &uart->port);
-       uart->port.flags = 0;
-       uart->port.type = PORT_UNKNOWN;
-       uart->port.iobase = 0;
-       uart->port.mapbase = 0;
-       uart->port.membase = NULL;
-       uart->port.dev = NULL;
-       mutex_unlock(&serial_txx9_mutex);
-}
-
-/*
- * Register a set of serial devices attached to a platform device.
- */
-static int __devinit serial_txx9_probe(struct platform_device *dev)
-{
-       struct uart_port *p = dev->dev.platform_data;
-       struct uart_port port;
-       int ret, i;
-
-       memset(&port, 0, sizeof(struct uart_port));
-       for (i = 0; p && p->uartclk != 0; p++, i++) {
-               port.iobase     = p->iobase;
-               port.membase    = p->membase;
-               port.irq        = p->irq;
-               port.uartclk    = p->uartclk;
-               port.iotype     = p->iotype;
-               port.flags      = p->flags;
-               port.mapbase    = p->mapbase;
-               port.dev        = &dev->dev;
-               ret = serial_txx9_register_port(&port);
-               if (ret < 0) {
-                       dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
-                               p->iobase, (unsigned long long)p->mapbase,
-                               p->irq, ret);
-               }
-       }
-       return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static int __devexit serial_txx9_remove(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.dev == &dev->dev)
-                       serial_txx9_unregister_port(i);
-       }
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_suspend_port(&serial_txx9_reg, &up->port);
-       }
-
-       return 0;
-}
-
-static int serial_txx9_resume(struct platform_device *dev)
-{
-       int i;
-
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-
-               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_resume_port(&serial_txx9_reg, &up->port);
-       }
-
-       return 0;
-}
-#endif
-
-static struct platform_driver serial_txx9_plat_driver = {
-       .probe          = serial_txx9_probe,
-       .remove         = __devexit_p(serial_txx9_remove),
-#ifdef CONFIG_PM
-       .suspend        = serial_txx9_suspend,
-       .resume         = serial_txx9_resume,
-#endif
-       .driver         = {
-               .name   = "serial_txx9",
-               .owner  = THIS_MODULE,
-       },
-};
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-/*
- * Probe one serial board.  Unfortunately, there is no rhyme nor reason
- * to the arrangement of serial ports on a PCI card.
- */
-static int __devinit
-pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
-{
-       struct uart_port port;
-       int line;
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       memset(&port, 0, sizeof(port));
-       port.ops = &serial_txx9_pops;
-       port.flags |= UPF_TXX9_HAVE_CTS_LINE;
-       port.uartclk = 66670000;
-       port.irq = dev->irq;
-       port.iotype = UPIO_PORT;
-       port.iobase = pci_resource_start(dev, 1);
-       port.dev = &dev->dev;
-       line = serial_txx9_register_port(&port);
-       if (line < 0) {
-               printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
-               pci_disable_device(dev);
-               return line;
-       }
-       pci_set_drvdata(dev, &serial_txx9_ports[line]);
-
-       return 0;
-}
-
-static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       pci_set_drvdata(dev, NULL);
-
-       if (up) {
-               serial_txx9_unregister_port(up->port.line);
-               pci_disable_device(dev);
-       }
-}
-
-#ifdef CONFIG_PM
-static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       if (up)
-               uart_suspend_port(&serial_txx9_reg, &up->port);
-       pci_save_state(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-       return 0;
-}
-
-static int pciserial_txx9_resume_one(struct pci_dev *dev)
-{
-       struct uart_txx9_port *up = pci_get_drvdata(dev);
-
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-       if (up)
-               uart_resume_port(&serial_txx9_reg, &up->port);
-       return 0;
-}
-#endif
-
-static const struct pci_device_id serial_txx9_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) },
-       { 0, }
-};
-
-static struct pci_driver serial_txx9_pci_driver = {
-       .name           = "serial_txx9",
-       .probe          = pciserial_txx9_init_one,
-       .remove         = __devexit_p(pciserial_txx9_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = pciserial_txx9_suspend_one,
-       .resume         = pciserial_txx9_resume_one,
-#endif
-       .id_table       = serial_txx9_pci_tbl,
-};
-
-MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
-#endif /* ENABLE_SERIAL_TXX9_PCI */
-
-static struct platform_device *serial_txx9_plat_devs;
-
-static int __init serial_txx9_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-
-       ret = uart_register_driver(&serial_txx9_reg);
-       if (ret)
-               goto out;
-
-       serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
-       if (!serial_txx9_plat_devs) {
-               ret = -ENOMEM;
-               goto unreg_uart_drv;
-       }
-
-       ret = platform_device_add(serial_txx9_plat_devs);
-       if (ret)
-               goto put_dev;
-
-       serial_txx9_register_ports(&serial_txx9_reg,
-                                  &serial_txx9_plat_devs->dev);
-
-       ret = platform_driver_register(&serial_txx9_plat_driver);
-       if (ret)
-               goto del_dev;
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-       ret = pci_register_driver(&serial_txx9_pci_driver);
-#endif
-       if (ret == 0)
-               goto out;
-
- del_dev:
-       platform_device_del(serial_txx9_plat_devs);
- put_dev:
-       platform_device_put(serial_txx9_plat_devs);
- unreg_uart_drv:
-       uart_unregister_driver(&serial_txx9_reg);
- out:
-       return ret;
-}
-
-static void __exit serial_txx9_exit(void)
-{
-       int i;
-
-#ifdef ENABLE_SERIAL_TXX9_PCI
-       pci_unregister_driver(&serial_txx9_pci_driver);
-#endif
-       platform_driver_unregister(&serial_txx9_plat_driver);
-       platform_device_unregister(serial_txx9_plat_devs);
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_txx9_port *up = &serial_txx9_ports[i];
-               if (up->port.iobase || up->port.mapbase)
-                       uart_remove_one_port(&serial_txx9_reg, &up->port);
-       }
-
-       uart_unregister_driver(&serial_txx9_reg);
-}
-
-module_init(serial_txx9_init);
-module_exit(serial_txx9_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TX39/49 serial driver");
-
-MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
deleted file mode 100644 (file)
index 92c91c8..0000000
+++ /dev/null
@@ -1,2079 +0,0 @@
-/*
- * drivers/serial/sh-sci.c
- *
- * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
- *
- *  Copyright (C) 2002 - 2011  Paul Mundt
- *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
- *
- * based off of the old drivers/char/sh-sci.c by:
- *
- *   Copyright (C) 1999, 2000  Niibe Yutaka
- *   Copyright (C) 2000  Sugioka Toshinobu
- *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
- *   Modified to support SecureEdge. David McCullough (2002)
- *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
- *   Removed SH7300 support (Jul 2007).
- *
- * 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.
- */
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/sysrq.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/platform_device.h>
-#include <linux/serial_sci.h>
-#include <linux/notifier.h>
-#include <linux/cpufreq.h>
-#include <linux/clk.h>
-#include <linux/ctype.h>
-#include <linux/err.h>
-#include <linux/list.h>
-#include <linux/dmaengine.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#ifdef CONFIG_SUPERH
-#include <asm/sh_bios.h>
-#endif
-
-#ifdef CONFIG_H8300
-#include <asm/gpio.h>
-#endif
-
-#include "sh-sci.h"
-
-struct sci_port {
-       struct uart_port        port;
-
-       /* Port type */
-       unsigned int            type;
-
-       /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
-       unsigned int            irqs[SCIx_NR_IRQS];
-
-       /* Port enable callback */
-       void                    (*enable)(struct uart_port *port);
-
-       /* Port disable callback */
-       void                    (*disable)(struct uart_port *port);
-
-       /* Break timer */
-       struct timer_list       break_timer;
-       int                     break_flag;
-
-       /* SCSCR initialization */
-       unsigned int            scscr;
-
-       /* SCBRR calculation algo */
-       unsigned int            scbrr_algo_id;
-
-       /* Interface clock */
-       struct clk              *iclk;
-       /* Function clock */
-       struct clk              *fclk;
-
-       struct list_head        node;
-
-       struct dma_chan                 *chan_tx;
-       struct dma_chan                 *chan_rx;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct device                   *dma_dev;
-       unsigned int                    slave_tx;
-       unsigned int                    slave_rx;
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx[2];
-       dma_cookie_t                    cookie_tx;
-       dma_cookie_t                    cookie_rx[2];
-       dma_cookie_t                    active_rx;
-       struct scatterlist              sg_tx;
-       unsigned int                    sg_len_tx;
-       struct scatterlist              sg_rx[2];
-       size_t                          buf_len_rx;
-       struct sh_dmae_slave            param_tx;
-       struct sh_dmae_slave            param_rx;
-       struct work_struct              work_tx;
-       struct work_struct              work_rx;
-       struct timer_list               rx_timer;
-       unsigned int                    rx_timeout;
-#endif
-};
-
-struct sh_sci_priv {
-       spinlock_t lock;
-       struct list_head ports;
-       struct notifier_block clk_nb;
-};
-
-/* Function prototypes */
-static void sci_stop_tx(struct uart_port *port);
-
-#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-
-static struct sci_port sci_ports[SCI_NPORTS];
-static struct uart_driver sci_uart_driver;
-
-static inline struct sci_port *
-to_sci_port(struct uart_port *uart)
-{
-       return container_of(uart, struct sci_port, port);
-}
-
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-
-#ifdef CONFIG_CONSOLE_POLL
-static inline void handle_error(struct uart_port *port)
-{
-       /* Clear error flags */
-       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-}
-
-static int sci_poll_get_char(struct uart_port *port)
-{
-       unsigned short status;
-       int c;
-
-       do {
-               status = sci_in(port, SCxSR);
-               if (status & SCxSR_ERRORS(port)) {
-                       handle_error(port);
-                       continue;
-               }
-               break;
-       } while (1);
-
-       if (!(status & SCxSR_RDxF(port)))
-               return NO_POLL_CHAR;
-
-       c = sci_in(port, SCxRDR);
-
-       /* Dummy read */
-       sci_in(port, SCxSR);
-       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-
-       return c;
-}
-#endif
-
-static void sci_poll_put_char(struct uart_port *port, unsigned char c)
-{
-       unsigned short status;
-
-       do {
-               status = sci_in(port, SCxSR);
-       } while (!(status & SCxSR_TDxE(port)));
-
-       sci_out(port, SCxTDR, c);
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
-}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
-
-#if defined(__H8300H__) || defined(__H8300S__)
-static void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-
-       /* set DDR regs */
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].rx,
-                      H8300_GPIO_INPUT);
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].tx,
-                      H8300_GPIO_OUTPUT);
-
-       /* tx mark output*/
-       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (port->mapbase == 0xA4400000) {
-               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
-               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
-       } else if (port->mapbase == 0xA4410000)
-               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (cflag & CRTSCTS) {
-               /* enable RTS/CTS */
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xfc03), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 9-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xfc03), PORT_PVCR);
-               }
-       } else {
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 5-2; enable only tx and rx  */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xffc3), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 5-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xffc3), PORT_PVCR);
-               }
-       }
-}
-#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       /* We need to set SCPCR to enable RTS/CTS */
-       data = __raw_readw(SCPCR);
-       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
-       __raw_writew(data & 0x0fcf, SCPCR);
-
-       if (!(cflag & CRTSCTS)) {
-               /* We need to set SCPCR to enable RTS/CTS */
-               data = __raw_readw(SCPCR);
-               /* Clear out SCP7MD1,0, SCP4MD1,0,
-                  Set SCP6MD1,0 = {01} (output)  */
-               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
-
-               data = __raw_readb(SCPDR);
-               /* Set /RTS2 (bit6) = 0 */
-               __raw_writeb(data & 0xbf, SCPDR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (port->mapbase == 0xffe00000) {
-               data = __raw_readw(PSCR);
-               data &= ~0x03cf;
-               if (!(cflag & CRTSCTS))
-                       data |= 0x0340;
-
-               __raw_writew(data, PSCR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
-      defined(CONFIG_CPU_SUBTYPE_SHX3)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
-}
-#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
-}
-#else
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       /* Nothing to do */
-}
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCTFDR) & 0xff;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCRFDR) & 0xff;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return sci_in(port, SCTFDR) & 0xff;
-       else
-               /* SCIF2 */
-               return sci_in(port, SCFDR) >> 8;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return SCIF_TXROOM_MAX - scif_txfill(port);
-       else
-               /* SCIF2 */
-               return SCIF2_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       if ((port->mapbase == 0xffe00000) ||
-           (port->mapbase == 0xffe08000)) {
-               /* SCIF0/1*/
-               return sci_in(port, SCRFDR) & 0xff;
-       } else {
-               /* SCIF2 */
-               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
-       }
-}
-#elif defined(CONFIG_ARCH_SH7372)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) >> 8;
-       else
-               return sci_in(port, SCTFDR);
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return port->fifosize - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-       else
-               return sci_in(port, SCRFDR);
-}
-#else
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) >> 8;
-}
-
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-}
-#endif
-
-static int sci_txfill(struct uart_port *port)
-{
-       return !(sci_in(port, SCxSR) & SCI_TDRE);
-}
-
-static int sci_txroom(struct uart_port *port)
-{
-       return !sci_txfill(port);
-}
-
-static int sci_rxfill(struct uart_port *port)
-{
-       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
-}
-
-/* ********************************************************************** *
- *                   the interrupt related routines                       *
- * ********************************************************************** */
-
-static void sci_transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned int stopped = uart_tx_stopped(port);
-       unsigned short status;
-       unsigned short ctrl;
-       int count;
-
-       status = sci_in(port, SCxSR);
-       if (!(status & SCxSR_TDxE(port))) {
-               ctrl = sci_in(port, SCSCR);
-               if (uart_circ_empty(xmit))
-                       ctrl &= ~SCSCR_TIE;
-               else
-                       ctrl |= SCSCR_TIE;
-               sci_out(port, SCSCR, ctrl);
-               return;
-       }
-
-       if (port->type == PORT_SCI)
-               count = sci_txroom(port);
-       else
-               count = scif_txroom(port);
-
-       do {
-               unsigned char c;
-
-               if (port->x_char) {
-                       c = port->x_char;
-                       port->x_char = 0;
-               } else if (!uart_circ_empty(xmit) && !stopped) {
-                       c = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               } else {
-                       break;
-               }
-
-               sci_out(port, SCxTDR, c);
-
-               port->icount.tx++;
-       } while (--count > 0);
-
-       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-       if (uart_circ_empty(xmit)) {
-               sci_stop_tx(port);
-       } else {
-               ctrl = sci_in(port, SCSCR);
-
-               if (port->type != PORT_SCI) {
-                       sci_in(port, SCxSR); /* Dummy read */
-                       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-               }
-
-               ctrl |= SCSCR_TIE;
-               sci_out(port, SCSCR, ctrl);
-       }
-}
-
-/* On SH3, SCIF may read end-of-break as a space->mark char */
-#define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
-
-static inline void sci_receive_chars(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-       struct tty_struct *tty = port->state->port.tty;
-       int i, count, copied = 0;
-       unsigned short status;
-       unsigned char flag;
-
-       status = sci_in(port, SCxSR);
-       if (!(status & SCxSR_RDxF(port)))
-               return;
-
-       while (1) {
-               if (port->type == PORT_SCI)
-                       count = sci_rxfill(port);
-               else
-                       count = scif_rxfill(port);
-
-               /* Don't copy more bytes than there is room for in the buffer */
-               count = tty_buffer_request_room(tty, count);
-
-               /* If for any reason we can't copy more data, we're done! */
-               if (count == 0)
-                       break;
-
-               if (port->type == PORT_SCI) {
-                       char c = sci_in(port, SCxRDR);
-                       if (uart_handle_sysrq_char(port, c) ||
-                           sci_port->break_flag)
-                               count = 0;
-                       else
-                               tty_insert_flip_char(tty, c, TTY_NORMAL);
-               } else {
-                       for (i = 0; i < count; i++) {
-                               char c = sci_in(port, SCxRDR);
-                               status = sci_in(port, SCxSR);
-#if defined(CONFIG_CPU_SH3)
-                               /* Skip "chars" during break */
-                               if (sci_port->break_flag) {
-                                       if ((c == 0) &&
-                                           (status & SCxSR_FER(port))) {
-                                               count--; i--;
-                                               continue;
-                                       }
-
-                                       /* Nonzero => end-of-break */
-                                       dev_dbg(port->dev, "debounce<%02x>\n", c);
-                                       sci_port->break_flag = 0;
-
-                                       if (STEPFN(c)) {
-                                               count--; i--;
-                                               continue;
-                                       }
-                               }
-#endif /* CONFIG_CPU_SH3 */
-                               if (uart_handle_sysrq_char(port, c)) {
-                                       count--; i--;
-                                       continue;
-                               }
-
-                               /* Store data and status */
-                               if (status & SCxSR_FER(port)) {
-                                       flag = TTY_FRAME;
-                                       dev_notice(port->dev, "frame error\n");
-                               } else if (status & SCxSR_PER(port)) {
-                                       flag = TTY_PARITY;
-                                       dev_notice(port->dev, "parity error\n");
-                               } else
-                                       flag = TTY_NORMAL;
-
-                               tty_insert_flip_char(tty, c, flag);
-                       }
-               }
-
-               sci_in(port, SCxSR); /* dummy read */
-               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-
-               copied += count;
-               port->icount.rx += count;
-       }
-
-       if (copied) {
-               /* Tell the rest of the system the news. New characters! */
-               tty_flip_buffer_push(tty);
-       } else {
-               sci_in(port, SCxSR); /* dummy read */
-               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-       }
-}
-
-#define SCI_BREAK_JIFFIES (HZ/20)
-/* The sci generates interrupts during the break,
- * 1 per millisecond or so during the break period, for 9600 baud.
- * So dont bother disabling interrupts.
- * But dont want more than 1 break event.
- * Use a kernel timer to periodically poll the rx line until
- * the break is finished.
- */
-static void sci_schedule_break_timer(struct sci_port *port)
-{
-       port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
-       add_timer(&port->break_timer);
-}
-/* Ensure that two consecutive samples find the break over. */
-static void sci_break_timer(unsigned long data)
-{
-       struct sci_port *port = (struct sci_port *)data;
-
-       if (sci_rxd_in(&port->port) == 0) {
-               port->break_flag = 1;
-               sci_schedule_break_timer(port);
-       } else if (port->break_flag == 1) {
-               /* break is over. */
-               port->break_flag = 2;
-               sci_schedule_break_timer(port);
-       } else
-               port->break_flag = 0;
-}
-
-static inline int sci_handle_errors(struct uart_port *port)
-{
-       int copied = 0;
-       unsigned short status = sci_in(port, SCxSR);
-       struct tty_struct *tty = port->state->port.tty;
-
-       if (status & SCxSR_ORER(port)) {
-               /* overrun error */
-               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
-                       copied++;
-
-               dev_notice(port->dev, "overrun error");
-       }
-
-       if (status & SCxSR_FER(port)) {
-               if (sci_rxd_in(port) == 0) {
-                       /* Notify of BREAK */
-                       struct sci_port *sci_port = to_sci_port(port);
-
-                       if (!sci_port->break_flag) {
-                               sci_port->break_flag = 1;
-                               sci_schedule_break_timer(sci_port);
-
-                               /* Do sysrq handling. */
-                               if (uart_handle_break(port))
-                                       return 0;
-
-                               dev_dbg(port->dev, "BREAK detected\n");
-
-                               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
-                                       copied++;
-                       }
-
-               } else {
-                       /* frame error */
-                       if (tty_insert_flip_char(tty, 0, TTY_FRAME))
-                               copied++;
-
-                       dev_notice(port->dev, "frame error\n");
-               }
-       }
-
-       if (status & SCxSR_PER(port)) {
-               /* parity error */
-               if (tty_insert_flip_char(tty, 0, TTY_PARITY))
-                       copied++;
-
-               dev_notice(port->dev, "parity error");
-       }
-
-       if (copied)
-               tty_flip_buffer_push(tty);
-
-       return copied;
-}
-
-static inline int sci_handle_fifo_overrun(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       int copied = 0;
-
-       if (port->type != PORT_SCIF)
-               return 0;
-
-       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
-               sci_out(port, SCLSR, 0);
-
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               tty_flip_buffer_push(tty);
-
-               dev_notice(port->dev, "overrun error\n");
-               copied++;
-       }
-
-       return copied;
-}
-
-static inline int sci_handle_breaks(struct uart_port *port)
-{
-       int copied = 0;
-       unsigned short status = sci_in(port, SCxSR);
-       struct tty_struct *tty = port->state->port.tty;
-       struct sci_port *s = to_sci_port(port);
-
-       if (uart_handle_break(port))
-               return 0;
-
-       if (!s->break_flag && status & SCxSR_BRK(port)) {
-#if defined(CONFIG_CPU_SH3)
-               /* Debounce break */
-               s->break_flag = 1;
-#endif
-               /* Notify of BREAK */
-               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
-                       copied++;
-
-               dev_dbg(port->dev, "BREAK detected\n");
-       }
-
-       if (copied)
-               tty_flip_buffer_push(tty);
-
-       copied += sci_handle_fifo_overrun(port);
-
-       return copied;
-}
-
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
-{
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-
-       if (s->chan_rx) {
-               u16 scr = sci_in(port, SCSCR);
-               u16 ssr = sci_in(port, SCxSR);
-
-               /* Disable future Rx interrupts */
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       disable_irq_nosync(irq);
-                       scr |= 0x4000;
-               } else {
-                       scr &= ~SCSCR_RIE;
-               }
-               sci_out(port, SCSCR, scr);
-               /* Clear current interrupt */
-               sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
-                       jiffies, s->rx_timeout);
-               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
-
-               return IRQ_HANDLED;
-       }
-#endif
-
-       /* I think sci_receive_chars has to be called irrespective
-        * of whether the I_IXOFF is set, otherwise, how is the interrupt
-        * to be disabled?
-        */
-       sci_receive_chars(ptr);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       sci_transmit_chars(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_er_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-
-       /* Handle errors */
-       if (port->type == PORT_SCI) {
-               if (sci_handle_errors(port)) {
-                       /* discard character in rx buffer */
-                       sci_in(port, SCxSR);
-                       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-               }
-       } else {
-               sci_handle_fifo_overrun(port);
-               sci_rx_interrupt(irq, ptr);
-       }
-
-       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-
-       /* Kick the transmission */
-       sci_tx_interrupt(irq, ptr);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t sci_br_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-
-       /* Handle BREAKs */
-       sci_handle_breaks(port);
-       sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
-
-       return IRQ_HANDLED;
-}
-
-static inline unsigned long port_rx_irq_mask(struct uart_port *port)
-{
-       /*
-        * Not all ports (such as SCIFA) will support REIE. Rather than
-        * special-casing the port type, we check the port initialization
-        * IRQ enable mask to see whether the IRQ is desired at all. If
-        * it's unset, it's logically inferred that there's no point in
-        * testing for it.
-        */
-       return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE);
-}
-
-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
-{
-       unsigned short ssr_status, scr_status, err_enabled;
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-       irqreturn_t ret = IRQ_NONE;
-
-       ssr_status = sci_in(port, SCxSR);
-       scr_status = sci_in(port, SCSCR);
-       err_enabled = scr_status & port_rx_irq_mask(port);
-
-       /* Tx Interrupt */
-       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
-           !s->chan_tx)
-               ret = sci_tx_interrupt(irq, ptr);
-
-       /*
-        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
-        * DR flags
-        */
-       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
-           (scr_status & SCSCR_RIE))
-               ret = sci_rx_interrupt(irq, ptr);
-
-       /* Error Interrupt */
-       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
-               ret = sci_er_interrupt(irq, ptr);
-
-       /* Break Interrupt */
-       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
-               ret = sci_br_interrupt(irq, ptr);
-
-       return ret;
-}
-
-/*
- * Here we define a transistion notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-                       unsigned long phase, void *p)
-{
-       struct sh_sci_priv *priv = container_of(self,
-                                               struct sh_sci_priv, clk_nb);
-       struct sci_port *sci_port;
-       unsigned long flags;
-
-       if ((phase == CPUFREQ_POSTCHANGE) ||
-           (phase == CPUFREQ_RESUMECHANGE)) {
-               spin_lock_irqsave(&priv->lock, flags);
-               list_for_each_entry(sci_port, &priv->ports, node)
-                       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-
-       return NOTIFY_OK;
-}
-
-static void sci_clk_enable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       clk_enable(sci_port->iclk);
-       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_enable(sci_port->fclk);
-}
-
-static void sci_clk_disable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       clk_disable(sci_port->fclk);
-       clk_disable(sci_port->iclk);
-}
-
-static int sci_request_irq(struct sci_port *port)
-{
-       int i;
-       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
-               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
-               sci_br_interrupt,
-       };
-       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
-                              "SCI Transmit Data Empty", "SCI Break" };
-
-       if (port->irqs[0] == port->irqs[1]) {
-               if (unlikely(!port->irqs[0]))
-                       return -ENODEV;
-
-               if (request_irq(port->irqs[0], sci_mpxed_interrupt,
-                               IRQF_DISABLED, "sci", port)) {
-                       dev_err(port->port.dev, "Can't allocate IRQ\n");
-                       return -ENODEV;
-               }
-       } else {
-               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
-                       if (unlikely(!port->irqs[i]))
-                               continue;
-
-                       if (request_irq(port->irqs[i], handlers[i],
-                                       IRQF_DISABLED, desc[i], port)) {
-                               dev_err(port->port.dev, "Can't allocate IRQ\n");
-                               return -ENODEV;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void sci_free_irq(struct sci_port *port)
-{
-       int i;
-
-       if (port->irqs[0] == port->irqs[1])
-               free_irq(port->irqs[0], port);
-       else {
-               for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
-                       if (!port->irqs[i])
-                               continue;
-
-                       free_irq(port->irqs[i], port);
-               }
-       }
-}
-
-static unsigned int sci_tx_empty(struct uart_port *port)
-{
-       unsigned short status = sci_in(port, SCxSR);
-       unsigned short in_tx_fifo = scif_txfill(port);
-
-       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
-}
-
-static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
-       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
-       /* If you have signals for DTR and DCD, please implement here. */
-}
-
-static unsigned int sci_get_mctrl(struct uart_port *port)
-{
-       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
-          and CTS/RTS */
-
-       return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static void sci_dma_tx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long flags;
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       xmit->tail += sg_dma_len(&s->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
-
-       port->icount.tx += sg_dma_len(&s->sg_tx);
-
-       async_tx_ack(s->desc_tx);
-       s->cookie_tx = -EINVAL;
-       s->desc_tx = NULL;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (!uart_circ_empty(xmit)) {
-               schedule_work(&s->work_tx);
-       } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 ctrl = sci_in(port, SCSCR);
-               sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Locking: called with port lock held */
-static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
-                          size_t count)
-{
-       struct uart_port *port = &s->port;
-       int i, active, room;
-
-       room = tty_buffer_request_room(tty, count);
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               active = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               active = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return 0;
-       }
-
-       if (room < count)
-               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
-                        count - room);
-       if (!room)
-               return room;
-
-       for (i = 0; i < room; i++)
-               tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
-                                    TTY_NORMAL);
-
-       port->icount.rx += room;
-
-       return room;
-}
-
-static void sci_dma_rx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned long flags;
-       int count;
-
-       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       count = sci_dma_rx_push(s, tty, s->buf_len_rx);
-
-       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (count)
-               tty_flip_buffer_push(tty);
-
-       schedule_work(&s->work_rx);
-}
-
-static void sci_start_rx(struct uart_port *port);
-static void sci_start_tx(struct uart_port *port);
-
-static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
-{
-       struct dma_chan *chan = s->chan_rx;
-       struct uart_port *port = &s->port;
-
-       s->chan_rx = NULL;
-       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
-       dma_release_channel(chan);
-       if (sg_dma_address(&s->sg_rx[0]))
-               dma_free_coherent(port->dev, s->buf_len_rx * 2,
-                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
-       if (enable_pio)
-               sci_start_rx(port);
-}
-
-static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
-{
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-
-       s->chan_tx = NULL;
-       s->cookie_tx = -EINVAL;
-       dma_release_channel(chan);
-       if (enable_pio)
-               sci_start_tx(port);
-}
-
-static void sci_submit_rx(struct sci_port *s)
-{
-       struct dma_chan *chan = s->chan_rx;
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               struct scatterlist *sg = &s->sg_rx[i];
-               struct dma_async_tx_descriptor *desc;
-
-               desc = chan->device->device_prep_slave_sg(chan,
-                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
-
-               if (desc) {
-                       s->desc_rx[i] = desc;
-                       desc->callback = sci_dma_rx_complete;
-                       desc->callback_param = s;
-                       s->cookie_rx[i] = desc->tx_submit(desc);
-               }
-
-               if (!desc || s->cookie_rx[i] < 0) {
-                       if (i) {
-                               async_tx_ack(s->desc_rx[0]);
-                               s->cookie_rx[0] = -EINVAL;
-                       }
-                       if (desc) {
-                               async_tx_ack(desc);
-                               s->cookie_rx[i] = -EINVAL;
-                       }
-                       dev_warn(s->port.dev,
-                                "failed to re-start DMA, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
-                       s->cookie_rx[i], i);
-       }
-
-       s->active_rx = s->cookie_rx[0];
-
-       dma_async_issue_pending(chan);
-}
-
-static void work_fn_rx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_rx);
-       struct uart_port *port = &s->port;
-       struct dma_async_tx_descriptor *desc;
-       int new;
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               new = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               new = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return;
-       }
-       desc = s->desc_rx[new];
-
-       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
-           DMA_SUCCESS) {
-               /* Handle incomplete DMA receive */
-               struct tty_struct *tty = port->state->port.tty;
-               struct dma_chan *chan = s->chan_rx;
-               struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
-                                                      async_tx);
-               unsigned long flags;
-               int count;
-
-               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
-               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
-                       sh_desc->partial, sh_desc->cookie);
-
-               spin_lock_irqsave(&port->lock, flags);
-               count = sci_dma_rx_push(s, tty, sh_desc->partial);
-               spin_unlock_irqrestore(&port->lock, flags);
-
-               if (count)
-                       tty_flip_buffer_push(tty);
-
-               sci_submit_rx(s);
-
-               return;
-       }
-
-       s->cookie_rx[new] = desc->tx_submit(desc);
-       if (s->cookie_rx[new] < 0) {
-               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
-               sci_rx_dma_release(s, true);
-               return;
-       }
-
-       s->active_rx = s->cookie_rx[!new];
-
-       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
-               s->cookie_rx[new], new, s->active_rx);
-}
-
-static void work_fn_tx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_tx);
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &s->sg_tx;
-
-       /*
-        * DMA is idle now.
-        * Port xmit buffer is already mapped, and it is one page... Just adjust
-        * offsets and lengths. Since it is a circular buffer, we have to
-        * transmit till the end, and then the rest. Take the port lock to get a
-        * consistent xmit buffer state.
-        */
-       spin_lock_irq(&port->lock);
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-               sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-       spin_unlock_irq(&port->lock);
-
-       BUG_ON(!sg_dma_len(sg));
-
-       desc = chan->device->device_prep_slave_sg(chan,
-                       sg, s->sg_len_tx, DMA_TO_DEVICE,
-                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
-
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
-
-       spin_lock_irq(&port->lock);
-       s->desc_tx = desc;
-       desc->callback = sci_dma_tx_complete;
-       desc->callback_param = s;
-       spin_unlock_irq(&port->lock);
-       s->cookie_tx = desc->tx_submit(desc);
-       if (s->cookie_tx < 0) {
-               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
-
-       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
-               xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
-
-       dma_async_issue_pending(chan);
-}
-#endif
-
-static void sci_start_tx(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       unsigned short ctrl;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 new, scr = sci_in(port, SCSCR);
-               if (s->chan_tx)
-                       new = scr | 0x8000;
-               else
-                       new = scr & ~0x8000;
-               if (new != scr)
-                       sci_out(port, SCSCR, new);
-       }
-
-       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
-           s->cookie_tx < 0)
-               schedule_work(&s->work_tx);
-#endif
-
-       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-               ctrl = sci_in(port, SCSCR);
-               sci_out(port, SCSCR, ctrl | SCSCR_TIE);
-       }
-}
-
-static void sci_stop_tx(struct uart_port *port)
-{
-       unsigned short ctrl;
-
-       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = sci_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x8000;
-
-       ctrl &= ~SCSCR_TIE;
-
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_start_rx(struct uart_port *port)
-{
-       unsigned short ctrl;
-
-       ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x4000;
-
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_stop_rx(struct uart_port *port)
-{
-       unsigned short ctrl;
-
-       ctrl = sci_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~0x4000;
-
-       ctrl &= ~port_rx_irq_mask(port);
-
-       sci_out(port, SCSCR, ctrl);
-}
-
-static void sci_enable_ms(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-}
-
-static void sci_break_ctl(struct uart_port *port, int break_state)
-{
-       /* Nothing here yet .. */
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct sh_dmae_slave *param = slave;
-
-       dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
-               param->slave_id);
-
-       if (param->dma_dev == chan->device->dev) {
-               chan->private = param;
-               return true;
-       } else {
-               return false;
-       }
-}
-
-static void rx_timer_fn(unsigned long arg)
-{
-       struct sci_port *s = (struct sci_port *)arg;
-       struct uart_port *port = &s->port;
-       u16 scr = sci_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               scr &= ~0x4000;
-               enable_irq(s->irqs[1]);
-       }
-       sci_out(port, SCSCR, scr | SCSCR_RIE);
-       dev_dbg(port->dev, "DMA Rx timed out\n");
-       schedule_work(&s->work_rx);
-}
-
-static void sci_request_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       struct sh_dmae_slave *param;
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-       int nent;
-
-       dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
-               port->line, s->dma_dev);
-
-       if (!s->dma_dev)
-               return;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       param = &s->param_tx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
-       param->slave_id = s->slave_tx;
-       param->dma_dev = s->dma_dev;
-
-       s->cookie_tx = -EINVAL;
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
-       if (chan) {
-               s->chan_tx = chan;
-               sg_init_table(&s->sg_tx, 1);
-               /* UART circular tx buffer is an aligned page. */
-               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
-               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
-                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
-               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
-               if (!nent)
-                       sci_tx_dma_release(s, false);
-               else
-                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
-                               sg_dma_len(&s->sg_tx),
-                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
-
-               s->sg_len_tx = nent;
-
-               INIT_WORK(&s->work_tx, work_fn_tx);
-       }
-
-       param = &s->param_rx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
-       param->slave_id = s->slave_rx;
-       param->dma_dev = s->dma_dev;
-
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
-       if (chan) {
-               dma_addr_t dma[2];
-               void *buf[2];
-               int i;
-
-               s->chan_rx = chan;
-
-               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
-               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
-                                           &dma[0], GFP_KERNEL);
-
-               if (!buf[0]) {
-                       dev_warn(port->dev,
-                                "failed to allocate dma buffer, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-
-               buf[1] = buf[0] + s->buf_len_rx;
-               dma[1] = dma[0] + s->buf_len_rx;
-
-               for (i = 0; i < 2; i++) {
-                       struct scatterlist *sg = &s->sg_rx[i];
-
-                       sg_init_table(sg, 1);
-                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
-                                   (int)buf[i] & ~PAGE_MASK);
-                       sg_dma_address(sg) = dma[i];
-               }
-
-               INIT_WORK(&s->work_rx, work_fn_rx);
-               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
-
-               sci_submit_rx(s);
-       }
-}
-
-static void sci_free_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (!s->dma_dev)
-               return;
-
-       if (s->chan_tx)
-               sci_tx_dma_release(s, false);
-       if (s->chan_rx)
-               sci_rx_dma_release(s, false);
-}
-#endif
-
-static int sci_startup(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       if (s->enable)
-               s->enable(port);
-
-       sci_request_irq(s);
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_request_dma(port);
-#endif
-       sci_start_tx(port);
-       sci_start_rx(port);
-
-       return 0;
-}
-
-static void sci_shutdown(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
-
-       sci_stop_rx(port);
-       sci_stop_tx(port);
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_free_dma(port);
-#endif
-       sci_free_irq(s);
-
-       if (s->disable)
-               s->disable(port);
-}
-
-static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
-                                  unsigned long freq)
-{
-       switch (algo_id) {
-       case SCBRR_ALGO_1:
-               return ((freq + 16 * bps) / (16 * bps) - 1);
-       case SCBRR_ALGO_2:
-               return ((freq + 16 * bps) / (32 * bps) - 1);
-       case SCBRR_ALGO_3:
-               return (((freq * 2) + 16 * bps) / (16 * bps) - 1);
-       case SCBRR_ALGO_4:
-               return (((freq * 2) + 16 * bps) / (32 * bps) - 1);
-       case SCBRR_ALGO_5:
-               return (((freq * 1000 / 32) / bps) - 1);
-       }
-
-       /* Warn, but use a safe default */
-       WARN_ON(1);
-       return ((freq + 16 * bps) / (32 * bps) - 1);
-}
-
-static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
-                           struct ktermios *old)
-{
-       struct sci_port *s = to_sci_port(port);
-       unsigned int status, baud, smr_val, max_baud;
-       int t = -1;
-       u16 scfcr = 0;
-
-       /*
-        * earlyprintk comes here early on with port->uartclk set to zero.
-        * the clock framework is not up and running at this point so here
-        * we assume that 115200 is the maximum baud rate. please note that
-        * the baud rate is not programmed during earlyprintk - it is assumed
-        * that the previous boot loader has enabled required clocks and
-        * setup the baud rate generator hardware for us already.
-        */
-       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
-       if (likely(baud && port->uartclk))
-               t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk);
-
-       do {
-               status = sci_in(port, SCxSR);
-       } while (!(status & SCxSR_TEND(port)));
-
-       sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
-
-       if (port->type != PORT_SCI)
-               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
-
-       smr_val = sci_in(port, SCSMR) & 3;
-       if ((termios->c_cflag & CSIZE) == CS7)
-               smr_val |= 0x40;
-       if (termios->c_cflag & PARENB)
-               smr_val |= 0x20;
-       if (termios->c_cflag & PARODD)
-               smr_val |= 0x30;
-       if (termios->c_cflag & CSTOPB)
-               smr_val |= 0x08;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       sci_out(port, SCSMR, smr_val);
-
-       dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
-               s->scscr);
-
-       if (t > 0) {
-               if (t >= 256) {
-                       sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
-                       t >>= 2;
-               } else
-                       sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
-
-               sci_out(port, SCBRR, t);
-               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
-       }
-
-       sci_init_pins(port, termios->c_cflag);
-       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
-
-       sci_out(port, SCSCR, s->scscr);
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       /*
-        * Calculate delay for 1.5 DMA buffers: see
-        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
-        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
-        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
-        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
-        * sizes), but it has been found out experimentally, that this is not
-        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
-        * as a minimum seem to work perfectly.
-        */
-       if (s->chan_rx) {
-               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
-                       port->fifosize / 2;
-               dev_dbg(port->dev,
-                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
-                       s->rx_timeout * 1000 / HZ, port->timeout);
-               if (s->rx_timeout < msecs_to_jiffies(20))
-                       s->rx_timeout = msecs_to_jiffies(20);
-       }
-#endif
-
-       if ((termios->c_cflag & CREAD) != 0)
-               sci_start_rx(port);
-}
-
-static const char *sci_type(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_IRDA:
-               return "irda";
-       case PORT_SCI:
-               return "sci";
-       case PORT_SCIF:
-               return "scif";
-       case PORT_SCIFA:
-               return "scifa";
-       case PORT_SCIFB:
-               return "scifb";
-       }
-
-       return NULL;
-}
-
-static void sci_release_port(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-}
-
-static int sci_request_port(struct uart_port *port)
-{
-       /* Nothing here yet .. */
-       return 0;
-}
-
-static void sci_config_port(struct uart_port *port, int flags)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       port->type = s->type;
-
-       if (port->membase)
-               return;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap_nocache(port->mapbase, 0x40);
-
-               if (IS_ERR(port->membase))
-                       dev_err(port->dev, "can't remap port#%d\n", port->line);
-       } else {
-               /*
-                * For the simple (and majority of) cases where we don't
-                * need to do any remapping, just cast the cookie
-                * directly.
-                */
-               port->membase = (void __iomem *)port->mapbase;
-       }
-}
-
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
-               return -EINVAL;
-       if (ser->baud_base < 2400)
-               /* No paper tape reader for Mitch.. */
-               return -EINVAL;
-
-       return 0;
-}
-
-static struct uart_ops sci_uart_ops = {
-       .tx_empty       = sci_tx_empty,
-       .set_mctrl      = sci_set_mctrl,
-       .get_mctrl      = sci_get_mctrl,
-       .start_tx       = sci_start_tx,
-       .stop_tx        = sci_stop_tx,
-       .stop_rx        = sci_stop_rx,
-       .enable_ms      = sci_enable_ms,
-       .break_ctl      = sci_break_ctl,
-       .startup        = sci_startup,
-       .shutdown       = sci_shutdown,
-       .set_termios    = sci_set_termios,
-       .type           = sci_type,
-       .release_port   = sci_release_port,
-       .request_port   = sci_request_port,
-       .config_port    = sci_config_port,
-       .verify_port    = sci_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = sci_poll_get_char,
-       .poll_put_char  = sci_poll_put_char,
-#endif
-};
-
-static int __devinit sci_init_single(struct platform_device *dev,
-                                    struct sci_port *sci_port,
-                                    unsigned int index,
-                                    struct plat_sci_port *p)
-{
-       struct uart_port *port = &sci_port->port;
-
-       port->ops       = &sci_uart_ops;
-       port->iotype    = UPIO_MEM;
-       port->line      = index;
-
-       switch (p->type) {
-       case PORT_SCIFB:
-               port->fifosize = 256;
-               break;
-       case PORT_SCIFA:
-               port->fifosize = 64;
-               break;
-       case PORT_SCIF:
-               port->fifosize = 16;
-               break;
-       default:
-               port->fifosize = 1;
-               break;
-       }
-
-       if (dev) {
-               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
-               if (IS_ERR(sci_port->iclk)) {
-                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
-                       if (IS_ERR(sci_port->iclk)) {
-                               dev_err(&dev->dev, "can't get iclk\n");
-                               return PTR_ERR(sci_port->iclk);
-                       }
-               }
-
-               /*
-                * The function clock is optional, ignore it if we can't
-                * find it.
-                */
-               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
-               if (IS_ERR(sci_port->fclk))
-                       sci_port->fclk = NULL;
-
-               sci_port->enable = sci_clk_enable;
-               sci_port->disable = sci_clk_disable;
-               port->dev = &dev->dev;
-       }
-
-       sci_port->break_timer.data = (unsigned long)sci_port;
-       sci_port->break_timer.function = sci_break_timer;
-       init_timer(&sci_port->break_timer);
-
-       port->mapbase   = p->mapbase;
-       port->membase   = p->membase;
-
-       port->irq               = p->irqs[SCIx_TXI_IRQ];
-       port->flags             = p->flags;
-       sci_port->type          = port->type = p->type;
-       sci_port->scscr         = p->scscr;
-       sci_port->scbrr_algo_id = p->scbrr_algo_id;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       sci_port->dma_dev       = p->dma_dev;
-       sci_port->slave_tx      = p->dma_slave_tx;
-       sci_port->slave_rx      = p->dma_slave_rx;
-
-       dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
-               p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
-#endif
-
-       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
-       return 0;
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static struct tty_driver *serial_console_device(struct console *co, int *index)
-{
-       struct uart_driver *p = &sci_uart_driver;
-       *index = co->index;
-       return p->tty_driver;
-}
-
-static void serial_console_putchar(struct uart_port *port, int ch)
-{
-       sci_poll_put_char(port, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-       struct uart_port *port = co->data;
-       struct sci_port *sci_port = to_sci_port(port);
-       unsigned short bits;
-
-       if (sci_port->enable)
-               sci_port->enable(port);
-
-       uart_console_write(port, s, count, serial_console_putchar);
-
-       /* wait until fifo is empty and last bit has been transmitted */
-       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
-       while ((sci_in(port, SCxSR) & bits) != bits)
-               cpu_relax();
-
-       if (sci_port->disable)
-               sci_port->disable(port);
-}
-
-static int __devinit serial_console_setup(struct console *co, char *options)
-{
-       struct sci_port *sci_port;
-       struct uart_port *port;
-       int baud = 115200;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= SCI_NPORTS)
-               co->index = 0;
-
-       if (co->data) {
-               port = co->data;
-               sci_port = to_sci_port(port);
-       } else {
-               sci_port = &sci_ports[co->index];
-               port = &sci_port->port;
-               co->data = port;
-       }
-
-       /*
-        * Also need to check port->type, we don't actually have any
-        * UPIO_PORT ports, but uart_report_port() handily misreports
-        * it anyways if we don't have a port available by the time this is
-        * called.
-        */
-       if (!port->type)
-               return -ENODEV;
-
-       sci_config_port(port, 0);
-
-       if (sci_port->enable)
-               sci_port->enable(port);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       ret = uart_set_options(port, co, baud, parity, bits, flow);
-#if defined(__H8300H__) || defined(__H8300S__)
-       /* disable rx interrupt */
-       if (ret == 0)
-               sci_stop_rx(port);
-#endif
-       /* TODO: disable clock */
-       return ret;
-}
-
-static struct console serial_console = {
-       .name           = "ttySC",
-       .device         = serial_console_device,
-       .write          = serial_console_write,
-       .setup          = serial_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static int __init sci_console_init(void)
-{
-       register_console(&serial_console);
-       return 0;
-}
-console_initcall(sci_console_init);
-
-static struct sci_port early_serial_port;
-static struct console early_serial_console = {
-       .name           = "early_ttySC",
-       .write          = serial_console_write,
-       .flags          = CON_PRINTBUFFER,
-};
-static char early_serial_buf[32];
-
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-#define SCI_CONSOLE    (&serial_console)
-#else
-#define SCI_CONSOLE    0
-#endif
-
-static char banner[] __initdata =
-       KERN_INFO "SuperH SCI(F) driver initialized\n";
-
-static struct uart_driver sci_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "sci",
-       .dev_name       = "ttySC",
-       .major          = SCI_MAJOR,
-       .minor          = SCI_MINOR_START,
-       .nr             = SCI_NPORTS,
-       .cons           = SCI_CONSOLE,
-};
-
-
-static int sci_remove(struct platform_device *dev)
-{
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node) {
-               uart_remove_one_port(&sci_uart_driver, &p->port);
-               clk_put(p->iclk);
-               clk_put(p->fclk);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       kfree(priv);
-       return 0;
-}
-
-static int __devinit sci_probe_single(struct platform_device *dev,
-                                     unsigned int index,
-                                     struct plat_sci_port *p,
-                                     struct sci_port *sciport)
-{
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
-       unsigned long flags;
-       int ret;
-
-       /* Sanity check */
-       if (unlikely(index >= SCI_NPORTS)) {
-               dev_notice(&dev->dev, "Attempting to register port "
-                          "%d when only %d are available.\n",
-                          index+1, SCI_NPORTS);
-               dev_notice(&dev->dev, "Consider bumping "
-                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
-               return 0;
-       }
-
-       ret = sci_init_single(dev, sciport, index, p);
-       if (ret)
-               return ret;
-
-       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
-       if (ret)
-               return ret;
-
-       INIT_LIST_HEAD(&sciport->node);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_add(&sciport->node, &priv->ports);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-/*
- * Register a set of serial devices attached to a platform device.  The
- * list is terminated with a zero flags entry, which means we expect
- * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
- * remapping (such as sh64) should also set UPF_IOREMAP.
- */
-static int __devinit sci_probe(struct platform_device *dev)
-{
-       struct plat_sci_port *p = dev->dev.platform_data;
-       struct sh_sci_priv *priv;
-       int i, ret = -EINVAL;
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-       if (is_early_platform_device(dev)) {
-               if (dev->id == -1)
-                       return -ENOTSUPP;
-               early_serial_console.index = dev->id;
-               early_serial_console.data = &early_serial_port.port;
-               sci_init_single(NULL, &early_serial_port, dev->id, p);
-               serial_console_setup(&early_serial_console, early_serial_buf);
-               if (!strstr(early_serial_buf, "keep"))
-                       early_serial_console.flags |= CON_BOOT;
-               register_console(&early_serial_console);
-               return 0;
-       }
-#endif
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&priv->ports);
-       spin_lock_init(&priv->lock);
-       platform_set_drvdata(dev, priv);
-
-       priv->clk_nb.notifier_call = sci_notifier;
-       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-
-       if (dev->id != -1) {
-               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
-               if (ret)
-                       goto err_unreg;
-       } else {
-               for (i = 0; p && p->flags != 0; p++, i++) {
-                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
-                       if (ret)
-                               goto err_unreg;
-               }
-       }
-
-#ifdef CONFIG_SH_STANDARD_BIOS
-       sh_bios_gdb_detach();
-#endif
-
-       return 0;
-
-err_unreg:
-       sci_remove(dev);
-       return ret;
-}
-
-static int sci_suspend(struct device *dev)
-{
-       struct sh_sci_priv *priv = dev_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node)
-               uart_suspend_port(&sci_uart_driver, &p->port);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-static int sci_resume(struct device *dev)
-{
-       struct sh_sci_priv *priv = dev_get_drvdata(dev);
-       struct sci_port *p;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry(p, &priv->ports, node)
-               uart_resume_port(&sci_uart_driver, &p->port);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-static const struct dev_pm_ops sci_dev_pm_ops = {
-       .suspend        = sci_suspend,
-       .resume         = sci_resume,
-};
-
-static struct platform_driver sci_driver = {
-       .probe          = sci_probe,
-       .remove         = sci_remove,
-       .driver         = {
-               .name   = "sh-sci",
-               .owner  = THIS_MODULE,
-               .pm     = &sci_dev_pm_ops,
-       },
-};
-
-static int __init sci_init(void)
-{
-       int ret;
-
-       printk(banner);
-
-       ret = uart_register_driver(&sci_uart_driver);
-       if (likely(ret == 0)) {
-               ret = platform_driver_register(&sci_driver);
-               if (unlikely(ret))
-                       uart_unregister_driver(&sci_uart_driver);
-       }
-
-       return ret;
-}
-
-static void __exit sci_exit(void)
-{
-       platform_driver_unregister(&sci_driver);
-       uart_unregister_driver(&sci_uart_driver);
-}
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-early_platform_init_buffer("earlyprintk", &sci_driver,
-                          early_serial_buf, ARRAY_SIZE(early_serial_buf));
-#endif
-module_init(sci_init);
-module_exit(sci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:sh-sci");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
deleted file mode 100644 (file)
index b223d6c..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#endif
-#if defined(CONFIG_H8S2678)
-#include <asm/regs267x.h>
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
-# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define SCIF0         0xA4400000
-# define SCIF2         0xA4410000
-# define SCPCR 0xA4000116
-# define SCPDR 0xA4000136
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372)
-# define PORT_PTCR        0xA405011EUL
-# define PORT_PVCR        0xA4050122UL
-# define SCIF_ORER        0x0200   /* overrun error bit */
-#elif defined(CONFIG_SH_RTS7751R2D)
-# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R)
-# define SCSPTR1 0xffe0001c /* 8  bit SCI */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
-# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
-# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define PACR 0xa4050100
-# define PBCR 0xa4050102
-#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
-# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
-# define SCSPTR1 0xffe10010    /* 16 bit SCIF */
-# define SCSPTR2 0xffe20010    /* 16 bit SCIF */
-# define SCSPTR3 0xffe30010    /* 16 bit SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define PADR                  0xA4050120
-# define PSDR                  0xA405013e
-# define PWDR                  0xA4050166
-# define PSCR                  0xA405011E
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
-# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
-# define SCSPTR0               SCPDR0
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-# define SCSPTR0                0xa4050160
-# define SCSPTR1                0xa405013e
-# define SCSPTR2                0xa4050160
-# define SCSPTR3                0xa405013e
-# define SCSPTR4                0xa4050128
-# define SCSPTR5                0xa4050128
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
-# define SCIF_PTR2_OFFS    0x0000020
-# define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_H8S2678)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-# define SCSPTR0 0xfe4b0020
-# define SCSPTR1 0xfe4b0020
-# define SCSPTR2 0xfe4b0020
-# define SCIF_ORER 0x0001
-# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
-# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
-# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
-# define SCSPTR0 0xff923020 /* 16 bit SCIF */
-# define SCSPTR1 0xff924020 /* 16 bit SCIF */
-# define SCSPTR2 0xff925020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
-# define SCSPTR1       0xffe10024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786)
-# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
-# define SCSPTR1       0xffeb0024      /* 16 bit SCIF */
-# define SCSPTR2       0xffec0024      /* 16 bit SCIF */
-# define SCSPTR3       0xffed0024      /* 16 bit SCIF */
-# define SCSPTR4       0xffee0024      /* 16 bit SCIF */
-# define SCSPTR5       0xffef0024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7263)
-# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
-# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
-# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
-# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
-# if defined(CONFIG_CPU_SUBTYPE_SH7201)
-#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
-#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
-#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
-#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
-# endif
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
-# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
-# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
-# define SCSPTR1 0xffc40020            /* 16 bit SCIF */
-# define SCSPTR2 0xffc50020            /* 16 bit SCIF */
-# define SCSPTR3 0xffc60020            /* 16 bit SCIF */
-# define SCIF_ORER 0x0001              /* Overrun error bit */
-#else
-# error CPU subtype not defined
-#endif
-
-/* SCxSR SCI */
-#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-
-#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
-
-/* SCxSR SCIF */
-#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCIF_ORER    0x0200
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-/* SH7763 SCIF2 support */
-# define SCIF2_RFDC_MASK 0x001f
-# define SCIF2_TXROOM_MAX 16
-#else
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-# define SCIF_RFDC_MASK 0x001f
-# define SCIF_TXROOM_MAX 16
-#endif
-
-#ifndef SCIF_ORER
-#define SCIF_ORER      0x0000
-#endif
-
-#define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
-#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
-#define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
-#define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
-#define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
-#define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
-#define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
-#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCxSR_RDxF_CLEAR(port)         (sci_in(port, SCxSR) & 0xfffc)
-# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
-# define SCxSR_TDxE_CLEAR(port)         (sci_in(port, SCxSR) & 0xffdf)
-# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
-#else
-# define SCxSR_RDxF_CLEAR(port)         (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
-# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
-# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
-# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
-#endif
-
-/* SCFCR */
-#define SCFCR_RFRST 0x0002
-#define SCFCR_TFRST 0x0004
-#define SCFCR_MCE   0x0008
-
-#define SCI_MAJOR              204
-#define SCI_MINOR_START                8
-
-#define SCI_IN(size, offset)                                   \
-  if ((size) == 8) {                                           \
-    return ioread8(port->membase + (offset));                  \
-  } else {                                                     \
-    return ioread16(port->membase + (offset));                 \
-  }
-#define SCI_OUT(size, offset, value)                           \
-  if ((size) == 8) {                                           \
-    iowrite8(value, port->membase + (offset));                 \
-  } else if ((size) == 16) {                                   \
-    iowrite16(value, port->membase + (offset));                        \
-  }
-
-#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_IN(scif_size, scif_offset)                                   \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_IN(sci_size, sci_offset);                                    \
-    }                                                                  \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_OUT(scif_size, scif_offset, value)                           \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_OUT(sci_size, sci_offset, value);                            \
-    }                                                                  \
-  }
-
-#ifdef CONFIG_H8300
-/* h8300 don't have SCIF */
-#define CPU_SCIF_FNS(name)                                             \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    return 0;                                                          \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-  }
-#else
-#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    SCI_IN(scif_size, scif_offset);                                    \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(scif_size, scif_offset, value);                            \
-  }
-#endif
-
-#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
-  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
-  {                                                                    \
-    SCI_IN(sci_size, sci_offset);                                      \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(sci_size, sci_offset, value);                              \
-  }
-
-#if defined(CONFIG_CPU_SH3) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#elif defined(CONFIG_ARCH_SH7372)
-#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
-  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
-#endif
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
-        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377)
-
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCxTDR, 0x20,  8)
-SCIF_FNS(SCxRDR, 0x24,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_ARCH_SH7372)
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c, 16)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCTFDR, 0x38, 16)
-SCIF_FNS(SCRFDR, 0x3c, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
-SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
-SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
-SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
-SCIx_FNS(SCSPTR, 0,     0,    0,  0)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCLSR,  0x24, 16)
-#else
-/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
-/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
-SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
-SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
-SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
-SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
-SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
-SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
-SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
-SCIF_FNS(SCSPTR2,                      0,  0, 0x20, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#else
-SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
-#else
-SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
-#endif
-SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
-#endif
-#endif
-#define sci_in(port, reg) sci_##reg##_in(port)
-#define sci_out(port, reg, value) sci_##reg##_out(port, value)
-
-/* H8/300 series SCI pins assignment */
-#if defined(__H8300H__) || defined(__H8300S__)
-static const struct __attribute__((packed)) {
-       int port;             /* GPIO port no */
-       unsigned short rx,tx; /* GPIO bit no */
-} h8300_sci_pins[] = {
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_PB,
-               .rx   = H8300_GPIO_B7,
-               .tx   = H8300_GPIO_B6,
-       }
-#elif defined(CONFIG_H8S2678)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_P5,
-               .rx   = H8300_GPIO_B1,
-               .tx   = H8300_GPIO_B0,
-       }
-#endif
-};
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xfffffe80)
-               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000)
-               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(__H8300H__) || defined(__H8300S__)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
-}
-#else /* default case for non-SCI processors */
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       return 1;
-}
-#endif
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
deleted file mode 100644 (file)
index cff9a30..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-/*
- * C-Brick Serial Port (and console) driver for SGI Altix machines.
- *
- * This driver is NOT suitable for talking to the l1-controller for
- * anything other than 'console activities' --- please use the l1
- * driver for that.
- *
- *
- * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/module.h>
-#include <linux/sysrq.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h> /* for mdelay */
-#include <linux/miscdevice.h>
-#include <linux/serial_core.h>
-
-#include <asm/io.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/sn_sal.h>
-
-/* number of characters we can transmit to the SAL console at a time */
-#define SN_SAL_MAX_CHARS 120
-
-/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
- * avoid losing chars, (always has to be a power of 2) */
-#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
-
-#define SN_SAL_UART_FIFO_DEPTH 16
-#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
-
-/* sn_transmit_chars() calling args */
-#define TRANSMIT_BUFFERED      0
-#define TRANSMIT_RAW           1
-
-/* To use dynamic numbers only and not use the assigned major and minor,
- * define the following.. */
-                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
-#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
-
-/* Device name we're using */
-#define DEVICE_NAME "ttySG"
-#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
-/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 40
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static char sysrq_serial_str[] = "\eSYS";
-static char *sysrq_serial_ptr = sysrq_serial_str;
-static unsigned long sysrq_requested;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-/*
- * Port definition - this kinda drives it all
- */
-struct sn_cons_port {
-       struct timer_list sc_timer;
-       struct uart_port sc_port;
-       struct sn_sal_ops {
-               int (*sal_puts_raw) (const char *s, int len);
-               int (*sal_puts) (const char *s, int len);
-               int (*sal_getc) (void);
-               int (*sal_input_pending) (void);
-               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
-       } *sc_ops;
-       unsigned long sc_interrupt_timeout;
-       int sc_is_asynch;
-};
-
-static struct sn_cons_port sal_console_port;
-static int sn_process_input;
-
-/* Only used if USE_DYNAMIC_MINOR is set to 1 */
-static struct miscdevice misc; /* used with misc_register for dynamic */
-
-extern void early_sn_setup(void);
-
-#undef DEBUG
-#ifdef DEBUG
-static int sn_debug_printf(const char *fmt, ...);
-#define DPRINTF(x...) sn_debug_printf(x)
-#else
-#define DPRINTF(x...) do { } while (0)
-#endif
-
-/* Prototypes */
-static int snt_hw_puts_raw(const char *, int);
-static int snt_hw_puts_buffered(const char *, int);
-static int snt_poll_getc(void);
-static int snt_poll_input_pending(void);
-static int snt_intr_getc(void);
-static int snt_intr_input_pending(void);
-static void sn_transmit_chars(struct sn_cons_port *, int);
-
-/* A table for polling:
- */
-static struct sn_sal_ops poll_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_raw,
-       .sal_getc = snt_poll_getc,
-       .sal_input_pending = snt_poll_input_pending
-};
-
-/* A table for interrupts enabled */
-static struct sn_sal_ops intr_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_buffered,
-       .sal_getc = snt_intr_getc,
-       .sal_input_pending = snt_intr_input_pending,
-       .sal_wakeup_transmit = sn_transmit_chars
-};
-
-/* the console does output in two distinctly different ways:
- * synchronous (raw) and asynchronous (buffered).  initally, early_printk
- * does synchronous output.  any data written goes directly to the SAL
- * to be output (incidentally, it is internally buffered by the SAL)
- * after interrupts and timers are initialized and available for use,
- * the console init code switches to asynchronous output.  this is
- * also the earliest opportunity to begin polling for console input.
- * after console initialization, console output and tty (serial port)
- * output is buffered and sent to the SAL asynchronously (either by
- * timer callback or by UART interrupt) */
-
-/* routines for running the console in polling mode */
-
-/**
- * snt_poll_getc - Get a character from the console in polling mode
- *
- */
-static int snt_poll_getc(void)
-{
-       int ch;
-
-       ia64_sn_console_getc(&ch);
-       return ch;
-}
-
-/**
- * snt_poll_input_pending - Check if any input is waiting - polling mode.
- *
- */
-static int snt_poll_input_pending(void)
-{
-       int status, input;
-
-       status = ia64_sn_console_check(&input);
-       return !status && input;
-}
-
-/* routines for an interrupt driven console (normal) */
-
-/**
- * snt_intr_getc - Get a character from the console, interrupt mode
- *
- */
-static int snt_intr_getc(void)
-{
-       return ia64_sn_console_readc();
-}
-
-/**
- * snt_intr_input_pending - Check if input is pending, interrupt mode
- *
- */
-static int snt_intr_input_pending(void)
-{
-       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
-}
-
-/* these functions are polled and interrupt */
-
-/**
- * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_raw(const char *s, int len)
-{
-       /* this will call the PROM and not return until this is done */
-       return ia64_sn_console_putb(s, len);
-}
-
-/**
- * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_buffered(const char *s, int len)
-{
-       /* queue data to the PROM */
-       return ia64_sn_console_xmit_chars((char *)s, len);
-}
-
-/* uart interface structs
- * These functions are associated with the uart_port that the serial core
- * infrastructure calls.
- *
- * Note: Due to how the console works, many routines are no-ops.
- */
-
-/**
- * snp_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *snp_type(struct uart_port *port)
-{
-       return ("SGI SN L1");
-}
-
-/**
- * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
- * @port: Port to operate on (we ignore since we only have one port)
- *
- */
-static unsigned int snp_tx_empty(struct uart_port *port)
-{
-       return 1;
-}
-
-/**
- * snp_stop_tx - stop the transmitter - no-op for us
- * @port: Port to operat eon - we ignore - no-op function
- *
- */
-static void snp_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * snp_release_port - Free i/o and resources for port - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_release_port(struct uart_port *port)
-{
-}
-
-/**
- * snp_enable_ms - Force modem status interrupts on - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_enable_ms(struct uart_port *port)
-{
-}
-
-/**
- * snp_shutdown - shut down the port - free irq and disable - no-op for us
- * @port: Port to shut down - we ignore
- *
- */
-static void snp_shutdown(struct uart_port *port)
-{
-}
-
-/**
- * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
- * @port: Port to operate on - we ignore
- * @mctrl: Lines to set/unset - we ignore
- *
- */
-static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * snp_get_mctrl - get contorl line info, we just return a static value
- * @port: port to operate on - we only have one port so we ignore this
- *
- */
-static unsigned int snp_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * snp_stop_rx - Stop the receiver - we ignor ethis
- * @port: Port to operate on - we ignore
- *
- */
-static void snp_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * snp_start_tx - Start transmitter
- * @port: Port to operate on
- *
- */
-static void snp_start_tx(struct uart_port *port)
-{
-       if (sal_console_port.sc_ops->sal_wakeup_transmit)
-               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
-                                                            TRANSMIT_BUFFERED);
-
-}
-
-/**
- * snp_break_ctl - handle breaks - ignored by us
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void snp_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * snp_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int snp_startup(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_set_termios - set termios stuff - we ignore these
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-snp_set_termios(struct uart_port *port, struct ktermios *termios,
-               struct ktermios *old)
-{
-}
-
-/**
- * snp_request_port - allocate resources for port - ignored by us
- * @port: port to operate on
- *
- */
-static int snp_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_config_port - allocate resources, set up - we ignore,  we're always on
- * @port: Port to operate on
- * @flags: flags used for port setup
- *
- */
-static void snp_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static struct uart_ops sn_console_ops = {
-       .tx_empty = snp_tx_empty,
-       .set_mctrl = snp_set_mctrl,
-       .get_mctrl = snp_get_mctrl,
-       .stop_tx = snp_stop_tx,
-       .start_tx = snp_start_tx,
-       .stop_rx = snp_stop_rx,
-       .enable_ms = snp_enable_ms,
-       .break_ctl = snp_break_ctl,
-       .startup = snp_startup,
-       .shutdown = snp_shutdown,
-       .set_termios = snp_set_termios,
-       .pm = NULL,
-       .type = snp_type,
-       .release_port = snp_release_port,
-       .request_port = snp_request_port,
-       .config_port = snp_config_port,
-       .verify_port = NULL,
-};
-
-/* End of uart struct functions and defines */
-
-#ifdef DEBUG
-
-/**
- * sn_debug_printf - close to hardware debugging printf
- * @fmt: printf format
- *
- * This is as "close to the metal" as we can get, used when the driver
- * itself may be broken.
- *
- */
-static int sn_debug_printf(const char *fmt, ...)
-{
-       static char printk_buf[1024];
-       int printed_len;
-       va_list args;
-
-       va_start(args, fmt);
-       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-
-       if (!sal_console_port.sc_ops) {
-               sal_console_port.sc_ops = &poll_ops;
-               early_sn_setup();
-       }
-       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
-
-       va_end(args);
-       return printed_len;
-}
-#endif                         /* DEBUG */
-
-/*
- * Interrupt handling routines.
- */
-
-/**
- * sn_receive_chars - Grab characters, pass them to tty layer
- * @port: Port to operate on
- * @flags: irq flags
- *
- * Note: If we're not registered with the serial core infrastructure yet,
- * we don't try to send characters to it...
- *
- */
-static void
-sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
-{
-       int ch;
-       struct tty_struct *tty;
-
-       if (!port) {
-               printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
-               return;
-       }
-
-       if (!port->sc_ops) {
-               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
-               return;
-       }
-
-       if (port->sc_port.state) {
-               /* The serial_core stuffs are initialized, use them */
-               tty = port->sc_port.state->port.tty;
-       }
-       else {
-               /* Not registered yet - can't pass to tty layer.  */
-               tty = NULL;
-       }
-
-       while (port->sc_ops->sal_input_pending()) {
-               ch = port->sc_ops->sal_getc();
-               if (ch < 0) {
-                       printk(KERN_ERR "sn_console: An error occured while "
-                              "obtaining data from the console (0x%0x)\n", ch);
-                       break;
-               }
-#ifdef CONFIG_MAGIC_SYSRQ
-                if (sysrq_requested) {
-                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
-
-                        sysrq_requested = 0;
-                        if (ch && time_before(jiffies, sysrq_timeout)) {
-                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                                handle_sysrq(ch);
-                                spin_lock_irqsave(&port->sc_port.lock, flags);
-                                /* ignore actual sysrq command char */
-                                continue;
-                        }
-                }
-                if (ch == *sysrq_serial_ptr) {
-                        if (!(*++sysrq_serial_ptr)) {
-                                sysrq_requested = jiffies;
-                                sysrq_serial_ptr = sysrq_serial_str;
-                        }
-                       /*
-                        * ignore the whole sysrq string except for the
-                        * leading escape
-                        */
-                       if (ch != '\e')
-                               continue;
-                }
-                else
-                       sysrq_serial_ptr = sysrq_serial_str;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-               /* record the character to pass up to the tty layer */
-               if (tty) {
-                       if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
-                               break;
-               }
-               port->sc_port.icount.rx++;
-       }
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-}
-
-/**
- * sn_transmit_chars - grab characters from serial core, send off
- * @port: Port to operate on
- * @raw: Transmit raw or buffered
- *
- * Note: If we're early, before we're registered with serial core, the
- * writes are going through sn_sal_console_write because that's how
- * register_console has been set up.  We currently could have asynch
- * polls calling this function due to sn_sal_switch_to_asynch but we can
- * ignore them until we register with the serial core stuffs.
- *
- */
-static void sn_transmit_chars(struct sn_cons_port *port, int raw)
-{
-       int xmit_count, tail, head, loops, ii;
-       int result;
-       char *start;
-       struct circ_buf *xmit;
-
-       if (!port)
-               return;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       if (port->sc_port.state) {
-               /* We're initialized, using serial core infrastructure */
-               xmit = &port->sc_port.state->xmit;
-       } else {
-               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
-                * initialized yet.  Just return.  Writes are going through
-                * sn_sal_console_write (due to register_console) at this time.
-                */
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
-               /* Nothing to do. */
-               ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
-               return;
-       }
-
-       head = xmit->head;
-       tail = xmit->tail;
-       start = &xmit->buf[tail];
-
-       /* twice around gets the tail to the end of the buffer and
-        * then to the head, if needed */
-       loops = (head < tail) ? 2 : 1;
-
-       for (ii = 0; ii < loops; ii++) {
-               xmit_count = (head < tail) ?
-                   (UART_XMIT_SIZE - tail) : (head - tail);
-
-               if (xmit_count > 0) {
-                       if (raw == TRANSMIT_RAW)
-                               result =
-                                   port->sc_ops->sal_puts_raw(start,
-                                                              xmit_count);
-                       else
-                               result =
-                                   port->sc_ops->sal_puts(start, xmit_count);
-#ifdef DEBUG
-                       if (!result)
-                               DPRINTF("`");
-#endif
-                       if (result > 0) {
-                               xmit_count -= result;
-                               port->sc_port.icount.tx += result;
-                               tail += result;
-                               tail &= UART_XMIT_SIZE - 1;
-                               xmit->tail = tail;
-                               start = &xmit->buf[tail];
-                       }
-               }
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&port->sc_port);
-
-       if (uart_circ_empty(xmit))
-               snp_stop_tx(&port->sc_port);    /* no-op for us */
-}
-
-/**
- * sn_sal_interrupt - Handle console interrupts
- * @irq: irq #, useful for debug statements
- * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
- *
- */
-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
-{
-       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
-       unsigned long flags;
-       int status = ia64_sn_console_intr_status();
-
-       if (!port)
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-       if (status & SAL_CONSOLE_INTR_RECV) {
-               sn_receive_chars(port, flags);
-       }
-       if (status & SAL_CONSOLE_INTR_XMIT) {
-               sn_transmit_chars(port, TRANSMIT_BUFFERED);
-       }
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-/**
- * sn_sal_timer_poll - this function handles polled console mode
- * @data: A pointer to our sn_cons_port (which contains the uart port)
- *
- * data is the pointer that init_timer will store for us.  This function is
- * associated with init_timer to see if there is any console traffic.
- * Obviously not used in interrupt mode
- *
- */
-static void sn_sal_timer_poll(unsigned long data)
-{
-       struct sn_cons_port *port = (struct sn_cons_port *)data;
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       if (!port->sc_port.irq) {
-               spin_lock_irqsave(&port->sc_port.lock, flags);
-               if (sn_process_input)
-                       sn_receive_chars(port, flags);
-               sn_transmit_chars(port, TRANSMIT_RAW);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               mod_timer(&port->sc_timer,
-                         jiffies + port->sc_interrupt_timeout);
-       }
-}
-
-/*
- * Boot-time initialization code
- */
-
-/**
- * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * So this is used by sn_sal_serial_console_init (early on, before we're
- * registered with serial core).  It's also used by sn_sal_module_init
- * right after we've registered with serial core.  The later only happens
- * if we didn't already come through here via sn_sal_serial_console_init.
- *
- */
-static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       DPRINTF("sn_console: about to switch to asynchronous console\n");
-
-       /* without early_printk, we may be invoked late enough to race
-        * with other cpus doing console IO at this point, however
-        * console interrupts will never be enabled */
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-
-       /* early_printk invocation may have done this for us */
-       if (!port->sc_ops)
-               port->sc_ops = &poll_ops;
-
-       /* we can't turn on the console interrupt (as request_irq
-        * calls kmalloc, which isn't set up yet), so we rely on a
-        * timer to poll for input and push data from the console
-        * buffer.
-        */
-       init_timer(&port->sc_timer);
-       port->sc_timer.function = sn_sal_timer_poll;
-       port->sc_timer.data = (unsigned long)port;
-
-       if (IS_RUNNING_ON_SIMULATOR())
-               port->sc_interrupt_timeout = 6;
-       else {
-               /* 960cps / 16 char FIFO = 60HZ
-                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
-               port->sc_interrupt_timeout =
-                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
-       }
-       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
-
-       port->sc_is_asynch = 1;
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-}
-
-/**
- * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * In sn_sal_module_init, after we're registered with serial core and
- * the port is added, this function is called to switch us to interrupt
- * mode.  We were previously in asynch/polling mode (using init_timer).
- *
- * We attempt to switch to interrupt mode here by calling
- * request_irq.  If that works out, we enable receive interrupts.
- */
-static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (port) {
-               DPRINTF("sn_console: switching to interrupt driven console\n");
-
-               if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
-                               IRQF_DISABLED | IRQF_SHARED,
-                               "SAL console driver", port) >= 0) {
-                       spin_lock_irqsave(&port->sc_port.lock, flags);
-                       port->sc_port.irq = SGI_UART_VECTOR;
-                       port->sc_ops = &intr_ops;
-
-                       /* turn on receive interrupts */
-                       ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               }
-               else {
-                       printk(KERN_INFO
-                           "sn_console: console proceeding in polled mode\n");
-               }
-       }
-}
-
-/*
- * Kernel console definitions
- */
-
-static void sn_sal_console_write(struct console *, const char *, unsigned);
-static int sn_sal_console_setup(struct console *, char *);
-static struct uart_driver sal_console_uart;
-extern struct tty_driver *uart_console_device(struct console *, int *);
-
-static struct console sal_console = {
-       .name = DEVICE_NAME,
-       .write = sn_sal_console_write,
-       .device = uart_console_device,
-       .setup = sn_sal_console_setup,
-       .index = -1,            /* unspecified */
-       .data = &sal_console_uart,
-};
-
-#define SAL_CONSOLE    &sal_console
-
-static struct uart_driver sal_console_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "sn_console",
-       .dev_name = DEVICE_NAME,
-       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
-       .minor = 0,
-       .nr = 1,                /* one port */
-       .cons = SAL_CONSOLE,
-};
-
-/**
- * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core
- *
- * Before this is called, we've been printing kernel messages in a special
- * early mode not making use of the serial core infrastructure.  When our
- * driver is loaded for real, we register the driver and port with serial
- * core and try to enable interrupt driven mode.
- *
- */
-static int __init sn_sal_module_init(void)
-{
-       int retval;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       printk(KERN_INFO "sn_console: Console driver init\n");
-
-       if (USE_DYNAMIC_MINOR == 1) {
-               misc.minor = MISC_DYNAMIC_MINOR;
-               misc.name = DEVICE_NAME_DYNAMIC;
-               retval = misc_register(&misc);
-               if (retval != 0) {
-                       printk(KERN_WARNING "Failed to register console "
-                              "device using misc_register.\n");
-                       return -ENODEV;
-               }
-               sal_console_uart.major = MISC_MAJOR;
-               sal_console_uart.minor = misc.minor;
-       } else {
-               sal_console_uart.major = DEVICE_MAJOR;
-               sal_console_uart.minor = DEVICE_MINOR;
-       }
-
-       /* We register the driver and the port before switching to interrupts
-        * or async above so the proper uart structures are populated */
-
-       if (uart_register_driver(&sal_console_uart) < 0) {
-               printk
-                   ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
-                    __LINE__);
-               return -ENODEV;
-       }
-
-       spin_lock_init(&sal_console_port.sc_port.lock);
-
-       /* Setup the port struct with the minimum needed */
-       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
-       sal_console_port.sc_port.type = PORT_16550A;
-       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
-       sal_console_port.sc_port.ops = &sn_console_ops;
-       sal_console_port.sc_port.line = 0;
-
-       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
-               /* error - not sure what I'd do - so I'll do nothing */
-               printk(KERN_ERR "%s: unable to add port\n", __func__);
-       }
-
-       /* when this driver is compiled in, the console initialization
-        * will have already switched us into asynchronous operation
-        * before we get here through the module initcalls */
-       if (!sal_console_port.sc_is_asynch) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-       }
-
-       /* at this point (module_init) we can try to turn on interrupts */
-       if (!IS_RUNNING_ON_SIMULATOR()) {
-               sn_sal_switch_to_interrupts(&sal_console_port);
-       }
-       sn_process_input = 1;
-       return 0;
-}
-
-/**
- * sn_sal_module_exit - When we're unloaded, remove the driver/port
- *
- */
-static void __exit sn_sal_module_exit(void)
-{
-       del_timer_sync(&sal_console_port.sc_timer);
-       uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
-       uart_unregister_driver(&sal_console_uart);
-       misc_deregister(&misc);
-}
-
-module_init(sn_sal_module_init);
-module_exit(sn_sal_module_exit);
-
-/**
- * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
- * @puts_raw : puts function to do the writing
- * @s: input string
- * @count: length
- *
- * We need a \r ahead of every \n for direct writes through
- * ia64_sn_console_putb (what sal_puts_raw below actually does).
- *
- */
-
-static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
-                          const char *s, int count)
-{
-       const char *s1;
-
-       /* Output '\r' before each '\n' */
-       while ((s1 = memchr(s, '\n', count)) != NULL) {
-               puts_raw(s, s1 - s);
-               puts_raw("\r\n", 2);
-               count -= s1 + 1 - s;
-               s = s1 + 1;
-       }
-       puts_raw(s, count);
-}
-
-/**
- * sn_sal_console_write - Print statements before serial core available
- * @console: Console to operate on - we ignore since we have just one
- * @s: String to send
- * @count: length
- *
- * This is referenced in the console struct.  It is used for early
- * console printing before we register with serial core and for things
- * such as kdb.  The console_lock must be held when we get here.
- *
- * This function has some code for trying to print output even if the lock
- * is held.  We try to cover the case where a lock holder could have died.
- * We don't use this special case code if we're not registered with serial
- * core yet.  After we're registered with serial core, the only time this
- * function would be used is for high level kernel output like magic sys req,
- * kdb, and printk's.
- */
-static void
-sn_sal_console_write(struct console *co, const char *s, unsigned count)
-{
-       unsigned long flags = 0;
-       struct sn_cons_port *port = &sal_console_port;
-       static int stole_lock = 0;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       /* We can't look at the xmit buffer if we're not registered with serial core
-        *  yet.  So only do the fancy recovery after registering
-        */
-       if (!port->sc_port.state) {
-               /* Not yet registered with serial core - simple case */
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-               return;
-       }
-
-       /* somebody really wants this output, might be an
-        * oops, kdb, panic, etc.  make sure they get it. */
-       if (spin_is_locked(&port->sc_port.lock)) {
-               int lhead = port->sc_port.state->xmit.head;
-               int ltail = port->sc_port.state->xmit.tail;
-               int counter, got_lock = 0;
-
-               /*
-                * We attempt to determine if someone has died with the
-                * lock. We wait ~20 secs after the head and tail ptrs
-                * stop moving and assume the lock holder is not functional
-                * and plow ahead. If the lock is freed within the time out
-                * period we re-get the lock and go ahead normally. We also
-                * remember if we have plowed ahead so that we don't have
-                * to wait out the time out period again - the asumption
-                * is that we will time out again.
-                */
-
-               for (counter = 0; counter < 150; mdelay(125), counter++) {
-                       if (!spin_is_locked(&port->sc_port.lock)
-                           || stole_lock) {
-                               if (!stole_lock) {
-                                       spin_lock_irqsave(&port->sc_port.lock,
-                                                         flags);
-                                       got_lock = 1;
-                               }
-                               break;
-                       } else {
-                               /* still locked */
-                               if ((lhead != port->sc_port.state->xmit.head)
-                                   || (ltail !=
-                                       port->sc_port.state->xmit.tail)) {
-                                       lhead =
-                                               port->sc_port.state->xmit.head;
-                                       ltail =
-                                               port->sc_port.state->xmit.tail;
-                                       counter = 0;
-                               }
-                       }
-               }
-               /* flush anything in the serial core xmit buffer, raw */
-               sn_transmit_chars(port, 1);
-               if (got_lock) {
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                       stole_lock = 0;
-               } else {
-                       /* fell thru */
-                       stole_lock = 1;
-               }
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       } else {
-               stole_lock = 0;
-               spin_lock_irqsave(&port->sc_port.lock, flags);
-               sn_transmit_chars(port, 1);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       }
-}
-
-
-/**
- * sn_sal_console_setup - Set up console for early printing
- * @co: Console to work with
- * @options: Options to set
- *
- * Altix console doesn't do anything with baud rates, etc, anyway.
- *
- * This isn't required since not providing the setup function in the
- * console struct is ok.  However, other patches like KDB plop something
- * here so providing it is easier.
- *
- */
-static int sn_sal_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-/**
- * sn_sal_console_write_early - simple early output routine
- * @co - console struct
- * @s - string to print
- * @count - count
- *
- * Simple function to provide early output, before even
- * sn_sal_serial_console_init is called.  Referenced in the
- * console struct registerd in sn_serial_console_early_setup.
- *
- */
-static void __init
-sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
-{
-       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
-}
-
-/* Used for very early console printing - again, before
- * sn_sal_serial_console_init is run */
-static struct console sal_console_early __initdata = {
-       .name = "sn_sal",
-       .write = sn_sal_console_write_early,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-};
-
-/**
- * sn_serial_console_early_setup - Sets up early console output support
- *
- * Register a console early on...  This is for output before even
- * sn_sal_serial_cosnole_init is called.  This function is called from
- * setup.c.  This allows us to do really early polled writes. When
- * sn_sal_serial_console_init is called, this console is unregistered
- * and a new one registered.
- */
-int __init sn_serial_console_early_setup(void)
-{
-       if (!ia64_platform_is("sn2"))
-               return -1;
-
-       sal_console_port.sc_ops = &poll_ops;
-       spin_lock_init(&sal_console_port.sc_port.lock);
-       early_sn_setup();       /* Find SAL entry points */
-       register_console(&sal_console_early);
-
-       return 0;
-}
-
-/**
- * sn_sal_serial_console_init - Early console output - set up for register
- *
- * This function is called when regular console init happens.  Because we
- * support even earlier console output with sn_serial_console_early_setup
- * (called from setup.c directly), this function unregisters the really
- * early console.
- *
- * Note: Even if setup.c doesn't register sal_console_early, unregistering
- * it here doesn't hurt anything.
- *
- */
-static int __init sn_sal_serial_console_init(void)
-{
-       if (ia64_platform_is("sn2")) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-               DPRINTF("sn_sal_serial_console_init : register console\n");
-               register_console(&sal_console);
-               unregister_console(&sal_console_early);
-       }
-       return 0;
-}
-
-console_initcall(sn_sal_serial_console_init);
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
deleted file mode 100644 (file)
index 6381a02..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* suncore.c
- *
- * Common SUN serial routines.  Based entirely
- * upon drivers/sbus/char/sunserial.c which is:
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Adaptation to new UART layer is:
- *
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/serial_core.h>
-#include <linux/init.h>
-
-#include <asm/prom.h>
-
-#include "suncore.h"
-
-static int sunserial_current_minor = 64;
-
-int sunserial_register_minors(struct uart_driver *drv, int count)
-{
-       int err = 0;
-
-       drv->minor = sunserial_current_minor;
-       drv->nr += count;
-       /* Register the driver on the first call */
-       if (drv->nr == count)
-               err = uart_register_driver(drv);
-       if (err == 0) {
-               sunserial_current_minor += count;
-               drv->tty_driver->name_base = drv->minor - 64;
-       }
-       return err;
-}
-EXPORT_SYMBOL(sunserial_register_minors);
-
-void sunserial_unregister_minors(struct uart_driver *drv, int count)
-{
-       drv->nr -= count;
-       sunserial_current_minor -= count;
-
-       if (drv->nr == 0)
-               uart_unregister_driver(drv);
-}
-EXPORT_SYMBOL(sunserial_unregister_minors);
-
-int sunserial_console_match(struct console *con, struct device_node *dp,
-                           struct uart_driver *drv, int line, bool ignore_line)
-{
-       if (!con)
-               return 0;
-
-       drv->cons = con;
-
-       if (of_console_device != dp)
-               return 0;
-
-       if (!ignore_line) {
-               int off = 0;
-
-               if (of_console_options &&
-                   *of_console_options == 'b')
-                       off = 1;
-
-               if ((line & 1) != off)
-                       return 0;
-       }
-
-       if (!console_set_on_cmdline) {
-               con->index = line;
-               add_preferred_console(con->name, line, NULL);
-       }
-       return 1;
-}
-EXPORT_SYMBOL(sunserial_console_match);
-
-void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
-{
-       const char *mode, *s;
-       char mode_prop[] = "ttyX-mode";
-       int baud, bits, stop, cflag;
-       char parity;
-
-       if (!strcmp(uart_dp->name, "rsc") ||
-           !strcmp(uart_dp->name, "rsc-console") ||
-           !strcmp(uart_dp->name, "rsc-control")) {
-               mode = of_get_property(uart_dp,
-                                      "ssp-console-modes", NULL);
-               if (!mode)
-                       mode = "115200,8,n,1,-";
-       } else if (!strcmp(uart_dp->name, "lom-console")) {
-               mode = "9600,8,n,1,-";
-       } else {
-               struct device_node *dp;
-               char c;
-
-               c = 'a';
-               if (of_console_options)
-                       c = *of_console_options;
-
-               mode_prop[3] = c;
-
-               dp = of_find_node_by_path("/options");
-               mode = of_get_property(dp, mode_prop, NULL);
-               if (!mode)
-                       mode = "9600,8,n,1,-";
-       }
-
-       cflag = CREAD | HUPCL | CLOCAL;
-
-       s = mode;
-       baud = simple_strtoul(s, NULL, 0);
-       s = strchr(s, ',');
-       bits = simple_strtoul(++s, NULL, 0);
-       s = strchr(s, ',');
-       parity = *(++s);
-       s = strchr(s, ',');
-       stop = simple_strtoul(++s, NULL, 0);
-       s = strchr(s, ',');
-       /* XXX handshake is not handled here. */
-
-       switch (baud) {
-               case 150: cflag |= B150; break;
-               case 300: cflag |= B300; break;
-               case 600: cflag |= B600; break;
-               case 1200: cflag |= B1200; break;
-               case 2400: cflag |= B2400; break;
-               case 4800: cflag |= B4800; break;
-               case 9600: cflag |= B9600; break;
-               case 19200: cflag |= B19200; break;
-               case 38400: cflag |= B38400; break;
-               case 57600: cflag |= B57600; break;
-               case 115200: cflag |= B115200; break;
-               case 230400: cflag |= B230400; break;
-               case 460800: cflag |= B460800; break;
-               default: baud = 9600; cflag |= B9600; break;
-       }
-
-       switch (bits) {
-               case 5: cflag |= CS5; break;
-               case 6: cflag |= CS6; break;
-               case 7: cflag |= CS7; break;
-               case 8: cflag |= CS8; break;
-               default: cflag |= CS8; break;
-       }
-
-       switch (parity) {
-               case 'o': cflag |= (PARENB | PARODD); break;
-               case 'e': cflag |= PARENB; break;
-               case 'n': default: break;
-       }
-
-       switch (stop) {
-               case 2: cflag |= CSTOPB; break;
-               case 1: default: break;
-       }
-
-       con->cflag = cflag;
-}
-
-/* Sun serial MOUSE auto baud rate detection.  */
-static struct mouse_baud_cflag {
-       int baud;
-       unsigned int cflag;
-} mouse_baud_table[] = {
-       { 1200, B1200 },
-       { 2400, B2400 },
-       { 4800, B4800 },
-       { 9600, B9600 },
-       { -1, ~0 },
-       { -1, ~0 },
-};
-
-unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud)
-{
-       int i;
-
-       for (i = 0; mouse_baud_table[i].baud != -1; i++)
-               if (mouse_baud_table[i].cflag == (cflag & CBAUD))
-                       break;
-
-       i += 1;
-       if (mouse_baud_table[i].baud == -1)
-               i = 0;
-
-       *new_baud = mouse_baud_table[i].baud;
-       return mouse_baud_table[i].cflag;
-}
-
-EXPORT_SYMBOL(suncore_mouse_baud_cflag_next);
-
-/* Basically, when the baud rate is wrong the mouse spits out
- * breaks to us.
- */
-int suncore_mouse_baud_detection(unsigned char ch, int is_break)
-{
-       static int mouse_got_break = 0;
-       static int ctr = 0;
-
-       if (is_break) {
-               /* Let a few normal bytes go by before we jump the gun
-                * and say we need to try another baud rate.
-                */
-               if (mouse_got_break && ctr < 8)
-                       return 1;
-
-               /* Ok, we need to try another baud. */
-               ctr = 0;
-               mouse_got_break = 1;
-               return 2;
-       }
-       if (mouse_got_break) {
-               ctr++;
-               if (ch == 0x87) {
-                       /* Correct baud rate determined. */
-                       mouse_got_break = 0;
-               }
-               return 1;
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL(suncore_mouse_baud_detection);
-
-static int __init suncore_init(void)
-{
-       return 0;
-}
-
-static void __exit suncore_exit(void)
-{
-}
-
-module_init(suncore_init);
-module_exit(suncore_exit);
-
-MODULE_AUTHOR("Eddie C. Dost, David S. Miller");
-MODULE_DESCRIPTION("Sun serial common layer");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
deleted file mode 100644 (file)
index db20579..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* suncore.h
- *
- * Generic SUN serial/kbd/ms layer.  Based entirely
- * upon drivers/sbus/char/sunserial.h which is:
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Port to new UART layer is:
- *
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- */
-
-#ifndef _SERIAL_SUN_H
-#define _SERIAL_SUN_H
-
-/* Serial keyboard defines for L1-A processing... */
-#define SUNKBD_RESET           0xff
-#define SUNKBD_L1              0x01
-#define SUNKBD_UP              0x80
-#define SUNKBD_A               0x4d
-
-extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
-extern int suncore_mouse_baud_detection(unsigned char, int);
-
-extern int sunserial_register_minors(struct uart_driver *, int);
-extern void sunserial_unregister_minors(struct uart_driver *, int);
-
-extern int sunserial_console_match(struct console *, struct device_node *,
-                                  struct uart_driver *, int, bool);
-extern void sunserial_console_termios(struct console *,
-                                     struct device_node *);
-
-#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
deleted file mode 100644 (file)
index c901486..0000000
+++ /dev/null
@@ -1,661 +0,0 @@
-/* sunhv.c: Serial driver for SUN4V hypervisor console.
- *
- * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/hypervisor.h>
-#include <asm/spitfire.h>
-#include <asm/prom.h>
-#include <asm/irq.h>
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-
-#define CON_BREAK      ((long)-1)
-#define CON_HUP                ((long)-2)
-
-#define IGNORE_BREAK   0x1
-#define IGNORE_ALL     0x2
-
-static char *con_write_page;
-static char *con_read_page;
-
-static int hung_up = 0;
-
-static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
-{
-       while (!uart_circ_empty(xmit)) {
-               long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
-
-               if (status != HV_EOK)
-                       break;
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-}
-
-static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
-{
-       while (!uart_circ_empty(xmit)) {
-               unsigned long ra = __pa(xmit->buf + xmit->tail);
-               unsigned long len, status, sent;
-
-               len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
-                                     UART_XMIT_SIZE);
-               status = sun4v_con_write(ra, len, &sent);
-               if (status != HV_EOK)
-                       break;
-               xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
-               port->icount.tx += sent;
-       }
-}
-
-static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
-{
-       int saw_console_brk = 0;
-       int limit = 10000;
-
-       while (limit-- > 0) {
-               long status;
-               long c = sun4v_con_getchar(&status);
-
-               if (status == HV_EWOULDBLOCK)
-                       break;
-
-               if (c == CON_BREAK) {
-                       if (uart_handle_break(port))
-                               continue;
-                       saw_console_brk = 1;
-                       c = 0;
-               }
-
-               if (c == CON_HUP) {
-                       hung_up = 1;
-                       uart_handle_dcd_change(port, 0);
-               } else if (hung_up) {
-                       hung_up = 0;
-                       uart_handle_dcd_change(port, 1);
-               }
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(port, c);
-                       continue;
-               }
-
-               port->icount.rx++;
-
-               if (uart_handle_sysrq_char(port, c))
-                       continue;
-
-               tty_insert_flip_char(tty, c, TTY_NORMAL);
-       }
-
-       return saw_console_brk;
-}
-
-static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
-{
-       int saw_console_brk = 0;
-       int limit = 10000;
-
-       while (limit-- > 0) {
-               unsigned long ra = __pa(con_read_page);
-               unsigned long bytes_read, i;
-               long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
-
-               if (stat != HV_EOK) {
-                       bytes_read = 0;
-
-                       if (stat == CON_BREAK) {
-                               if (uart_handle_break(port))
-                                       continue;
-                               saw_console_brk = 1;
-                               *con_read_page = 0;
-                               bytes_read = 1;
-                       } else if (stat == CON_HUP) {
-                               hung_up = 1;
-                               uart_handle_dcd_change(port, 0);
-                               continue;
-                       } else {
-                               /* HV_EWOULDBLOCK, etc.  */
-                               break;
-                       }
-               }
-
-               if (hung_up) {
-                       hung_up = 0;
-                       uart_handle_dcd_change(port, 1);
-               }
-
-               for (i = 0; i < bytes_read; i++)
-                       uart_handle_sysrq_char(port, con_read_page[i]);
-
-               if (tty == NULL)
-                       continue;
-
-               port->icount.rx += bytes_read;
-
-               tty_insert_flip_string(tty, con_read_page, bytes_read);
-       }
-
-       return saw_console_brk;
-}
-
-struct sunhv_ops {
-       void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
-       int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
-};
-
-static struct sunhv_ops bychar_ops = {
-       .transmit_chars = transmit_chars_putchar,
-       .receive_chars = receive_chars_getchar,
-};
-
-static struct sunhv_ops bywrite_ops = {
-       .transmit_chars = transmit_chars_write,
-       .receive_chars = receive_chars_read,
-};
-
-static struct sunhv_ops *sunhv_ops = &bychar_ops;
-
-static struct tty_struct *receive_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = NULL;
-
-       if (port->state != NULL)                /* Unopened serial console */
-               tty = port->state->port.tty;
-
-       if (sunhv_ops->receive_chars(port, tty))
-               sun_do_break();
-
-       return tty;
-}
-
-static void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-
-       if (!port->state)
-               return;
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       sunhv_ops->transmit_chars(port, xmit);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       struct tty_struct *tty;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty = receive_chars(port);
-       transmit_chars(port);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sunhv_tx_empty(struct uart_port *port)
-{
-       /* Transmitter is always empty for us.  If the circ buffer
-        * is non-empty or there is an x_char pending, our caller
-        * will do the right thing and ignore what we return here.
-        */
-       return TIOCSER_TEMT;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       return;
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sunhv_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* port->lock held by caller.  */
-static void sunhv_start_tx(struct uart_port *port)
-{
-       transmit_chars(port);
-}
-
-/* port->lock is not held.  */
-static void sunhv_send_xchar(struct uart_port *port, char ch)
-{
-       unsigned long flags;
-       int limit = 10000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (limit-- > 0) {
-               long status = sun4v_con_putchar(ch);
-               if (status == HV_EOK)
-                       break;
-               udelay(1);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* port->lock held by caller.  */
-static void sunhv_stop_rx(struct uart_port *port)
-{
-}
-
-/* port->lock held by caller.  */
-static void sunhv_enable_ms(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sunhv_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state) {
-               unsigned long flags;
-               int limit = 10000;
-
-               spin_lock_irqsave(&port->lock, flags);
-
-               while (limit-- > 0) {
-                       long status = sun4v_con_putchar(CON_BREAK);
-                       if (status == HV_EOK)
-                               break;
-                       udelay(1);
-               }
-
-               spin_unlock_irqrestore(&port->lock, flags);
-       }
-}
-
-/* port->lock is not held.  */
-static int sunhv_startup(struct uart_port *port)
-{
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sunhv_shutdown(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-       unsigned int iflag, cflag;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       iflag = termios->c_iflag;
-       cflag = termios->c_cflag;
-
-       port->ignore_status_mask = 0;
-       if (iflag & IGNBRK)
-               port->ignore_status_mask |= IGNORE_BREAK;
-       if ((cflag & CREAD) == 0)
-               port->ignore_status_mask |= IGNORE_ALL;
-
-       /* XXX */
-       uart_update_timeout(port, cflag,
-                           (port->uartclk / (16 * quot)));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *sunhv_type(struct uart_port *port)
-{
-       return "SUN4V HCONS";
-}
-
-static void sunhv_release_port(struct uart_port *port)
-{
-}
-
-static int sunhv_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunhv_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sunhv_pops = {
-       .tx_empty       = sunhv_tx_empty,
-       .set_mctrl      = sunhv_set_mctrl,
-       .get_mctrl      = sunhv_get_mctrl,
-       .stop_tx        = sunhv_stop_tx,
-       .start_tx       = sunhv_start_tx,
-       .send_xchar     = sunhv_send_xchar,
-       .stop_rx        = sunhv_stop_rx,
-       .enable_ms      = sunhv_enable_ms,
-       .break_ctl      = sunhv_break_ctl,
-       .startup        = sunhv_startup,
-       .shutdown       = sunhv_shutdown,
-       .set_termios    = sunhv_set_termios,
-       .type           = sunhv_type,
-       .release_port   = sunhv_release_port,
-       .request_port   = sunhv_request_port,
-       .config_port    = sunhv_config_port,
-       .verify_port    = sunhv_verify_port,
-};
-
-static struct uart_driver sunhv_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunhv",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static struct uart_port *sunhv_port;
-
-/* Copy 's' into the con_write_page, decoding "\n" into
- * "\r\n" along the way.  We have to return two lengths
- * because the caller needs to know how much to advance
- * 's' and also how many bytes to output via con_write_page.
- */
-static int fill_con_write_page(const char *s, unsigned int n,
-                              unsigned long *page_bytes)
-{
-       const char *orig_s = s;
-       char *p = con_write_page;
-       int left = PAGE_SIZE;
-
-       while (n--) {
-               if (*s == '\n') {
-                       if (left < 2)
-                               break;
-                       *p++ = '\r';
-                       left--;
-               } else if (left < 1)
-                       break;
-               *p++ = *s++;
-               left--;
-       }
-       *page_bytes = p - con_write_page;
-       return s - orig_s;
-}
-
-static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sunhv_port;
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
-
-       while (n > 0) {
-               unsigned long ra = __pa(con_write_page);
-               unsigned long page_bytes;
-               unsigned int cpy = fill_con_write_page(s, n,
-                                                      &page_bytes);
-
-               n -= cpy;
-               s += cpy;
-               while (page_bytes > 0) {
-                       unsigned long written;
-                       int limit = 1000000;
-
-                       while (limit--) {
-                               unsigned long stat;
-
-                               stat = sun4v_con_write(ra, page_bytes,
-                                                      &written);
-                               if (stat == HV_EOK)
-                                       break;
-                               udelay(1);
-                       }
-                       if (limit < 0)
-                               break;
-                       page_bytes -= written;
-                       ra += written;
-               }
-       }
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-static inline void sunhv_console_putchar(struct uart_port *port, char c)
-{
-       int limit = 1000000;
-
-       while (limit-- > 0) {
-               long status = sun4v_con_putchar(c);
-               if (status == HV_EOK)
-                       break;
-               udelay(1);
-       }
-}
-
-static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sunhv_port;
-       unsigned long flags;
-       int i, locked = 1;
-
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
-
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sunhv_console_putchar(port, '\r');
-               sunhv_console_putchar(port, *s++);
-       }
-
-       if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
-}
-
-static struct console sunhv_console = {
-       .name   =       "ttyHV",
-       .write  =       sunhv_console_write_bychar,
-       .device =       uart_console_device,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunhv_reg,
-};
-
-static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       struct uart_port *port;
-       unsigned long minor;
-       int err;
-
-       if (op->archdata.irqs[0] == 0xffffffff)
-               return -ENODEV;
-
-       port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
-       if (unlikely(!port))
-               return -ENOMEM;
-
-       minor = 1;
-       if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
-           minor >= 1) {
-               err = -ENOMEM;
-               con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-               if (!con_write_page)
-                       goto out_free_port;
-
-               con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-               if (!con_read_page)
-                       goto out_free_con_write_page;
-
-               sunhv_console.write = sunhv_console_write_paged;
-               sunhv_ops = &bywrite_ops;
-       }
-
-       sunhv_port = port;
-
-       port->line = 0;
-       port->ops = &sunhv_pops;
-       port->type = PORT_SUNHV;
-       port->uartclk = ( 29491200 / 16 ); /* arbitrary */
-
-       port->membase = (unsigned char __iomem *) __pa(port);
-
-       port->irq = op->archdata.irqs[0];
-
-       port->dev = &op->dev;
-
-       err = sunserial_register_minors(&sunhv_reg, 1);
-       if (err)
-               goto out_free_con_read_page;
-
-       sunserial_console_match(&sunhv_console, op->dev.of_node,
-                               &sunhv_reg, port->line, false);
-
-       err = uart_add_one_port(&sunhv_reg, port);
-       if (err)
-               goto out_unregister_driver;
-
-       err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
-       if (err)
-               goto out_remove_port;
-
-       dev_set_drvdata(&op->dev, port);
-
-       return 0;
-
-out_remove_port:
-       uart_remove_one_port(&sunhv_reg, port);
-
-out_unregister_driver:
-       sunserial_unregister_minors(&sunhv_reg, 1);
-
-out_free_con_read_page:
-       kfree(con_read_page);
-
-out_free_con_write_page:
-       kfree(con_write_page);
-
-out_free_port:
-       kfree(port);
-       sunhv_port = NULL;
-       return err;
-}
-
-static int __devexit hv_remove(struct platform_device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(&dev->dev);
-
-       free_irq(port->irq, port);
-
-       uart_remove_one_port(&sunhv_reg, port);
-
-       sunserial_unregister_minors(&sunhv_reg, 1);
-
-       kfree(port);
-       sunhv_port = NULL;
-
-       dev_set_drvdata(&dev->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id hv_match[] = {
-       {
-               .name = "console",
-               .compatible = "qcn",
-       },
-       {
-               .name = "console",
-               .compatible = "SUNW,sun4v-console",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, hv_match);
-
-static struct of_platform_driver hv_driver = {
-       .driver = {
-               .name = "hv",
-               .owner = THIS_MODULE,
-               .of_match_table = hv_match,
-       },
-       .probe          = hv_probe,
-       .remove         = __devexit_p(hv_remove),
-};
-
-static int __init sunhv_init(void)
-{
-       if (tlb_type != hypervisor)
-               return -ENODEV;
-
-       return of_register_platform_driver(&hv_driver);
-}
-
-static void __exit sunhv_exit(void)
-{
-       of_unregister_platform_driver(&hv_driver);
-}
-
-module_init(sunhv_init);
-module_exit(sunhv_exit);
-
-MODULE_AUTHOR("David S. Miller");
-MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
deleted file mode 100644 (file)
index 5b246b1..0000000
+++ /dev/null
@@ -1,1152 +0,0 @@
-/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 2002, 2006  David S. Miller (davem@davemloft.net)
- *
- * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
- *   Maxim Krasnyanskiy <maxk@qualcomm.com>
- *
- * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
- * rates to be programmed into the UART.  Also eliminated a lot of
- * duplicated code in the console setup.
- *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- *
- * Ported to new 2.5.x UART layer.
- *   David S. Miller <davem@davemloft.net>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-#include "sunsab.h"
-
-struct uart_sunsab_port {
-       struct uart_port                port;           /* Generic UART port    */
-       union sab82532_async_regs       __iomem *regs;  /* Chip registers       */
-       unsigned long                   irqflags;       /* IRQ state flags      */
-       int                             dsr;            /* Current DSR state    */
-       unsigned int                    cec_timeout;    /* Chip poll timeout... */
-       unsigned int                    tec_timeout;    /* likewise             */
-       unsigned char                   interrupt_mask0;/* ISR0 masking         */
-       unsigned char                   interrupt_mask1;/* ISR1 masking         */
-       unsigned char                   pvr_dtr_bit;    /* Which PVR bit is DTR */
-       unsigned char                   pvr_dsr_bit;    /* Which PVR bit is DSR */
-       unsigned int                    gis_shift;
-       int                             type;           /* SAB82532 version     */
-
-       /* Setting configuration bits while the transmitter is active
-        * can cause garbage characters to get emitted by the chip.
-        * Therefore, we cache such writes here and do the real register
-        * write the next time the transmitter becomes idle.
-        */
-       unsigned int                    cached_ebrg;
-       unsigned char                   cached_mode;
-       unsigned char                   cached_pvr;
-       unsigned char                   cached_dafo;
-};
-
-/*
- * This assumes you have a 29.4912 MHz clock for your UART.
- */
-#define SAB_BASE_BAUD ( 29491200 / 16 )
-
-static char *sab82532_version[16] = {
-       "V1.0", "V2.0", "V3.2", "V(0x03)",
-       "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)",
-       "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
-       "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
-};
-
-#define SAB82532_MAX_TEC_TIMEOUT 200000        /* 1 character time (at 50 baud) */
-#define SAB82532_MAX_CEC_TIMEOUT  50000        /* 2.5 TX CLKs (at 50 baud) */
-
-#define SAB82532_RECV_FIFO_SIZE        32      /* Standard async fifo sizes */
-#define SAB82532_XMIT_FIFO_SIZE        32
-
-static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up)
-{
-       int timeout = up->tec_timeout;
-
-       while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout)
-               udelay(1);
-}
-
-static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
-{
-       int timeout = up->cec_timeout;
-
-       while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout)
-               udelay(1);
-}
-
-static struct tty_struct *
-receive_chars(struct uart_sunsab_port *up,
-             union sab82532_irq_status *stat)
-{
-       struct tty_struct *tty = NULL;
-       unsigned char buf[32];
-       int saw_console_brk = 0;
-       int free_fifo = 0;
-       int count = 0;
-       int i;
-
-       if (up->port.state != NULL)             /* Unopened serial console */
-               tty = up->port.state->port.tty;
-
-       /* Read number of BYTES (Character + Status) available. */
-       if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
-               count = SAB82532_RECV_FIFO_SIZE;
-               free_fifo++;
-       }
-
-       if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
-               count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1);
-               free_fifo++;
-       }
-
-       /* Issue a FIFO read command in case we where idle. */
-       if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
-               sunsab_cec_wait(up);
-               writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
-               return tty;
-       }
-
-       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-               free_fifo++;
-
-       /* Read the FIFO. */
-       for (i = 0; i < count; i++)
-               buf[i] = readb(&up->regs->r.rfifo[i]);
-
-       /* Issue Receive Message Complete command. */
-       if (free_fifo) {
-               sunsab_cec_wait(up);
-               writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr);
-       }
-
-       /* Count may be zero for BRK, so we check for it here */
-       if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) &&
-           (up->port.line == up->port.cons->index))
-               saw_console_brk = 1;
-
-       for (i = 0; i < count; i++) {
-               unsigned char ch = buf[i], flag;
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(&up->port, ch);
-                       continue;
-               }
-
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR |
-                                               SAB82532_ISR0_FERR |
-                                               SAB82532_ISR0_RFO)) ||
-                   unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
-                       /*
-                        * For statistics only
-                        */
-                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
-                               stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
-                                                    SAB82532_ISR0_FERR);
-                               up->port.icount.brk++;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       continue;
-                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
-                               up->port.icount.parity++;
-                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
-                               up->port.icount.frame++;
-                       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       stat->sreg.isr0 &= (up->port.read_status_mask & 0xff);
-                       stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff);
-
-                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
-                               flag = TTY_BREAK;
-                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
-                               flag = TTY_PARITY;
-                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
-                   (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-               if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       if (saw_console_brk)
-               sun_do_break();
-
-       return tty;
-}
-
-static void sunsab_stop_tx(struct uart_port *);
-static void sunsab_tx_idle(struct uart_sunsab_port *);
-
-static void transmit_chars(struct uart_sunsab_port *up,
-                          union sab82532_irq_status *stat)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int i;
-
-       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
-               up->interrupt_mask1 |= SAB82532_IMR1_ALLS;
-               writeb(up->interrupt_mask1, &up->regs->w.imr1);
-               set_bit(SAB82532_ALLS, &up->irqflags);
-       }
-
-#if 0 /* bde@nwlink.com says this check causes problems */
-       if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
-               return;
-#endif
-
-       if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW))
-               return;
-
-       set_bit(SAB82532_XPR, &up->irqflags);
-       sunsab_tx_idle(up);
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-               up->interrupt_mask1 |= SAB82532_IMR1_XPR;
-               writeb(up->interrupt_mask1, &up->regs->w.imr1);
-               return;
-       }
-
-       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       clear_bit(SAB82532_ALLS, &up->irqflags);
-
-       /* Stuff 32 bytes into Transmit FIFO. */
-       clear_bit(SAB82532_XPR, &up->irqflags);
-       for (i = 0; i < up->port.fifosize; i++) {
-               writeb(xmit->buf[xmit->tail],
-                      &up->regs->w.xfifo[i]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Issue a Transmit Frame command. */
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               sunsab_stop_tx(&up->port);
-}
-
-static void check_status(struct uart_sunsab_port *up,
-                        union sab82532_irq_status *stat)
-{
-       if (stat->sreg.isr0 & SAB82532_ISR0_CDSC)
-               uart_handle_dcd_change(&up->port,
-                                      !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD));
-
-       if (stat->sreg.isr1 & SAB82532_ISR1_CSC)
-               uart_handle_cts_change(&up->port,
-                                      (readb(&up->regs->r.star) & SAB82532_STAR_CTS));
-
-       if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) {
-               up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1;
-               up->port.icount.dsr++;
-       }
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsab_port *up = dev_id;
-       struct tty_struct *tty;
-       union sab82532_irq_status status;
-       unsigned long flags;
-       unsigned char gis;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       status.stat = 0;
-       gis = readb(&up->regs->r.gis) >> up->gis_shift;
-       if (gis & 1)
-               status.sreg.isr0 = readb(&up->regs->r.isr0);
-       if (gis & 2)
-               status.sreg.isr1 = readb(&up->regs->r.isr1);
-
-       tty = NULL;
-       if (status.stat) {
-               if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
-                                        SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
-                   (status.sreg.isr1 & SAB82532_ISR1_BRK))
-                       tty = receive_chars(up, &status);
-               if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
-                   (status.sreg.isr1 & SAB82532_ISR1_CSC))
-                       check_status(up, &status);
-               if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
-                       transmit_chars(up, &status);
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       if (tty)
-               tty_flip_buffer_push(tty);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sunsab_tx_empty(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       int ret;
-
-       /* Do not need a lock for a state test like this.  */
-       if (test_bit(SAB82532_ALLS, &up->irqflags))
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* port->lock held by caller.  */
-static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       if (mctrl & TIOCM_RTS) {
-               up->cached_mode &= ~SAB82532_MODE_FRTS;
-               up->cached_mode |= SAB82532_MODE_RTS;
-       } else {
-               up->cached_mode |= (SAB82532_MODE_FRTS |
-                                   SAB82532_MODE_RTS);
-       }
-       if (mctrl & TIOCM_DTR) {
-               up->cached_pvr &= ~(up->pvr_dtr_bit);
-       } else {
-               up->cached_pvr |= up->pvr_dtr_bit;
-       }
-
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sunsab_get_mctrl(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned char val;
-       unsigned int result;
-
-       result = 0;
-
-       val = readb(&up->regs->r.pvr);
-       result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
-
-       val = readb(&up->regs->r.vstr);
-       result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR;
-
-       val = readb(&up->regs->r.star);
-       result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
-
-       return result;
-}
-
-/* port->lock held by caller.  */
-static void sunsab_stop_tx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       up->interrupt_mask1 |= SAB82532_IMR1_XPR;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_tx_idle(struct uart_sunsab_port *up)
-{
-       if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
-               u8 tmp;
-
-               clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
-               writeb(up->cached_mode, &up->regs->rw.mode);
-               writeb(up->cached_pvr, &up->regs->rw.pvr);
-               writeb(up->cached_dafo, &up->regs->w.dafo);
-
-               writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
-               tmp = readb(&up->regs->rw.ccr2);
-               tmp &= ~0xc0;
-               tmp |= (up->cached_ebrg >> 2) & 0xc0;
-               writeb(tmp, &up->regs->rw.ccr2);
-       }
-}
-
-/* port->lock held by caller.  */
-static void sunsab_start_tx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int i;
-
-       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       
-       if (!test_bit(SAB82532_XPR, &up->irqflags))
-               return;
-
-       clear_bit(SAB82532_ALLS, &up->irqflags);
-       clear_bit(SAB82532_XPR, &up->irqflags);
-
-       for (i = 0; i < up->port.fifosize; i++) {
-               writeb(xmit->buf[xmit->tail],
-                      &up->regs->w.xfifo[i]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       }
-
-       /* Issue a Transmit Frame command.  */
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
-}
-
-/* port->lock is not held.  */
-static void sunsab_send_xchar(struct uart_port *port, char ch)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       sunsab_tec_wait(up);
-       writeb(ch, &up->regs->w.tic);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_stop_rx(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-
-       up->interrupt_mask0 |= SAB82532_IMR0_TCD;
-       writeb(up->interrupt_mask1, &up->regs->w.imr0);
-}
-
-/* port->lock held by caller.  */
-static void sunsab_enable_ms(struct uart_port *port)
-{
-       /* For now we always receive these interrupts.  */
-}
-
-/* port->lock is not held.  */
-static void sunsab_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned char val;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       val = up->cached_dafo;
-       if (break_state)
-               val |= SAB82532_DAFO_XBRK;
-       else
-               val &= ~SAB82532_DAFO_XBRK;
-       up->cached_dafo = val;
-
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/* port->lock is not held.  */
-static int sunsab_startup(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned char tmp;
-       int err = request_irq(up->port.irq, sunsab_interrupt,
-                             IRQF_SHARED, "sab", up);
-       if (err)
-               return err;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Wait for any commands or immediate characters
-        */
-       sunsab_cec_wait(up);
-       sunsab_tec_wait(up);
-
-       /*
-        * Clear the FIFO buffers.
-        */
-       writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr);
-       sunsab_cec_wait(up);
-       writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr);
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) readb(&up->regs->r.isr0);
-       (void) readb(&up->regs->r.isr1);
-
-       /*
-        * Now, initialize the UART 
-        */
-       writeb(0, &up->regs->w.ccr0);                           /* power-down */
-       writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |
-              SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0);
-       writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1);
-       writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL |
-              SAB82532_CCR2_TOE, &up->regs->w.ccr2);
-       writeb(0, &up->regs->w.ccr3);
-       writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
-       up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
-                          SAB82532_MODE_RAC);
-       writeb(up->cached_mode, &up->regs->w.mode);
-       writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
-       
-       tmp = readb(&up->regs->rw.ccr0);
-       tmp |= SAB82532_CCR0_PU;        /* power-up */
-       writeb(tmp, &up->regs->rw.ccr0);
-
-       /*
-        * Finally, enable interrupts
-        */
-       up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
-                              SAB82532_IMR0_PLLA);
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
-                              SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
-                              SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
-                              SAB82532_IMR1_XPR);
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-       set_bit(SAB82532_ALLS, &up->irqflags);
-       set_bit(SAB82532_XPR, &up->irqflags);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sunsab_shutdown(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /* Disable Interrupts */
-       up->interrupt_mask0 = 0xff;
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = 0xff;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-
-       /* Disable break condition */
-       up->cached_dafo = readb(&up->regs->rw.dafo);
-       up->cached_dafo &= ~SAB82532_DAFO_XBRK;
-       writeb(up->cached_dafo, &up->regs->rw.dafo);
-
-       /* Disable Receiver */  
-       up->cached_mode &= ~SAB82532_MODE_RAC;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-
-       /*
-        * XXX FIXME
-        *
-        * If the chip is powered down here the system hangs/crashes during
-        * reboot or shutdown.  This needs to be investigated further,
-        * similar behaviour occurs in 2.4 when the driver is configured
-        * as a module only.  One hint may be that data is sometimes
-        * transmitted at 9600 baud during shutdown (regardless of the
-        * speed the chip was configured for when the port was open).
-        */
-#if 0
-       /* Power Down */        
-       tmp = readb(&up->regs->rw.ccr0);
-       tmp &= ~SAB82532_CCR0_PU;
-       writeb(tmp, &up->regs->rw.ccr0);
-#endif
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       free_irq(up->port.irq, up);
-}
-
-/*
- * This is used to figure out the divisor speeds.
- *
- * The formula is:    Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)),
- *
- * with               0 <= N < 64 and 0 <= M < 16
- */
-
-static void calc_ebrg(int baud, int *n_ret, int *m_ret)
-{
-       int     n, m;
-
-       if (baud == 0) {
-               *n_ret = 0;
-               *m_ret = 0;
-               return;
-       }
-     
-       /*
-        * We scale numbers by 10 so that we get better accuracy
-        * without having to use floating point.  Here we increment m
-        * until n is within the valid range.
-        */
-       n = (SAB_BASE_BAUD * 10) / baud;
-       m = 0;
-       while (n >= 640) {
-               n = n / 2;
-               m++;
-       }
-       n = (n+5) / 10;
-       /*
-        * We try very hard to avoid speeds with M == 0 since they may
-        * not work correctly for XTAL frequences above 10 MHz.
-        */
-       if ((m == 0) && ((n & 1) == 0)) {
-               n = n / 2;
-               m++;
-       }
-       *n_ret = n - 1;
-       *m_ret = m;
-}
-
-/* Internal routine, port->lock is held and local interrupts are disabled.  */
-static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag,
-                                 unsigned int iflag, unsigned int baud,
-                                 unsigned int quot)
-{
-       unsigned char dafo;
-       int bits, n, m;
-
-       /* Byte size and parity */
-       switch (cflag & CSIZE) {
-             case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-             case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
-             case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
-             case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
-             /* Never happens, but GCC is too dumb to figure it out */
-             default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;
-       }
-
-       if (cflag & CSTOPB) {
-               dafo |= SAB82532_DAFO_STOP;
-               bits++;
-       }
-
-       if (cflag & PARENB) {
-               dafo |= SAB82532_DAFO_PARE;
-               bits++;
-       }
-
-       if (cflag & PARODD) {
-               dafo |= SAB82532_DAFO_PAR_ODD;
-       } else {
-               dafo |= SAB82532_DAFO_PAR_EVEN;
-       }
-       up->cached_dafo = dafo;
-
-       calc_ebrg(baud, &n, &m);
-
-       up->cached_ebrg = n | (m << 6);
-
-       up->tec_timeout = (10 * 1000000) / baud;
-       up->cec_timeout = up->tec_timeout >> 2;
-
-       /* CTS flow control flags */
-       /* We encode read_status_mask and ignore_status_mask like so:
-        *
-        * ---------------------
-        * | ... | ISR1 | ISR0 |
-        * ---------------------
-        *  ..    15   8 7    0
-        */
-
-       up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
-                                    SAB82532_ISR0_RFO | SAB82532_ISR0_RPF |
-                                    SAB82532_ISR0_CDSC);
-       up->port.read_status_mask |= (SAB82532_ISR1_CSC |
-                                     SAB82532_ISR1_ALLS |
-                                     SAB82532_ISR1_XPR) << 8;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= (SAB82532_ISR0_PERR |
-                                             SAB82532_ISR0_FERR);
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= (SAB82532_ISR0_PERR |
-                                               SAB82532_ISR0_FERR);
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8);
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= SAB82532_ISR0_RFO;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= (SAB82532_ISR0_RPF |
-                                               SAB82532_ISR0_TCD);
-
-       uart_update_timeout(&up->port, cflag,
-                           (up->port.uartclk / (16 * quot)));
-
-       /* Now schedule a register update when the chip's
-        * transmitter is idle.
-        */
-       up->cached_mode |= SAB82532_MODE_RAC;
-       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
-       if (test_bit(SAB82532_XPR, &up->irqflags))
-               sunsab_tx_idle(up);
-}
-
-/* port->lock is not held.  */
-static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
-                              struct ktermios *old)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
-       unsigned long flags;
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *sunsab_type(struct uart_port *port)
-{
-       struct uart_sunsab_port *up = (void *)port;
-       static char buf[36];
-       
-       sprintf(buf, "SAB82532 %s", sab82532_version[up->type]);
-       return buf;
-}
-
-static void sunsab_release_port(struct uart_port *port)
-{
-}
-
-static int sunsab_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunsab_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sunsab_pops = {
-       .tx_empty       = sunsab_tx_empty,
-       .set_mctrl      = sunsab_set_mctrl,
-       .get_mctrl      = sunsab_get_mctrl,
-       .stop_tx        = sunsab_stop_tx,
-       .start_tx       = sunsab_start_tx,
-       .send_xchar     = sunsab_send_xchar,
-       .stop_rx        = sunsab_stop_rx,
-       .enable_ms      = sunsab_enable_ms,
-       .break_ctl      = sunsab_break_ctl,
-       .startup        = sunsab_startup,
-       .shutdown       = sunsab_shutdown,
-       .set_termios    = sunsab_set_termios,
-       .type           = sunsab_type,
-       .release_port   = sunsab_release_port,
-       .request_port   = sunsab_request_port,
-       .config_port    = sunsab_config_port,
-       .verify_port    = sunsab_verify_port,
-};
-
-static struct uart_driver sunsab_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunsab",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static struct uart_sunsab_port *sunsab_ports;
-
-#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
-
-static void sunsab_console_putchar(struct uart_port *port, int c)
-{
-       struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
-
-       sunsab_tec_wait(up);
-       writeb(c, &up->regs->w.tic);
-}
-
-static void sunsab_console_write(struct console *con, const char *s, unsigned n)
-{
-       struct uart_sunsab_port *up = &sunsab_ports[con->index];
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       uart_console_write(&up->port, s, n, sunsab_console_putchar);
-       sunsab_tec_wait(up);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int sunsab_console_setup(struct console *con, char *options)
-{
-       struct uart_sunsab_port *up = &sunsab_ports[con->index];
-       unsigned long flags;
-       unsigned int baud, quot;
-
-       /*
-        * The console framework calls us for each and every port
-        * registered. Defer the console setup until the requested
-        * port has been properly discovered. A bit of a hack,
-        * though...
-        */
-       if (up->port.type != PORT_SUNSAB)
-               return -1;
-
-       printk("Console: ttyS%d (SAB82532)\n",
-              (sunsab_reg.minor - 64) + con->index);
-
-       sunserial_console_termios(con, up->port.dev->of_node);
-
-       switch (con->cflag & CBAUD) {
-       case B150: baud = 150; break;
-       case B300: baud = 300; break;
-       case B600: baud = 600; break;
-       case B1200: baud = 1200; break;
-       case B2400: baud = 2400; break;
-       case B4800: baud = 4800; break;
-       default: case B9600: baud = 9600; break;
-       case B19200: baud = 19200; break;
-       case B38400: baud = 38400; break;
-       case B57600: baud = 57600; break;
-       case B115200: baud = 115200; break;
-       case B230400: baud = 230400; break;
-       case B460800: baud = 460800; break;
-       };
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&up->port.lock);
-
-       /*
-        * Initialize the hardware
-        */
-       sunsab_startup(&up->port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts
-        */
-       up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
-                               SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;
-       writeb(up->interrupt_mask0, &up->regs->w.imr0);
-       up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
-                               SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
-                               SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
-                               SAB82532_IMR1_XPR;
-       writeb(up->interrupt_mask1, &up->regs->w.imr1);
-
-       quot = uart_get_divisor(&up->port, baud);
-       sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
-       sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-       
-       return 0;
-}
-
-static struct console sunsab_console = {
-       .name   =       "ttyS",
-       .write  =       sunsab_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunsab_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunsab_reg,
-};
-
-static inline struct console *SUNSAB_CONSOLE(void)
-{
-       return &sunsab_console;
-}
-#else
-#define SUNSAB_CONSOLE()       (NULL)
-#define sunsab_console_init()  do { } while (0)
-#endif
-
-static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
-                                    struct platform_device *op,
-                                    unsigned long offset,
-                                    int line)
-{
-       up->port.line = line;
-       up->port.dev = &op->dev;
-
-       up->port.mapbase = op->resource[0].start + offset;
-       up->port.membase = of_ioremap(&op->resource[0], offset,
-                                     sizeof(union sab82532_async_regs),
-                                     "sab");
-       if (!up->port.membase)
-               return -ENOMEM;
-       up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
-
-       up->port.irq = op->archdata.irqs[0];
-
-       up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
-       up->port.iotype = UPIO_MEM;
-
-       writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
-
-       up->port.ops = &sunsab_pops;
-       up->port.type = PORT_SUNSAB;
-       up->port.uartclk = SAB_BASE_BAUD;
-
-       up->type = readb(&up->regs->r.vstr) & 0x0f;
-       writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
-       writeb(0xff, &up->regs->w.pim);
-       if ((up->port.line & 0x1) == 0) {
-               up->pvr_dsr_bit = (1 << 0);
-               up->pvr_dtr_bit = (1 << 1);
-               up->gis_shift = 2;
-       } else {
-               up->pvr_dsr_bit = (1 << 3);
-               up->pvr_dtr_bit = (1 << 2);
-               up->gis_shift = 0;
-       }
-       up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
-       writeb(up->cached_pvr, &up->regs->w.pvr);
-       up->cached_mode = readb(&up->regs->rw.mode);
-       up->cached_mode |= SAB82532_MODE_FRTS;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-       up->cached_mode |= SAB82532_MODE_RTS;
-       writeb(up->cached_mode, &up->regs->rw.mode);
-
-       up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
-       up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
-
-       return 0;
-}
-
-static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int inst;
-       struct uart_sunsab_port *up;
-       int err;
-
-       up = &sunsab_ports[inst * 2];
-
-       err = sunsab_init_one(&up[0], op,
-                             0,
-                             (inst * 2) + 0);
-       if (err)
-               goto out;
-
-       err = sunsab_init_one(&up[1], op,
-                             sizeof(union sab82532_async_regs),
-                             (inst * 2) + 1);
-       if (err)
-               goto out1;
-
-       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
-                               &sunsab_reg, up[0].port.line,
-                               false);
-
-       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
-                               &sunsab_reg, up[1].port.line,
-                               false);
-
-       err = uart_add_one_port(&sunsab_reg, &up[0].port);
-       if (err)
-               goto out2;
-
-       err = uart_add_one_port(&sunsab_reg, &up[1].port);
-       if (err)
-               goto out3;
-
-       dev_set_drvdata(&op->dev, &up[0]);
-
-       inst++;
-
-       return 0;
-
-out3:
-       uart_remove_one_port(&sunsab_reg, &up[0].port);
-out2:
-       of_iounmap(&op->resource[0],
-                  up[1].port.membase,
-                  sizeof(union sab82532_async_regs));
-out1:
-       of_iounmap(&op->resource[0],
-                  up[0].port.membase,
-                  sizeof(union sab82532_async_regs));
-out:
-       return err;
-}
-
-static int __devexit sab_remove(struct platform_device *op)
-{
-       struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
-
-       uart_remove_one_port(&sunsab_reg, &up[1].port);
-       uart_remove_one_port(&sunsab_reg, &up[0].port);
-       of_iounmap(&op->resource[0],
-                  up[1].port.membase,
-                  sizeof(union sab82532_async_regs));
-       of_iounmap(&op->resource[0],
-                  up[0].port.membase,
-                  sizeof(union sab82532_async_regs));
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id sab_match[] = {
-       {
-               .name = "se",
-       },
-       {
-               .name = "serial",
-               .compatible = "sab82532",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, sab_match);
-
-static struct of_platform_driver sab_driver = {
-       .driver = {
-               .name = "sab",
-               .owner = THIS_MODULE,
-               .of_match_table = sab_match,
-       },
-       .probe          = sab_probe,
-       .remove         = __devexit_p(sab_remove),
-};
-
-static int __init sunsab_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_channels = 0;
-
-       for_each_node_by_name(dp, "se")
-               num_channels += 2;
-       for_each_node_by_name(dp, "serial") {
-               if (of_device_is_compatible(dp, "sab82532"))
-                       num_channels += 2;
-       }
-
-       if (num_channels) {
-               sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) *
-                                      num_channels, GFP_KERNEL);
-               if (!sunsab_ports)
-                       return -ENOMEM;
-
-               err = sunserial_register_minors(&sunsab_reg, num_channels);
-               if (err) {
-                       kfree(sunsab_ports);
-                       sunsab_ports = NULL;
-
-                       return err;
-               }
-       }
-
-       return of_register_platform_driver(&sab_driver);
-}
-
-static void __exit sunsab_exit(void)
-{
-       of_unregister_platform_driver(&sab_driver);
-       if (sunsab_reg.nr) {
-               sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
-       }
-
-       kfree(sunsab_ports);
-       sunsab_ports = NULL;
-}
-
-module_init(sunsab_init);
-module_exit(sunsab_exit);
-
-MODULE_AUTHOR("Eddie C. Dost and David S. Miller");
-MODULE_DESCRIPTION("Sun SAB82532 serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h
deleted file mode 100644 (file)
index b78e1f7..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- */
-
-#ifndef _SUNSAB_H
-#define _SUNSAB_H
-
-struct sab82532_async_rd_regs {
-       u8      rfifo[0x20];    /* Receive FIFO                         */
-       u8      star;           /* Status Register                      */
-       u8      __pad1;
-       u8      mode;           /* Mode Register                        */
-       u8      timr;           /* Timer Register                       */
-       u8      xon;            /* XON Character                        */
-       u8      xoff;           /* XOFF Character                       */
-       u8      tcr;            /* Termination Character Register       */
-       u8      dafo;           /* Data Format                          */
-       u8      rfc;            /* RFIFO Control Register               */
-       u8      __pad2;
-       u8      rbcl;           /* Receive Byte Count Low               */
-       u8      rbch;           /* Receive Byte Count High              */
-       u8      ccr0;           /* Channel Configuration Register 0     */
-       u8      ccr1;           /* Channel Configuration Register 1     */
-       u8      ccr2;           /* Channel Configuration Register 2     */
-       u8      ccr3;           /* Channel Configuration Register 3     */
-       u8      __pad3[4];
-       u8      vstr;           /* Version Status Register              */
-       u8      __pad4[3];
-       u8      gis;            /* Global Interrupt Status              */
-       u8      ipc;            /* Interrupt Port Configuration         */
-       u8      isr0;           /* Interrupt Status 0                   */
-       u8      isr1;           /* Interrupt Status 1                   */
-       u8      pvr;            /* Port Value Register                  */
-       u8      pis;            /* Port Interrupt Status                */
-       u8      pcr;            /* Port Configuration Register          */
-       u8      ccr4;           /* Channel Configuration Register 4     */
-};
-
-struct sab82532_async_wr_regs {
-       u8      xfifo[0x20];    /* Transmit FIFO                        */
-       u8      cmdr;           /* Command Register                     */
-       u8      __pad1;
-       u8      mode;
-       u8      timr;
-       u8      xon;
-       u8      xoff;
-       u8      tcr;
-       u8      dafo;
-       u8      rfc;
-       u8      __pad2;
-       u8      xbcl;           /* Transmit Byte Count Low              */
-       u8      xbch;           /* Transmit Byte Count High             */
-       u8      ccr0;
-       u8      ccr1;
-       u8      ccr2;
-       u8      ccr3;
-       u8      tsax;           /* Time-Slot Assignment Reg. Transmit   */
-       u8      tsar;           /* Time-Slot Assignment Reg. Receive    */
-       u8      xccr;           /* Transmit Channel Capacity Register   */
-       u8      rccr;           /* Receive Channel Capacity Register    */
-       u8      bgr;            /* Baud Rate Generator Register         */
-       u8      tic;            /* Transmit Immediate Character         */
-       u8      mxn;            /* Mask XON Character                   */
-       u8      mxf;            /* Mask XOFF Character                  */
-       u8      iva;            /* Interrupt Vector Address             */
-       u8      ipc;
-       u8      imr0;           /* Interrupt Mask Register 0            */
-       u8      imr1;           /* Interrupt Mask Register 1            */
-       u8      pvr;
-       u8      pim;            /* Port Interrupt Mask                  */
-       u8      pcr;
-       u8      ccr4;
-};
-
-struct sab82532_async_rw_regs {        /* Read/Write registers                 */
-       u8      __pad1[0x20];
-       u8      __pad2;
-       u8      __pad3;
-       u8      mode;
-       u8      timr;
-       u8      xon;
-       u8      xoff;
-       u8      tcr;
-       u8      dafo;
-       u8      rfc;
-       u8      __pad4;
-       u8      __pad5;
-       u8      __pad6;
-       u8      ccr0;
-       u8      ccr1;
-       u8      ccr2;
-       u8      ccr3;
-       u8      __pad7;
-       u8      __pad8;
-       u8      __pad9;
-       u8      __pad10;
-       u8      __pad11;
-       u8      __pad12;
-       u8      __pad13;
-       u8      __pad14;
-       u8      __pad15;
-       u8      ipc;
-       u8      __pad16;
-       u8      __pad17;
-       u8      pvr;
-       u8      __pad18;
-       u8      pcr;
-       u8      ccr4;
-};
-
-union sab82532_async_regs {
-       __volatile__ struct sab82532_async_rd_regs      r;
-       __volatile__ struct sab82532_async_wr_regs      w;
-       __volatile__ struct sab82532_async_rw_regs      rw;
-};
-
-union sab82532_irq_status {
-       unsigned short                   stat;
-       struct {
-               unsigned char            isr0;
-               unsigned char            isr1;
-       } sreg;
-};
-
-/* irqflags bits */
-#define SAB82532_ALLS                  0x00000001
-#define SAB82532_XPR                   0x00000002
-#define SAB82532_REGS_PENDING          0x00000004
-
-/* RFIFO Status Byte */
-#define SAB82532_RSTAT_PE              0x80
-#define SAB82532_RSTAT_FE              0x40
-#define SAB82532_RSTAT_PARITY          0x01
-
-/* Status Register (STAR) */
-#define SAB82532_STAR_XDOV             0x80
-#define SAB82532_STAR_XFW              0x40
-#define SAB82532_STAR_RFNE             0x20
-#define SAB82532_STAR_FCS              0x10
-#define SAB82532_STAR_TEC              0x08
-#define SAB82532_STAR_CEC              0x04
-#define SAB82532_STAR_CTS              0x02
-
-/* Command Register (CMDR) */
-#define SAB82532_CMDR_RMC              0x80
-#define SAB82532_CMDR_RRES             0x40
-#define SAB82532_CMDR_RFRD             0x20
-#define SAB82532_CMDR_STI              0x10
-#define SAB82532_CMDR_XF               0x08
-#define SAB82532_CMDR_XRES             0x01
-
-/* Mode Register (MODE) */
-#define SAB82532_MODE_FRTS             0x40
-#define SAB82532_MODE_FCTS             0x20
-#define SAB82532_MODE_FLON             0x10
-#define SAB82532_MODE_RAC              0x08
-#define SAB82532_MODE_RTS              0x04
-#define SAB82532_MODE_TRS              0x02
-#define SAB82532_MODE_TLP              0x01
-
-/* Timer Register (TIMR) */
-#define SAB82532_TIMR_CNT_MASK         0xe0
-#define SAB82532_TIMR_VALUE_MASK       0x1f
-
-/* Data Format (DAFO) */
-#define SAB82532_DAFO_XBRK             0x40
-#define SAB82532_DAFO_STOP             0x20
-#define SAB82532_DAFO_PAR_SPACE                0x00
-#define SAB82532_DAFO_PAR_ODD          0x08
-#define SAB82532_DAFO_PAR_EVEN         0x10
-#define SAB82532_DAFO_PAR_MARK         0x18
-#define SAB82532_DAFO_PARE             0x04
-#define SAB82532_DAFO_CHL8             0x00
-#define SAB82532_DAFO_CHL7             0x01
-#define SAB82532_DAFO_CHL6             0x02
-#define SAB82532_DAFO_CHL5             0x03
-
-/* RFIFO Control Register (RFC) */
-#define SAB82532_RFC_DPS               0x40
-#define SAB82532_RFC_DXS               0x20
-#define SAB82532_RFC_RFDF              0x10
-#define SAB82532_RFC_RFTH_1            0x00
-#define SAB82532_RFC_RFTH_4            0x04
-#define SAB82532_RFC_RFTH_16           0x08
-#define SAB82532_RFC_RFTH_32           0x0c
-#define SAB82532_RFC_TCDE              0x01
-
-/* Received Byte Count High (RBCH) */
-#define SAB82532_RBCH_DMA              0x80
-#define SAB82532_RBCH_CAS              0x20
-
-/* Transmit Byte Count High (XBCH) */
-#define SAB82532_XBCH_DMA              0x80
-#define SAB82532_XBCH_CAS              0x20
-#define SAB82532_XBCH_XC               0x10
-
-/* Channel Configuration Register 0 (CCR0) */
-#define SAB82532_CCR0_PU               0x80
-#define SAB82532_CCR0_MCE              0x40
-#define SAB82532_CCR0_SC_NRZ           0x00
-#define SAB82532_CCR0_SC_NRZI          0x08
-#define SAB82532_CCR0_SC_FM0           0x10
-#define SAB82532_CCR0_SC_FM1           0x14
-#define SAB82532_CCR0_SC_MANCH         0x18
-#define SAB82532_CCR0_SM_HDLC          0x00
-#define SAB82532_CCR0_SM_SDLC_LOOP     0x01
-#define SAB82532_CCR0_SM_BISYNC                0x02
-#define SAB82532_CCR0_SM_ASYNC         0x03
-
-/* Channel Configuration Register 1 (CCR1) */
-#define SAB82532_CCR1_ODS              0x10
-#define SAB82532_CCR1_BCR              0x08
-#define SAB82532_CCR1_CM_MASK          0x07
-
-/* Channel Configuration Register 2 (CCR2) */
-#define SAB82532_CCR2_SOC1             0x80
-#define SAB82532_CCR2_SOC0             0x40
-#define SAB82532_CCR2_BR9              0x80
-#define SAB82532_CCR2_BR8              0x40
-#define SAB82532_CCR2_BDF              0x20
-#define SAB82532_CCR2_SSEL             0x10
-#define SAB82532_CCR2_XCS0             0x20
-#define SAB82532_CCR2_RCS0             0x10
-#define SAB82532_CCR2_TOE              0x08
-#define SAB82532_CCR2_RWX              0x04
-#define SAB82532_CCR2_DIV              0x01
-
-/* Channel Configuration Register 3 (CCR3) */
-#define SAB82532_CCR3_PSD              0x01
-
-/* Time Slot Assignment Register Transmit (TSAX) */
-#define SAB82532_TSAX_TSNX_MASK                0xfc
-#define SAB82532_TSAX_XCS2             0x02    /* see also CCR2 */
-#define SAB82532_TSAX_XCS1             0x01
-
-/* Time Slot Assignment Register Receive (TSAR) */
-#define SAB82532_TSAR_TSNR_MASK                0xfc
-#define SAB82532_TSAR_RCS2             0x02    /* see also CCR2 */
-#define SAB82532_TSAR_RCS1             0x01
-
-/* Version Status Register (VSTR) */
-#define SAB82532_VSTR_CD               0x80
-#define SAB82532_VSTR_DPLA             0x40
-#define SAB82532_VSTR_VN_MASK          0x0f
-#define SAB82532_VSTR_VN_1             0x00
-#define SAB82532_VSTR_VN_2             0x01
-#define SAB82532_VSTR_VN_3_2           0x02
-
-/* Global Interrupt Status Register (GIS) */
-#define SAB82532_GIS_PI                        0x80
-#define SAB82532_GIS_ISA1              0x08
-#define SAB82532_GIS_ISA0              0x04
-#define SAB82532_GIS_ISB1              0x02
-#define SAB82532_GIS_ISB0              0x01
-
-/* Interrupt Vector Address (IVA) */
-#define SAB82532_IVA_MASK              0xf1
-
-/* Interrupt Port Configuration (IPC) */
-#define SAB82532_IPC_VIS               0x80
-#define SAB82532_IPC_SLA1              0x10
-#define SAB82532_IPC_SLA0              0x08
-#define SAB82532_IPC_CASM              0x04
-#define SAB82532_IPC_IC_OPEN_DRAIN     0x00
-#define SAB82532_IPC_IC_ACT_LOW                0x01
-#define SAB82532_IPC_IC_ACT_HIGH       0x03
-
-/* Interrupt Status Register 0 (ISR0) */
-#define SAB82532_ISR0_TCD              0x80
-#define SAB82532_ISR0_TIME             0x40
-#define SAB82532_ISR0_PERR             0x20
-#define SAB82532_ISR0_FERR             0x10
-#define SAB82532_ISR0_PLLA             0x08
-#define SAB82532_ISR0_CDSC             0x04
-#define SAB82532_ISR0_RFO              0x02
-#define SAB82532_ISR0_RPF              0x01
-
-/* Interrupt Status Register 1 (ISR1) */
-#define SAB82532_ISR1_BRK              0x80
-#define SAB82532_ISR1_BRKT             0x40
-#define SAB82532_ISR1_ALLS             0x20
-#define SAB82532_ISR1_XOFF             0x10
-#define SAB82532_ISR1_TIN              0x08
-#define SAB82532_ISR1_CSC              0x04
-#define SAB82532_ISR1_XON              0x02
-#define SAB82532_ISR1_XPR              0x01
-
-/* Interrupt Mask Register 0 (IMR0) */
-#define SAB82532_IMR0_TCD              0x80
-#define SAB82532_IMR0_TIME             0x40
-#define SAB82532_IMR0_PERR             0x20
-#define SAB82532_IMR0_FERR             0x10
-#define SAB82532_IMR0_PLLA             0x08
-#define SAB82532_IMR0_CDSC             0x04
-#define SAB82532_IMR0_RFO              0x02
-#define SAB82532_IMR0_RPF              0x01
-
-/* Interrupt Mask Register 1 (IMR1) */
-#define SAB82532_IMR1_BRK              0x80
-#define SAB82532_IMR1_BRKT             0x40
-#define SAB82532_IMR1_ALLS             0x20
-#define SAB82532_IMR1_XOFF             0x10
-#define SAB82532_IMR1_TIN              0x08
-#define SAB82532_IMR1_CSC              0x04
-#define SAB82532_IMR1_XON              0x02
-#define SAB82532_IMR1_XPR              0x01
-
-/* Port Interrupt Status Register (PIS) */
-#define SAB82532_PIS_SYNC_B            0x08
-#define SAB82532_PIS_DTR_B             0x04
-#define SAB82532_PIS_DTR_A             0x02
-#define SAB82532_PIS_SYNC_A            0x01
-
-/* Channel Configuration Register 4 (CCR4) */
-#define SAB82532_CCR4_MCK4             0x80
-#define SAB82532_CCR4_EBRG             0x40
-#define SAB82532_CCR4_TST1             0x20
-#define SAB82532_CCR4_ICD              0x10
-
-
-#endif /* !(_SUNSAB_H) */
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
deleted file mode 100644 (file)
index 551ebfe..0000000
+++ /dev/null
@@ -1,1608 +0,0 @@
-/*
- * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@yahoo.com)
- *
- * This is mainly a variation of 8250.c, credits go to authors mentioned
- * therein.  In fact this driver should be merged into the generic 8250.c
- * infrastructure perhaps using a 8250_sparc.c module.
- *
- * Fixed to use tty_get_baud_rate().
- *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- *
- * Converted to new 2.5.x UART layer.
- *   David S. Miller (davem@davemloft.net), 2002-Jul-29
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/slab.h>
-#ifdef CONFIG_SERIO
-#include <linux/serio.h>
-#endif
-#include <linux/serial_reg.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-
-/* We are on a NS PC87303 clocked with 24.0 MHz, which results
- * in a UART clock of 1.8462 MHz.
- */
-#define SU_BASE_BAUD   (1846200 / 16)
-
-enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
-static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
-       { "unknown",    1,      0 },
-       { "8250",       1,      0 },
-       { "16450",      1,      0 },
-       { "16550",      1,      0 },
-       { "16550A",     16,     UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "Cirrus",     1,      0 },
-       { "ST16650",    1,      UART_CLEAR_FIFO | UART_STARTECH },
-       { "ST16650V2",  32,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "TI16750",    64,     UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "Startech",   1,      0 },
-       { "16C950/954", 128,    UART_CLEAR_FIFO | UART_USE_FIFO },
-       { "ST16654",    64,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "XR16850",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-       { "RSA",        2048,   UART_CLEAR_FIFO | UART_USE_FIFO }
-};
-
-struct uart_sunsu_port {
-       struct uart_port        port;
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned short          rev;
-       unsigned char           lcr;
-       unsigned int            lsr_break_flag;
-       unsigned int            cflag;
-
-       /* Probing information.  */
-       enum su_type            su_type;
-       unsigned int            type_probed;    /* XXX Stupid */
-       unsigned long           reg_size;
-
-#ifdef CONFIG_SERIO
-       struct serio            serio;
-       int                     serio_open;
-#endif
-};
-
-static unsigned int serial_in(struct uart_sunsu_port *up, int offset)
-{
-       offset <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               return inb(up->port.iobase + 1);
-
-       case UPIO_MEM:
-               return readb(up->port.membase + offset);
-
-       default:
-               return inb(up->port.iobase + offset);
-       }
-}
-
-static void serial_out(struct uart_sunsu_port *up, int offset, int value)
-{
-#ifndef CONFIG_SPARC64
-       /*
-        * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
-        * connected with a gate then go to SlavIO. When IRQ4 goes tristated
-        * gate outputs a logical one. Since we use level triggered interrupts
-        * we have lockup and watchdog reset. We cannot mask IRQ because
-        * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
-        * This problem is similar to what Alpha people suffer, see serial.c.
-        */
-       if (offset == UART_MCR)
-               value |= UART_MCR_OUT2;
-#endif
-       offset <<= up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               outb(value, up->port.iobase + 1);
-               break;
-
-       case UPIO_MEM:
-               writeb(value, up->port.membase + offset);
-               break;
-
-       default:
-               outb(value, up->port.iobase + offset);
-       }
-}
-
-/*
- * We used to support using pause I/O for certain machines.  We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset)         serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-
-/*
- * For the 16C950
- */
-static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
-{
-       serial_out(up, UART_SCR, offset);
-       serial_out(up, UART_ICR, value);
-}
-
-#if 0 /* Unused currently */
-static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
-{
-       unsigned int value;
-
-       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
-       serial_out(up, UART_SCR, offset);
-       value = serial_in(up, UART_ICR);
-       serial_icr_write(up, UART_ACR, up->acr);
-
-       return value;
-}
-#endif
-
-#ifdef CONFIG_SERIAL_8250_RSA
-/*
- * Attempts to turn on the RSA FIFO.  Returns zero on failure.
- * We set the port uart clock rate if we succeed.
- */
-static int __enable_rsa(struct uart_sunsu_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       mode = serial_inp(up, UART_RSA_MSR);
-       result = mode & UART_RSA_MSR_FIFO;
-
-       if (!result) {
-               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = mode & UART_RSA_MSR_FIFO;
-       }
-
-       if (result)
-               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
-
-       return result;
-}
-
-static void enable_rsa(struct uart_sunsu_port *up)
-{
-       if (up->port.type == PORT_RSA) {
-               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
-                       spin_lock_irq(&up->port.lock);
-                       __enable_rsa(up);
-                       spin_unlock_irq(&up->port.lock);
-               }
-               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
-                       serial_outp(up, UART_RSA_FRR, 0);
-       }
-}
-
-/*
- * Attempts to turn off the RSA FIFO.  Returns zero on failure.
- * It is unknown why interrupts were disabled in here.  However,
- * the caller is expected to preserve this behaviour by grabbing
- * the spinlock before calling this function.
- */
-static void disable_rsa(struct uart_sunsu_port *up)
-{
-       unsigned char mode;
-       int result;
-
-       if (up->port.type == PORT_RSA &&
-           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
-               spin_lock_irq(&up->port.lock);
-
-               mode = serial_inp(up, UART_RSA_MSR);
-               result = !(mode & UART_RSA_MSR_FIFO);
-
-               if (!result) {
-                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
-                       mode = serial_inp(up, UART_RSA_MSR);
-                       result = !(mode & UART_RSA_MSR_FIFO);
-               }
-
-               if (result)
-                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
-               spin_unlock_irq(&up->port.lock);
-       }
-}
-#endif /* CONFIG_SERIAL_8250_RSA */
-
-static inline void __stop_tx(struct uart_sunsu_port *p)
-{
-       if (p->ier & UART_IER_THRI) {
-               p->ier &= ~UART_IER_THRI;
-               serial_out(p, UART_IER, p->ier);
-       }
-}
-
-static void sunsu_stop_tx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       __stop_tx(up);
-
-       /*
-        * We really want to stop the transmitter from sending.
-        */
-       if (up->port.type == PORT_16C950) {
-               up->acr |= UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void sunsu_start_tx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       if (!(up->ier & UART_IER_THRI)) {
-               up->ier |= UART_IER_THRI;
-               serial_out(up, UART_IER, up->ier);
-       }
-
-       /*
-        * Re-enable the transmitter if we disabled it.
-        */
-       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
-               up->acr &= ~UART_ACR_TXDIS;
-               serial_icr_write(up, UART_ACR, up->acr);
-       }
-}
-
-static void sunsu_stop_rx(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       up->ier &= ~UART_IER_RLSI;
-       up->port.read_status_mask &= ~UART_LSR_DR;
-       serial_out(up, UART_IER, up->ier);
-}
-
-static void sunsu_enable_ms(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       up->ier |= UART_IER_MSI;
-       serial_out(up, UART_IER, up->ier);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct tty_struct *
-receive_chars(struct uart_sunsu_port *up, unsigned char *status)
-{
-       struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch, flag;
-       int max_count = 256;
-       int saw_console_brk = 0;
-
-       do {
-               ch = serial_inp(up, UART_RX);
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-
-               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-                                      UART_LSR_FE | UART_LSR_OE))) {
-                       /*
-                        * For statistics only
-                        */
-                       if (*status & UART_LSR_BI) {
-                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
-                               up->port.icount.brk++;
-                               if (up->port.cons != NULL &&
-                                   up->port.line == up->port.cons->index)
-                                       saw_console_brk = 1;
-                               /*
-                                * We do the SysRQ and SAK checking
-                                * here because otherwise the break
-                                * may get masked by ignore_status_mask
-                                * or read_status_mask.
-                                */
-                               if (uart_handle_break(&up->port))
-                                       goto ignore_char;
-                       } else if (*status & UART_LSR_PE)
-                               up->port.icount.parity++;
-                       else if (*status & UART_LSR_FE)
-                               up->port.icount.frame++;
-                       if (*status & UART_LSR_OE)
-                               up->port.icount.overrun++;
-
-                       /*
-                        * Mask off conditions which should be ingored.
-                        */
-                       *status &= up->port.read_status_mask;
-
-                       if (up->port.cons != NULL &&
-                           up->port.line == up->port.cons->index) {
-                               /* Recover the break flag from console xmit */
-                               *status |= up->lsr_break_flag;
-                               up->lsr_break_flag = 0;
-                       }
-
-                       if (*status & UART_LSR_BI) {
-                               flag = TTY_BREAK;
-                       } else if (*status & UART_LSR_PE)
-                               flag = TTY_PARITY;
-                       else if (*status & UART_LSR_FE)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       goto ignore_char;
-               if ((*status & up->port.ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-               if (*status & UART_LSR_OE)
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       ignore_char:
-               *status = serial_inp(up, UART_LSR);
-       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-
-       if (saw_console_brk)
-               sun_do_break();
-
-       return tty;
-}
-
-static void transmit_chars(struct uart_sunsu_port *up)
-{
-       struct circ_buf *xmit = &up->port.state->xmit;
-       int count;
-
-       if (up->port.x_char) {
-               serial_outp(up, UART_TX, up->port.x_char);
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-       if (uart_tx_stopped(&up->port)) {
-               sunsu_stop_tx(&up->port);
-               return;
-       }
-       if (uart_circ_empty(xmit)) {
-               __stop_tx(up);
-               return;
-       }
-
-       count = up->port.fifosize;
-       do {
-               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               up->port.icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (--count > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       if (uart_circ_empty(xmit))
-               __stop_tx(up);
-}
-
-static void check_modem_status(struct uart_sunsu_port *up)
-{
-       int status;
-
-       status = serial_in(up, UART_MSR);
-
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
-
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsu_port *up = dev_id;
-       unsigned long flags;
-       unsigned char status;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       do {
-               struct tty_struct *tty;
-
-               status = serial_inp(up, UART_LSR);
-               tty = NULL;
-               if (status & UART_LSR_DR)
-                       tty = receive_chars(up, &status);
-               check_modem_status(up);
-               if (status & UART_LSR_THRE)
-                       transmit_chars(up);
-
-               spin_unlock_irqrestore(&up->port.lock, flags);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               spin_lock_irqsave(&up->port.lock, flags);
-
-       } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-/* Separate interrupt handling path for keyboard/mouse ports.  */
-
-static void
-sunsu_change_speed(struct uart_port *port, unsigned int cflag,
-                  unsigned int iflag, unsigned int quot);
-
-static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
-{
-       unsigned int cur_cflag = up->cflag;
-       int quot, new_baud;
-
-       up->cflag &= ~CBAUD;
-       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
-
-       quot = up->port.uartclk / (16 * new_baud);
-
-       sunsu_change_speed(&up->port, up->cflag, 0, quot);
-}
-
-static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
-{
-       do {
-               unsigned char ch = serial_inp(up, UART_RX);
-
-               /* Stop-A is handled by drivers/char/keyboard.c now. */
-               if (up->su_type == SU_PORT_KBD) {
-#ifdef CONFIG_SERIO
-                       serio_interrupt(&up->serio, ch, 0);
-#endif
-               } else if (up->su_type == SU_PORT_MS) {
-                       int ret = suncore_mouse_baud_detection(ch, is_break);
-
-                       switch (ret) {
-                       case 2:
-                               sunsu_change_mouse_baud(up);
-                               /* fallthru */
-                       case 1:
-                               break;
-
-                       case 0:
-#ifdef CONFIG_SERIO
-                               serio_interrupt(&up->serio, ch, 0);
-#endif
-                               break;
-                       };
-               }
-       } while (serial_in(up, UART_LSR) & UART_LSR_DR);
-}
-
-static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunsu_port *up = dev_id;
-
-       if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
-               unsigned char status = serial_inp(up, UART_LSR);
-
-               if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
-                       receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int sunsu_tx_empty(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return ret;
-}
-
-static unsigned int sunsu_get_mctrl(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char status;
-       unsigned int ret;
-
-       status = serial_in(up, UART_MSR);
-
-       ret = 0;
-       if (status & UART_MSR_DCD)
-               ret |= TIOCM_CAR;
-       if (status & UART_MSR_RI)
-               ret |= TIOCM_RNG;
-       if (status & UART_MSR_DSR)
-               ret |= TIOCM_DSR;
-       if (status & UART_MSR_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       serial_out(up, UART_MCR, mcr);
-}
-
-static void sunsu_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (break_state == -1)
-               up->lcr |= UART_LCR_SBC;
-       else
-               up->lcr &= ~UART_LCR_SBC;
-       serial_out(up, UART_LCR, up->lcr);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int sunsu_startup(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-       int retval;
-
-       if (up->port.type == PORT_16C950) {
-               /* Wake up and initialize UART */
-               up->acr = 0;
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_IER, 0);
-               serial_outp(up, UART_LCR, 0);
-               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, UART_EFR_ECB);
-               serial_outp(up, UART_LCR, 0);
-       }
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * If this is an RSA port, see if we can kick it up to the
-        * higher speed clock.
-        */
-       enable_rsa(up);
-#endif
-
-       /*
-        * Clear the FIFO buffers and disable them.
-        * (they will be reenabled in set_termios())
-        */
-       if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-               serial_outp(up, UART_FCR, 0);
-       }
-
-       /*
-        * Clear the interrupt registers.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       /*
-        * At this point, there's no way the LSR could still be 0xff;
-        * if it is, then bail out, because there's likely no UART
-        * here.
-        */
-       if (!(up->port.flags & UPF_BUGGY_UART) &&
-           (serial_inp(up, UART_LSR) == 0xff)) {
-               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
-               return -ENODEV;
-       }
-
-       if (up->su_type != SU_PORT_PORT) {
-               retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt,
-                                    IRQF_SHARED, su_typev[up->su_type], up);
-       } else {
-               retval = request_irq(up->port.irq, sunsu_serial_interrupt,
-                                    IRQF_SHARED, su_typev[up->su_type], up);
-       }
-       if (retval) {
-               printk("su: Cannot register IRQ %d\n", up->port.irq);
-               return retval;
-       }
-
-       /*
-        * Now, initialize the UART
-        */
-       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->port.mctrl |= TIOCM_OUT2;
-
-       sunsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occurring imminently
-        * anyway, so we don't enable them here.
-        */
-       up->ier = UART_IER_RLSI | UART_IER_RDI;
-       serial_outp(up, UART_IER, up->ier);
-
-       if (up->port.flags & UPF_FOURPORT) {
-               unsigned int icp;
-               /*
-                * Enable interrupts on the AST Fourport board
-                */
-               icp = (up->port.iobase & 0xfe0) | 0x01f;
-               outb_p(0x80, icp);
-               (void) inb_p(icp);
-       }
-
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
-       return 0;
-}
-
-static void sunsu_shutdown(struct uart_port *port)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this port
-        */
-       up->ier = 0;
-       serial_outp(up, UART_IER, 0);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & UPF_FOURPORT) {
-               /* reset interrupts on the AST Fourport board */
-               inb((up->port.iobase & 0xfe0) | 0x1f);
-               up->port.mctrl |= TIOCM_OUT1;
-       } else
-               up->port.mctrl &= ~TIOCM_OUT2;
-
-       sunsu_set_mctrl(&up->port, up->port.mctrl);
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       /*
-        * Disable break condition and FIFOs
-        */
-       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-                                 UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       serial_outp(up, UART_FCR, 0);
-
-#ifdef CONFIG_SERIAL_8250_RSA
-       /*
-        * Reset the RSA board back to 115kbps compat mode.
-        */
-       disable_rsa(up);
-#endif
-
-       /*
-        * Read data port to reset things.
-        */
-       (void) serial_in(up, UART_RX);
-
-       free_irq(up->port.irq, up);
-}
-
-static void
-sunsu_change_speed(struct uart_port *port, unsigned int cflag,
-                  unsigned int iflag, unsigned int quot)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-       unsigned char cval, fcr = 0;
-       unsigned long flags;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               cval = 0x00;
-               break;
-       case CS6:
-               cval = 0x01;
-               break;
-       case CS7:
-               cval = 0x02;
-               break;
-       default:
-       case CS8:
-               cval = 0x03;
-               break;
-       }
-
-       if (cflag & CSTOPB)
-               cval |= 0x04;
-       if (cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-       if (cflag & CMSPAR)
-               cval |= UART_LCR_SPAR;
-#endif
-
-       /*
-        * Work around a bug in the Oxford Semiconductor 952 rev B
-        * chip which causes it to seriously miscalculate baud rates
-        * when DLL is 0.
-        */
-       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
-           up->rev == 0x5201)
-               quot ++;
-
-       if (uart_config[up->port.type].flags & UART_USE_FIFO) {
-               if ((up->port.uartclk / quot) < (2400 * 16))
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-#ifdef CONFIG_SERIAL_8250_RSA
-               else if (up->port.type == PORT_RSA)
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
-#endif
-               else
-                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-       }
-       if (up->port.type == PORT_16750)
-               fcr |= UART_FCR7_64BYTE;
-
-       /*
-        * Ok, we're now changing the port state.  Do it with
-        * interrupts disabled.
-        */
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       /*
-        * Update the per-port timeout.
-        */
-       uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
-
-       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= UART_LSR_BI;
-
-       /*
-        * Characteres to ignore
-        */
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= UART_LSR_BI;
-               /*
-                * If we're ignoring parity and break indicators,
-                * ignore overruns too (for real raw support).
-                */
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= UART_LSR_OE;
-       }
-
-       /*
-        * ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask |= UART_LSR_DR;
-
-       /*
-        * CTS flow control flag and modem status interrupts
-        */
-       up->ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(&up->port, cflag))
-               up->ier |= UART_IER_MSI;
-
-       serial_out(up, UART_IER, up->ier);
-
-       if (uart_config[up->port.type].flags & UART_STARTECH) {
-               serial_outp(up, UART_LCR, 0xBF);
-               serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
-       }
-       serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
-       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
-       if (up->port.type == PORT_16750)
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
-       up->lcr = cval;                                 /* Save LCR */
-       if (up->port.type != PORT_16750) {
-               if (fcr & UART_FCR_ENABLE_FIFO) {
-                       /* emulated UARTs (Lucent Venus 167x) need two steps */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-               }
-               serial_outp(up, UART_FCR, fcr);         /* set fcr */
-       }
-
-       up->cflag = cflag;
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
-                 struct ktermios *old)
-{
-       unsigned int baud, quot;
-
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-       quot = uart_get_divisor(port, baud);
-
-       sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
-}
-
-static void sunsu_release_port(struct uart_port *port)
-{
-}
-
-static int sunsu_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sunsu_config_port(struct uart_port *port, int flags)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
-
-       if (flags & UART_CONFIG_TYPE) {
-               /*
-                * We are supposed to call autoconfig here, but this requires
-                * splitting all the OBP probing crap from the UART probing.
-                * We'll do it when we kill sunsu.c altogether.
-                */
-               port->type = up->type_probed;   /* XXX */
-       }
-}
-
-static int
-sunsu_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static const char *
-sunsu_type(struct uart_port *port)
-{
-       int type = port->type;
-
-       if (type >= ARRAY_SIZE(uart_config))
-               type = 0;
-       return uart_config[type].name;
-}
-
-static struct uart_ops sunsu_pops = {
-       .tx_empty       = sunsu_tx_empty,
-       .set_mctrl      = sunsu_set_mctrl,
-       .get_mctrl      = sunsu_get_mctrl,
-       .stop_tx        = sunsu_stop_tx,
-       .start_tx       = sunsu_start_tx,
-       .stop_rx        = sunsu_stop_rx,
-       .enable_ms      = sunsu_enable_ms,
-       .break_ctl      = sunsu_break_ctl,
-       .startup        = sunsu_startup,
-       .shutdown       = sunsu_shutdown,
-       .set_termios    = sunsu_set_termios,
-       .type           = sunsu_type,
-       .release_port   = sunsu_release_port,
-       .request_port   = sunsu_request_port,
-       .config_port    = sunsu_config_port,
-       .verify_port    = sunsu_verify_port,
-};
-
-#define UART_NR        4
-
-static struct uart_sunsu_port sunsu_ports[UART_NR];
-
-#ifdef CONFIG_SERIO
-
-static DEFINE_SPINLOCK(sunsu_serio_lock);
-
-static int sunsu_serio_write(struct serio *serio, unsigned char ch)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-       int lsr;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-
-       do {
-               lsr = serial_in(up, UART_LSR);
-       } while (!(lsr & UART_LSR_THRE));
-
-       /* Send the character out. */
-       serial_out(up, UART_TX, ch);
-
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-
-       return 0;
-}
-
-static int sunsu_serio_open(struct serio *serio)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-       if (!up->serio_open) {
-               up->serio_open = 1;
-               ret = 0;
-       } else
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-
-       return ret;
-}
-
-static void sunsu_serio_close(struct serio *serio)
-{
-       struct uart_sunsu_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunsu_serio_lock, flags);
-       up->serio_open = 0;
-       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
-}
-
-#endif /* CONFIG_SERIO */
-
-static void sunsu_autoconfig(struct uart_sunsu_port *up)
-{
-       unsigned char status1, status2, scratch, scratch2, scratch3;
-       unsigned char save_lcr, save_mcr;
-       unsigned long flags;
-
-       if (up->su_type == SU_PORT_NONE)
-               return;
-
-       up->type_probed = PORT_UNKNOWN;
-       up->port.iotype = UPIO_MEM;
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       if (!(up->port.flags & UPF_BUGGY_UART)) {
-               /*
-                * Do a simple existence test first; if we fail this, there's
-                * no point trying anything else.
-                *
-                * 0x80 is used as a nonsense port to prevent against false
-                * positives due to ISA bus float.  The assumption is that
-                * 0x80 is a non-existent port; which should be safe since
-                * include/asm/io.h also makes this assumption.
-                */
-               scratch = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0);
-#ifdef __i386__
-               outb(0xff, 0x080);
-#endif
-               scratch2 = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, 0x0f);
-#ifdef __i386__
-               outb(0, 0x080);
-#endif
-               scratch3 = serial_inp(up, UART_IER);
-               serial_outp(up, UART_IER, scratch);
-               if (scratch2 != 0 || scratch3 != 0x0F)
-                       goto out;       /* We failed; there's nothing here */
-       }
-
-       save_mcr = serial_in(up, UART_MCR);
-       save_lcr = serial_in(up, UART_LCR);
-
-       /* 
-        * Check to see if a UART is really there.  Certain broken
-        * internal modems based on the Rockwell chipset fail this
-        * test, because they apparently don't implement the loopback
-        * test mode.  So this test is skipped on the COM 1 through
-        * COM 4 ports.  This *should* be safe, since no board
-        * manufacturer would be stupid enough to design a board
-        * that conflicts with COM 1-4 --- we hope!
-        */
-       if (!(up->port.flags & UPF_SKIP_TEST)) {
-               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
-               status1 = serial_inp(up, UART_MSR) & 0xF0;
-               serial_outp(up, UART_MCR, save_mcr);
-               if (status1 != 0x90)
-                       goto out;       /* We failed loopback test */
-       }
-       serial_outp(up, UART_LCR, 0xBF);        /* set up for StarTech test */
-       serial_outp(up, UART_EFR, 0);           /* EFR is the same as FCR */
-       serial_outp(up, UART_LCR, 0);
-       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       scratch = serial_in(up, UART_IIR) >> 6;
-       switch (scratch) {
-               case 0:
-                       up->port.type = PORT_16450;
-                       break;
-               case 1:
-                       up->port.type = PORT_UNKNOWN;
-                       break;
-               case 2:
-                       up->port.type = PORT_16550;
-                       break;
-               case 3:
-                       up->port.type = PORT_16550A;
-                       break;
-       }
-       if (up->port.type == PORT_16550A) {
-               /* Check for Startech UART's */
-               serial_outp(up, UART_LCR, UART_LCR_DLAB);
-               if (serial_in(up, UART_EFR) == 0) {
-                       up->port.type = PORT_16650;
-               } else {
-                       serial_outp(up, UART_LCR, 0xBF);
-                       if (serial_in(up, UART_EFR) == 0)
-                               up->port.type = PORT_16650V2;
-               }
-       }
-       if (up->port.type == PORT_16550A) {
-               /* Check for TI 16750 */
-               serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
-               serial_outp(up, UART_FCR,
-                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-               scratch = serial_in(up, UART_IIR) >> 5;
-               if (scratch == 7) {
-                       /*
-                        * If this is a 16750, and not a cheap UART
-                        * clone, then it should only go into 64 byte
-                        * mode if the UART_FCR7_64BYTE bit was set
-                        * while UART_LCR_DLAB was latched.
-                        */
-                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-                       serial_outp(up, UART_LCR, 0);
-                       serial_outp(up, UART_FCR,
-                                   UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-                       scratch = serial_in(up, UART_IIR) >> 5;
-                       if (scratch == 6)
-                               up->port.type = PORT_16750;
-               }
-               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-       }
-       serial_outp(up, UART_LCR, save_lcr);
-       if (up->port.type == PORT_16450) {
-               scratch = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, 0xa5);
-               status1 = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, 0x5a);
-               status2 = serial_in(up, UART_SCR);
-               serial_outp(up, UART_SCR, scratch);
-
-               if ((status1 != 0xa5) || (status2 != 0x5a))
-                       up->port.type = PORT_8250;
-       }
-
-       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
-
-       if (up->port.type == PORT_UNKNOWN)
-               goto out;
-       up->type_probed = up->port.type;        /* XXX */
-
-       /*
-        * Reset the UART.
-        */
-#ifdef CONFIG_SERIAL_8250_RSA
-       if (up->port.type == PORT_RSA)
-               serial_outp(up, UART_RSA_FRR, 0);
-#endif
-       serial_outp(up, UART_MCR, save_mcr);
-       serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
-                                    UART_FCR_CLEAR_RCVR |
-                                    UART_FCR_CLEAR_XMIT));
-       serial_outp(up, UART_FCR, 0);
-       (void)serial_in(up, UART_RX);
-       serial_outp(up, UART_IER, 0);
-
-out:
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver sunsu_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "sunsu",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-};
-
-static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
-{
-       int quot, baud;
-#ifdef CONFIG_SERIO
-       struct serio *serio;
-#endif
-
-       if (up->su_type == SU_PORT_KBD) {
-               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
-               baud = 1200;
-       } else {
-               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
-               baud = 4800;
-       }
-       quot = up->port.uartclk / (16 * baud);
-
-       sunsu_autoconfig(up);
-       if (up->port.type == PORT_UNKNOWN)
-               return -ENODEV;
-
-       printk("%s: %s port at %llx, irq %u\n",
-              up->port.dev->of_node->full_name,
-              (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
-              (unsigned long long) up->port.mapbase,
-              up->port.irq);
-
-#ifdef CONFIG_SERIO
-       serio = &up->serio;
-       serio->port_data = up;
-
-       serio->id.type = SERIO_RS232;
-       if (up->su_type == SU_PORT_KBD) {
-               serio->id.proto = SERIO_SUNKBD;
-               strlcpy(serio->name, "sukbd", sizeof(serio->name));
-       } else {
-               serio->id.proto = SERIO_SUN;
-               serio->id.extra = 1;
-               strlcpy(serio->name, "sums", sizeof(serio->name));
-       }
-       strlcpy(serio->phys,
-               (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
-               sizeof(serio->phys));
-
-       serio->write = sunsu_serio_write;
-       serio->open = sunsu_serio_open;
-       serio->close = sunsu_serio_close;
-       serio->dev.parent = up->port.dev;
-
-       serio_register_port(serio);
-#endif
-
-       sunsu_change_speed(&up->port, up->cflag, 0, quot);
-
-       sunsu_startup(&up->port);
-       return 0;
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-
-#ifdef CONFIG_SERIAL_SUNSU_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = serial_in(up, UART_LSR);
-
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-                       udelay(1);
-       }
-}
-
-static void sunsu_console_putchar(struct uart_port *port, int ch)
-{
-       struct uart_sunsu_port *up = (struct uart_sunsu_port *)port;
-
-       wait_for_xmitr(up);
-       serial_out(up, UART_TX, ch);
-}
-
-/*
- *     Print a string to the serial port trying not to disturb
- *     any possible real use of the port...
- */
-static void sunsu_console_write(struct console *co, const char *s,
-                               unsigned int count)
-{
-       struct uart_sunsu_port *up = &sunsu_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       /*
-        *      First save the UER then disable the interrupts
-        */
-       ier = serial_in(up, UART_IER);
-       serial_out(up, UART_IER, 0);
-
-       uart_console_write(&up->port, s, count, sunsu_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and restore the IER
-        */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-/*
- *     Setup initial baud/bits/parity. We do two things here:
- *     - construct a cflag setting for the first su_open()
- *     - initialize the serial port
- *     Return non-zero if we didn't find a serial port.
- */
-static int __init sunsu_console_setup(struct console *co, char *options)
-{
-       static struct ktermios dummy;
-       struct ktermios termios;
-       struct uart_port *port;
-
-       printk("Console: ttyS%d (SU)\n",
-              (sunsu_reg.minor - 64) + co->index);
-
-       /*
-        * Check whether an invalid uart number has been specified, and
-        * if so, search for the first available port that does have
-        * console support.
-        */
-       if (co->index >= UART_NR)
-               co->index = 0;
-       port = &sunsu_ports[co->index].port;
-
-       /*
-        * Temporary fix.
-        */
-       spin_lock_init(&port->lock);
-
-       /* Get firmware console settings.  */
-       sunserial_console_termios(co, port->dev->of_node);
-
-       memset(&termios, 0, sizeof(struct ktermios));
-       termios.c_cflag = co->cflag;
-       port->mctrl |= TIOCM_DTR;
-       port->ops->set_termios(port, &termios, &dummy);
-
-       return 0;
-}
-
-static struct console sunsu_console = {
-       .name   =       "ttyS",
-       .write  =       sunsu_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunsu_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunsu_reg,
-};
-
-/*
- *     Register console.
- */
-
-static inline struct console *SUNSU_CONSOLE(void)
-{
-       return &sunsu_console;
-}
-#else
-#define SUNSU_CONSOLE()                        (NULL)
-#define sunsu_serial_console_init()    do { } while (0)
-#endif
-
-static enum su_type __devinit su_get_type(struct device_node *dp)
-{
-       struct device_node *ap = of_find_node_by_path("/aliases");
-
-       if (ap) {
-               const char *keyb = of_get_property(ap, "keyboard", NULL);
-               const char *ms = of_get_property(ap, "mouse", NULL);
-
-               if (keyb) {
-                       if (dp == of_find_node_by_path(keyb))
-                               return SU_PORT_KBD;
-               }
-               if (ms) {
-                       if (dp == of_find_node_by_path(ms))
-                               return SU_PORT_MS;
-               }
-       }
-
-       return SU_PORT_PORT;
-}
-
-static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int inst;
-       struct device_node *dp = op->dev.of_node;
-       struct uart_sunsu_port *up;
-       struct resource *rp;
-       enum su_type type;
-       bool ignore_line;
-       int err;
-
-       type = su_get_type(dp);
-       if (type == SU_PORT_PORT) {
-               if (inst >= UART_NR)
-                       return -EINVAL;
-               up = &sunsu_ports[inst];
-       } else {
-               up = kzalloc(sizeof(*up), GFP_KERNEL);
-               if (!up)
-                       return -ENOMEM;
-       }
-
-       up->port.line = inst;
-
-       spin_lock_init(&up->port.lock);
-
-       up->su_type = type;
-
-       rp = &op->resource[0];
-       up->port.mapbase = rp->start;
-       up->reg_size = (rp->end - rp->start) + 1;
-       up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
-       if (!up->port.membase) {
-               if (type != SU_PORT_PORT)
-                       kfree(up);
-               return -ENOMEM;
-       }
-
-       up->port.irq = op->archdata.irqs[0];
-
-       up->port.dev = &op->dev;
-
-       up->port.type = PORT_UNKNOWN;
-       up->port.uartclk = (SU_BASE_BAUD * 16);
-
-       err = 0;
-       if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
-               err = sunsu_kbd_ms_init(up);
-               if (err) {
-                       of_iounmap(&op->resource[0],
-                                  up->port.membase, up->reg_size);
-                       kfree(up);
-                       return err;
-               }
-               dev_set_drvdata(&op->dev, up);
-
-               return 0;
-       }
-
-       up->port.flags |= UPF_BOOT_AUTOCONF;
-
-       sunsu_autoconfig(up);
-
-       err = -ENODEV;
-       if (up->port.type == PORT_UNKNOWN)
-               goto out_unmap;
-
-       up->port.ops = &sunsu_pops;
-
-       ignore_line = false;
-       if (!strcmp(dp->name, "rsc-console") ||
-           !strcmp(dp->name, "lom-console"))
-               ignore_line = true;
-
-       sunserial_console_match(SUNSU_CONSOLE(), dp,
-                               &sunsu_reg, up->port.line,
-                               ignore_line);
-       err = uart_add_one_port(&sunsu_reg, &up->port);
-       if (err)
-               goto out_unmap;
-
-       dev_set_drvdata(&op->dev, up);
-
-       inst++;
-
-       return 0;
-
-out_unmap:
-       of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
-       return err;
-}
-
-static int __devexit su_remove(struct platform_device *op)
-{
-       struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
-       bool kbdms = false;
-
-       if (up->su_type == SU_PORT_MS ||
-           up->su_type == SU_PORT_KBD)
-               kbdms = true;
-
-       if (kbdms) {
-#ifdef CONFIG_SERIO
-               serio_unregister_port(&up->serio);
-#endif
-       } else if (up->port.type != PORT_UNKNOWN)
-               uart_remove_one_port(&sunsu_reg, &up->port);
-
-       if (up->port.membase)
-               of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
-
-       if (kbdms)
-               kfree(up);
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id su_match[] = {
-       {
-               .name = "su",
-       },
-       {
-               .name = "su_pnp",
-       },
-       {
-               .name = "serial",
-               .compatible = "su",
-       },
-       {
-               .type = "serial",
-               .compatible = "su",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, su_match);
-
-static struct of_platform_driver su_driver = {
-       .driver = {
-               .name = "su",
-               .owner = THIS_MODULE,
-               .of_match_table = su_match,
-       },
-       .probe          = su_probe,
-       .remove         = __devexit_p(su_remove),
-};
-
-static int __init sunsu_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_uart = 0;
-
-       for_each_node_by_name(dp, "su") {
-               if (su_get_type(dp) == SU_PORT_PORT)
-                       num_uart++;
-       }
-       for_each_node_by_name(dp, "su_pnp") {
-               if (su_get_type(dp) == SU_PORT_PORT)
-                       num_uart++;
-       }
-       for_each_node_by_name(dp, "serial") {
-               if (of_device_is_compatible(dp, "su")) {
-                       if (su_get_type(dp) == SU_PORT_PORT)
-                               num_uart++;
-               }
-       }
-       for_each_node_by_type(dp, "serial") {
-               if (of_device_is_compatible(dp, "su")) {
-                       if (su_get_type(dp) == SU_PORT_PORT)
-                               num_uart++;
-               }
-       }
-
-       if (num_uart) {
-               err = sunserial_register_minors(&sunsu_reg, num_uart);
-               if (err)
-                       return err;
-       }
-
-       err = of_register_platform_driver(&su_driver);
-       if (err && num_uart)
-               sunserial_unregister_minors(&sunsu_reg, num_uart);
-
-       return err;
-}
-
-static void __exit sunsu_exit(void)
-{
-       if (sunsu_reg.nr)
-               sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
-}
-
-module_init(sunsu_init);
-module_exit(sunsu_exit);
-
-MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller");
-MODULE_DESCRIPTION("Sun SU serial port driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
deleted file mode 100644 (file)
index c1967ac..0000000
+++ /dev/null
@@ -1,1655 +0,0 @@
-/* sunzilog.c: Zilog serial driver for Sparc systems.
- *
- * Driver for Zilog serial chips found on Sun workstations and
- * servers.  This driver could actually be made more generic.
- *
- * This is based on the old drivers/sbus/char/zs.c code.  A lot
- * of code has been simply moved over directly from there but
- * much has been rewritten.  Credits therefore go out to Eddie
- * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
- * work there.
- *
- * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIO
-#include <linux/serio.h>
-#endif
-#include <linux/init.h>
-#include <linux/of_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-
-#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#include "suncore.h"
-#include "sunzilog.h"
-
-/* On 32-bit sparcs we need to delay after register accesses
- * to accommodate sun4 systems, but we do not need to flush writes.
- * On 64-bit sparc we only need to flush single writes to ensure
- * completion.
- */
-#ifndef CONFIG_SPARC64
-#define ZSDELAY()              udelay(5)
-#define ZSDELAY_LONG()         udelay(20)
-#define ZS_WSYNC(channel)      do { } while (0)
-#else
-#define ZSDELAY()
-#define ZSDELAY_LONG()
-#define ZS_WSYNC(__channel) \
-       readb(&((__channel)->control))
-#endif
-
-#define ZS_CLOCK               4915200 /* Zilog input clock rate. */
-#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_sunzilog_port {
-       struct uart_port                port;
-
-       /* IRQ servicing chain.  */
-       struct uart_sunzilog_port       *next;
-
-       /* Current values of Zilog write registers.  */
-       unsigned char                   curregs[NUM_ZSREGS];
-
-       unsigned int                    flags;
-#define SUNZILOG_FLAG_CONS_KEYB                0x00000001
-#define SUNZILOG_FLAG_CONS_MOUSE       0x00000002
-#define SUNZILOG_FLAG_IS_CONS          0x00000004
-#define SUNZILOG_FLAG_IS_KGDB          0x00000008
-#define SUNZILOG_FLAG_MODEM_STATUS     0x00000010
-#define SUNZILOG_FLAG_IS_CHANNEL_A     0x00000020
-#define SUNZILOG_FLAG_REGS_HELD                0x00000040
-#define SUNZILOG_FLAG_TX_STOPPED       0x00000080
-#define SUNZILOG_FLAG_TX_ACTIVE                0x00000100
-#define SUNZILOG_FLAG_ESCC             0x00000200
-#define SUNZILOG_FLAG_ISR_HANDLER      0x00000400
-
-       unsigned int cflag;
-
-       unsigned char                   parity_mask;
-       unsigned char                   prev_status;
-
-#ifdef CONFIG_SERIO
-       struct serio                    serio;
-       int                             serio_open;
-#endif
-};
-
-static void sunzilog_putchar(struct uart_port *port, int ch);
-
-#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel __iomem *)((PORT)->membase))
-#define UART_ZILOG(PORT)               ((struct uart_sunzilog_port *)(PORT))
-
-#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
-#define ZS_IS_MOUSE(UP)        ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE)
-#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS)
-#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB)
-#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A)
-#define ZS_REGS_HELD(UP)       ((UP)->flags & SUNZILOG_FLAG_REGS_HELD)
-#define ZS_TX_STOPPED(UP)      ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED)
-#define ZS_TX_ACTIVE(UP)       ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE)
-
-/* Reading and writing Zilog8530 registers.  The delays are to make this
- * driver work on the Sun4 which needs a settling delay after each chip
- * register access, other machines handle this in hardware via auxiliary
- * flip-flops which implement the settle time we do in software.
- *
- * The port lock must be held and local IRQs must be disabled
- * when {read,write}_zsreg is invoked.
- */
-static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
-                               unsigned char reg)
-{
-       unsigned char retval;
-
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       retval = readb(&channel->control);
-       ZSDELAY();
-
-       return retval;
-}
-
-static void write_zsreg(struct zilog_channel __iomem *channel,
-                       unsigned char reg, unsigned char value)
-{
-       writeb(reg, &channel->control);
-       ZSDELAY();
-       writeb(value, &channel->control);
-       ZSDELAY();
-}
-
-static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
-{
-       int i;
-
-       for (i = 0; i < 32; i++) {
-               unsigned char regval;
-
-               regval = readb(&channel->control);
-               ZSDELAY();
-               if (regval & Rx_CH_AV)
-                       break;
-
-               regval = read_zsreg(channel, R1);
-               readb(&channel->data);
-               ZSDELAY();
-
-               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-       }
-}
-
-/* This function must only be called when the TX is not busy.  The UART
- * port lock must be held and local interrupts disabled.
- */
-static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
-{
-       int i;
-       int escc;
-       unsigned char r15;
-
-       /* Let pending transmits finish.  */
-       for (i = 0; i < 1000; i++) {
-               unsigned char stat = read_zsreg(channel, R1);
-               if (stat & ALL_SNT)
-                       break;
-               udelay(100);
-       }
-
-       writeb(ERR_RES, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       sunzilog_clear_fifo(channel);
-
-       /* Disable all interrupts.  */
-       write_zsreg(channel, R1,
-                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
-
-       /* Set parity, sync config, stop bits, and clock divisor.  */
-       write_zsreg(channel, R4, regs[R4]);
-
-       /* Set misc. TX/RX control bits.  */
-       write_zsreg(channel, R10, regs[R10]);
-
-       /* Set TX/RX controls sans the enable bits.  */
-       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
-       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-
-       /* Synchronous mode config.  */
-       write_zsreg(channel, R6, regs[R6]);
-       write_zsreg(channel, R7, regs[R7]);
-
-       /* Don't mess with the interrupt vector (R2, unused by us) and
-        * master interrupt control (R9).  We make sure this is setup
-        * properly at probe time then never touch it again.
-        */
-
-       /* Disable baud generator.  */
-       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
-
-       /* Clock mode control.  */
-       write_zsreg(channel, R11, regs[R11]);
-
-       /* Lower and upper byte of baud rate generator divisor.  */
-       write_zsreg(channel, R12, regs[R12]);
-       write_zsreg(channel, R13, regs[R13]);
-       
-       /* Now rewrite R14, with BRENAB (if set).  */
-       write_zsreg(channel, R14, regs[R14]);
-
-       /* External status interrupt control.  */
-       write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
-
-       /* ESCC Extension Register */
-       r15 = read_zsreg(channel, R15);
-       if (r15 & 0x01) {
-               write_zsreg(channel, R7,  regs[R7p]);
-
-               /* External status interrupt and FIFO control.  */
-               write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
-               escc = 1;
-       } else {
-                /* Clear FIFO bit case it is an issue */
-               regs[R15] &= ~FIFOEN;
-               escc = 0;
-       }
-
-       /* Reset external status interrupts.  */
-       write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
-       write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
-
-       /* Rewrite R3/R5, this time without enables masked.  */
-       write_zsreg(channel, R3, regs[R3]);
-       write_zsreg(channel, R5, regs[R5]);
-
-       /* Rewrite R1, this time without IRQ enabled masked.  */
-       write_zsreg(channel, R1, regs[R1]);
-
-       return escc;
-}
-
-/* Reprogram the Zilog channel HW registers with the copies found in the
- * software state struct.  If the transmitter is busy, we defer this update
- * until the next TX complete interrupt.  Else, we do it right now.
- *
- * The UART port lock must be held and local interrupts disabled.
- */
-static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up,
-                                      struct zilog_channel __iomem *channel)
-{
-       if (!ZS_REGS_HELD(up)) {
-               if (ZS_TX_ACTIVE(up)) {
-                       up->flags |= SUNZILOG_FLAG_REGS_HELD;
-               } else {
-                       __load_zsregs(channel, up->curregs);
-               }
-       }
-}
-
-static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
-{
-       unsigned int cur_cflag = up->cflag;
-       int brg, new_baud;
-
-       up->cflag &= ~CBAUD;
-       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
-
-       brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-       up->curregs[R12] = (brg & 0xff);
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port));
-}
-
-static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
-                                        unsigned char ch, int is_break)
-{
-       if (ZS_IS_KEYB(up)) {
-               /* Stop-A is handled by drivers/char/keyboard.c now. */
-#ifdef CONFIG_SERIO
-               if (up->serio_open)
-                       serio_interrupt(&up->serio, ch, 0);
-#endif
-       } else if (ZS_IS_MOUSE(up)) {
-               int ret = suncore_mouse_baud_detection(ch, is_break);
-
-               switch (ret) {
-               case 2:
-                       sunzilog_change_mouse_baud(up);
-                       /* fallthru */
-               case 1:
-                       break;
-
-               case 0:
-#ifdef CONFIG_SERIO
-                       if (up->serio_open)
-                               serio_interrupt(&up->serio, ch, 0);
-#endif
-                       break;
-               };
-       }
-}
-
-static struct tty_struct *
-sunzilog_receive_chars(struct uart_sunzilog_port *up,
-                      struct zilog_channel __iomem *channel)
-{
-       struct tty_struct *tty;
-       unsigned char ch, r1, flag;
-
-       tty = NULL;
-       if (up->port.state != NULL &&           /* Unopened serial console */
-           up->port.state->port.tty != NULL)   /* Keyboard || mouse */
-               tty = up->port.state->port.tty;
-
-       for (;;) {
-
-               r1 = read_zsreg(channel, R1);
-               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       writeb(ERR_RES, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-               }
-
-               ch = readb(&channel->control);
-               ZSDELAY();
-
-               /* This funny hack depends upon BRK_ABRT not interfering
-                * with the other bits we care about in R1.
-                */
-               if (ch & BRK_ABRT)
-                       r1 |= BRK_ABRT;
-
-               if (!(ch & Rx_CH_AV))
-                       break;
-
-               ch = readb(&channel->data);
-               ZSDELAY();
-
-               ch &= up->parity_mask;
-
-               if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
-                       sunzilog_kbdms_receive_chars(up, ch, 0);
-                       continue;
-               }
-
-               if (tty == NULL) {
-                       uart_handle_sysrq_char(&up->port, ch);
-                       continue;
-               }
-
-               /* A real serial line, record the character and status.  */
-               flag = TTY_NORMAL;
-               up->port.icount.rx++;
-               if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
-                       if (r1 & BRK_ABRT) {
-                               r1 &= ~(PAR_ERR | CRC_ERR);
-                               up->port.icount.brk++;
-                               if (uart_handle_break(&up->port))
-                                       continue;
-                       }
-                       else if (r1 & PAR_ERR)
-                               up->port.icount.parity++;
-                       else if (r1 & CRC_ERR)
-                               up->port.icount.frame++;
-                       if (r1 & Rx_OVR)
-                               up->port.icount.overrun++;
-                       r1 &= up->port.read_status_mask;
-                       if (r1 & BRK_ABRT)
-                               flag = TTY_BREAK;
-                       else if (r1 & PAR_ERR)
-                               flag = TTY_PARITY;
-                       else if (r1 & CRC_ERR)
-                               flag = TTY_FRAME;
-               }
-               if (uart_handle_sysrq_char(&up->port, ch))
-                       continue;
-
-               if (up->port.ignore_status_mask == 0xff ||
-                   (r1 & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if (r1 & Rx_OVR)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       return tty;
-}
-
-static void sunzilog_status_handle(struct uart_sunzilog_port *up,
-                                  struct zilog_channel __iomem *channel)
-{
-       unsigned char status;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       writeb(RES_EXT_INT, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       if (status & BRK_ABRT) {
-               if (ZS_IS_MOUSE(up))
-                       sunzilog_kbdms_receive_chars(up, 0, 1);
-               if (ZS_IS_CONS(up)) {
-                       /* Wait for BREAK to deassert to avoid potentially
-                        * confusing the PROM.
-                        */
-                       while (1) {
-                               status = readb(&channel->control);
-                               ZSDELAY();
-                               if (!(status & BRK_ABRT))
-                                       break;
-                       }
-                       sun_do_break();
-                       return;
-               }
-       }
-
-       if (ZS_WANTS_MODEM_STATUS(up)) {
-               if (status & SYNC)
-                       up->port.icount.dsr++;
-
-               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
-                * But it does not tell us which bit has changed, we have to keep
-                * track of this ourselves.
-                */
-               if ((status ^ up->prev_status) ^ DCD)
-                       uart_handle_dcd_change(&up->port,
-                                              (status & DCD));
-               if ((status ^ up->prev_status) ^ CTS)
-                       uart_handle_cts_change(&up->port,
-                                              (status & CTS));
-
-               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-       }
-
-       up->prev_status = status;
-}
-
-static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
-                                   struct zilog_channel __iomem *channel)
-{
-       struct circ_buf *xmit;
-
-       if (ZS_IS_CONS(up)) {
-               unsigned char status = readb(&channel->control);
-               ZSDELAY();
-
-               /* TX still busy?  Just wait for the next TX done interrupt.
-                *
-                * It can occur because of how we do serial console writes.  It would
-                * be nice to transmit console writes just like we normally would for
-                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
-                * easy because console writes cannot sleep.  One solution might be
-                * to poll on enough port->xmit space becomming free.  -DaveM
-                */
-               if (!(status & Tx_BUF_EMP))
-                       return;
-       }
-
-       up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE;
-
-       if (ZS_REGS_HELD(up)) {
-               __load_zsregs(channel, up->curregs);
-               up->flags &= ~SUNZILOG_FLAG_REGS_HELD;
-       }
-
-       if (ZS_TX_STOPPED(up)) {
-               up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
-               goto ack_tx_int;
-       }
-
-       if (up->port.x_char) {
-               up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-               writeb(up->port.x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               up->port.icount.tx++;
-               up->port.x_char = 0;
-               return;
-       }
-
-       if (up->port.state == NULL)
-               goto ack_tx_int;
-       xmit = &up->port.state->xmit;
-       if (uart_circ_empty(xmit))
-               goto ack_tx_int;
-
-       if (uart_tx_stopped(&up->port))
-               goto ack_tx_int;
-
-       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-       writeb(xmit->buf[xmit->tail], &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       up->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&up->port);
-
-       return;
-
-ack_tx_int:
-       writeb(RES_Tx_P, &channel->control);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
-{
-       struct uart_sunzilog_port *up = dev_id;
-
-       while (up) {
-               struct zilog_channel __iomem *channel
-                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
-               struct tty_struct *tty;
-               unsigned char r3;
-
-               spin_lock(&up->port.lock);
-               r3 = read_zsreg(channel, R3);
-
-               /* Channel A */
-               tty = NULL;
-               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHARxIP)
-                               tty = sunzilog_receive_chars(up, channel);
-                       if (r3 & CHAEXT)
-                               sunzilog_status_handle(up, channel);
-                       if (r3 & CHATxIP)
-                               sunzilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               /* Channel B */
-               up = up->next;
-               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-               spin_lock(&up->port.lock);
-               tty = NULL;
-               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
-                       writeb(RES_H_IUS, &channel->control);
-                       ZSDELAY();
-                       ZS_WSYNC(channel);
-
-                       if (r3 & CHBRxIP)
-                               tty = sunzilog_receive_chars(up, channel);
-                       if (r3 & CHBEXT)
-                               sunzilog_status_handle(up, channel);
-                       if (r3 & CHBTxIP)
-                               sunzilog_transmit_chars(up, channel);
-               }
-               spin_unlock(&up->port.lock);
-
-               if (tty)
-                       tty_flip_buffer_push(tty);
-
-               up = up->next;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
- * port lock, it is acquired here.
- */
-static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
-{
-       struct zilog_channel __iomem *channel;
-       unsigned char status;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       return status;
-}
-
-/* The port lock is not held.  */
-static unsigned int sunzilog_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned char status;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       status = sunzilog_read_channel_status(port);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (status & Tx_BUF_EMP)
-               ret = TIOCSER_TEMT;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static unsigned int sunzilog_get_mctrl(struct uart_port *port)
-{
-       unsigned char status;
-       unsigned int ret;
-
-       status = sunzilog_read_channel_status(port);
-
-       ret = 0;
-       if (status & DCD)
-               ret |= TIOCM_CAR;
-       if (status & SYNC)
-               ret |= TIOCM_DSR;
-       if (status & CTS)
-               ret |= TIOCM_CTS;
-
-       return ret;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits;
-
-       set_bits = clear_bits = 0;
-
-       if (mctrl & TIOCM_RTS)
-               set_bits |= RTS;
-       else
-               clear_bits |= RTS;
-       if (mctrl & TIOCM_DTR)
-               set_bits |= DTR;
-       else
-               clear_bits |= DTR;
-
-       /* NOTE: Not subject to 'transmitter active' rule.  */ 
-       up->curregs[R5] |= set_bits;
-       up->curregs[R5] &= ~clear_bits;
-       write_zsreg(channel, R5, up->curregs[R5]);
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_stop_tx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-
-       up->flags |= SUNZILOG_FLAG_TX_STOPPED;
-}
-
-/* The port lock is held and interrupts are disabled.  */
-static void sunzilog_start_tx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char status;
-
-       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
-       up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
-
-       status = readb(&channel->control);
-       ZSDELAY();
-
-       /* TX busy?  Just wait for the TX done interrupt.  */
-       if (!(status & Tx_BUF_EMP))
-               return;
-
-       /* Send the first character to jump-start the TX done
-        * IRQ sending engine.
-        */
-       if (port->x_char) {
-               writeb(port->x_char, &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               port->icount.tx++;
-               port->x_char = 0;
-       } else {
-               struct circ_buf *xmit = &port->state->xmit;
-
-               writeb(xmit->buf[xmit->tail], &channel->data);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(&up->port);
-       }
-}
-
-/* The port lock is held.  */
-static void sunzilog_stop_rx(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel __iomem *channel;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable all RX interrupts.  */
-       up->curregs[R1] &= ~RxINT_MASK;
-       sunzilog_maybe_update_regs(up, channel);
-}
-
-/* The port lock is held.  */
-static void sunzilog_enable_ms(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char new_reg;
-
-       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
-       if (new_reg != up->curregs[R15]) {
-               up->curregs[R15] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
-               write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
-       }
-}
-
-/* The port lock is not held.  */
-static void sunzilog_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       unsigned char set_bits, clear_bits, new_reg;
-       unsigned long flags;
-
-       set_bits = clear_bits = 0;
-
-       if (break_state)
-               set_bits |= SND_BRK;
-       else
-               clear_bits |= SND_BRK;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
-       if (new_reg != up->curregs[R5]) {
-               up->curregs[R5] = new_reg;
-
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
-               write_zsreg(channel, R5, up->curregs[R5]);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __sunzilog_startup(struct uart_sunzilog_port *up)
-{
-       struct zilog_channel __iomem *channel;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-       up->prev_status = readb(&channel->control);
-
-       /* Enable receiver and transmitter.  */
-       up->curregs[R3] |= RxENAB;
-       up->curregs[R5] |= TxENAB;
-
-       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-       sunzilog_maybe_update_regs(up, channel);
-}
-
-static int sunzilog_startup(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return 0;
-
-       spin_lock_irqsave(&port->lock, flags);
-       __sunzilog_startup(up);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return 0;
-}
-
-/*
- * The test for ZS_IS_CONS is explained by the following e-mail:
- *****
- * From: Russell King <rmk@arm.linux.org.uk>
- * Date: Sun, 8 Dec 2002 10:18:38 +0000
- *
- * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
- * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
- * > and I noticed that something is not right with reference
- * > counting in this case. It seems that when the console
- * > is open by kernel initially, this is not accounted
- * > as an open, and uart_startup is not called.
- *
- * That is correct.  We are unable to call uart_startup when the serial
- * console is initialised because it may need to allocate memory (as
- * request_irq does) and the memory allocators may not have been
- * initialised.
- *
- * 1. initialise the port into a state where it can send characters in the
- *    console write method.
- *
- * 2. don't do the actual hardware shutdown in your shutdown() method (but
- *    do the normal software shutdown - ie, free irqs etc)
- *****
- */
-static void sunzilog_shutdown(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-       struct zilog_channel __iomem *channel;
-       unsigned long flags;
-
-       if (ZS_IS_CONS(up))
-               return;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       channel = ZILOG_CHANNEL_FROM_PORT(port);
-
-       /* Disable receiver and transmitter.  */
-       up->curregs[R3] &= ~RxENAB;
-       up->curregs[R5] &= ~TxENAB;
-
-       /* Disable all interrupts and BRK assertion.  */
-       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-       up->curregs[R5] &= ~SND_BRK;
-       sunzilog_maybe_update_regs(up, channel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/* Shared by TTY driver and serial console setup.  The port lock is held
- * and local interrupts are disabled.
- */
-static void
-sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
-                      unsigned int iflag, int brg)
-{
-
-       up->curregs[R10] = NRZ;
-       up->curregs[R11] = TCBR | RCBR;
-
-       /* Program BAUD and clock source. */
-       up->curregs[R4] &= ~XCLK_MASK;
-       up->curregs[R4] |= X16CLK;
-       up->curregs[R12] = brg & 0xff;
-       up->curregs[R13] = (brg >> 8) & 0xff;
-       up->curregs[R14] = BRSRC | BRENAB;
-
-       /* Character size, stop bits, and parity. */
-       up->curregs[R3] &= ~RxN_MASK;
-       up->curregs[R5] &= ~TxN_MASK;
-       switch (cflag & CSIZE) {
-       case CS5:
-               up->curregs[R3] |= Rx5;
-               up->curregs[R5] |= Tx5;
-               up->parity_mask = 0x1f;
-               break;
-       case CS6:
-               up->curregs[R3] |= Rx6;
-               up->curregs[R5] |= Tx6;
-               up->parity_mask = 0x3f;
-               break;
-       case CS7:
-               up->curregs[R3] |= Rx7;
-               up->curregs[R5] |= Tx7;
-               up->parity_mask = 0x7f;
-               break;
-       case CS8:
-       default:
-               up->curregs[R3] |= Rx8;
-               up->curregs[R5] |= Tx8;
-               up->parity_mask = 0xff;
-               break;
-       };
-       up->curregs[R4] &= ~0x0c;
-       if (cflag & CSTOPB)
-               up->curregs[R4] |= SB2;
-       else
-               up->curregs[R4] |= SB1;
-       if (cflag & PARENB)
-               up->curregs[R4] |= PAR_ENAB;
-       else
-               up->curregs[R4] &= ~PAR_ENAB;
-       if (!(cflag & PARODD))
-               up->curregs[R4] |= PAR_EVEN;
-       else
-               up->curregs[R4] &= ~PAR_EVEN;
-
-       up->port.read_status_mask = Rx_OVR;
-       if (iflag & INPCK)
-               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
-               up->port.read_status_mask |= BRK_ABRT;
-
-       up->port.ignore_status_mask = 0;
-       if (iflag & IGNPAR)
-               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & IGNBRK) {
-               up->port.ignore_status_mask |= BRK_ABRT;
-               if (iflag & IGNPAR)
-                       up->port.ignore_status_mask |= Rx_OVR;
-       }
-
-       if ((cflag & CREAD) == 0)
-               up->port.ignore_status_mask = 0xff;
-}
-
-/* The port lock is not held.  */
-static void
-sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
-                    struct ktermios *old)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       unsigned long flags;
-       int baud, brg;
-
-       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
-
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-               up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
-       else
-               up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
-
-       up->cflag = termios->c_cflag;
-
-       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static const char *sunzilog_type(struct uart_port *port)
-{
-       struct uart_sunzilog_port *up = UART_ZILOG(port);
-
-       return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
-}
-
-/* We do not request/release mappings of the registers here, this
- * happens at early serial probe time.
- */
-static void sunzilog_release_port(struct uart_port *port)
-{
-}
-
-static int sunzilog_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* These do not need to do anything interesting either.  */
-static void sunzilog_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* We do not support letting the user mess with the divisor, IRQ, etc. */
-static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int sunzilog_get_poll_char(struct uart_port *port)
-{
-       unsigned char ch, r1;
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
-       struct zilog_channel __iomem *channel
-               = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-
-       r1 = read_zsreg(channel, R1);
-       if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-               writeb(ERR_RES, &channel->control);
-               ZSDELAY();
-               ZS_WSYNC(channel);
-       }
-
-       ch = readb(&channel->control);
-       ZSDELAY();
-
-       /* This funny hack depends upon BRK_ABRT not interfering
-        * with the other bits we care about in R1.
-        */
-       if (ch & BRK_ABRT)
-               r1 |= BRK_ABRT;
-
-       if (!(ch & Rx_CH_AV))
-               return NO_POLL_CHAR;
-
-       ch = readb(&channel->data);
-       ZSDELAY();
-
-       ch &= up->parity_mask;
-       return ch;
-}
-
-static void sunzilog_put_poll_char(struct uart_port *port,
-                       unsigned char ch)
-{
-       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
-
-       sunzilog_putchar(&up->port, ch);
-}
-#endif /* CONFIG_CONSOLE_POLL */
-
-static struct uart_ops sunzilog_pops = {
-       .tx_empty       =       sunzilog_tx_empty,
-       .set_mctrl      =       sunzilog_set_mctrl,
-       .get_mctrl      =       sunzilog_get_mctrl,
-       .stop_tx        =       sunzilog_stop_tx,
-       .start_tx       =       sunzilog_start_tx,
-       .stop_rx        =       sunzilog_stop_rx,
-       .enable_ms      =       sunzilog_enable_ms,
-       .break_ctl      =       sunzilog_break_ctl,
-       .startup        =       sunzilog_startup,
-       .shutdown       =       sunzilog_shutdown,
-       .set_termios    =       sunzilog_set_termios,
-       .type           =       sunzilog_type,
-       .release_port   =       sunzilog_release_port,
-       .request_port   =       sunzilog_request_port,
-       .config_port    =       sunzilog_config_port,
-       .verify_port    =       sunzilog_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  =       sunzilog_get_poll_char,
-       .poll_put_char  =       sunzilog_put_poll_char,
-#endif
-};
-
-static int uart_chip_count;
-static struct uart_sunzilog_port *sunzilog_port_table;
-static struct zilog_layout __iomem **sunzilog_chip_regs;
-
-static struct uart_sunzilog_port *sunzilog_irq_chain;
-
-static struct uart_driver sunzilog_reg = {
-       .owner          =       THIS_MODULE,
-       .driver_name    =       "sunzilog",
-       .dev_name       =       "ttyS",
-       .major          =       TTY_MAJOR,
-};
-
-static int __init sunzilog_alloc_tables(int num_sunzilog)
-{
-       struct uart_sunzilog_port *up;
-       unsigned long size;
-       int num_channels = num_sunzilog * 2;
-       int i;
-
-       size = num_channels * sizeof(struct uart_sunzilog_port);
-       sunzilog_port_table = kzalloc(size, GFP_KERNEL);
-       if (!sunzilog_port_table)
-               return -ENOMEM;
-
-       for (i = 0; i < num_channels; i++) {
-               up = &sunzilog_port_table[i];
-
-               spin_lock_init(&up->port.lock);
-
-               if (i == 0)
-                       sunzilog_irq_chain = up;
-
-               if (i < num_channels - 1)
-                       up->next = up + 1;
-               else
-                       up->next = NULL;
-       }
-
-       size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
-       sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
-       if (!sunzilog_chip_regs) {
-               kfree(sunzilog_port_table);
-               sunzilog_irq_chain = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void sunzilog_free_tables(void)
-{
-       kfree(sunzilog_port_table);
-       sunzilog_irq_chain = NULL;
-       kfree(sunzilog_chip_regs);
-}
-
-#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
-
-static void sunzilog_putchar(struct uart_port *port, int ch)
-{
-       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
-       int loops = ZS_PUT_CHAR_MAX_DELAY;
-
-       /* This is a timed polling loop so do not switch the explicit
-        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
-        */
-       do {
-               unsigned char val = readb(&channel->control);
-               if (val & Tx_BUF_EMP) {
-                       ZSDELAY();
-                       break;
-               }
-               udelay(5);
-       } while (--loops);
-
-       writeb(ch, &channel->data);
-       ZSDELAY();
-       ZS_WSYNC(channel);
-}
-
-#ifdef CONFIG_SERIO
-
-static DEFINE_SPINLOCK(sunzilog_serio_lock);
-
-static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-
-       sunzilog_putchar(&up->port, ch);
-
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-
-       return 0;
-}
-
-static int sunzilog_serio_open(struct serio *serio)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-       if (!up->serio_open) {
-               up->serio_open = 1;
-               ret = 0;
-       } else
-               ret = -EBUSY;
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-
-       return ret;
-}
-
-static void sunzilog_serio_close(struct serio *serio)
-{
-       struct uart_sunzilog_port *up = serio->port_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sunzilog_serio_lock, flags);
-       up->serio_open = 0;
-       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
-}
-
-#endif /* CONFIG_SERIO */
-
-#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE
-static void
-sunzilog_console_write(struct console *con, const char *s, unsigned int count)
-{
-       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
-       unsigned long flags;
-       int locked = 1;
-
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
-
-       uart_console_write(&up->port, s, count, sunzilog_putchar);
-       udelay(2);
-
-       if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
-}
-
-static int __init sunzilog_console_setup(struct console *con, char *options)
-{
-       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
-       unsigned long flags;
-       int baud, brg;
-
-       if (up->port.type != PORT_SUNZILOG)
-               return -1;
-
-       printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
-              (sunzilog_reg.minor - 64) + con->index, con->index);
-
-       /* Get firmware console settings.  */
-       sunserial_console_termios(con, up->port.dev->of_node);
-
-       /* Firmware console speed is limited to 150-->38400 baud so
-        * this hackish cflag thing is OK.
-        */
-       switch (con->cflag & CBAUD) {
-       case B150: baud = 150; break;
-       case B300: baud = 300; break;
-       case B600: baud = 600; break;
-       case B1200: baud = 1200; break;
-       case B2400: baud = 2400; break;
-       case B4800: baud = 4800; break;
-       default: case B9600: baud = 9600; break;
-       case B19200: baud = 19200; break;
-       case B38400: baud = 38400; break;
-       };
-
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-
-       up->curregs[R15] |= BRKIE;
-       sunzilog_convert_to_zs(up, con->cflag, 0, brg);
-
-       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-       __sunzilog_startup(up);
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-       return 0;
-}
-
-static struct console sunzilog_console_ops = {
-       .name   =       "ttyS",
-       .write  =       sunzilog_console_write,
-       .device =       uart_console_device,
-       .setup  =       sunzilog_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sunzilog_reg,
-};
-
-static inline struct console *SUNZILOG_CONSOLE(void)
-{
-       return &sunzilog_console_ops;
-}
-
-#else
-#define SUNZILOG_CONSOLE()     (NULL)
-#endif
-
-static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
-{
-       int baud, brg;
-
-       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
-               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
-               baud = 1200;
-       } else {
-               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
-               baud = 4800;
-       }
-
-       up->curregs[R15] |= BRKIE;
-       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-       sunzilog_convert_to_zs(up, up->cflag, 0, brg);
-       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
-       __sunzilog_startup(up);
-}
-
-#ifdef CONFIG_SERIO
-static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
-{
-       struct serio *serio = &up->serio;
-
-       serio->port_data = up;
-
-       serio->id.type = SERIO_RS232;
-       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
-               serio->id.proto = SERIO_SUNKBD;
-               strlcpy(serio->name, "zskbd", sizeof(serio->name));
-       } else {
-               serio->id.proto = SERIO_SUN;
-               serio->id.extra = 1;
-               strlcpy(serio->name, "zsms", sizeof(serio->name));
-       }
-       strlcpy(serio->phys,
-               ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
-                "zs/serio0" : "zs/serio1"),
-               sizeof(serio->phys));
-
-       serio->write = sunzilog_serio_write;
-       serio->open = sunzilog_serio_open;
-       serio->close = sunzilog_serio_close;
-       serio->dev.parent = up->port.dev;
-
-       serio_register_port(serio);
-}
-#endif
-
-static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
-{
-       struct zilog_channel __iomem *channel;
-       unsigned long flags;
-       int baud, brg;
-
-       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-
-       spin_lock_irqsave(&up->port.lock, flags);
-       if (ZS_IS_CHANNEL_A(up)) {
-               write_zsreg(channel, R9, FHWRES);
-               ZSDELAY_LONG();
-               (void) read_zsreg(channel, R0);
-       }
-
-       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
-                        SUNZILOG_FLAG_CONS_MOUSE)) {
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R6] = 0x00; /* SDLC Address */
-               up->curregs[R7] = 0x7E; /* SDLC Flag    */
-               up->curregs[R9] = NV;
-               up->curregs[R7p] = 0x00;
-               sunzilog_init_kbdms(up);
-               /* Only enable interrupts if an ISR handler available */
-               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
-                       up->curregs[R9] |= MIE;
-               write_zsreg(channel, R9, up->curregs[R9]);
-       } else {
-               /* Normal serial TTY. */
-               up->parity_mask = 0xff;
-               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
-               up->curregs[R3] = RxENAB | Rx8;
-               up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R6] = 0x00; /* SDLC Address */
-               up->curregs[R7] = 0x7E; /* SDLC Flag    */
-               up->curregs[R9] = NV;
-               up->curregs[R10] = NRZ;
-               up->curregs[R11] = TCBR | RCBR;
-               baud = 9600;
-               brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
-               up->curregs[R12] = (brg & 0xff);
-               up->curregs[R13] = (brg >> 8) & 0xff;
-               up->curregs[R14] = BRSRC | BRENAB;
-               up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
-               up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
-               if (__load_zsregs(channel, up->curregs)) {
-                       up->flags |= SUNZILOG_FLAG_ESCC;
-               }
-               /* Only enable interrupts if an ISR handler available */
-               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
-                       up->curregs[R9] |= MIE;
-               write_zsreg(channel, R9, up->curregs[R9]);
-       }
-
-       spin_unlock_irqrestore(&up->port.lock, flags);
-
-#ifdef CONFIG_SERIO
-       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
-                        SUNZILOG_FLAG_CONS_MOUSE))
-               sunzilog_register_serio(up);
-#endif
-}
-
-static int zilog_irq = -1;
-
-static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       static int kbm_inst, uart_inst;
-       int inst;
-       struct uart_sunzilog_port *up;
-       struct zilog_layout __iomem *rp;
-       int keyboard_mouse = 0;
-       int err;
-
-       if (of_find_property(op->dev.of_node, "keyboard", NULL))
-               keyboard_mouse = 1;
-
-       /* uarts must come before keyboards/mice */
-       if (keyboard_mouse)
-               inst = uart_chip_count + kbm_inst;
-       else
-               inst = uart_inst;
-
-       sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
-                                             sizeof(struct zilog_layout),
-                                             "zs");
-       if (!sunzilog_chip_regs[inst])
-               return -ENOMEM;
-
-       rp = sunzilog_chip_regs[inst];
-
-       if (zilog_irq == -1)
-               zilog_irq = op->archdata.irqs[0];
-
-       up = &sunzilog_port_table[inst * 2];
-
-       /* Channel A */
-       up[0].port.mapbase = op->resource[0].start + 0x00;
-       up[0].port.membase = (void __iomem *) &rp->channelA;
-       up[0].port.iotype = UPIO_MEM;
-       up[0].port.irq = op->archdata.irqs[0];
-       up[0].port.uartclk = ZS_CLOCK;
-       up[0].port.fifosize = 1;
-       up[0].port.ops = &sunzilog_pops;
-       up[0].port.type = PORT_SUNZILOG;
-       up[0].port.flags = 0;
-       up[0].port.line = (inst * 2) + 0;
-       up[0].port.dev = &op->dev;
-       up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
-       if (keyboard_mouse)
-               up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
-       sunzilog_init_hw(&up[0]);
-
-       /* Channel B */
-       up[1].port.mapbase = op->resource[0].start + 0x04;
-       up[1].port.membase = (void __iomem *) &rp->channelB;
-       up[1].port.iotype = UPIO_MEM;
-       up[1].port.irq = op->archdata.irqs[0];
-       up[1].port.uartclk = ZS_CLOCK;
-       up[1].port.fifosize = 1;
-       up[1].port.ops = &sunzilog_pops;
-       up[1].port.type = PORT_SUNZILOG;
-       up[1].port.flags = 0;
-       up[1].port.line = (inst * 2) + 1;
-       up[1].port.dev = &op->dev;
-       up[1].flags |= 0;
-       if (keyboard_mouse)
-               up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
-       sunzilog_init_hw(&up[1]);
-
-       if (!keyboard_mouse) {
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
-                                           &sunzilog_reg, up[0].port.line,
-                                           false))
-                       up->flags |= SUNZILOG_FLAG_IS_CONS;
-               err = uart_add_one_port(&sunzilog_reg, &up[0].port);
-               if (err) {
-                       of_iounmap(&op->resource[0],
-                                  rp, sizeof(struct zilog_layout));
-                       return err;
-               }
-               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
-                                           &sunzilog_reg, up[1].port.line,
-                                           false))
-                       up->flags |= SUNZILOG_FLAG_IS_CONS;
-               err = uart_add_one_port(&sunzilog_reg, &up[1].port);
-               if (err) {
-                       uart_remove_one_port(&sunzilog_reg, &up[0].port);
-                       of_iounmap(&op->resource[0],
-                                  rp, sizeof(struct zilog_layout));
-                       return err;
-               }
-               uart_inst++;
-       } else {
-               printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
-                      "is a %s\n",
-                      dev_name(&op->dev),
-                      (unsigned long long) up[0].port.mapbase,
-                      op->archdata.irqs[0], sunzilog_type(&up[0].port));
-               printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
-                      "is a %s\n",
-                      dev_name(&op->dev),
-                      (unsigned long long) up[1].port.mapbase,
-                      op->archdata.irqs[0], sunzilog_type(&up[1].port));
-               kbm_inst++;
-       }
-
-       dev_set_drvdata(&op->dev, &up[0]);
-
-       return 0;
-}
-
-static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
-{
-       if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
-#ifdef CONFIG_SERIO
-               serio_unregister_port(&up->serio);
-#endif
-       } else
-               uart_remove_one_port(&sunzilog_reg, &up->port);
-}
-
-static int __devexit zs_remove(struct platform_device *op)
-{
-       struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
-       struct zilog_layout __iomem *regs;
-
-       zs_remove_one(&up[0]);
-       zs_remove_one(&up[1]);
-
-       regs = sunzilog_chip_regs[up[0].port.line / 2];
-       of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
-
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id zs_match[] = {
-       {
-               .name = "zs",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, zs_match);
-
-static struct of_platform_driver zs_driver = {
-       .driver = {
-               .name = "zs",
-               .owner = THIS_MODULE,
-               .of_match_table = zs_match,
-       },
-       .probe          = zs_probe,
-       .remove         = __devexit_p(zs_remove),
-};
-
-static int __init sunzilog_init(void)
-{
-       struct device_node *dp;
-       int err;
-       int num_keybms = 0;
-       int num_sunzilog = 0;
-
-       for_each_node_by_name(dp, "zs") {
-               num_sunzilog++;
-               if (of_find_property(dp, "keyboard", NULL))
-                       num_keybms++;
-       }
-
-       if (num_sunzilog) {
-               err = sunzilog_alloc_tables(num_sunzilog);
-               if (err)
-                       goto out;
-
-               uart_chip_count = num_sunzilog - num_keybms;
-
-               err = sunserial_register_minors(&sunzilog_reg,
-                                               uart_chip_count * 2);
-               if (err)
-                       goto out_free_tables;
-       }
-
-       err = of_register_platform_driver(&zs_driver);
-       if (err)
-               goto out_unregister_uart;
-
-       if (zilog_irq != -1) {
-               struct uart_sunzilog_port *up = sunzilog_irq_chain;
-               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
-                                 "zs", sunzilog_irq_chain);
-               if (err)
-                       goto out_unregister_driver;
-
-               /* Enable Interrupts */
-               while (up) {
-                       struct zilog_channel __iomem *channel;
-
-                       /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
-                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
-                       up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
-                       up->curregs[R9] |= MIE;
-                       write_zsreg(channel, R9, up->curregs[R9]);
-                       up = up->next;
-               }
-       }
-
-out:
-       return err;
-
-out_unregister_driver:
-       of_unregister_platform_driver(&zs_driver);
-
-out_unregister_uart:
-       if (num_sunzilog) {
-               sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
-               sunzilog_reg.cons = NULL;
-       }
-
-out_free_tables:
-       sunzilog_free_tables();
-       goto out;
-}
-
-static void __exit sunzilog_exit(void)
-{
-       of_unregister_platform_driver(&zs_driver);
-
-       if (zilog_irq != -1) {
-               struct uart_sunzilog_port *up = sunzilog_irq_chain;
-
-               /* Disable Interrupts */
-               while (up) {
-                       struct zilog_channel __iomem *channel;
-
-                       /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
-                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
-                       up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
-                       up->curregs[R9] &= ~MIE;
-                       write_zsreg(channel, R9, up->curregs[R9]);
-                       up = up->next;
-               }
-
-               free_irq(zilog_irq, sunzilog_irq_chain);
-               zilog_irq = -1;
-       }
-
-       if (sunzilog_reg.nr) {
-               sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
-               sunzilog_free_tables();
-       }
-}
-
-module_init(sunzilog_init);
-module_exit(sunzilog_exit);
-
-MODULE_AUTHOR("David S. Miller");
-MODULE_DESCRIPTION("Sun Zilog serial port driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h
deleted file mode 100644 (file)
index 5dec7b4..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#ifndef _SUNZILOG_H
-#define _SUNZILOG_H
-
-struct zilog_channel {
-       volatile unsigned char control;
-       volatile unsigned char __pad1;
-       volatile unsigned char data;
-       volatile unsigned char __pad2;
-};
-
-struct zilog_layout {
-       struct zilog_channel channelB;
-       struct zilog_channel channelA;
-};
-
-#define        NUM_ZSREGS      17
-#define        R7p             16 /* Written as R7 with P15 bit 0 set */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define        FLAG    0x7e
-
-/* Write Register 0 */
-#define        R0      0               /* Register selects */
-#define        R1      1
-#define        R2      2
-#define        R3      3
-#define        R4      4
-#define        R5      5
-#define        R6      6
-#define        R7      7
-#define        R8      8
-#define        R9      9
-#define        R10     10
-#define        R11     11
-#define        R12     12
-#define        R13     13
-#define        R14     14
-#define        R15     15
-
-#define        NULLCODE        0       /* Null Code */
-#define        POINT_HIGH      0x8     /* Select upper half of registers */
-#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
-#define        SEND_ABORT      0x18    /* HDLC Abort */
-#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
-#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
-#define        ERR_RES         0x30    /* Error Reset */
-#define        RES_H_IUS       0x38    /* Reset highest IUS */
-
-#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
-#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
-#define        RES_EOM_L       0xC0    /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
-#define        TxINT_ENAB      0x2     /* Tx Int Enable */
-#define        PAR_SPEC        0x4     /* Parity is special condition */
-
-#define        RxINT_DISAB     0       /* Rx Int Disable */
-#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define        RxENAB          0x1     /* Rx Enable */
-#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
-#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
-#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
-#define        ENT_HM          0x10    /* Enter Hunt Mode */
-#define        AUTO_ENAB       0x20    /* Auto Enables */
-#define        Rx5             0x0     /* Rx 5 Bits/Character */
-#define        Rx7             0x40    /* Rx 7 Bits/Character */
-#define        Rx6             0x80    /* Rx 6 Bits/Character */
-#define        Rx8             0xc0    /* Rx 8 Bits/Character */
-#define RxN_MASK       0xc0
-
-/* Write Register 4 */
-
-#define        PAR_ENAB        0x1     /* Parity Enable */
-#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
-
-#define        SYNC_ENAB       0       /* Sync Modes Enable */
-#define        SB1             0x4     /* 1 stop bit/char */
-#define        SB15            0x8     /* 1.5 stop bits/char */
-#define        SB2             0xc     /* 2 stop bits/char */
-
-#define        MONSYNC         0       /* 8 Bit Sync character */
-#define        BISYNC          0x10    /* 16 bit sync character */
-#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define        EXTSYNC         0x30    /* External Sync Mode */
-
-#define        X1CLK           0x0     /* x1 clock mode */
-#define        X16CLK          0x40    /* x16 clock mode */
-#define        X32CLK          0x80    /* x32 clock mode */
-#define        X64CLK          0xC0    /* x64 clock mode */
-#define XCLK_MASK      0xC0
-
-/* Write Register 5 */
-
-#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
-#define        RTS             0x2     /* RTS */
-#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
-#define        TxENAB          0x8     /* Tx Enable */
-#define        SND_BRK         0x10    /* Send Break */
-#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
-#define        Tx7             0x20    /* Tx 7 bits/character */
-#define        Tx6             0x40    /* Tx 6 bits/character */
-#define        Tx8             0x60    /* Tx 8 bits/character */
-#define TxN_MASK       0x60
-#define        DTR             0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (ESCC Only) */
-#define        AUTO_TxFLAG     1       /* Automatic Tx SDLC Flag */
-#define        AUTO_EOM_RST    2       /* Automatic EOM Reset */
-#define        AUTOnRTS        4       /* Automatic /RTS pin deactivation */
-#define        RxFIFO_LVL      8       /* Receive FIFO interrupt level */
-#define        nDTRnREQ        0x10    /* /DTR/REQ timing */
-#define        TxFIFO_LVL      0x20    /* Transmit FIFO interrupt level */
-#define        EXT_RD_EN       0x40    /* Extended read register enable */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define        VIS     1       /* Vector Includes Status */
-#define        NV      2       /* No Vector */
-#define        DLC     4       /* Disable Lower Chain */
-#define        MIE     8       /* Master Interrupt Enable */
-#define        STATHI  0x10    /* Status high */
-#define        SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
-#define        NORESET 0       /* No reset on write to R9 */
-#define        CHRB    0x40    /* Reset channel B */
-#define        CHRA    0x80    /* Reset channel A */
-#define        FHWRES  0xc0    /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define        BIT6    1       /* 6 bit/8bit sync */
-#define        LOOPMODE 2      /* SDLC Loop mode */
-#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
-#define        MARKIDLE 8      /* Mark/flag on idle */
-#define        GAOP    0x10    /* Go active on poll */
-#define        NRZ     0       /* NRZ mode */
-#define        NRZI    0x20    /* NRZI mode */
-#define        FM1     0x40    /* FM1 (transition = 1) */
-#define        FM0     0x60    /* FM0 (transition = 0) */
-#define        CRCPS   0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define        TRxCXT  0       /* TRxC = Xtal output */
-#define        TRxCTC  1       /* TRxC = Transmit clock */
-#define        TRxCBR  2       /* TRxC = BR Generator Output */
-#define        TRxCDP  3       /* TRxC = DPLL output */
-#define        TRxCOI  4       /* TRxC O/I */
-#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
-#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
-#define        TCBR    0x10    /* Transmit clock = BR Generator output */
-#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
-#define        RCRTxCP 0       /* Receive clock = RTxC pin */
-#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
-#define        RCBR    0x40    /* Receive clock = BR Generator output */
-#define        RCDPLL  0x60    /* Receive clock = DPLL output */
-#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define        BRENAB  1       /* Baud rate generator enable */
-#define        BRSRC   2       /* Baud rate generator source */
-#define        DTRREQ  4       /* DTR/Request function */
-#define        AUTOECHO 8      /* Auto Echo */
-#define        LOOPBAK 0x10    /* Local loopback */
-#define        SEARCH  0x20    /* Enter search mode */
-#define        RMC     0x40    /* Reset missing clock */
-#define        DISDPLL 0x60    /* Disable DPLL */
-#define        SSBR    0x80    /* Set DPLL source = BR generator */
-#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
-#define        SFMM    0xc0    /* Set FM mode */
-#define        SNRZI   0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define        WR7pEN  1       /* WR7' Enable (ESCC only) */
-#define        ZCIE    2       /* Zero count IE */
-#define        FIFOEN  4       /* FIFO Enable (ESCC only) */
-#define        DCDIE   8       /* DCD IE */
-#define        SYNCIE  0x10    /* Sync/hunt IE */
-#define        CTSIE   0x20    /* CTS IE */
-#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
-#define        BRKIE   0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define        Rx_CH_AV        0x1     /* Rx Character Available */
-#define        ZCOUNT          0x2     /* Zero count */
-#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
-#define        DCD             0x8     /* DCD */
-#define        SYNC            0x10    /* Sync/hunt */
-#define        CTS             0x20    /* CTS */
-#define        TxEOM           0x40    /* Tx underrun */
-#define        BRK_ABRT        0x80    /* Break/Abort */
-
-/* Read Register 1 */
-#define        ALL_SNT         0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define        RES3            0x8     /* 0/3 */
-#define        RES4            0x4     /* 0/4 */
-#define        RES5            0xc     /* 0/5 */
-#define        RES6            0x2     /* 0/6 */
-#define        RES7            0xa     /* 0/7 */
-#define        RES8            0x6     /* 0/8 */
-#define        RES18           0xe     /* 1/8 */
-#define        RES28           0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define        PAR_ERR         0x10    /* Parity error */
-#define        Rx_OVR          0x20    /* Rx Overrun Error */
-#define        CRC_ERR         0x40    /* CRC/Framing Error */
-#define        END_FR          0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY   0x00
-#define CHB_EXT_STAT   0x02
-#define CHB_Rx_AVAIL   0x04
-#define CHB_SPECIAL    0x06
-#define CHA_Tx_EMPTY   0x08
-#define CHA_EXT_STAT   0x0a
-#define CHA_Rx_AVAIL   0x0c
-#define CHA_SPECIAL    0x0e
-#define STATUS_MASK    0x0e
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
-#define        CHBTxIP 0x2             /* Channel B Tx IP */
-#define        CHBRxIP 0x4             /* Channel B Rx IP */
-#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
-#define        CHATxIP 0x10            /* Channel A Tx IP */
-#define        CHARxIP 0x20            /* Channel A Rx IP */
-
-/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
-
-/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define        ONLOOP  2               /* On loop */
-#define        LOOPSEND 0x10           /* Loop sending */
-#define        CLK2MIS 0x40            /* Two clocks missing */
-#define        CLK1MIS 0x80            /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    do { sbus_writeb(ERR_RES, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARSTAT(channel)   do { sbus_writeb(RES_EXT_INT, &channel->control); \
-                                    udelay(5); } while(0)
-
-#define ZS_CLEARFIFO(channel)   do { sbus_readb(&channel->data); \
-                                    udelay(2); \
-                                    sbus_readb(&channel->data); \
-                                    udelay(2); \
-                                    sbus_readb(&channel->data); \
-                                    udelay(2); } while(0)
-
-#endif /* _SUNZILOG_H */
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c
deleted file mode 100644 (file)
index 1f36b7e..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * timbuart.c timberdale FPGA UART driver
- * Copyright (c) 2009 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.
- */
-
-/* Supports:
- * Timberdale FPGA UART
- */
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/serial_core.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-
-#include "timbuart.h"
-
-struct timbuart_port {
-       struct uart_port        port;
-       struct tasklet_struct   tasklet;
-       int                     usedma;
-       u32                     last_ier;
-       struct platform_device  *dev;
-};
-
-static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
-       921600, 1843200, 3250000};
-
-static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
-
-static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
-
-static void timbuart_stop_rx(struct uart_port *port)
-{
-       /* spin lock held by upper layer, disable all RX interrupts */
-       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
-       iowrite32(ier, port->membase + TIMBUART_IER);
-}
-
-static void timbuart_stop_tx(struct uart_port *port)
-{
-       /* spinlock held by upper layer, disable TX interrupt */
-       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
-       iowrite32(ier, port->membase + TIMBUART_IER);
-}
-
-static void timbuart_start_tx(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-
-       /* do not transfer anything here -> fire off the tasklet */
-       tasklet_schedule(&uart->tasklet);
-}
-
-static unsigned int timbuart_tx_empty(struct uart_port *port)
-{
-       u32 isr = ioread32(port->membase + TIMBUART_ISR);
-
-       return (isr & TXBE) ? TIOCSER_TEMT : 0;
-}
-
-static void timbuart_flush_buffer(struct uart_port *port)
-{
-       if (!timbuart_tx_empty(port)) {
-               u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
-                       TIMBUART_CTRL_FLSHTX;
-
-               iowrite8(ctl, port->membase + TIMBUART_CTRL);
-               iowrite32(TXBF, port->membase + TIMBUART_ISR);
-       }
-}
-
-static void timbuart_rx_chars(struct uart_port *port)
-{
-       struct tty_struct *tty = port->state->port.tty;
-
-       while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
-               u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
-               port->icount.rx++;
-               tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(port->state->port.tty);
-       spin_lock(&port->lock);
-
-       dev_dbg(port->dev, "%s - total read %d bytes\n",
-               __func__, port->icount.rx);
-}
-
-static void timbuart_tx_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
-               !uart_circ_empty(xmit)) {
-               iowrite8(xmit->buf[xmit->tail],
-                       port->membase + TIMBUART_TXFIFO);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       dev_dbg(port->dev,
-               "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
-                __func__,
-               port->icount.tx,
-               ioread8(port->membase + TIMBUART_CTRL),
-               port->mctrl & TIOCM_RTS,
-               ioread8(port->membase + TIMBUART_BAUDRATE));
-}
-
-static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
-
-       if (port->x_char)
-               return;
-
-       if (isr & TXFLAGS) {
-               timbuart_tx_chars(port);
-               /* clear all TX interrupts */
-               iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
-
-               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                       uart_write_wakeup(port);
-       } else
-               /* Re-enable any tx interrupt */
-               *ier |= uart->last_ier & TXFLAGS;
-
-       /* enable interrupts if there are chars in the transmit buffer,
-        * Or if we delivered some bytes and want the almost empty interrupt
-        * we wake up the upper layer later when we got the interrupt
-        * to give it some time to go out...
-        */
-       if (!uart_circ_empty(xmit))
-               *ier |= TXBAE;
-
-       dev_dbg(port->dev, "%s - leaving\n", __func__);
-}
-
-void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
-{
-       if (isr & RXFLAGS) {
-               /* Some RX status is set */
-               if (isr & RXBF) {
-                       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
-                               TIMBUART_CTRL_FLSHRX;
-                       iowrite8(ctl, port->membase + TIMBUART_CTRL);
-                       port->icount.overrun++;
-               } else if (isr & (RXDP))
-                       timbuart_rx_chars(port);
-
-               /* ack all RX interrupts */
-               iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
-       }
-
-       /* always have the RX interrupts enabled */
-       *ier |= RXBAF | RXBF | RXTT;
-
-       dev_dbg(port->dev, "%s - leaving\n", __func__);
-}
-
-void timbuart_tasklet(unsigned long arg)
-{
-       struct timbuart_port *uart = (struct timbuart_port *)arg;
-       u32 isr, ier = 0;
-
-       spin_lock(&uart->port.lock);
-
-       isr = ioread32(uart->port.membase + TIMBUART_ISR);
-       dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
-
-       if (!uart->usedma)
-               timbuart_handle_tx_port(&uart->port, isr, &ier);
-
-       timbuart_mctrl_check(&uart->port, isr, &ier);
-
-       if (!uart->usedma)
-               timbuart_handle_rx_port(&uart->port, isr, &ier);
-
-       iowrite32(ier, uart->port.membase + TIMBUART_IER);
-
-       spin_unlock(&uart->port.lock);
-       dev_dbg(uart->port.dev, "%s leaving\n", __func__);
-}
-
-static unsigned int timbuart_get_mctrl(struct uart_port *port)
-{
-       u8 cts = ioread8(port->membase + TIMBUART_CTRL);
-       dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
-
-       if (cts & TIMBUART_CTRL_CTS)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-       else
-               return TIOCM_DSR | TIOCM_CAR;
-}
-
-static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
-
-       if (mctrl & TIOCM_RTS)
-               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
-       else
-               iowrite8(0, port->membase + TIMBUART_CTRL);
-}
-
-static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
-{
-       unsigned int cts;
-
-       if (isr & CTS_DELTA) {
-               /* ack */
-               iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
-               cts = timbuart_get_mctrl(port);
-               uart_handle_cts_change(port, cts & TIOCM_CTS);
-               wake_up_interruptible(&port->state->port.delta_msr_wait);
-       }
-
-       *ier |= CTS_DELTA;
-}
-
-static void timbuart_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void timbuart_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static int timbuart_startup(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-
-       dev_dbg(port->dev, "%s\n", __func__);
-
-       iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
-       iowrite32(0x1ff, port->membase + TIMBUART_ISR);
-       /* Enable all but TX interrupts */
-       iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
-               port->membase + TIMBUART_IER);
-
-       return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
-               "timb-uart", uart);
-}
-
-static void timbuart_shutdown(struct uart_port *port)
-{
-       struct timbuart_port *uart =
-               container_of(port, struct timbuart_port, port);
-       dev_dbg(port->dev, "%s\n", __func__);
-       free_irq(port->irq, uart);
-       iowrite32(0, port->membase + TIMBUART_IER);
-}
-
-static int get_bindex(int baud)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(baudrates); i++)
-               if (baud <= baudrates[i])
-                       return i;
-
-       return -1;
-}
-
-static void timbuart_set_termios(struct uart_port *port,
-       struct ktermios *termios,
-       struct ktermios *old)
-{
-       unsigned int baud;
-       short bindex;
-       unsigned long flags;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       bindex = get_bindex(baud);
-       dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
-
-       if (bindex < 0)
-               bindex = 0;
-       baud = baudrates[bindex];
-
-       /* The serial layer calls into this once with old = NULL when setting
-          up initially */
-       if (old)
-               tty_termios_copy_hw(termios, old);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-
-       spin_lock_irqsave(&port->lock, flags);
-       iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
-       uart_update_timeout(port, termios->c_cflag, baud);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *timbuart_type(struct uart_port *port)
-{
-       return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
-}
-
-/* We do not request/release mappings of the registers here,
- * currently it's done in the proble function.
- */
-static void timbuart_release_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size =
-               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       release_mem_region(port->mapbase, size);
-}
-
-static int timbuart_request_port(struct uart_port *port)
-{
-       struct platform_device *pdev = to_platform_device(port->dev);
-       int size =
-               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
-
-       if (!request_mem_region(port->mapbase, size, "timb-uart"))
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_mem_region(port->mapbase, size);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
-{
-       struct timbuart_port *uart = (struct timbuart_port *)devid;
-
-       if (ioread8(uart->port.membase + TIMBUART_IPR)) {
-               uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
-
-               /* disable interrupts, the tasklet enables them again */
-               iowrite32(0, uart->port.membase + TIMBUART_IER);
-
-               /* fire off bottom half */
-               tasklet_schedule(&uart->tasklet);
-
-               return IRQ_HANDLED;
-       } else
-               return IRQ_NONE;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void timbuart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_TIMBUART;
-               timbuart_request_port(port);
-       }
-}
-
-static int timbuart_verify_port(struct uart_port *port,
-       struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-static struct uart_ops timbuart_ops = {
-       .tx_empty = timbuart_tx_empty,
-       .set_mctrl = timbuart_set_mctrl,
-       .get_mctrl = timbuart_get_mctrl,
-       .stop_tx = timbuart_stop_tx,
-       .start_tx = timbuart_start_tx,
-       .flush_buffer = timbuart_flush_buffer,
-       .stop_rx = timbuart_stop_rx,
-       .enable_ms = timbuart_enable_ms,
-       .break_ctl = timbuart_break_ctl,
-       .startup = timbuart_startup,
-       .shutdown = timbuart_shutdown,
-       .set_termios = timbuart_set_termios,
-       .type = timbuart_type,
-       .release_port = timbuart_release_port,
-       .request_port = timbuart_request_port,
-       .config_port = timbuart_config_port,
-       .verify_port = timbuart_verify_port
-};
-
-static struct uart_driver timbuart_driver = {
-       .owner = THIS_MODULE,
-       .driver_name = "timberdale_uart",
-       .dev_name = "ttyTU",
-       .major = TIMBUART_MAJOR,
-       .minor = TIMBUART_MINOR,
-       .nr = 1
-};
-
-static int __devinit timbuart_probe(struct platform_device *dev)
-{
-       int err, irq;
-       struct timbuart_port *uart;
-       struct resource *iomem;
-
-       dev_dbg(&dev->dev, "%s\n", __func__);
-
-       uart = kzalloc(sizeof(*uart), GFP_KERNEL);
-       if (!uart) {
-               err = -EINVAL;
-               goto err_mem;
-       }
-
-       uart->usedma = 0;
-
-       uart->port.uartclk = 3250000 * 16;
-       uart->port.fifosize  = TIMBUART_FIFO_SIZE;
-       uart->port.regshift  = 2;
-       uart->port.iotype  = UPIO_MEM;
-       uart->port.ops = &timbuart_ops;
-       uart->port.irq = 0;
-       uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
-       uart->port.line  = 0;
-       uart->port.dev  = &dev->dev;
-
-       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!iomem) {
-               err = -ENOMEM;
-               goto err_register;
-       }
-       uart->port.mapbase = iomem->start;
-       uart->port.membase = NULL;
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0) {
-               err = -EINVAL;
-               goto err_register;
-       }
-       uart->port.irq = irq;
-
-       tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
-
-       err = uart_register_driver(&timbuart_driver);
-       if (err)
-               goto err_register;
-
-       err = uart_add_one_port(&timbuart_driver, &uart->port);
-       if (err)
-               goto err_add_port;
-
-       platform_set_drvdata(dev, uart);
-
-       return 0;
-
-err_add_port:
-       uart_unregister_driver(&timbuart_driver);
-err_register:
-       kfree(uart);
-err_mem:
-       printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
-               err);
-
-       return err;
-}
-
-static int __devexit timbuart_remove(struct platform_device *dev)
-{
-       struct timbuart_port *uart = platform_get_drvdata(dev);
-
-       tasklet_kill(&uart->tasklet);
-       uart_remove_one_port(&timbuart_driver, &uart->port);
-       uart_unregister_driver(&timbuart_driver);
-       kfree(uart);
-
-       return 0;
-}
-
-static struct platform_driver timbuart_platform_driver = {
-       .driver = {
-               .name   = "timb-uart",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = timbuart_probe,
-       .remove         = __devexit_p(timbuart_remove),
-};
-
-/*--------------------------------------------------------------------------*/
-
-static int __init timbuart_init(void)
-{
-       return platform_driver_register(&timbuart_platform_driver);
-}
-
-static void __exit timbuart_exit(void)
-{
-       platform_driver_unregister(&timbuart_platform_driver);
-}
-
-module_init(timbuart_init);
-module_exit(timbuart_exit);
-
-MODULE_DESCRIPTION("Timberdale UART driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:timb-uart");
-
diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h
deleted file mode 100644 (file)
index 7e56676..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * timbuart.c timberdale FPGA GPIO driver
- * Copyright (c) 2009 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.
- */
-
-/* Supports:
- * Timberdale FPGA UART
- */
-
-#ifndef _TIMBUART_H
-#define _TIMBUART_H
-
-#define TIMBUART_FIFO_SIZE     2048
-
-#define TIMBUART_RXFIFO                0x08
-#define TIMBUART_TXFIFO                0x0c
-#define TIMBUART_IER           0x10
-#define TIMBUART_IPR           0x14
-#define TIMBUART_ISR           0x18
-#define TIMBUART_CTRL          0x1c
-#define TIMBUART_BAUDRATE      0x20
-
-#define TIMBUART_CTRL_RTS      0x01
-#define TIMBUART_CTRL_CTS      0x02
-#define TIMBUART_CTRL_FLSHTX   0x40
-#define TIMBUART_CTRL_FLSHRX   0x80
-
-#define TXBF           0x01
-#define TXBAE          0x02
-#define CTS_DELTA      0x04
-#define RXDP           0x08
-#define RXBAF          0x10
-#define RXBF           0x20
-#define RXTT           0x40
-#define RXBNAE         0x80
-#define TXBE           0x100
-
-#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
-#define TXFLAGS (TXBF | TXBAE)
-
-#define TIMBUART_MAJOR 204
-#define TIMBUART_MINOR 192
-
-#endif /* _TIMBUART_H */
-
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
deleted file mode 100644 (file)
index d2fce86..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * uartlite.c: Serial driver for Xilinx uartlite serial controller
- *
- * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
- * Copyright (C) 2007 Secret Lab Technologies Ltd.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-/* Match table for of_platform binding */
-static struct of_device_id ulite_of_match[] __devinitdata = {
-       { .compatible = "xlnx,opb-uartlite-1.00.b", },
-       { .compatible = "xlnx,xps-uartlite-1.00.a", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, ulite_of_match);
-
-#endif
-
-#define ULITE_NAME             "ttyUL"
-#define ULITE_MAJOR            204
-#define ULITE_MINOR            187
-#define ULITE_NR_UARTS         4
-
-/* ---------------------------------------------------------------------
- * Register definitions
- *
- * For register details see datasheet:
- * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf 
- */
-
-#define ULITE_RX               0x00
-#define ULITE_TX               0x04
-#define ULITE_STATUS           0x08
-#define ULITE_CONTROL          0x0c
-
-#define ULITE_REGION           16
-
-#define ULITE_STATUS_RXVALID   0x01
-#define ULITE_STATUS_RXFULL    0x02
-#define ULITE_STATUS_TXEMPTY   0x04
-#define ULITE_STATUS_TXFULL    0x08
-#define ULITE_STATUS_IE                0x10
-#define ULITE_STATUS_OVERRUN   0x20
-#define ULITE_STATUS_FRAME     0x40
-#define ULITE_STATUS_PARITY    0x80
-
-#define ULITE_CONTROL_RST_TX   0x01
-#define ULITE_CONTROL_RST_RX   0x02
-#define ULITE_CONTROL_IE       0x10
-
-
-static struct uart_port ulite_ports[ULITE_NR_UARTS];
-
-/* ---------------------------------------------------------------------
- * Core UART driver operations
- */
-
-static int ulite_receive(struct uart_port *port, int stat)
-{
-       struct tty_struct *tty = port->state->port.tty;
-       unsigned char ch = 0;
-       char flag = TTY_NORMAL;
-
-       if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-                    | ULITE_STATUS_FRAME)) == 0)
-               return 0;
-
-       /* stats */
-       if (stat & ULITE_STATUS_RXVALID) {
-               port->icount.rx++;
-               ch = ioread32be(port->membase + ULITE_RX);
-
-               if (stat & ULITE_STATUS_PARITY)
-                       port->icount.parity++;
-       }
-
-       if (stat & ULITE_STATUS_OVERRUN)
-               port->icount.overrun++;
-
-       if (stat & ULITE_STATUS_FRAME)
-               port->icount.frame++;
-
-
-       /* drop byte with parity error if IGNPAR specificed */
-       if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
-               stat &= ~ULITE_STATUS_RXVALID;
-
-       stat &= port->read_status_mask;
-
-       if (stat & ULITE_STATUS_PARITY)
-               flag = TTY_PARITY;
-
-
-       stat &= ~port->ignore_status_mask;
-
-       if (stat & ULITE_STATUS_RXVALID)
-               tty_insert_flip_char(tty, ch, flag);
-
-       if (stat & ULITE_STATUS_FRAME)
-               tty_insert_flip_char(tty, 0, TTY_FRAME);
-
-       if (stat & ULITE_STATUS_OVERRUN)
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-
-       return 1;
-}
-
-static int ulite_transmit(struct uart_port *port, int stat)
-{
-       struct circ_buf *xmit  = &port->state->xmit;
-
-       if (stat & ULITE_STATUS_TXFULL)
-               return 0;
-
-       if (port->x_char) {
-               iowrite32be(port->x_char, port->membase + ULITE_TX);
-               port->x_char = 0;
-               port->icount.tx++;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return 0;
-
-       iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-       port->icount.tx++;
-
-       /* wake up */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       return 1;
-}
-
-static irqreturn_t ulite_isr(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       int busy, n = 0;
-
-       do {
-               int stat = ioread32be(port->membase + ULITE_STATUS);
-               busy  = ulite_receive(port, stat);
-               busy |= ulite_transmit(port, stat);
-               n++;
-       } while (busy);
-
-       /* work done? */
-       if (n > 1) {
-               tty_flip_buffer_push(port->state->port.tty);
-               return IRQ_HANDLED;
-       } else {
-               return IRQ_NONE;
-       }
-}
-
-static unsigned int ulite_tx_empty(struct uart_port *port)
-{
-       unsigned long flags;
-       unsigned int ret;
-
-       spin_lock_irqsave(&port->lock, flags);
-       ret = ioread32be(port->membase + ULITE_STATUS);
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int ulite_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* N/A */
-}
-
-static void ulite_stop_tx(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void ulite_start_tx(struct uart_port *port)
-{
-       ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
-}
-
-static void ulite_stop_rx(struct uart_port *port)
-{
-       /* don't forward any more data (like !CREAD) */
-       port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
-               | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-}
-
-static void ulite_enable_ms(struct uart_port *port)
-{
-       /* N/A */
-}
-
-static void ulite_break_ctl(struct uart_port *port, int ctl)
-{
-       /* N/A */
-}
-
-static int ulite_startup(struct uart_port *port)
-{
-       int ret;
-
-       ret = request_irq(port->irq, ulite_isr,
-                         IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port);
-       if (ret)
-               return ret;
-
-       iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
-              port->membase + ULITE_CONTROL);
-       iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
-
-       return 0;
-}
-
-static void ulite_shutdown(struct uart_port *port)
-{
-       iowrite32be(0, port->membase + ULITE_CONTROL);
-       ioread32be(port->membase + ULITE_CONTROL); /* dummy */
-       free_irq(port->irq, port);
-}
-
-static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned long flags;
-       unsigned int baud;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-               | ULITE_STATUS_TXFULL;
-
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |=
-                       ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
-
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= ULITE_STATUS_PARITY
-                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-
-       /* ignore all characters if CREAD is not set */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->ignore_status_mask |=
-                       ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
-                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-
-       /* update timeout */
-       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *ulite_type(struct uart_port *port)
-{
-       return port->type == PORT_UARTLITE ? "uartlite" : NULL;
-}
-
-static void ulite_release_port(struct uart_port *port)
-{
-       release_mem_region(port->mapbase, ULITE_REGION);
-       iounmap(port->membase);
-       port->membase = NULL;
-}
-
-static int ulite_request_port(struct uart_port *port)
-{
-       pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
-                port, (unsigned long long) port->mapbase);
-
-       if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
-               dev_err(port->dev, "Memory region busy\n");
-               return -EBUSY;
-       }
-
-       port->membase = ioremap(port->mapbase, ULITE_REGION);
-       if (!port->membase) {
-               dev_err(port->dev, "Unable to map registers\n");
-               release_mem_region(port->mapbase, ULITE_REGION);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void ulite_config_port(struct uart_port *port, int flags)
-{
-       if (!ulite_request_port(port))
-               port->type = PORT_UARTLITE;
-}
-
-static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       /* we don't want the core code to modify any port params */
-       return -EINVAL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int ulite_get_poll_char(struct uart_port *port)
-{
-       if (!(ioread32be(port->membase + ULITE_STATUS)
-                                               & ULITE_STATUS_RXVALID))
-               return NO_POLL_CHAR;
-
-       return ioread32be(port->membase + ULITE_RX);
-}
-
-static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
-{
-       while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
-               cpu_relax();
-
-       /* write char to device */
-       iowrite32be(ch, port->membase + ULITE_TX);
-}
-#endif
-
-static struct uart_ops ulite_ops = {
-       .tx_empty       = ulite_tx_empty,
-       .set_mctrl      = ulite_set_mctrl,
-       .get_mctrl      = ulite_get_mctrl,
-       .stop_tx        = ulite_stop_tx,
-       .start_tx       = ulite_start_tx,
-       .stop_rx        = ulite_stop_rx,
-       .enable_ms      = ulite_enable_ms,
-       .break_ctl      = ulite_break_ctl,
-       .startup        = ulite_startup,
-       .shutdown       = ulite_shutdown,
-       .set_termios    = ulite_set_termios,
-       .type           = ulite_type,
-       .release_port   = ulite_release_port,
-       .request_port   = ulite_request_port,
-       .config_port    = ulite_config_port,
-       .verify_port    = ulite_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char  = ulite_get_poll_char,
-       .poll_put_char  = ulite_put_poll_char,
-#endif
-};
-
-/* ---------------------------------------------------------------------
- * Console driver operations
- */
-
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
-static void ulite_console_wait_tx(struct uart_port *port)
-{
-       int i;
-       u8 val;
-
-       /* Spin waiting for TX fifo to have space available */
-       for (i = 0; i < 100000; i++) {
-               val = ioread32be(port->membase + ULITE_STATUS);
-               if ((val & ULITE_STATUS_TXFULL) == 0)
-                       break;
-               cpu_relax();
-       }
-}
-
-static void ulite_console_putchar(struct uart_port *port, int ch)
-{
-       ulite_console_wait_tx(port);
-       iowrite32be(ch, port->membase + ULITE_TX);
-}
-
-static void ulite_console_write(struct console *co, const char *s,
-                               unsigned int count)
-{
-       struct uart_port *port = &ulite_ports[co->index];
-       unsigned long flags;
-       unsigned int ier;
-       int locked = 1;
-
-       if (oops_in_progress) {
-               locked = spin_trylock_irqsave(&port->lock, flags);
-       } else
-               spin_lock_irqsave(&port->lock, flags);
-
-       /* save and disable interrupt */
-       ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
-       iowrite32be(0, port->membase + ULITE_CONTROL);
-
-       uart_console_write(port, s, count, ulite_console_putchar);
-
-       ulite_console_wait_tx(port);
-
-       /* restore interrupt state */
-       if (ier)
-               iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
-
-       if (locked)
-               spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int __devinit ulite_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= ULITE_NR_UARTS)
-               return -EINVAL;
-
-       port = &ulite_ports[co->index];
-
-       /* Has the device been initialized yet? */
-       if (!port->mapbase) {
-               pr_debug("console on ttyUL%i not present\n", co->index);
-               return -ENODEV;
-       }
-
-       /* not initialized yet? */
-       if (!port->membase) {
-               if (ulite_request_port(port))
-                       return -ENODEV;
-       }
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver ulite_uart_driver;
-
-static struct console ulite_console = {
-       .name   = ULITE_NAME,
-       .write  = ulite_console_write,
-       .device = uart_console_device,
-       .setup  = ulite_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
-       .data   = &ulite_uart_driver,
-};
-
-static int __init ulite_console_init(void)
-{
-       register_console(&ulite_console);
-       return 0;
-}
-
-console_initcall(ulite_console_init);
-
-#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
-
-static struct uart_driver ulite_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "uartlite",
-       .dev_name       = ULITE_NAME,
-       .major          = ULITE_MAJOR,
-       .minor          = ULITE_MINOR,
-       .nr             = ULITE_NR_UARTS,
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
-       .cons           = &ulite_console,
-#endif
-};
-
-/* ---------------------------------------------------------------------
- * Port assignment functions (mapping devices to uart_port structures)
- */
-
-/** ulite_assign: register a uartlite device with the driver
- *
- * @dev: pointer to device structure
- * @id: requested id number.  Pass -1 for automatic port assignment
- * @base: base address of uartlite registers
- * @irq: irq number for uartlite
- *
- * Returns: 0 on success, <0 otherwise
- */
-static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
-{
-       struct uart_port *port;
-       int rc;
-
-       /* if id = -1; then scan for a free id and use that */
-       if (id < 0) {
-               for (id = 0; id < ULITE_NR_UARTS; id++)
-                       if (ulite_ports[id].mapbase == 0)
-                               break;
-       }
-       if (id < 0 || id >= ULITE_NR_UARTS) {
-               dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
-               return -EINVAL;
-       }
-
-       if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
-               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
-                       ULITE_NAME, id);
-               return -EBUSY;
-       }
-
-       port = &ulite_ports[id];
-
-       spin_lock_init(&port->lock);
-       port->fifosize = 16;
-       port->regshift = 2;
-       port->iotype = UPIO_MEM;
-       port->iobase = 1; /* mark port in use */
-       port->mapbase = base;
-       port->membase = NULL;
-       port->ops = &ulite_ops;
-       port->irq = irq;
-       port->flags = UPF_BOOT_AUTOCONF;
-       port->dev = dev;
-       port->type = PORT_UNKNOWN;
-       port->line = id;
-
-       dev_set_drvdata(dev, port);
-
-       /* Register the port */
-       rc = uart_add_one_port(&ulite_uart_driver, port);
-       if (rc) {
-               dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
-               port->mapbase = 0;
-               dev_set_drvdata(dev, NULL);
-               return rc;
-       }
-
-       return 0;
-}
-
-/** ulite_release: register a uartlite device with the driver
- *
- * @dev: pointer to device structure
- */
-static int __devexit ulite_release(struct device *dev)
-{
-       struct uart_port *port = dev_get_drvdata(dev);
-       int rc = 0;
-
-       if (port) {
-               rc = uart_remove_one_port(&ulite_uart_driver, port);
-               dev_set_drvdata(dev, NULL);
-               port->mapbase = 0;
-       }
-
-       return rc;
-}
-
-/* ---------------------------------------------------------------------
- * Platform bus binding
- */
-
-static int __devinit ulite_probe(struct platform_device *pdev)
-{
-       struct resource *res, *res2;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
-
-       return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
-}
-
-static int __devexit ulite_remove(struct platform_device *pdev)
-{
-       return ulite_release(&pdev->dev);
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:uartlite");
-
-static struct platform_driver ulite_platform_driver = {
-       .probe  = ulite_probe,
-       .remove = __devexit_p(ulite_remove),
-       .driver = {
-                  .owner = THIS_MODULE,
-                  .name  = "uartlite",
-                  },
-};
-
-/* ---------------------------------------------------------------------
- * OF bus bindings
- */
-#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
-static int __devinit
-ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
-{
-       struct resource res;
-       const unsigned int *id;
-       int irq, rc;
-
-       dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
-
-       rc = of_address_to_resource(op->dev.of_node, 0, &res);
-       if (rc) {
-               dev_err(&op->dev, "invalid address\n");
-               return rc;
-       }
-
-       irq = irq_of_parse_and_map(op->dev.of_node, 0);
-
-       id = of_get_property(op->dev.of_node, "port-number", NULL);
-
-       return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
-}
-
-static int __devexit ulite_of_remove(struct platform_device *op)
-{
-       return ulite_release(&op->dev);
-}
-
-static struct of_platform_driver ulite_of_driver = {
-       .probe = ulite_of_probe,
-       .remove = __devexit_p(ulite_of_remove),
-       .driver = {
-               .name = "uartlite",
-               .owner = THIS_MODULE,
-               .of_match_table = ulite_of_match,
-       },
-};
-
-/* Registration helpers to keep the number of #ifdefs to a minimum */
-static inline int __init ulite_of_register(void)
-{
-       pr_debug("uartlite: calling of_register_platform_driver()\n");
-       return of_register_platform_driver(&ulite_of_driver);
-}
-
-static inline void __exit ulite_of_unregister(void)
-{
-       of_unregister_platform_driver(&ulite_of_driver);
-}
-#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
-/* Appropriate config not enabled; do nothing helpers */
-static inline int __init ulite_of_register(void) { return 0; }
-static inline void __exit ulite_of_unregister(void) { }
-#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
-
-/* ---------------------------------------------------------------------
- * Module setup/teardown
- */
-
-int __init ulite_init(void)
-{
-       int ret;
-
-       pr_debug("uartlite: calling uart_register_driver()\n");
-       ret = uart_register_driver(&ulite_uart_driver);
-       if (ret)
-               goto err_uart;
-
-       ret = ulite_of_register();
-       if (ret)
-               goto err_of;
-
-       pr_debug("uartlite: calling platform_driver_register()\n");
-       ret = platform_driver_register(&ulite_platform_driver);
-       if (ret)
-               goto err_plat;
-
-       return 0;
-
-err_plat:
-       ulite_of_unregister();
-err_of:
-       uart_unregister_driver(&ulite_uart_driver);
-err_uart:
-       printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
-       return ret;
-}
-
-void __exit ulite_exit(void)
-{
-       platform_driver_unregister(&ulite_platform_driver);
-       ulite_of_unregister();
-       uart_unregister_driver(&ulite_uart_driver);
-}
-
-module_init(ulite_init);
-module_exit(ulite_exit);
-
-MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
-MODULE_DESCRIPTION("Xilinx uartlite serial driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
deleted file mode 100644 (file)
index 3f4848e..0000000
+++ /dev/null
@@ -1,1537 +0,0 @@
-/*
- * Freescale QUICC Engine UART device driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * This driver adds support for UART devices via Freescale's QUICC Engine
- * found on some Freescale SOCs.
- *
- * If Soft-UART support is needed but not already present, then this driver
- * will request and upload the "Soft-UART" microcode upon probe.  The
- * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X"
- * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC,
- * (e.g. "11" for 1.1).
- */
-
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/slab.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-#include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/fs_uart_pd.h>
-#include <asm/ucc_slow.h>
-
-#include <linux/firmware.h>
-#include <asm/reg.h>
-
-/*
- * The GUMR flag for Soft UART.  This would normally be defined in qe.h,
- * but Soft-UART is a hack and we want to keep everything related to it in
- * this file.
- */
-#define UCC_SLOW_GUMR_H_SUART          0x00004000      /* Soft-UART */
-
-/*
- * soft_uart is 1 if we need to use Soft-UART mode
- */
-static int soft_uart;
-/*
- * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise.
- */
-static int firmware_loaded;
-
-/* Enable this macro to configure all serial ports in internal loopback
-   mode */
-/* #define LOOPBACK */
-
-/* The major and minor device numbers are defined in
- * http://www.lanana.org/docs/device-list/devices-2.6+.txt.  For the QE
- * UART, we have major number 204 and minor numbers 46 - 49, which are the
- * same as for the CPM2.  This decision was made because no Freescale part
- * has both a CPM and a QE.
- */
-#define SERIAL_QE_MAJOR 204
-#define SERIAL_QE_MINOR 46
-
-/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */
-#define UCC_MAX_UART    4
-
-/* The number of buffer descriptors for receiving characters. */
-#define RX_NUM_FIFO     4
-
-/* The number of buffer descriptors for transmitting characters. */
-#define TX_NUM_FIFO     4
-
-/* The maximum size of the character buffer for a single RX BD. */
-#define RX_BUF_SIZE     32
-
-/* The maximum size of the character buffer for a single TX BD. */
-#define TX_BUF_SIZE     32
-
-/*
- * The number of jiffies to wait after receiving a close command before the
- * device is actually closed.  This allows the last few characters to be
- * sent over the wire.
- */
-#define UCC_WAIT_CLOSING 100
-
-struct ucc_uart_pram {
-       struct ucc_slow_pram common;
-       u8 res1[8];             /* reserved */
-       __be16 maxidl;          /* Maximum idle chars */
-       __be16 idlc;            /* temp idle counter */
-       __be16 brkcr;           /* Break count register */
-       __be16 parec;           /* receive parity error counter */
-       __be16 frmec;           /* receive framing error counter */
-       __be16 nosec;           /* receive noise counter */
-       __be16 brkec;           /* receive break condition counter */
-       __be16 brkln;           /* last received break length */
-       __be16 uaddr[2];        /* UART address character 1 & 2 */
-       __be16 rtemp;           /* Temp storage */
-       __be16 toseq;           /* Transmit out of sequence char */
-       __be16 cchars[8];       /* control characters 1-8 */
-       __be16 rccm;            /* receive control character mask */
-       __be16 rccr;            /* receive control character register */
-       __be16 rlbc;            /* receive last break character */
-       __be16 res2;            /* reserved */
-       __be32 res3;            /* reserved, should be cleared */
-       u8 res4;                /* reserved, should be cleared */
-       u8 res5[3];             /* reserved, should be cleared */
-       __be32 res6;            /* reserved, should be cleared */
-       __be32 res7;            /* reserved, should be cleared */
-       __be32 res8;            /* reserved, should be cleared */
-       __be32 res9;            /* reserved, should be cleared */
-       __be32 res10;           /* reserved, should be cleared */
-       __be32 res11;           /* reserved, should be cleared */
-       __be32 res12;           /* reserved, should be cleared */
-       __be32 res13;           /* reserved, should be cleared */
-/* The rest is for Soft-UART only */
-       __be16 supsmr;          /* 0x90, Shadow UPSMR */
-       __be16 res92;           /* 0x92, reserved, initialize to 0 */
-       __be32 rx_state;        /* 0x94, RX state, initialize to 0 */
-       __be32 rx_cnt;          /* 0x98, RX count, initialize to 0 */
-       u8 rx_length;           /* 0x9C, Char length, set to 1+CL+PEN+1+SL */
-       u8 rx_bitmark;          /* 0x9D, reserved, initialize to 0 */
-       u8 rx_temp_dlst_qe;     /* 0x9E, reserved, initialize to 0 */
-       u8 res14[0xBC - 0x9F];  /* reserved */
-       __be32 dump_ptr;        /* 0xBC, Dump pointer */
-       __be32 rx_frame_rem;    /* 0xC0, reserved, initialize to 0 */
-       u8 rx_frame_rem_size;   /* 0xC4, reserved, initialize to 0 */
-       u8 tx_mode;             /* 0xC5, mode, 0=AHDLC, 1=UART */
-       __be16 tx_state;        /* 0xC6, TX state */
-       u8 res15[0xD0 - 0xC8];  /* reserved */
-       __be32 resD0;           /* 0xD0, reserved, initialize to 0 */
-       u8 resD4;               /* 0xD4, reserved, initialize to 0 */
-       __be16 resD5;           /* 0xD5, reserved, initialize to 0 */
-} __attribute__ ((packed));
-
-/* SUPSMR definitions, for Soft-UART only */
-#define UCC_UART_SUPSMR_SL             0x8000
-#define UCC_UART_SUPSMR_RPM_MASK       0x6000
-#define UCC_UART_SUPSMR_RPM_ODD        0x0000
-#define UCC_UART_SUPSMR_RPM_LOW        0x2000
-#define UCC_UART_SUPSMR_RPM_EVEN       0x4000
-#define UCC_UART_SUPSMR_RPM_HIGH       0x6000
-#define UCC_UART_SUPSMR_PEN            0x1000
-#define UCC_UART_SUPSMR_TPM_MASK       0x0C00
-#define UCC_UART_SUPSMR_TPM_ODD        0x0000
-#define UCC_UART_SUPSMR_TPM_LOW        0x0400
-#define UCC_UART_SUPSMR_TPM_EVEN       0x0800
-#define UCC_UART_SUPSMR_TPM_HIGH       0x0C00
-#define UCC_UART_SUPSMR_FRZ            0x0100
-#define UCC_UART_SUPSMR_UM_MASK        0x00c0
-#define UCC_UART_SUPSMR_UM_NORMAL       0x0000
-#define UCC_UART_SUPSMR_UM_MAN_MULTI    0x0040
-#define UCC_UART_SUPSMR_UM_AUTO_MULTI   0x00c0
-#define UCC_UART_SUPSMR_CL_MASK        0x0030
-#define UCC_UART_SUPSMR_CL_8           0x0030
-#define UCC_UART_SUPSMR_CL_7           0x0020
-#define UCC_UART_SUPSMR_CL_6           0x0010
-#define UCC_UART_SUPSMR_CL_5           0x0000
-
-#define UCC_UART_TX_STATE_AHDLC        0x00
-#define UCC_UART_TX_STATE_UART         0x01
-#define UCC_UART_TX_STATE_X1           0x00
-#define UCC_UART_TX_STATE_X16          0x80
-
-#define UCC_UART_PRAM_ALIGNMENT 0x100
-
-#define UCC_UART_SIZE_OF_BD     UCC_SLOW_SIZE_OF_BD
-#define NUM_CONTROL_CHARS       8
-
-/* Private per-port data structure */
-struct uart_qe_port {
-       struct uart_port port;
-       struct ucc_slow __iomem *uccp;
-       struct ucc_uart_pram __iomem *uccup;
-       struct ucc_slow_info us_info;
-       struct ucc_slow_private *us_private;
-       struct device_node *np;
-       unsigned int ucc_num;   /* First ucc is 0, not 1 */
-
-       u16 rx_nrfifos;
-       u16 rx_fifosize;
-       u16 tx_nrfifos;
-       u16 tx_fifosize;
-       int wait_closing;
-       u32 flags;
-       struct qe_bd *rx_bd_base;
-       struct qe_bd *rx_cur;
-       struct qe_bd *tx_bd_base;
-       struct qe_bd *tx_cur;
-       unsigned char *tx_buf;
-       unsigned char *rx_buf;
-       void *bd_virt;          /* virtual address of the BD buffers */
-       dma_addr_t bd_dma_addr; /* bus address of the BD buffers */
-       unsigned int bd_size;   /* size of BD buffer space */
-};
-
-static struct uart_driver ucc_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ucc_uart",
-       .dev_name       = "ttyQE",
-       .major          = SERIAL_QE_MAJOR,
-       .minor          = SERIAL_QE_MINOR,
-       .nr             = UCC_MAX_UART,
-};
-
-/*
- * Virtual to physical address translation.
- *
- * Given the virtual address for a character buffer, this function returns
- * the physical (DMA) equivalent.
- */
-static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
-{
-       if (likely((addr >= qe_port->bd_virt)) &&
-           (addr < (qe_port->bd_virt + qe_port->bd_size)))
-               return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
-
-       /* something nasty happened */
-       printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
-       BUG();
-       return 0;
-}
-
-/*
- * Physical to virtual address translation.
- *
- * Given the physical (DMA) address for a character buffer, this function
- * returns the virtual equivalent.
- */
-static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
-{
-       /* sanity check */
-       if (likely((addr >= qe_port->bd_dma_addr) &&
-                  (addr < (qe_port->bd_dma_addr + qe_port->bd_size))))
-               return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
-
-       /* something nasty happened */
-       printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
-       BUG();
-       return NULL;
-}
-
-/*
- * Return 1 if the QE is done transmitting all buffers for this port
- *
- * This function scans each BD in sequence.  If we find a BD that is not
- * ready (READY=1), then we return 0 indicating that the QE is still sending
- * data.  If we reach the last BD (WRAP=1), then we know we've scanned
- * the entire list, and all BDs are done.
- */
-static unsigned int qe_uart_tx_empty(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct qe_bd *bdp = qe_port->tx_bd_base;
-
-       while (1) {
-               if (in_be16(&bdp->status) & BD_SC_READY)
-                       /* This BD is not done, so return "not done" */
-                       return 0;
-
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       /*
-                        * This BD is done and it's the last one, so return
-                        * "done"
-                        */
-                       return 1;
-
-               bdp++;
-       };
-}
-
-/*
- * Set the modem control lines
- *
- * Although the QE can control the modem control lines (e.g. CTS), we
- * don't need that support. This function must exist, however, otherwise
- * the kernel will panic.
- */
-void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/*
- * Get the current modem control line status
- *
- * Although the QE can control the modem control lines (e.g. CTS), this
- * driver currently doesn't support that, so we always return Carrier
- * Detect, Data Set Ready, and Clear To Send.
- */
-static unsigned int qe_uart_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
-}
-
-/*
- * Disable the transmit interrupt.
- *
- * Although this function is called "stop_tx", it does not actually stop
- * transmission of data.  Instead, it tells the QE to not generate an
- * interrupt when the UCC is finished sending characters.
- */
-static void qe_uart_stop_tx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
-}
-
-/*
- * Transmit as many characters to the HW as possible.
- *
- * This function will attempt to stuff of all the characters from the
- * kernel's transmit buffer into TX BDs.
- *
- * A return value of non-zero indicates that it successfully stuffed all
- * characters from the kernel buffer.
- *
- * A return value of zero indicates that there are still characters in the
- * kernel's buffer that have not been transmitted, but there are no more BDs
- * available.  This function should be called again after a BD has been made
- * available.
- */
-static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
-{
-       struct qe_bd *bdp;
-       unsigned char *p;
-       unsigned int count;
-       struct uart_port *port = &qe_port->port;
-       struct circ_buf *xmit = &port->state->xmit;
-
-       bdp = qe_port->rx_cur;
-
-       /* Handle xon/xoff */
-       if (port->x_char) {
-               /* Pick next descriptor and fill from buffer */
-               bdp = qe_port->tx_cur;
-
-               p = qe2cpu_addr(bdp->buf, qe_port);
-
-               *p++ = port->x_char;
-               out_be16(&bdp->length, 1);
-               setbits16(&bdp->status, BD_SC_READY);
-               /* Get next BD. */
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->tx_bd_base;
-               else
-                       bdp++;
-               qe_port->tx_cur = bdp;
-
-               port->icount.tx++;
-               port->x_char = 0;
-               return 1;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               qe_uart_stop_tx(port);
-               return 0;
-       }
-
-       /* Pick next descriptor and fill from buffer */
-       bdp = qe_port->tx_cur;
-
-       while (!(in_be16(&bdp->status) & BD_SC_READY) &&
-              (xmit->tail != xmit->head)) {
-               count = 0;
-               p = qe2cpu_addr(bdp->buf, qe_port);
-               while (count < qe_port->tx_fifosize) {
-                       *p++ = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                       port->icount.tx++;
-                       count++;
-                       if (xmit->head == xmit->tail)
-                               break;
-               }
-
-               out_be16(&bdp->length, count);
-               setbits16(&bdp->status, BD_SC_READY);
-
-               /* Get next BD. */
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->tx_bd_base;
-               else
-                       bdp++;
-       }
-       qe_port->tx_cur = bdp;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit)) {
-               /* The kernel buffer is empty, so turn off TX interrupts.  We
-                  don't need to be told when the QE is finished transmitting
-                  the data. */
-               qe_uart_stop_tx(port);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * Start transmitting data
- *
- * This function will start transmitting any available data, if the port
- * isn't already transmitting data.
- */
-static void qe_uart_start_tx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       /* If we currently are transmitting, then just return */
-       if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX)
-               return;
-
-       /* Otherwise, pump the port and start transmission */
-       if (qe_uart_tx_pump(qe_port))
-               setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
-}
-
-/*
- * Stop transmitting data
- */
-static void qe_uart_stop_rx(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
-}
-
-/*
- * Enable status change interrupts
- *
- * We don't support status change interrupts, but we need to define this
- * function otherwise the kernel will panic.
- */
-static void qe_uart_enable_ms(struct uart_port *port)
-{
-}
-
-/* Start or stop sending  break signal
- *
- * This function controls the sending of a break signal.  If break_state=1,
- * then we start sending a break signal.  If break_state=0, then we stop
- * sending the break signal.
- */
-static void qe_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-
-       if (break_state)
-               ucc_slow_stop_tx(qe_port->us_private);
-       else
-               ucc_slow_restart_tx(qe_port->us_private);
-}
-
-/* ISR helper function for receiving character.
- *
- * This function is called by the ISR to handling receiving characters
- */
-static void qe_uart_int_rx(struct uart_qe_port *qe_port)
-{
-       int i;
-       unsigned char ch, *cp;
-       struct uart_port *port = &qe_port->port;
-       struct tty_struct *tty = port->state->port.tty;
-       struct qe_bd *bdp;
-       u16 status;
-       unsigned int flg;
-
-       /* Just loop through the closed BDs and copy the characters into
-        * the buffer.
-        */
-       bdp = qe_port->rx_cur;
-       while (1) {
-               status = in_be16(&bdp->status);
-
-               /* If this one is empty, then we assume we've read them all */
-               if (status & BD_SC_EMPTY)
-                       break;
-
-               /* get number of characters, and check space in RX buffer */
-               i = in_be16(&bdp->length);
-
-               /* If we don't have enough room in RX buffer for the entire BD,
-                * then we try later, which will be the next RX interrupt.
-                */
-               if (tty_buffer_request_room(tty, i) < i) {
-                       dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n");
-                       return;
-               }
-
-               /* get pointer */
-               cp = qe2cpu_addr(bdp->buf, qe_port);
-
-               /* loop through the buffer */
-               while (i-- > 0) {
-                       ch = *cp++;
-                       port->icount.rx++;
-                       flg = TTY_NORMAL;
-
-                       if (!i && status &
-                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
-                               goto handle_error;
-                       if (uart_handle_sysrq_char(port, ch))
-                               continue;
-
-error_return:
-                       tty_insert_flip_char(tty, ch, flg);
-
-               }
-
-               /* This BD is ready to be used again. Clear status. get next */
-               clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR |
-                       BD_SC_OV | BD_SC_ID, BD_SC_EMPTY);
-               if (in_be16(&bdp->status) & BD_SC_WRAP)
-                       bdp = qe_port->rx_bd_base;
-               else
-                       bdp++;
-
-       }
-
-       /* Write back buffer pointer */
-       qe_port->rx_cur = bdp;
-
-       /* Activate BH processing */
-       tty_flip_buffer_push(tty);
-
-       return;
-
-       /* Error processing */
-
-handle_error:
-       /* Statistics */
-       if (status & BD_SC_BR)
-               port->icount.brk++;
-       if (status & BD_SC_PR)
-               port->icount.parity++;
-       if (status & BD_SC_FR)
-               port->icount.frame++;
-       if (status & BD_SC_OV)
-               port->icount.overrun++;
-
-       /* Mask out ignored conditions */
-       status &= port->read_status_mask;
-
-       /* Handle the remaining ones */
-       if (status & BD_SC_BR)
-               flg = TTY_BREAK;
-       else if (status & BD_SC_PR)
-               flg = TTY_PARITY;
-       else if (status & BD_SC_FR)
-               flg = TTY_FRAME;
-
-       /* Overrun does not affect the current character ! */
-       if (status & BD_SC_OV)
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-#ifdef SUPPORT_SYSRQ
-       port->sysrq = 0;
-#endif
-       goto error_return;
-}
-
-/* Interrupt handler
- *
- * This interrupt handler is called after a BD is processed.
- */
-static irqreturn_t qe_uart_int(int irq, void *data)
-{
-       struct uart_qe_port *qe_port = (struct uart_qe_port *) data;
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       u16 events;
-
-       /* Clear the interrupts */
-       events = in_be16(&uccp->ucce);
-       out_be16(&uccp->ucce, events);
-
-       if (events & UCC_UART_UCCE_BRKE)
-               uart_handle_break(&qe_port->port);
-
-       if (events & UCC_UART_UCCE_RX)
-               qe_uart_int_rx(qe_port);
-
-       if (events & UCC_UART_UCCE_TX)
-               qe_uart_tx_pump(qe_port);
-
-       return events ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/* Initialize buffer descriptors
- *
- * This function initializes all of the RX and TX buffer descriptors.
- */
-static void qe_uart_initbd(struct uart_qe_port *qe_port)
-{
-       int i;
-       void *bd_virt;
-       struct qe_bd *bdp;
-
-       /* Set the physical address of the host memory buffers in the buffer
-        * descriptors, and the virtual address for us to work with.
-        */
-       bd_virt = qe_port->bd_virt;
-       bdp = qe_port->rx_bd_base;
-       qe_port->rx_cur = qe_port->rx_bd_base;
-       for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) {
-               out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT);
-               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-               out_be16(&bdp->length, 0);
-               bd_virt += qe_port->rx_fifosize;
-               bdp++;
-       }
-
-       /* */
-       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
-       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-       out_be16(&bdp->length, 0);
-
-       /* Set the physical address of the host memory
-        * buffers in the buffer descriptors, and the
-        * virtual address for us to work with.
-        */
-       bd_virt = qe_port->bd_virt +
-               L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
-       qe_port->tx_cur = qe_port->tx_bd_base;
-       bdp = qe_port->tx_bd_base;
-       for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) {
-               out_be16(&bdp->status, BD_SC_INTRPT);
-               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-               out_be16(&bdp->length, 0);
-               bd_virt += qe_port->tx_fifosize;
-               bdp++;
-       }
-
-       /* Loopback requires the preamble bit to be set on the first TX BD */
-#ifdef LOOPBACK
-       setbits16(&qe_port->tx_cur->status, BD_SC_P);
-#endif
-
-       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT);
-       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
-       out_be16(&bdp->length, 0);
-}
-
-/*
- * Initialize a UCC for UART.
- *
- * This function configures a given UCC to be used as a UART device. Basic
- * UCC initialization is handled in qe_uart_request_port().  This function
- * does all the UART-specific stuff.
- */
-static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
-{
-       u32 cecr_subblock;
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       struct ucc_uart_pram *uccup = qe_port->uccup;
-
-       unsigned int i;
-
-       /* First, disable TX and RX in the UCC */
-       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-
-       /* Program the UCC UART parameter RAM */
-       out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
-       out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
-       out_be16(&uccup->common.mrblr, qe_port->rx_fifosize);
-       out_be16(&uccup->maxidl, 0x10);
-       out_be16(&uccup->brkcr, 1);
-       out_be16(&uccup->parec, 0);
-       out_be16(&uccup->frmec, 0);
-       out_be16(&uccup->nosec, 0);
-       out_be16(&uccup->brkec, 0);
-       out_be16(&uccup->uaddr[0], 0);
-       out_be16(&uccup->uaddr[1], 0);
-       out_be16(&uccup->toseq, 0);
-       for (i = 0; i < 8; i++)
-               out_be16(&uccup->cchars[i], 0xC000);
-       out_be16(&uccup->rccm, 0xc0ff);
-
-       /* Configure the GUMR registers for UART */
-       if (soft_uart) {
-               /* Soft-UART requires a 1X multiplier for TX */
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW,
-                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX);
-       } else {
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h,
-                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX,
-                       UCC_SLOW_GUMR_H_RFW);
-       }
-
-#ifdef LOOPBACK
-       clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
-               UCC_SLOW_GUMR_L_DIAG_LOOP);
-       clrsetbits_be32(&uccp->gumr_h,
-               UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN,
-               UCC_SLOW_GUMR_H_CDS);
-#endif
-
-       /* Disable rx interrupts  and clear all pending events.  */
-       out_be16(&uccp->uccm, 0);
-       out_be16(&uccp->ucce, 0xffff);
-       out_be16(&uccp->udsr, 0x7e7e);
-
-       /* Initialize UPSMR */
-       out_be16(&uccp->upsmr, 0);
-
-       if (soft_uart) {
-               out_be16(&uccup->supsmr, 0x30);
-               out_be16(&uccup->res92, 0);
-               out_be32(&uccup->rx_state, 0);
-               out_be32(&uccup->rx_cnt, 0);
-               out_8(&uccup->rx_bitmark, 0);
-               out_8(&uccup->rx_length, 10);
-               out_be32(&uccup->dump_ptr, 0x4000);
-               out_8(&uccup->rx_temp_dlst_qe, 0);
-               out_be32(&uccup->rx_frame_rem, 0);
-               out_8(&uccup->rx_frame_rem_size, 0);
-               /* Soft-UART requires TX to be 1X */
-               out_8(&uccup->tx_mode,
-                       UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1);
-               out_be16(&uccup->tx_state, 0);
-               out_8(&uccup->resD4, 0);
-               out_be16(&uccup->resD5, 0);
-
-               /* Set UART mode.
-                * Enable receive and transmit.
-                */
-
-               /* From the microcode errata:
-                * 1.GUMR_L register, set mode=0010 (QMC).
-                * 2.Set GUMR_H[17] bit. (UART/AHDLC mode).
-                * 3.Set GUMR_H[19:20] (Transparent mode)
-                * 4.Clear GUMR_H[26] (RFW)
-                * ...
-                * 6.Receiver must use 16x over sampling
-                */
-               clrsetbits_be32(&uccp->gumr_l,
-                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
-                       UCC_SLOW_GUMR_L_RDCR_MASK,
-                       UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 |
-                       UCC_SLOW_GUMR_L_RDCR_16);
-
-               clrsetbits_be32(&uccp->gumr_h,
-                       UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN,
-                       UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX |
-                       UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL);
-
-#ifdef LOOPBACK
-               clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
-                               UCC_SLOW_GUMR_L_DIAG_LOOP);
-               clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP |
-                         UCC_SLOW_GUMR_H_CDS);
-#endif
-
-               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
-               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
-                       QE_CR_PROTOCOL_UNSPECIFIED, 0);
-       } else {
-               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
-               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
-                       QE_CR_PROTOCOL_UART, 0);
-       }
-}
-
-/*
- * Initialize the port.
- */
-static int qe_uart_startup(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       int ret;
-
-       /*
-        * If we're using Soft-UART mode, then we need to make sure the
-        * firmware has been uploaded first.
-        */
-       if (soft_uart && !firmware_loaded) {
-               dev_err(port->dev, "Soft-UART firmware not uploaded\n");
-               return -ENODEV;
-       }
-
-       qe_uart_initbd(qe_port);
-       qe_uart_init_ucc(qe_port);
-
-       /* Install interrupt handler. */
-       ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart",
-               qe_port);
-       if (ret) {
-               dev_err(port->dev, "could not claim IRQ %u\n", port->irq);
-               return ret;
-       }
-
-       /* Startup rx-int */
-       setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
-       ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-
-       return 0;
-}
-
-/*
- * Shutdown the port.
- */
-static void qe_uart_shutdown(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       unsigned int timeout = 20;
-
-       /* Disable RX and TX */
-
-       /* Wait for all the BDs marked sent */
-       while (!qe_uart_tx_empty(port)) {
-               if (!--timeout) {
-                       dev_warn(port->dev, "shutdown timeout\n");
-                       break;
-               }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(2);
-       }
-
-       if (qe_port->wait_closing) {
-               /* Wait a bit longer */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(qe_port->wait_closing);
-       }
-
-       /* Stop uarts */
-       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
-       clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX);
-
-       /* Shut them really down and reinit buffer descriptors */
-       ucc_slow_graceful_stop_tx(qe_port->us_private);
-       qe_uart_initbd(qe_port);
-
-       free_irq(port->irq, qe_port);
-}
-
-/*
- * Set the serial port parameters.
- */
-static void qe_uart_set_termios(struct uart_port *port,
-                               struct ktermios *termios, struct ktermios *old)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow __iomem *uccp = qe_port->uccp;
-       unsigned int baud;
-       unsigned long flags;
-       u16 upsmr = in_be16(&uccp->upsmr);
-       struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
-       u16 supsmr = in_be16(&uccup->supsmr);
-       u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */
-
-       /* Character length programmed into the mode register is the
-        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
-        * 1 or 2 stop bits, minus 1.
-        * The value 'bits' counts this for us.
-        */
-
-       /* byte size */
-       upsmr &= UCC_UART_UPSMR_CL_MASK;
-       supsmr &= UCC_UART_SUPSMR_CL_MASK;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               upsmr |= UCC_UART_UPSMR_CL_5;
-               supsmr |= UCC_UART_SUPSMR_CL_5;
-               char_length += 5;
-               break;
-       case CS6:
-               upsmr |= UCC_UART_UPSMR_CL_6;
-               supsmr |= UCC_UART_SUPSMR_CL_6;
-               char_length += 6;
-               break;
-       case CS7:
-               upsmr |= UCC_UART_UPSMR_CL_7;
-               supsmr |= UCC_UART_SUPSMR_CL_7;
-               char_length += 7;
-               break;
-       default:        /* case CS8 */
-               upsmr |= UCC_UART_UPSMR_CL_8;
-               supsmr |= UCC_UART_SUPSMR_CL_8;
-               char_length += 8;
-               break;
-       }
-
-       /* If CSTOPB is set, we want two stop bits */
-       if (termios->c_cflag & CSTOPB) {
-               upsmr |= UCC_UART_UPSMR_SL;
-               supsmr |= UCC_UART_SUPSMR_SL;
-               char_length++;  /* + SL */
-       }
-
-       if (termios->c_cflag & PARENB) {
-               upsmr |= UCC_UART_UPSMR_PEN;
-               supsmr |= UCC_UART_SUPSMR_PEN;
-               char_length++;  /* + PEN */
-
-               if (!(termios->c_cflag & PARODD)) {
-                       upsmr &= ~(UCC_UART_UPSMR_RPM_MASK |
-                                  UCC_UART_UPSMR_TPM_MASK);
-                       upsmr |= UCC_UART_UPSMR_RPM_EVEN |
-                               UCC_UART_UPSMR_TPM_EVEN;
-                       supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK |
-                                   UCC_UART_SUPSMR_TPM_MASK);
-                       supsmr |= UCC_UART_SUPSMR_RPM_EVEN |
-                               UCC_UART_SUPSMR_TPM_EVEN;
-               }
-       }
-
-       /*
-        * Set up parity check flag
-        */
-       port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
-       if (termios->c_iflag & INPCK)
-               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= BD_SC_BR;
-
-       /*
-        * Characters to ignore
-        */
-       port->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-       if (termios->c_iflag & IGNBRK) {
-               port->ignore_status_mask |= BD_SC_BR;
-               /*
-                * If we're ignore parity and break indicators, ignore
-                * overruns too.  (For real raw support).
-                */
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= BD_SC_OV;
-       }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((termios->c_cflag & CREAD) == 0)
-               port->read_status_mask &= ~BD_SC_EMPTY;
-
-       baud = uart_get_baud_rate(port, termios, old, 0, 115200);
-
-       /* Do we really need a spinlock here? */
-       spin_lock_irqsave(&port->lock, flags);
-
-       out_be16(&uccp->upsmr, upsmr);
-       if (soft_uart) {
-               out_be16(&uccup->supsmr, supsmr);
-               out_8(&uccup->rx_length, char_length);
-
-               /* Soft-UART requires a 1X multiplier for TX */
-               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
-               qe_setbrg(qe_port->us_info.tx_clock, baud, 1);
-       } else {
-               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
-               qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return a pointer to a string that describes what kind of port this is.
- */
-static const char *qe_uart_type(struct uart_port *port)
-{
-       return "QE";
-}
-
-/*
- * Allocate any memory and I/O resources required by the port.
- */
-static int qe_uart_request_port(struct uart_port *port)
-{
-       int ret;
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow_info *us_info = &qe_port->us_info;
-       struct ucc_slow_private *uccs;
-       unsigned int rx_size, tx_size;
-       void *bd_virt;
-       dma_addr_t bd_dma_addr = 0;
-
-       ret = ucc_slow_init(us_info, &uccs);
-       if (ret) {
-               dev_err(port->dev, "could not initialize UCC%u\n",
-                      qe_port->ucc_num);
-               return ret;
-       }
-
-       qe_port->us_private = uccs;
-       qe_port->uccp = uccs->us_regs;
-       qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
-       qe_port->rx_bd_base = uccs->rx_bd;
-       qe_port->tx_bd_base = uccs->tx_bd;
-
-       /*
-        * Allocate the transmit and receive data buffers.
-        */
-
-       rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
-       tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
-
-       bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
-               GFP_KERNEL);
-       if (!bd_virt) {
-               dev_err(port->dev, "could not allocate buffer descriptors\n");
-               return -ENOMEM;
-       }
-
-       qe_port->bd_virt = bd_virt;
-       qe_port->bd_dma_addr = bd_dma_addr;
-       qe_port->bd_size = rx_size + tx_size;
-
-       qe_port->rx_buf = bd_virt;
-       qe_port->tx_buf = qe_port->rx_buf + rx_size;
-
-       return 0;
-}
-
-/*
- * Configure the port.
- *
- * We say we're a CPM-type port because that's mostly true.  Once the device
- * is configured, this driver operates almost identically to the CPM serial
- * driver.
- */
-static void qe_uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_CPM;
-               qe_uart_request_port(port);
-       }
-}
-
-/*
- * Release any memory and I/O resources that were allocated in
- * qe_uart_request_port().
- */
-static void qe_uart_release_port(struct uart_port *port)
-{
-       struct uart_qe_port *qe_port =
-               container_of(port, struct uart_qe_port, port);
-       struct ucc_slow_private *uccs = qe_port->us_private;
-
-       dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
-                         qe_port->bd_dma_addr);
-
-       ucc_slow_free(uccs);
-}
-
-/*
- * Verify that the data in serial_struct is suitable for this device.
- */
-static int qe_uart_verify_port(struct uart_port *port,
-                              struct serial_struct *ser)
-{
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
-               return -EINVAL;
-
-       if (ser->irq < 0 || ser->irq >= nr_irqs)
-               return -EINVAL;
-
-       if (ser->baud_base < 9600)
-               return -EINVAL;
-
-       return 0;
-}
-/* UART operations
- *
- * Details on these functions can be found in Documentation/serial/driver
- */
-static struct uart_ops qe_uart_pops = {
-       .tx_empty       = qe_uart_tx_empty,
-       .set_mctrl      = qe_uart_set_mctrl,
-       .get_mctrl      = qe_uart_get_mctrl,
-       .stop_tx        = qe_uart_stop_tx,
-       .start_tx       = qe_uart_start_tx,
-       .stop_rx        = qe_uart_stop_rx,
-       .enable_ms      = qe_uart_enable_ms,
-       .break_ctl      = qe_uart_break_ctl,
-       .startup        = qe_uart_startup,
-       .shutdown       = qe_uart_shutdown,
-       .set_termios    = qe_uart_set_termios,
-       .type           = qe_uart_type,
-       .release_port   = qe_uart_release_port,
-       .request_port   = qe_uart_request_port,
-       .config_port    = qe_uart_config_port,
-       .verify_port    = qe_uart_verify_port,
-};
-
-/*
- * Obtain the SOC model number and revision level
- *
- * This function parses the device tree to obtain the SOC model.  It then
- * reads the SVR register to the revision.
- *
- * The device tree stores the SOC model two different ways.
- *
- * The new way is:
- *
- *             cpu@0 {
- *                     compatible = "PowerPC,8323";
- *                     device_type = "cpu";
- *                     ...
- *
- *
- * The old way is:
- *              PowerPC,8323@0 {
- *                     device_type = "cpu";
- *                     ...
- *
- * This code first checks the new way, and then the old way.
- */
-static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
-{
-       struct device_node *np;
-       const char *soc_string;
-       unsigned int svr;
-       unsigned int soc;
-
-       /* Find the CPU node */
-       np = of_find_node_by_type(NULL, "cpu");
-       if (!np)
-               return 0;
-       /* Find the compatible property */
-       soc_string = of_get_property(np, "compatible", NULL);
-       if (!soc_string)
-               /* No compatible property, so try the name. */
-               soc_string = np->name;
-
-       /* Extract the SOC number from the "PowerPC," string */
-       if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
-               return 0;
-
-       /* Get the revision from the SVR */
-       svr = mfspr(SPRN_SVR);
-       *rev_h = (svr >> 4) & 0xf;
-       *rev_l = svr & 0xf;
-
-       return soc;
-}
-
-/*
- * requst_firmware_nowait() callback function
- *
- * This function is called by the kernel when a firmware is made available,
- * or if it times out waiting for the firmware.
- */
-static void uart_firmware_cont(const struct firmware *fw, void *context)
-{
-       struct qe_firmware *firmware;
-       struct device *dev = context;
-       int ret;
-
-       if (!fw) {
-               dev_err(dev, "firmware not found\n");
-               return;
-       }
-
-       firmware = (struct qe_firmware *) fw->data;
-
-       if (firmware->header.length != fw->size) {
-               dev_err(dev, "invalid firmware\n");
-               goto out;
-       }
-
-       ret = qe_upload_firmware(firmware);
-       if (ret) {
-               dev_err(dev, "could not load firmware\n");
-               goto out;
-       }
-
-       firmware_loaded = 1;
- out:
-       release_firmware(fw);
-}
-
-static int ucc_uart_probe(struct platform_device *ofdev,
-       const struct of_device_id *match)
-{
-       struct device_node *np = ofdev->dev.of_node;
-       const unsigned int *iprop;      /* Integer OF properties */
-       const char *sprop;      /* String OF properties */
-       struct uart_qe_port *qe_port = NULL;
-       struct resource res;
-       int ret;
-
-       /*
-        * Determine if we need Soft-UART mode
-        */
-       if (of_find_property(np, "soft-uart", NULL)) {
-               dev_dbg(&ofdev->dev, "using Soft-UART mode\n");
-               soft_uart = 1;
-       }
-
-       /*
-        * If we are using Soft-UART, determine if we need to upload the
-        * firmware, too.
-        */
-       if (soft_uart) {
-               struct qe_firmware_info *qe_fw_info;
-
-               qe_fw_info = qe_get_firmware_info();
-
-               /* Check if the firmware has been uploaded. */
-               if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) {
-                       firmware_loaded = 1;
-               } else {
-                       char filename[32];
-                       unsigned int soc;
-                       unsigned int rev_h;
-                       unsigned int rev_l;
-
-                       soc = soc_info(&rev_h, &rev_l);
-                       if (!soc) {
-                               dev_err(&ofdev->dev, "unknown CPU model\n");
-                               return -ENXIO;
-                       }
-                       sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin",
-                               soc, rev_h, rev_l);
-
-                       dev_info(&ofdev->dev, "waiting for firmware %s\n",
-                               filename);
-
-                       /*
-                        * We call request_firmware_nowait instead of
-                        * request_firmware so that the driver can load and
-                        * initialize the ports without holding up the rest of
-                        * the kernel.  If hotplug support is enabled in the
-                        * kernel, then we use it.
-                        */
-                       ret = request_firmware_nowait(THIS_MODULE,
-                               FW_ACTION_HOTPLUG, filename, &ofdev->dev,
-                               GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
-                       if (ret) {
-                               dev_err(&ofdev->dev,
-                                       "could not load firmware %s\n",
-                                       filename);
-                               return ret;
-                       }
-               }
-       }
-
-       qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL);
-       if (!qe_port) {
-               dev_err(&ofdev->dev, "can't allocate QE port structure\n");
-               return -ENOMEM;
-       }
-
-       /* Search for IRQ and mapbase */
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
-               kfree(qe_port);
-               return ret;
-       }
-       if (!res.start) {
-               dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-       qe_port->port.mapbase = res.start;
-
-       /* Get the UCC number (device ID) */
-       /* UCCs are numbered 1-7 */
-       iprop = of_get_property(np, "cell-index", NULL);
-       if (!iprop) {
-               iprop = of_get_property(np, "device-id", NULL);
-               if (!iprop) {
-                       kfree(qe_port);
-                       dev_err(&ofdev->dev, "UCC is unspecified in "
-                               "device tree\n");
-                       return -EINVAL;
-               }
-       }
-
-       if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
-               dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
-               kfree(qe_port);
-               return -ENODEV;
-       }
-       qe_port->ucc_num = *iprop - 1;
-
-       /*
-        * In the future, we should not require the BRG to be specified in the
-        * device tree.  If no clock-source is specified, then just pick a BRG
-        * to use.  This requires a new QE library function that manages BRG
-        * assignments.
-        */
-
-       sprop = of_get_property(np, "rx-clock-name", NULL);
-       if (!sprop) {
-               dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-       qe_port->us_info.rx_clock = qe_clock_source(sprop);
-       if ((qe_port->us_info.rx_clock < QE_BRG1) ||
-           (qe_port->us_info.rx_clock > QE_BRG16)) {
-               dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-#ifdef LOOPBACK
-       /* In internal loopback mode, TX and RX must use the same clock */
-       qe_port->us_info.tx_clock = qe_port->us_info.rx_clock;
-#else
-       sprop = of_get_property(np, "tx-clock-name", NULL);
-       if (!sprop) {
-               dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-       qe_port->us_info.tx_clock = qe_clock_source(sprop);
-#endif
-       if ((qe_port->us_info.tx_clock < QE_BRG1) ||
-           (qe_port->us_info.tx_clock > QE_BRG16)) {
-               dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
-               kfree(qe_port);
-               return -ENODEV;
-       }
-
-       /* Get the port number, numbered 0-3 */
-       iprop = of_get_property(np, "port-number", NULL);
-       if (!iprop) {
-               dev_err(&ofdev->dev, "missing port-number in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-       qe_port->port.line = *iprop;
-       if (qe_port->port.line >= UCC_MAX_UART) {
-               dev_err(&ofdev->dev, "port-number must be 0-%u\n",
-                       UCC_MAX_UART - 1);
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       qe_port->port.irq = irq_of_parse_and_map(np, 0);
-       if (qe_port->port.irq == NO_IRQ) {
-               dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
-                      qe_port->ucc_num + 1);
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       /*
-        * Newer device trees have an "fsl,qe" compatible property for the QE
-        * node, but we still need to support older device trees.
-        */
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!np) {
-               np = of_find_node_by_type(NULL, "qe");
-               if (!np) {
-                       dev_err(&ofdev->dev, "could not find 'qe' node\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-       }
-
-       iprop = of_get_property(np, "brg-frequency", NULL);
-       if (!iprop) {
-               dev_err(&ofdev->dev,
-                      "missing brg-frequency in device tree\n");
-               kfree(qe_port);
-               return -EINVAL;
-       }
-
-       if (*iprop)
-               qe_port->port.uartclk = *iprop;
-       else {
-               /*
-                * Older versions of U-Boot do not initialize the brg-frequency
-                * property, so in this case we assume the BRG frequency is
-                * half the QE bus frequency.
-                */
-               iprop = of_get_property(np, "bus-frequency", NULL);
-               if (!iprop) {
-                       dev_err(&ofdev->dev,
-                               "missing QE bus-frequency in device tree\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-               if (*iprop)
-                       qe_port->port.uartclk = *iprop / 2;
-               else {
-                       dev_err(&ofdev->dev,
-                               "invalid QE bus-frequency in device tree\n");
-                       kfree(qe_port);
-                       return -EINVAL;
-               }
-       }
-
-       spin_lock_init(&qe_port->port.lock);
-       qe_port->np = np;
-       qe_port->port.dev = &ofdev->dev;
-       qe_port->port.ops = &qe_uart_pops;
-       qe_port->port.iotype = UPIO_MEM;
-
-       qe_port->tx_nrfifos = TX_NUM_FIFO;
-       qe_port->tx_fifosize = TX_BUF_SIZE;
-       qe_port->rx_nrfifos = RX_NUM_FIFO;
-       qe_port->rx_fifosize = RX_BUF_SIZE;
-
-       qe_port->wait_closing = UCC_WAIT_CLOSING;
-       qe_port->port.fifosize = 512;
-       qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
-
-       qe_port->us_info.ucc_num = qe_port->ucc_num;
-       qe_port->us_info.regs = (phys_addr_t) res.start;
-       qe_port->us_info.irq = qe_port->port.irq;
-
-       qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos;
-       qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos;
-
-       /* Make sure ucc_slow_init() initializes both TX and RX */
-       qe_port->us_info.init_tx = 1;
-       qe_port->us_info.init_rx = 1;
-
-       /* Add the port to the uart sub-system.  This will cause
-        * qe_uart_config_port() to be called, so the us_info structure must
-        * be initialized.
-        */
-       ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port);
-       if (ret) {
-               dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
-                      qe_port->port.line);
-               kfree(qe_port);
-               return ret;
-       }
-
-       dev_set_drvdata(&ofdev->dev, qe_port);
-
-       dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
-               qe_port->ucc_num + 1, qe_port->port.line);
-
-       /* Display the mknod command for this device */
-       dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n",
-              qe_port->port.line, SERIAL_QE_MAJOR,
-              SERIAL_QE_MINOR + qe_port->port.line);
-
-       return 0;
-}
-
-static int ucc_uart_remove(struct platform_device *ofdev)
-{
-       struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
-
-       dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
-
-       uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
-
-       dev_set_drvdata(&ofdev->dev, NULL);
-       kfree(qe_port);
-
-       return 0;
-}
-
-static struct of_device_id ucc_uart_match[] = {
-       {
-               .type = "serial",
-               .compatible = "ucc_uart",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ucc_uart_match);
-
-static struct of_platform_driver ucc_uart_of_driver = {
-       .driver = {
-               .name = "ucc_uart",
-               .owner = THIS_MODULE,
-               .of_match_table    = ucc_uart_match,
-       },
-       .probe          = ucc_uart_probe,
-       .remove         = ucc_uart_remove,
-};
-
-static int __init ucc_uart_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Freescale QUICC Engine UART device driver\n");
-#ifdef LOOPBACK
-       printk(KERN_INFO "ucc-uart: Using loopback mode\n");
-#endif
-
-       ret = uart_register_driver(&ucc_uart_driver);
-       if (ret) {
-               printk(KERN_ERR "ucc-uart: could not register UART driver\n");
-               return ret;
-       }
-
-       ret = of_register_platform_driver(&ucc_uart_of_driver);
-       if (ret)
-               printk(KERN_ERR
-                      "ucc-uart: could not register platform driver\n");
-
-       return ret;
-}
-
-static void __exit ucc_uart_exit(void)
-{
-       printk(KERN_INFO
-              "Freescale QUICC Engine UART device driver unloading\n");
-
-       of_unregister_platform_driver(&ucc_uart_of_driver);
-       uart_unregister_driver(&ucc_uart_driver);
-}
-
-module_init(ucc_uart_init);
-module_exit(ucc_uart_exit);
-
-MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART");
-MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR);
-
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
deleted file mode 100644 (file)
index 3beb6ab..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- *  Driver for NEC VR4100 series Serial Interface Unit.
- *
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
- *
- *  Based on drivers/serial/8250.c, by Russell King.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/console.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/siu.h>
-#include <asm/vr41xx/vr41xx.h>
-
-#define SIU_BAUD_BASE  1152000
-#define SIU_MAJOR      204
-#define SIU_MINOR_BASE 82
-
-#define RX_MAX_COUNT   256
-#define TX_MAX_COUNT   15
-
-#define SIUIRSEL       0x08
- #define TMICMODE      0x20
- #define TMICTX                0x10
- #define IRMSEL                0x0c
- #define IRMSEL_HP     0x08
- #define IRMSEL_TEMIC  0x04
- #define IRMSEL_SHARP  0x00
- #define IRUSESEL      0x02
- #define SIRSEL                0x01
-
-static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
-       [0 ... SIU_PORTS_MAX-1] = {
-               .lock   = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
-               .irq    = -1,
-       },
-};
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-static uint8_t lsr_break_flag[SIU_PORTS_MAX];
-#endif
-
-#define siu_read(port, offset)         readb((port)->membase + (offset))
-#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
-
-void vr41xx_select_siu_interface(siu_interface_t interface)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       if (interface == SIU_INTERFACE_IRDA)
-               irsel |= SIRSEL;
-       else
-               irsel &= ~SIRSEL;
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
-
-void vr41xx_use_irda(irda_use_t use)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       if (use == FIR_USE_IRDA)
-               irsel |= IRUSESEL;
-       else
-               irsel &= ~IRUSESEL;
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_use_irda);
-
-void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
-{
-       struct uart_port *port;
-       unsigned long flags;
-       uint8_t irsel;
-
-       port = &siu_uart_ports[0];
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       irsel = siu_read(port, SIUIRSEL);
-       irsel &= ~(IRMSEL | TMICTX | TMICMODE);
-       switch (module) {
-       case SHARP_IRDA:
-               irsel |= IRMSEL_SHARP;
-               break;
-       case TEMIC_IRDA:
-               irsel |= IRMSEL_TEMIC | TMICMODE;
-               if (speed == IRDA_TX_4MBPS)
-                       irsel |= TMICTX;
-               break;
-       case HP_IRDA:
-               irsel |= IRMSEL_HP;
-               break;
-       default:
-               break;
-       }
-       siu_write(port, SIUIRSEL, irsel);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
-
-static inline void siu_clear_fifo(struct uart_port *port)
-{
-       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
-       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
-                                 UART_FCR_CLEAR_XMIT);
-       siu_write(port, UART_FCR, 0);
-}
-
-static inline unsigned long siu_port_size(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_VR41XX_SIU:
-               return 11UL;
-       case PORT_VR41XX_DSIU:
-               return 8UL;
-       }
-
-       return 0;
-}
-
-static inline unsigned int siu_check_type(struct uart_port *port)
-{
-       if (port->line == 0)
-               return PORT_VR41XX_SIU;
-       if (port->line == 1 && port->irq != -1)
-               return PORT_VR41XX_DSIU;
-
-       return PORT_UNKNOWN;
-}
-
-static inline const char *siu_type_name(struct uart_port *port)
-{
-       switch (port->type) {
-       case PORT_VR41XX_SIU:
-               return "SIU";
-       case PORT_VR41XX_DSIU:
-               return "DSIU";
-       }
-
-       return NULL;
-}
-
-static unsigned int siu_tx_empty(struct uart_port *port)
-{
-       uint8_t lsr;
-
-       lsr = siu_read(port, UART_LSR);
-       if (lsr & UART_LSR_TEMT)
-               return TIOCSER_TEMT;
-
-       return 0;
-}
-
-static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       uint8_t mcr = 0;
-
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       siu_write(port, UART_MCR, mcr);
-}
-
-static unsigned int siu_get_mctrl(struct uart_port *port)
-{
-       uint8_t msr;
-       unsigned int mctrl = 0;
-
-       msr = siu_read(port, UART_MSR);
-       if (msr & UART_MSR_DCD)
-               mctrl |= TIOCM_CAR;
-       if (msr & UART_MSR_RI)
-               mctrl |= TIOCM_RNG;
-       if (msr & UART_MSR_DSR)
-               mctrl |= TIOCM_DSR;
-       if (msr & UART_MSR_CTS)
-               mctrl |= TIOCM_CTS;
-
-       return mctrl;
-}
-
-static void siu_stop_tx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_THRI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_start_tx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier |= UART_IER_THRI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_stop_rx(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_RLSI;
-       siu_write(port, UART_IER, ier);
-
-       port->read_status_mask &= ~UART_LSR_DR;
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_enable_ms(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t ier;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       ier = siu_read(port, UART_IER);
-       ier |= UART_IER_MSI;
-       siu_write(port, UART_IER, ier);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_break_ctl(struct uart_port *port, int ctl)
-{
-       unsigned long flags;
-       uint8_t lcr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       lcr = siu_read(port, UART_LCR);
-       if (ctl == -1)
-               lcr |= UART_LCR_SBC;
-       else
-               lcr &= ~UART_LCR_SBC;
-       siu_write(port, UART_LCR, lcr);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static inline void receive_chars(struct uart_port *port, uint8_t *status)
-{
-       struct tty_struct *tty;
-       uint8_t lsr, ch;
-       char flag;
-       int max_count = RX_MAX_COUNT;
-
-       tty = port->state->port.tty;
-       lsr = *status;
-
-       do {
-               ch = siu_read(port, UART_RX);
-               port->icount.rx++;
-               flag = TTY_NORMAL;
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-               lsr |= lsr_break_flag[port->line];
-               lsr_break_flag[port->line] = 0;
-#endif
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
-                                   UART_LSR_PE | UART_LSR_OE))) {
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
-                               port->icount.brk++;
-
-                               if (uart_handle_break(port))
-                                       goto ignore_char;
-                       }
-
-                       if (lsr & UART_LSR_FE)
-                               port->icount.frame++;
-                       if (lsr & UART_LSR_PE)
-                               port->icount.parity++;
-                       if (lsr & UART_LSR_OE)
-                               port->icount.overrun++;
-
-                       lsr &= port->read_status_mask;
-                       if (lsr & UART_LSR_BI)
-                               flag = TTY_BREAK;
-                       if (lsr & UART_LSR_FE)
-                               flag = TTY_FRAME;
-                       if (lsr & UART_LSR_PE)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
-
-               uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-       ignore_char:
-               lsr = siu_read(port, UART_LSR);
-       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
-
-       tty_flip_buffer_push(tty);
-
-       *status = lsr;
-}
-
-static inline void check_modem_status(struct uart_port *port)
-{
-       uint8_t msr;
-
-       msr = siu_read(port, UART_MSR);
-       if ((msr & UART_MSR_ANY_DELTA) == 0)
-               return;
-       if (msr & UART_MSR_DDCD)
-               uart_handle_dcd_change(port, msr & UART_MSR_DCD);
-       if (msr & UART_MSR_TERI)
-               port->icount.rng++;
-       if (msr & UART_MSR_DDSR)
-               port->icount.dsr++;
-       if (msr & UART_MSR_DCTS)
-               uart_handle_cts_change(port, msr & UART_MSR_CTS);
-
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static inline void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-       int max_count = TX_MAX_COUNT;
-
-       xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               siu_write(port, UART_TX, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               siu_stop_tx(port);
-               return;
-       }
-
-       do {
-               siu_write(port, UART_TX, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               if (uart_circ_empty(xmit))
-                       break;
-       } while (max_count-- > 0);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               siu_stop_tx(port);
-}
-
-static irqreturn_t siu_interrupt(int irq, void *dev_id)
-{
-       struct uart_port *port;
-       uint8_t iir, lsr;
-
-       port = (struct uart_port *)dev_id;
-
-       iir = siu_read(port, UART_IIR);
-       if (iir & UART_IIR_NO_INT)
-               return IRQ_NONE;
-
-       lsr = siu_read(port, UART_LSR);
-       if (lsr & UART_LSR_DR)
-               receive_chars(port, &lsr);
-
-       check_modem_status(port);
-
-       if (lsr & UART_LSR_THRE)
-               transmit_chars(port);
-
-       return IRQ_HANDLED;
-}
-
-static int siu_startup(struct uart_port *port)
-{
-       int retval;
-
-       if (port->membase == NULL)
-               return -ENODEV;
-
-       siu_clear_fifo(port);
-
-       (void)siu_read(port, UART_LSR);
-       (void)siu_read(port, UART_RX);
-       (void)siu_read(port, UART_IIR);
-       (void)siu_read(port, UART_MSR);
-
-       if (siu_read(port, UART_LSR) == 0xff)
-               return -ENODEV;
-
-       retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
-       if (retval)
-               return retval;
-
-       if (port->type == PORT_VR41XX_DSIU)
-               vr41xx_enable_dsiuint(DSIUINT_ALL);
-
-       siu_write(port, UART_LCR, UART_LCR_WLEN8);
-
-       spin_lock_irq(&port->lock);
-       siu_set_mctrl(port, port->mctrl);
-       spin_unlock_irq(&port->lock);
-
-       siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
-
-       (void)siu_read(port, UART_LSR);
-       (void)siu_read(port, UART_RX);
-       (void)siu_read(port, UART_IIR);
-       (void)siu_read(port, UART_MSR);
-
-       return 0;
-}
-
-static void siu_shutdown(struct uart_port *port)
-{
-       unsigned long flags;
-       uint8_t lcr;
-
-       siu_write(port, UART_IER, 0);
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       port->mctrl &= ~TIOCM_OUT2;
-       siu_set_mctrl(port, port->mctrl);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       lcr = siu_read(port, UART_LCR);
-       lcr &= ~UART_LCR_SBC;
-       siu_write(port, UART_LCR, lcr);
-
-       siu_clear_fifo(port);
-
-       (void)siu_read(port, UART_RX);
-
-       if (port->type == PORT_VR41XX_DSIU)
-               vr41xx_disable_dsiuint(DSIUINT_ALL);
-
-       free_irq(port->irq, port);
-}
-
-static void siu_set_termios(struct uart_port *port, struct ktermios *new,
-                            struct ktermios *old)
-{
-       tcflag_t c_cflag, c_iflag;
-       uint8_t lcr, fcr, ier;
-       unsigned int baud, quot;
-       unsigned long flags;
-
-       c_cflag = new->c_cflag;
-       switch (c_cflag & CSIZE) {
-       case CS5:
-               lcr = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               lcr = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               lcr = UART_LCR_WLEN7;
-               break;
-       default:
-               lcr = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (c_cflag & CSTOPB)
-               lcr |= UART_LCR_STOP;
-       if (c_cflag & PARENB)
-               lcr |= UART_LCR_PARITY;
-       if ((c_cflag & PARODD) != PARODD)
-               lcr |= UART_LCR_EPAR;
-       if (c_cflag & CMSPAR)
-               lcr |= UART_LCR_SPAR;
-
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       uart_update_timeout(port, c_cflag, baud);
-
-       c_iflag = new->c_iflag;
-
-       port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
-       if (c_iflag & INPCK)
-               port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= UART_LSR_BI;
-
-       port->ignore_status_mask = 0;
-       if (c_iflag & IGNPAR)
-               port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (c_iflag & IGNBRK) {
-               port->ignore_status_mask |= UART_LSR_BI;
-               if (c_iflag & IGNPAR)
-                       port->ignore_status_mask |= UART_LSR_OE;
-       }
-
-       if ((c_cflag & CREAD) == 0)
-               port->ignore_status_mask |= UART_LSR_DR;
-
-       ier = siu_read(port, UART_IER);
-       ier &= ~UART_IER_MSI;
-       if (UART_ENABLE_MS(port, c_cflag))
-               ier |= UART_IER_MSI;
-       siu_write(port, UART_IER, ier);
-
-       siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
-
-       siu_write(port, UART_DLL, (uint8_t)quot);
-       siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
-
-       siu_write(port, UART_LCR, lcr);
-
-       siu_write(port, UART_FCR, fcr);
-
-       siu_set_mctrl(port, port->mctrl);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
-{
-       switch (state) {
-       case 0:
-               switch (port->type) {
-               case PORT_VR41XX_SIU:
-                       vr41xx_supply_clock(SIU_CLOCK);
-                       break;
-               case PORT_VR41XX_DSIU:
-                       vr41xx_supply_clock(DSIU_CLOCK);
-                       break;
-               }
-               break;
-       case 3:
-               switch (port->type) {
-               case PORT_VR41XX_SIU:
-                       vr41xx_mask_clock(SIU_CLOCK);
-                       break;
-               case PORT_VR41XX_DSIU:
-                       vr41xx_mask_clock(DSIU_CLOCK);
-                       break;
-               }
-               break;
-       }
-}
-
-static const char *siu_type(struct uart_port *port)
-{
-       return siu_type_name(port);
-}
-
-static void siu_release_port(struct uart_port *port)
-{
-       unsigned long size;
-
-       if (port->flags & UPF_IOREMAP) {
-               iounmap(port->membase);
-               port->membase = NULL;
-       }
-
-       size = siu_port_size(port);
-       release_mem_region(port->mapbase, size);
-}
-
-static int siu_request_port(struct uart_port *port)
-{
-       unsigned long size;
-       struct resource *res;
-
-       size = siu_port_size(port);
-       res = request_mem_region(port->mapbase, size, siu_type_name(port));
-       if (res == NULL)
-               return -EBUSY;
-
-       if (port->flags & UPF_IOREMAP) {
-               port->membase = ioremap(port->mapbase, size);
-               if (port->membase == NULL) {
-                       release_resource(res);
-                       return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-
-static void siu_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = siu_check_type(port);
-               (void)siu_request_port(port);
-       }
-}
-
-static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
-{
-       if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
-               return -EINVAL;
-       if (port->irq != serial->irq)
-               return -EINVAL;
-       if (port->iotype != serial->io_type)
-               return -EINVAL;
-       if (port->mapbase != (unsigned long)serial->iomem_base)
-               return -EINVAL;
-
-       return 0;
-}
-
-static struct uart_ops siu_uart_ops = {
-       .tx_empty       = siu_tx_empty,
-       .set_mctrl      = siu_set_mctrl,
-       .get_mctrl      = siu_get_mctrl,
-       .stop_tx        = siu_stop_tx,
-       .start_tx       = siu_start_tx,
-       .stop_rx        = siu_stop_rx,
-       .enable_ms      = siu_enable_ms,
-       .break_ctl      = siu_break_ctl,
-       .startup        = siu_startup,
-       .shutdown       = siu_shutdown,
-       .set_termios    = siu_set_termios,
-       .pm             = siu_pm,
-       .type           = siu_type,
-       .release_port   = siu_release_port,
-       .request_port   = siu_request_port,
-       .config_port    = siu_config_port,
-       .verify_port    = siu_verify_port,
-};
-
-static int siu_init_ports(struct platform_device *pdev)
-{
-       struct uart_port *port;
-       struct resource *res;
-       int *type = pdev->dev.platform_data;
-       int i;
-
-       if (!type)
-               return 0;
-
-       port = siu_uart_ports;
-       for (i = 0; i < SIU_PORTS_MAX; i++) {
-               port->type = type[i];
-               if (port->type == PORT_UNKNOWN)
-                       continue;
-               port->irq = platform_get_irq(pdev, i);
-               port->uartclk = SIU_BAUD_BASE * 16;
-               port->fifosize = 16;
-               port->regshift = 0;
-               port->iotype = UPIO_MEM;
-               port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-               port->line = i;
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               port->mapbase = res->start;
-               port++;
-       }
-
-       return i;
-}
-
-#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
-
-#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
-static void wait_for_xmitr(struct uart_port *port)
-{
-       int timeout = 10000;
-       uint8_t lsr, msr;
-
-       do {
-               lsr = siu_read(port, UART_LSR);
-               if (lsr & UART_LSR_BI)
-                       lsr_break_flag[port->line] = UART_LSR_BI;
-
-               if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
-                       break;
-       } while (timeout-- > 0);
-
-       if (port->flags & UPF_CONS_FLOW) {
-               timeout = 1000000;
-
-               do {
-                       msr = siu_read(port, UART_MSR);
-                       if ((msr & UART_MSR_CTS) != 0)
-                               break;
-               } while (timeout-- > 0);
-       }
-}
-
-static void siu_console_putchar(struct uart_port *port, int ch)
-{
-       wait_for_xmitr(port);
-       siu_write(port, UART_TX, ch);
-}
-
-static void siu_console_write(struct console *con, const char *s, unsigned count)
-{
-       struct uart_port *port;
-       uint8_t ier;
-
-       port = &siu_uart_ports[con->index];
-
-       ier = siu_read(port, UART_IER);
-       siu_write(port, UART_IER, 0);
-
-       uart_console_write(port, s, count, siu_console_putchar);
-
-       wait_for_xmitr(port);
-       siu_write(port, UART_IER, ier);
-}
-
-static int __init siu_console_setup(struct console *con, char *options)
-{
-       struct uart_port *port;
-       int baud = 9600;
-       int parity = 'n';
-       int bits = 8;
-       int flow = 'n';
-
-       if (con->index >= SIU_PORTS_MAX)
-               con->index = 0;
-
-       port = &siu_uart_ports[con->index];
-       if (port->membase == NULL) {
-               if (port->mapbase == 0)
-                       return -ENODEV;
-               port->membase = ioremap(port->mapbase, siu_port_size(port));
-       }
-
-       if (port->type == PORT_VR41XX_SIU)
-               vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
-
-       if (options != NULL)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver siu_uart_driver;
-
-static struct console siu_console = {
-       .name   = "ttyVR",
-       .write  = siu_console_write,
-       .device = uart_console_device,
-       .setup  = siu_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &siu_uart_driver,
-};
-
-static int __devinit siu_console_init(void)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < SIU_PORTS_MAX; i++) {
-               port = &siu_uart_ports[i];
-               port->ops = &siu_uart_ops;
-       }
-
-       register_console(&siu_console);
-
-       return 0;
-}
-
-console_initcall(siu_console_init);
-
-void __init vr41xx_siu_early_setup(struct uart_port *port)
-{
-       if (port->type == PORT_UNKNOWN)
-               return;
-
-       siu_uart_ports[port->line].line = port->line;
-       siu_uart_ports[port->line].type = port->type;
-       siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
-       siu_uart_ports[port->line].mapbase = port->mapbase;
-       siu_uart_ports[port->line].mapbase = port->mapbase;
-       siu_uart_ports[port->line].ops = &siu_uart_ops;
-}
-
-#define SERIAL_VR41XX_CONSOLE  &siu_console
-#else
-#define SERIAL_VR41XX_CONSOLE  NULL
-#endif
-
-static struct uart_driver siu_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "SIU",
-       .dev_name       = "ttyVR",
-       .major          = SIU_MAJOR,
-       .minor          = SIU_MINOR_BASE,
-       .cons           = SERIAL_VR41XX_CONSOLE,
-};
-
-static int __devinit siu_probe(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int num, i, retval;
-
-       num = siu_init_ports(dev);
-       if (num <= 0)
-               return -ENODEV;
-
-       siu_uart_driver.nr = num;
-       retval = uart_register_driver(&siu_uart_driver);
-       if (retval)
-               return retval;
-
-       for (i = 0; i < num; i++) {
-               port = &siu_uart_ports[i];
-               port->ops = &siu_uart_ops;
-               port->dev = &dev->dev;
-
-               retval = uart_add_one_port(&siu_uart_driver, port);
-               if (retval < 0) {
-                       port->dev = NULL;
-                       break;
-               }
-       }
-
-       if (i == 0 && retval < 0) {
-               uart_unregister_driver(&siu_uart_driver);
-               return retval;
-       }
-
-       return 0;
-}
-
-static int __devexit siu_remove(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if (port->dev == &dev->dev) {
-                       uart_remove_one_port(&siu_uart_driver, port);
-                       port->dev = NULL;
-               }
-       }
-
-       uart_unregister_driver(&siu_uart_driver);
-
-       return 0;
-}
-
-static int siu_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
-                       uart_suspend_port(&siu_uart_driver, port);
-
-       }
-
-       return 0;
-}
-
-static int siu_resume(struct platform_device *dev)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; i < siu_uart_driver.nr; i++) {
-               port = &siu_uart_ports[i];
-               if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
-                       uart_resume_port(&siu_uart_driver, port);
-       }
-
-       return 0;
-}
-
-static struct platform_driver siu_device_driver = {
-       .probe          = siu_probe,
-       .remove         = __devexit_p(siu_remove),
-       .suspend        = siu_suspend,
-       .resume         = siu_resume,
-       .driver         = {
-               .name   = "SIU",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init vr41xx_siu_init(void)
-{
-       return platform_driver_register(&siu_device_driver);
-}
-
-static void __exit vr41xx_siu_exit(void)
-{
-       platform_driver_unregister(&siu_device_driver);
-}
-
-module_init(vr41xx_siu_init);
-module_exit(vr41xx_siu_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:SIU");
diff --git a/drivers/serial/vt8500_serial.c b/drivers/serial/vt8500_serial.c
deleted file mode 100644 (file)
index 322bf56..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * drivers/serial/vt8500_serial.c
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on msm_serial.c, which is:
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-# define SUPPORT_SYSRQ
-#endif
-
-#include <linux/hrtimer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-/*
- * UART Register offsets
- */
-
-#define VT8500_URTDR           0x0000  /* Transmit data */
-#define VT8500_URRDR           0x0004  /* Receive data */
-#define VT8500_URDIV           0x0008  /* Clock/Baud rate divisor */
-#define VT8500_URLCR           0x000C  /* Line control */
-#define VT8500_URICR           0x0010  /* IrDA control */
-#define VT8500_URIER           0x0014  /* Interrupt enable */
-#define VT8500_URISR           0x0018  /* Interrupt status */
-#define VT8500_URUSR           0x001c  /* UART status */
-#define VT8500_URFCR           0x0020  /* FIFO control */
-#define VT8500_URFIDX          0x0024  /* FIFO index */
-#define VT8500_URBKR           0x0028  /* Break signal count */
-#define VT8500_URTOD           0x002c  /* Time out divisor */
-#define VT8500_TXFIFO          0x1000  /* Transmit FIFO (16x8) */
-#define VT8500_RXFIFO          0x1020  /* Receive FIFO (16x10) */
-
-/*
- * Interrupt enable and status bits
- */
-
-#define TXDE   (1 << 0)        /* Tx Data empty */
-#define RXDF   (1 << 1)        /* Rx Data full */
-#define TXFAE  (1 << 2)        /* Tx FIFO almost empty */
-#define TXFE   (1 << 3)        /* Tx FIFO empty */
-#define RXFAF  (1 << 4)        /* Rx FIFO almost full */
-#define RXFF   (1 << 5)        /* Rx FIFO full */
-#define TXUDR  (1 << 6)        /* Tx underrun */
-#define RXOVER (1 << 7)        /* Rx overrun */
-#define PER    (1 << 8)        /* Parity error */
-#define FER    (1 << 9)        /* Frame error */
-#define TCTS   (1 << 10)       /* Toggle of CTS */
-#define RXTOUT (1 << 11)       /* Rx timeout */
-#define BKDONE (1 << 12)       /* Break signal done */
-#define ERR    (1 << 13)       /* AHB error response */
-
-#define RX_FIFO_INTS   (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
-#define TX_FIFO_INTS   (TXFAE | TXFE | TXUDR)
-
-struct vt8500_port {
-       struct uart_port        uart;
-       char                    name[16];
-       struct clk              *clk;
-       unsigned int            ier;
-};
-
-static inline void vt8500_write(struct uart_port *port, unsigned int val,
-                            unsigned int off)
-{
-       writel(val, port->membase + off);
-}
-
-static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
-{
-       return readl(port->membase + off);
-}
-
-static void vt8500_stop_tx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void vt8500_stop_rx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~RX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void vt8500_enable_ms(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier |= TCTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void handle_rx(struct uart_port *port)
-{
-       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-       if (!tty) {
-               /* Discard data: no tty available */
-               int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
-               u16 ch;
-               while (count--)
-                       ch = readw(port->membase + VT8500_RXFIFO);
-               return;
-       }
-
-       /*
-        * Handle overrun
-        */
-       if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
-               port->icount.overrun++;
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       }
-
-       /* and now the main RX loop */
-       while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
-               unsigned int c;
-               char flag = TTY_NORMAL;
-
-               c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
-
-               /* Mask conditions we're ignorning. */
-               c &= ~port->read_status_mask;
-
-               if (c & FER) {
-                       port->icount.frame++;
-                       flag = TTY_FRAME;
-               } else if (c & PER) {
-                       port->icount.parity++;
-                       flag = TTY_PARITY;
-               }
-               port->icount.rx++;
-
-               if (!uart_handle_sysrq_char(port, c))
-                       tty_insert_flip_char(tty, c, flag);
-       }
-
-       tty_flip_buffer_push(tty);
-       tty_kref_put(tty);
-}
-
-static void handle_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       if (port->x_char) {
-               writeb(port->x_char, port->membase + VT8500_TXFIFO);
-               port->icount.tx++;
-               port->x_char = 0;
-       }
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               vt8500_stop_tx(port);
-               return;
-       }
-
-       while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
-               if (uart_circ_empty(xmit))
-                       break;
-
-               writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
-
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-
-       if (uart_circ_empty(xmit))
-               vt8500_stop_tx(port);
-}
-
-static void vt8500_start_tx(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port = container_of(port,
-                                                      struct vt8500_port,
-                                                      uart);
-
-       vt8500_port->ier &= ~TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-       handle_tx(port);
-       vt8500_port->ier |= TX_FIFO_INTS;
-       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
-}
-
-static void handle_delta_cts(struct uart_port *port)
-{
-       port->icount.cts++;
-       wake_up_interruptible(&port->state->port.delta_msr_wait);
-}
-
-static irqreturn_t vt8500_irq(int irq, void *dev_id)
-{
-       struct uart_port *port = dev_id;
-       unsigned long isr;
-
-       spin_lock(&port->lock);
-       isr = vt8500_read(port, VT8500_URISR);
-
-       /* Acknowledge active status bits */
-       vt8500_write(port, isr, VT8500_URISR);
-
-       if (isr & RX_FIFO_INTS)
-               handle_rx(port);
-       if (isr & TX_FIFO_INTS)
-               handle_tx(port);
-       if (isr & TCTS)
-               handle_delta_cts(port);
-
-       spin_unlock(&port->lock);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int vt8500_tx_empty(struct uart_port *port)
-{
-       return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
-                                               TIOCSER_TEMT : 0;
-}
-
-static unsigned int vt8500_get_mctrl(struct uart_port *port)
-{
-       unsigned int usr;
-
-       usr = vt8500_read(port, VT8500_URUSR);
-       if (usr & (1 << 4))
-               return TIOCM_CTS;
-       else
-               return 0;
-}
-
-static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
-{
-       if (break_ctl)
-               vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
-                            VT8500_URLCR);
-}
-
-static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
-{
-       unsigned long div;
-       unsigned int loops = 1000;
-
-       div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
-
-       if (unlikely((baud < 900) || (baud > 921600)))
-               div |= 7;
-       else
-               div |= (921600 / baud) - 1;
-
-       while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
-               cpu_relax();
-       vt8500_write(port, div, VT8500_URDIV);
-
-       return baud;
-}
-
-static int vt8500_startup(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       int ret;
-
-       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
-                "vt8500_serial%d", port->line);
-
-       ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
-                         vt8500_port->name, port);
-       if (unlikely(ret))
-               return ret;
-
-       vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */
-
-       return 0;
-}
-
-static void vt8500_shutdown(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-
-       vt8500_port->ier = 0;
-
-       /* disable interrupts and FIFOs */
-       vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
-       vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
-       free_irq(port->irq, port);
-}
-
-static void vt8500_set_termios(struct uart_port *port,
-                              struct ktermios *termios,
-                              struct ktermios *old)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       unsigned long flags;
-       unsigned int baud, lcr;
-       unsigned int loops = 1000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 900, 921600);
-       baud = vt8500_set_baud_rate(port, baud);
-       if (tty_termios_baud_rate(termios))
-               tty_termios_encode_baud_rate(termios, baud, baud);
-
-       /* calculate parity */
-       lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
-       lcr &= ~((1 << 5) | (1 << 4));
-       if (termios->c_cflag & PARENB) {
-               lcr |= (1 << 4);
-               termios->c_cflag &= ~CMSPAR;
-               if (termios->c_cflag & PARODD)
-                       lcr |= (1 << 5);
-       }
-
-       /* calculate bits per char */
-       lcr &= ~(1 << 2);
-       switch (termios->c_cflag & CSIZE) {
-       case CS7:
-               break;
-       case CS8:
-       default:
-               lcr |= (1 << 2);
-               termios->c_cflag &= ~CSIZE;
-               termios->c_cflag |= CS8;
-               break;
-       }
-
-       /* calculate stop bits */
-       lcr &= ~(1 << 3);
-       if (termios->c_cflag & CSTOPB)
-               lcr |= (1 << 3);
-
-       /* set parity, bits per char, and stop bit */
-       vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
-
-       /* Configure status bits to ignore based on termio flags. */
-       port->read_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               port->read_status_mask = FER | PER;
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       /* Reset FIFOs */
-       vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
-       while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
-                                                       && --loops)
-               cpu_relax();
-
-       /* Every possible FIFO-related interrupt */
-       vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
-
-       /*
-        * CTS flow control
-        */
-       if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
-               vt8500_port->ier |= TCTS;
-
-       vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
-       vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *vt8500_type(struct uart_port *port)
-{
-       struct vt8500_port *vt8500_port =
-                       container_of(port, struct vt8500_port, uart);
-       return vt8500_port->name;
-}
-
-static void vt8500_release_port(struct uart_port *port)
-{
-}
-
-static int vt8500_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void vt8500_config_port(struct uart_port *port, int flags)
-{
-       port->type = PORT_VT8500;
-}
-
-static int vt8500_verify_port(struct uart_port *port,
-                             struct serial_struct *ser)
-{
-       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
-               return -EINVAL;
-       if (unlikely(port->irq != ser->irq))
-               return -EINVAL;
-       return 0;
-}
-
-static struct vt8500_port *vt8500_uart_ports[4];
-static struct uart_driver vt8500_uart_driver;
-
-#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-
-static inline void wait_for_xmitr(struct uart_port *port)
-{
-       unsigned int status, tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       do {
-               status = vt8500_read(port, VT8500_URFIDX);
-
-               if (--tmout == 0)
-                       break;
-               udelay(1);
-       } while (status & 0x10);
-}
-
-static void vt8500_console_putchar(struct uart_port *port, int c)
-{
-       wait_for_xmitr(port);
-       writeb(c, port->membase + VT8500_TXFIFO);
-}
-
-static void vt8500_console_write(struct console *co, const char *s,
-                             unsigned int count)
-{
-       struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
-       unsigned long ier;
-
-       BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
-
-       ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
-       vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
-
-       uart_console_write(&vt8500_port->uart, s, count,
-                          vt8500_console_putchar);
-
-       /*
-        *      Finally, wait for transmitter to become empty
-        *      and switch back to FIFO
-        */
-       wait_for_xmitr(&vt8500_port->uart);
-       vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
-}
-
-static int __init vt8500_console_setup(struct console *co, char *options)
-{
-       struct vt8500_port *vt8500_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
-               return -ENXIO;
-
-       vt8500_port = vt8500_uart_ports[co->index];
-
-       if (!vt8500_port)
-               return -ENODEV;
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(&vt8500_port->uart,
-                                co, baud, parity, bits, flow);
-}
-
-static struct console vt8500_console = {
-       .name = "ttyWMT",
-       .write = vt8500_console_write,
-       .device = uart_console_device,
-       .setup = vt8500_console_setup,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-       .data = &vt8500_uart_driver,
-};
-
-#define VT8500_CONSOLE (&vt8500_console)
-
-#else
-#define VT8500_CONSOLE NULL
-#endif
-
-static struct uart_ops vt8500_uart_pops = {
-       .tx_empty       = vt8500_tx_empty,
-       .set_mctrl      = vt8500_set_mctrl,
-       .get_mctrl      = vt8500_get_mctrl,
-       .stop_tx        = vt8500_stop_tx,
-       .start_tx       = vt8500_start_tx,
-       .stop_rx        = vt8500_stop_rx,
-       .enable_ms      = vt8500_enable_ms,
-       .break_ctl      = vt8500_break_ctl,
-       .startup        = vt8500_startup,
-       .shutdown       = vt8500_shutdown,
-       .set_termios    = vt8500_set_termios,
-       .type           = vt8500_type,
-       .release_port   = vt8500_release_port,
-       .request_port   = vt8500_request_port,
-       .config_port    = vt8500_config_port,
-       .verify_port    = vt8500_verify_port,
-};
-
-static struct uart_driver vt8500_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "vt8500_serial",
-       .dev_name       = "ttyWMT",
-       .nr             = 6,
-       .cons           = VT8500_CONSOLE,
-};
-
-static int __init vt8500_serial_probe(struct platform_device *pdev)
-{
-       struct vt8500_port *vt8500_port;
-       struct resource *mmres, *irqres;
-       int ret;
-
-       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!mmres || !irqres)
-               return -ENODEV;
-
-       vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
-       if (!vt8500_port)
-               return -ENOMEM;
-
-       vt8500_port->uart.type = PORT_VT8500;
-       vt8500_port->uart.iotype = UPIO_MEM;
-       vt8500_port->uart.mapbase = mmres->start;
-       vt8500_port->uart.irq = irqres->start;
-       vt8500_port->uart.fifosize = 16;
-       vt8500_port->uart.ops = &vt8500_uart_pops;
-       vt8500_port->uart.line = pdev->id;
-       vt8500_port->uart.dev = &pdev->dev;
-       vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-       vt8500_port->uart.uartclk = 24000000;
-
-       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
-                "VT8500 UART%d", pdev->id);
-
-       vt8500_port->uart.membase = ioremap(mmres->start,
-                                           mmres->end - mmres->start + 1);
-       if (!vt8500_port->uart.membase) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       vt8500_uart_ports[pdev->id] = vt8500_port;
-
-       uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
-
-       platform_set_drvdata(pdev, vt8500_port);
-
-       return 0;
-
-err:
-       kfree(vt8500_port);
-       return ret;
-}
-
-static int __devexit vt8500_serial_remove(struct platform_device *pdev)
-{
-       struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-       uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
-       kfree(vt8500_port);
-
-       return 0;
-}
-
-static struct platform_driver vt8500_platform_driver = {
-       .probe  = vt8500_serial_probe,
-       .remove = vt8500_serial_remove,
-       .driver = {
-               .name = "vt8500_serial",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init vt8500_serial_init(void)
-{
-       int ret;
-
-       ret = uart_register_driver(&vt8500_uart_driver);
-       if (unlikely(ret))
-               return ret;
-
-       ret = platform_driver_register(&vt8500_platform_driver);
-
-       if (unlikely(ret))
-               uart_unregister_driver(&vt8500_uart_driver);
-
-       return ret;
-}
-
-static void __exit vt8500_serial_exit(void)
-{
-#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-       unregister_console(&vt8500_console);
-#endif
-       platform_driver_unregister(&vt8500_platform_driver);
-       uart_unregister_driver(&vt8500_uart_driver);
-}
-
-module_init(vt8500_serial_init);
-module_exit(vt8500_serial_exit);
-
-MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
-MODULE_DESCRIPTION("Driver for vt8500 serial device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
deleted file mode 100644 (file)
index 1a7fd3e..0000000
+++ /dev/null
@@ -1,1304 +0,0 @@
-/*
- * zs.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4  signal        SCC
- * 2     1     TxD       <-  A.TxD
- * 3     4     RxD       ->  A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal        SCC
- * 2     2     TxD       <-  B.TxD
- * 3     5     RxD       ->  B.RxD
- * 4           RTS       <- ~A.RTS
- * 5           CTS       -> ~B.CTS
- * 6     6     DSR       -> ~A.SYNC
- * 8           CD        -> ~B.DCD
- * 12          DSRS(DCE) -> ~A.CTS  (*)
- * 15          TxC       ->  B.TxC
- * 17          RxC       ->  B.RxC
- * 20    1     DTR       <- ~A.DTR
- * 22          RI        -> ~A.DCD
- * 23          DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- *     is shared with DSRS(DTE) at pin 23.
- *
- * As you can immediately notice the wiring of the RTS, DTR and DSR signals
- * is a bit odd.  This makes the handling of port B unnecessarily
- * complicated and prevents the use of some automatic modes of operation.
- */
-
-#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/bug.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/irqflags.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/spinlock.h>
-#include <linux/sysrq.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-
-#include <asm/atomic.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/system.h>
-
-#include "zs.h"
-
-
-MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
-MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
-MODULE_LICENSE("GPL");
-
-
-static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
-static char zs_version[] __initdata = "0.10";
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on ZS_NUM_SCCS, so we could support any number of
- * Z85C30s, but for now...
- */
-#define ZS_NUM_SCCS    2               /* Max # of ZS chips supported.  */
-#define ZS_NUM_CHAN    2               /* 2 channels per chip.  */
-#define ZS_CHAN_A      0               /* Index of the channel A.  */
-#define ZS_CHAN_B      1               /* Index of the channel B.  */
-#define ZS_CHAN_IO_SIZE 8              /* IOMEM space size.  */
-#define ZS_CHAN_IO_STRIDE 4            /* Register alignment.  */
-#define ZS_CHAN_IO_OFFSET 1            /* The SCC resides on the high byte
-                                          of the 16-bit IOBUS.  */
-#define ZS_CLOCK        7372800        /* Z85C30 PCLK input clock rate.  */
-
-#define to_zport(uport) container_of(uport, struct zs_port, port)
-
-struct zs_parms {
-       resource_size_t scc[ZS_NUM_SCCS];
-       int irq[ZS_NUM_SCCS];
-};
-
-static struct zs_scc zs_sccs[ZS_NUM_SCCS];
-
-static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
-       0,                              /* write 0 */
-       PAR_SPEC,                       /* write 1 */
-       0,                              /* write 2 */
-       0,                              /* write 3 */
-       X16CLK | SB1,                   /* write 4 */
-       0,                              /* write 5 */
-       0, 0, 0,                        /* write 6, 7, 8 */
-       MIE | DLC | NV,                 /* write 9 */
-       NRZ,                            /* write 10 */
-       TCBR | RCBR,                    /* write 11 */
-       0, 0,                           /* BRG time constant, write 12 + 13 */
-       BRSRC | BRENABL,                /* write 14 */
-       0,                              /* write 15 */
-};
-
-/*
- * Debugging.
- */
-#undef ZS_DEBUG_REGS
-
-
-/*
- * Reading and writing Z85C30 registers.
- */
-static void recovery_delay(void)
-{
-       udelay(2);
-}
-
-static u8 read_zsreg(struct zs_port *zport, int reg)
-{
-       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
-       u8 retval;
-
-       if (reg != 0) {
-               writeb(reg & 0xf, control);
-               fast_iob();
-               recovery_delay();
-       }
-       retval = readb(control);
-       recovery_delay();
-       return retval;
-}
-
-static void write_zsreg(struct zs_port *zport, int reg, u8 value)
-{
-       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
-
-       if (reg != 0) {
-               writeb(reg & 0xf, control);
-               fast_iob(); recovery_delay();
-       }
-       writeb(value, control);
-       fast_iob();
-       recovery_delay();
-       return;
-}
-
-static u8 read_zsdata(struct zs_port *zport)
-{
-       void __iomem *data = zport->port.membase +
-                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
-       u8 retval;
-
-       retval = readb(data);
-       recovery_delay();
-       return retval;
-}
-
-static void write_zsdata(struct zs_port *zport, u8 value)
-{
-       void __iomem *data = zport->port.membase +
-                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
-
-       writeb(value, data);
-       fast_iob();
-       recovery_delay();
-       return;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump(void)
-{
-       struct zs_port *zport;
-       int i, j;
-
-       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
-               zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
-
-               if (!zport->scc)
-                       continue;
-
-               for (j = 0; j < 16; j++)
-                       printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
-               printk("\n");
-               for (j = 0; j < 16; j++)
-                       printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
-               printk("\n\n");
-       }
-}
-#endif
-
-
-static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
-{
-       if (irq)
-               spin_lock_irq(lock);
-       else
-               spin_lock(lock);
-}
-
-static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
-{
-       if (irq)
-               spin_unlock_irq(lock);
-       else
-               spin_unlock(lock);
-}
-
-static int zs_receive_drain(struct zs_port *zport)
-{
-       int loops = 10000;
-
-       while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops)
-               read_zsdata(zport);
-       return loops;
-}
-
-static int zs_transmit_drain(struct zs_port *zport, int irq)
-{
-       struct zs_scc *scc = zport->scc;
-       int loops = 10000;
-
-       while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) {
-               zs_spin_unlock_cond_irq(&scc->zlock, irq);
-               udelay(2);
-               zs_spin_lock_cond_irq(&scc->zlock, irq);
-       }
-       return loops;
-}
-
-static int zs_line_drain(struct zs_port *zport, int irq)
-{
-       struct zs_scc *scc = zport->scc;
-       int loops = 10000;
-
-       while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) {
-               zs_spin_unlock_cond_irq(&scc->zlock, irq);
-               udelay(2);
-               zs_spin_lock_cond_irq(&scc->zlock, irq);
-       }
-       return loops;
-}
-
-
-static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
-{
-       /* Let the current transmission finish.  */
-       zs_line_drain(zport, irq);
-       /* Load 'em up.  */
-       write_zsreg(zport, R3, regs[3] & ~RxENABLE);
-       write_zsreg(zport, R5, regs[5] & ~TxENAB);
-       write_zsreg(zport, R4, regs[4]);
-       write_zsreg(zport, R9, regs[9]);
-       write_zsreg(zport, R1, regs[1]);
-       write_zsreg(zport, R2, regs[2]);
-       write_zsreg(zport, R10, regs[10]);
-       write_zsreg(zport, R14, regs[14] & ~BRENABL);
-       write_zsreg(zport, R11, regs[11]);
-       write_zsreg(zport, R12, regs[12]);
-       write_zsreg(zport, R13, regs[13]);
-       write_zsreg(zport, R14, regs[14]);
-       write_zsreg(zport, R15, regs[15]);
-       if (regs[3] & RxENABLE)
-               write_zsreg(zport, R3, regs[3]);
-       if (regs[5] & TxENAB)
-               write_zsreg(zport, R5, regs[5]);
-       return;
-}
-
-
-/*
- * Status handling routines.
- */
-
-/*
- * zs_tx_empty() -- get the transmitter empty status
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting.  This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space.
- */
-static unsigned int zs_tx_empty(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       u8 status;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       status = read_zsreg(zport, R1);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       return status & ALL_SNT ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
-                                       struct zs_port *zport_b)
-{
-       u8 status_a, status_b;
-       unsigned int mctrl;
-
-       status_a = read_zsreg(zport_a, R0);
-       status_b = read_zsreg(zport_b, R0);
-
-       mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
-               ((status_b & DCD) ? TIOCM_CAR : 0) |
-               ((status_a & DCD) ? TIOCM_RNG : 0) |
-               ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
-
-       return mctrl;
-}
-
-static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
-{
-       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
-
-       return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
-}
-
-static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
-{
-       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
-       unsigned int mmask, mctrl, delta;
-       u8 mask_a, mask_b;
-
-       if (zport == zport_a)
-               return 0;
-
-       mask_a = zport_a->regs[15];
-       mask_b = zport->regs[15];
-
-       mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
-               ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
-               ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
-               ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
-
-       mctrl = zport->mctrl;
-       if (mmask) {
-               mctrl &= ~mmask;
-               mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
-       }
-
-       delta = mctrl ^ zport->mctrl;
-       if (delta)
-               zport->mctrl = mctrl;
-
-       return delta;
-}
-
-static unsigned int zs_get_mctrl(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned int mctrl;
-
-       spin_lock(&scc->zlock);
-       mctrl = zs_raw_get_mctrl(zport);
-       spin_unlock(&scc->zlock);
-
-       return mctrl;
-}
-
-static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       u8 oldloop, newloop;
-
-       spin_lock(&scc->zlock);
-       if (zport != zport_a) {
-               if (mctrl & TIOCM_DTR)
-                       zport_a->regs[5] |= DTR;
-               else
-                       zport_a->regs[5] &= ~DTR;
-               if (mctrl & TIOCM_RTS)
-                       zport_a->regs[5] |= RTS;
-               else
-                       zport_a->regs[5] &= ~RTS;
-               write_zsreg(zport_a, R5, zport_a->regs[5]);
-       }
-
-       /* Rarely modified, so don't poke at hardware unless necessary. */
-       oldloop = zport->regs[14];
-       newloop = oldloop;
-       if (mctrl & TIOCM_LOOP)
-               newloop |= LOOPBAK;
-       else
-               newloop &= ~LOOPBAK;
-       if (newloop != oldloop) {
-               zport->regs[14] = newloop;
-               write_zsreg(zport, R14, zport->regs[14]);
-       }
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_raw_stop_tx(struct zs_port *zport)
-{
-       write_zsreg(zport, R0, RES_Tx_P);
-       zport->tx_stopped = 1;
-}
-
-static void zs_stop_tx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       zs_raw_stop_tx(zport);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_raw_transmit_chars(struct zs_port *);
-
-static void zs_start_tx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       if (zport->tx_stopped) {
-               zs_transmit_drain(zport, 0);
-               zport->tx_stopped = 0;
-               zs_raw_transmit_chars(zport);
-       }
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_stop_rx(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-
-       spin_lock(&scc->zlock);
-       zport->regs[15] &= ~BRKIE;
-       zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
-       zport->regs[1] |= RxINT_DISAB;
-
-       if (zport != zport_a) {
-               /* A-side DCD tracks RI and SYNC tracks DSR.  */
-               zport_a->regs[15] &= ~(DCDIE | SYNCIE);
-               write_zsreg(zport_a, R15, zport_a->regs[15]);
-               if (!(zport_a->regs[15] & BRKIE)) {
-                       zport_a->regs[1] &= ~EXT_INT_ENAB;
-                       write_zsreg(zport_a, R1, zport_a->regs[1]);
-               }
-
-               /* This-side DCD tracks DCD and CTS tracks CTS.  */
-               zport->regs[15] &= ~(DCDIE | CTSIE);
-               zport->regs[1] &= ~EXT_INT_ENAB;
-       } else {
-               /* DCD tracks RI and SYNC tracks DSR for the B side.  */
-               if (!(zport->regs[15] & (DCDIE | SYNCIE)))
-                       zport->regs[1] &= ~EXT_INT_ENAB;
-       }
-
-       write_zsreg(zport, R15, zport->regs[15]);
-       write_zsreg(zport, R1, zport->regs[1]);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_enable_ms(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-
-       if (zport == zport_a)
-               return;
-
-       spin_lock(&scc->zlock);
-
-       /* Clear Ext interrupts if not being handled already.  */
-       if (!(zport_a->regs[1] & EXT_INT_ENAB))
-               write_zsreg(zport_a, R0, RES_EXT_INT);
-
-       /* A-side DCD tracks RI and SYNC tracks DSR.  */
-       zport_a->regs[1] |= EXT_INT_ENAB;
-       zport_a->regs[15] |= DCDIE | SYNCIE;
-
-       /* This-side DCD tracks DCD and CTS tracks CTS.  */
-       zport->regs[15] |= DCDIE | CTSIE;
-
-       zs_raw_xor_mctrl(zport);
-
-       write_zsreg(zport_a, R1, zport_a->regs[1]);
-       write_zsreg(zport_a, R15, zport_a->regs[15]);
-       write_zsreg(zport, R15, zport->regs[15]);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_break_ctl(struct uart_port *uport, int break_state)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       if (break_state == -1)
-               zport->regs[5] |= SND_BRK;
-       else
-               zport->regs[5] &= ~SND_BRK;
-       write_zsreg(zport, R5, zport->regs[5]);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-
-/*
- * Interrupt handling routines.
- */
-#define Rx_BRK 0x0100                  /* BREAK event software flag.  */
-#define Rx_SYS 0x0200                  /* SysRq event software flag.  */
-
-static void zs_receive_chars(struct zs_port *zport)
-{
-       struct uart_port *uport = &zport->port;
-       struct zs_scc *scc = zport->scc;
-       struct uart_icount *icount;
-       unsigned int avail, status, ch, flag;
-       int count;
-
-       for (count = 16; count; count--) {
-               spin_lock(&scc->zlock);
-               avail = read_zsreg(zport, R0) & Rx_CH_AV;
-               spin_unlock(&scc->zlock);
-               if (!avail)
-                       break;
-
-               spin_lock(&scc->zlock);
-               status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
-               ch = read_zsdata(zport);
-               spin_unlock(&scc->zlock);
-
-               flag = TTY_NORMAL;
-
-               icount = &uport->icount;
-               icount->rx++;
-
-               /* Handle the null char got when BREAK is removed.  */
-               if (!ch)
-                       status |= zport->tty_break;
-               if (unlikely(status &
-                            (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
-                       zport->tty_break = 0;
-
-                       /* Reset the error indication.  */
-                       if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
-                               spin_lock(&scc->zlock);
-                               write_zsreg(zport, R0, ERR_RES);
-                               spin_unlock(&scc->zlock);
-                       }
-
-                       if (status & (Rx_SYS | Rx_BRK)) {
-                               icount->brk++;
-                               /* SysRq discards the null char.  */
-                               if (status & Rx_SYS)
-                                       continue;
-                       } else if (status & FRM_ERR)
-                               icount->frame++;
-                       else if (status & PAR_ERR)
-                               icount->parity++;
-                       if (status & Rx_OVR)
-                               icount->overrun++;
-
-                       status &= uport->read_status_mask;
-                       if (status & Rx_BRK)
-                               flag = TTY_BREAK;
-                       else if (status & FRM_ERR)
-                               flag = TTY_FRAME;
-                       else if (status & PAR_ERR)
-                               flag = TTY_PARITY;
-               }
-
-               if (uart_handle_sysrq_char(uport, ch))
-                       continue;
-
-               uart_insert_char(uport, status, Rx_OVR, ch, flag);
-       }
-
-       tty_flip_buffer_push(uport->state->port.tty);
-}
-
-static void zs_raw_transmit_chars(struct zs_port *zport)
-{
-       struct circ_buf *xmit = &zport->port.state->xmit;
-
-       /* XON/XOFF chars.  */
-       if (zport->port.x_char) {
-               write_zsdata(zport, zport->port.x_char);
-               zport->port.icount.tx++;
-               zport->port.x_char = 0;
-               return;
-       }
-
-       /* If nothing to do or stopped or hardware stopped.  */
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
-               zs_raw_stop_tx(zport);
-               return;
-       }
-
-       /* Send char.  */
-       write_zsdata(zport, xmit->buf[xmit->tail]);
-       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-       zport->port.icount.tx++;
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&zport->port);
-
-       /* Are we are done?  */
-       if (uart_circ_empty(xmit))
-               zs_raw_stop_tx(zport);
-}
-
-static void zs_transmit_chars(struct zs_port *zport)
-{
-       struct zs_scc *scc = zport->scc;
-
-       spin_lock(&scc->zlock);
-       zs_raw_transmit_chars(zport);
-       spin_unlock(&scc->zlock);
-}
-
-static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
-{
-       struct uart_port *uport = &zport->port;
-       struct zs_scc *scc = zport->scc;
-       unsigned int delta;
-       u8 status, brk;
-
-       spin_lock(&scc->zlock);
-
-       /* Get status from Read Register 0.  */
-       status = read_zsreg(zport, R0);
-
-       if (zport->regs[15] & BRKIE) {
-               brk = status & BRK_ABRT;
-               if (brk && !zport->brk) {
-                       spin_unlock(&scc->zlock);
-                       if (uart_handle_break(uport))
-                               zport->tty_break = Rx_SYS;
-                       else
-                               zport->tty_break = Rx_BRK;
-                       spin_lock(&scc->zlock);
-               }
-               zport->brk = brk;
-       }
-
-       if (zport != zport_a) {
-               delta = zs_raw_xor_mctrl(zport);
-               spin_unlock(&scc->zlock);
-
-               if (delta & TIOCM_CTS)
-                       uart_handle_cts_change(uport,
-                                              zport->mctrl & TIOCM_CTS);
-               if (delta & TIOCM_CAR)
-                       uart_handle_dcd_change(uport,
-                                              zport->mctrl & TIOCM_CAR);
-               if (delta & TIOCM_RNG)
-                       uport->icount.dsr++;
-               if (delta & TIOCM_DSR)
-                       uport->icount.rng++;
-
-               if (delta)
-                       wake_up_interruptible(&uport->state->port.delta_msr_wait);
-
-               spin_lock(&scc->zlock);
-       }
-
-       /* Clear the status condition...  */
-       write_zsreg(zport, R0, RES_EXT_INT);
-
-       spin_unlock(&scc->zlock);
-}
-
-/*
- * This is the Z85C30 driver's generic interrupt routine.
- */
-static irqreturn_t zs_interrupt(int irq, void *dev_id)
-{
-       struct zs_scc *scc = dev_id;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
-       irqreturn_t status = IRQ_NONE;
-       u8 zs_intreg;
-       int count;
-
-       /*
-        * NOTE: The read register 3, which holds the irq status,
-        *       does so for both channels on each chip.  Although
-        *       the status value itself must be read from the A
-        *       channel and is only valid when read from channel A.
-        *       Yes... broken hardware...
-        */
-       for (count = 16; count; count--) {
-               spin_lock(&scc->zlock);
-               zs_intreg = read_zsreg(zport_a, R3);
-               spin_unlock(&scc->zlock);
-               if (!zs_intreg)
-                       break;
-
-               /*
-                * We do not like losing characters, so we prioritise
-                * interrupt sources a little bit differently than
-                * the SCC would, was it allowed to.
-                */
-               if (zs_intreg & CHBRxIP)
-                       zs_receive_chars(zport_b);
-               if (zs_intreg & CHARxIP)
-                       zs_receive_chars(zport_a);
-               if (zs_intreg & CHBEXT)
-                       zs_status_handle(zport_b, zport_a);
-               if (zs_intreg & CHAEXT)
-                       zs_status_handle(zport_a, zport_a);
-               if (zs_intreg & CHBTxIP)
-                       zs_transmit_chars(zport_b);
-               if (zs_intreg & CHATxIP)
-                       zs_transmit_chars(zport_a);
-
-               status = IRQ_HANDLED;
-       }
-
-       return status;
-}
-
-
-/*
- * Finally, routines used to initialize the serial port.
- */
-static int zs_startup(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       int irq_guard;
-       int ret;
-
-       irq_guard = atomic_add_return(1, &scc->irq_guard);
-       if (irq_guard == 1) {
-               ret = request_irq(zport->port.irq, zs_interrupt,
-                                 IRQF_SHARED, "scc", scc);
-               if (ret) {
-                       atomic_add(-1, &scc->irq_guard);
-                       printk(KERN_ERR "zs: can't get irq %d\n",
-                              zport->port.irq);
-                       return ret;
-               }
-       }
-
-       spin_lock_irqsave(&scc->zlock, flags);
-
-       /* Clear the receive FIFO.  */
-       zs_receive_drain(zport);
-
-       /* Clear the interrupt registers.  */
-       write_zsreg(zport, R0, ERR_RES);
-       write_zsreg(zport, R0, RES_Tx_P);
-       /* But Ext only if not being handled already.  */
-       if (!(zport->regs[1] & EXT_INT_ENAB))
-               write_zsreg(zport, R0, RES_EXT_INT);
-
-       /* Finally, enable sequencing and interrupts.  */
-       zport->regs[1] &= ~RxINT_MASK;
-       zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
-       zport->regs[3] |= RxENABLE;
-       zport->regs[15] |= BRKIE;
-       write_zsreg(zport, R1, zport->regs[1]);
-       write_zsreg(zport, R3, zport->regs[3]);
-       write_zsreg(zport, R5, zport->regs[5]);
-       write_zsreg(zport, R15, zport->regs[15]);
-
-       /* Record the current state of RR0.  */
-       zport->mctrl = zs_raw_get_mctrl(zport);
-       zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
-
-       zport->tx_stopped = 1;
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       return 0;
-}
-
-static void zs_shutdown(struct uart_port *uport)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       int irq_guard;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-
-       zport->regs[3] &= ~RxENABLE;
-       write_zsreg(zport, R5, zport->regs[5]);
-       write_zsreg(zport, R3, zport->regs[3]);
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       irq_guard = atomic_add_return(-1, &scc->irq_guard);
-       if (!irq_guard)
-               free_irq(zport->port.irq, scc);
-}
-
-
-static void zs_reset(struct zs_port *zport)
-{
-       struct zs_scc *scc = zport->scc;
-       int irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       if (!scc->initialised) {
-               /* Reset the pointer first, just in case...  */
-               read_zsreg(zport, R0);
-               /* And let the current transmission finish.  */
-               zs_line_drain(zport, irq);
-               write_zsreg(zport, R9, FHWRES);
-               udelay(10);
-               write_zsreg(zport, R9, 0);
-               scc->initialised = 1;
-       }
-       load_zsregs(zport, zport->regs, irq);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
-                          struct ktermios *old_termios)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
-       int irq;
-       unsigned int baud, brg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-
-       /* Byte size.  */
-       zport->regs[3] &= ~RxNBITS_MASK;
-       zport->regs[5] &= ~TxNBITS_MASK;
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               zport->regs[3] |= Rx5;
-               zport->regs[5] |= Tx5;
-               break;
-       case CS6:
-               zport->regs[3] |= Rx6;
-               zport->regs[5] |= Tx6;
-               break;
-       case CS7:
-               zport->regs[3] |= Rx7;
-               zport->regs[5] |= Tx7;
-               break;
-       case CS8:
-       default:
-               zport->regs[3] |= Rx8;
-               zport->regs[5] |= Tx8;
-               break;
-       }
-
-       /* Parity and stop bits.  */
-       zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
-       if (termios->c_cflag & CSTOPB)
-               zport->regs[4] |= SB2;
-       else
-               zport->regs[4] |= SB1;
-       if (termios->c_cflag & PARENB)
-               zport->regs[4] |= PAR_ENA;
-       if (!(termios->c_cflag & PARODD))
-               zport->regs[4] |= PAR_EVEN;
-       switch (zport->clk_mode) {
-       case 64:
-               zport->regs[4] |= X64CLK;
-               break;
-       case 32:
-               zport->regs[4] |= X32CLK;
-               break;
-       case 16:
-               zport->regs[4] |= X16CLK;
-               break;
-       case 1:
-               zport->regs[4] |= X1CLK;
-               break;
-       default:
-               BUG();
-       }
-
-       baud = uart_get_baud_rate(uport, termios, old_termios, 0,
-                                 uport->uartclk / zport->clk_mode / 4);
-
-       brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
-       zport->regs[12] = brg & 0xff;
-       zport->regs[13] = (brg >> 8) & 0xff;
-
-       uart_update_timeout(uport, termios->c_cflag, baud);
-
-       uport->read_status_mask = Rx_OVR;
-       if (termios->c_iflag & INPCK)
-               uport->read_status_mask |= FRM_ERR | PAR_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               uport->read_status_mask |= Rx_BRK;
-
-       uport->ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
-       if (termios->c_iflag & IGNBRK) {
-               uport->ignore_status_mask |= Rx_BRK;
-               if (termios->c_iflag & IGNPAR)
-                       uport->ignore_status_mask |= Rx_OVR;
-       }
-
-       if (termios->c_cflag & CREAD)
-               zport->regs[3] |= RxENABLE;
-       else
-               zport->regs[3] &= ~RxENABLE;
-
-       if (zport != zport_a) {
-               if (!(termios->c_cflag & CLOCAL)) {
-                       zport->regs[15] |= DCDIE;
-               } else
-                       zport->regs[15] &= ~DCDIE;
-               if (termios->c_cflag & CRTSCTS) {
-                       zport->regs[15] |= CTSIE;
-               } else
-                       zport->regs[15] &= ~CTSIE;
-               zs_raw_xor_mctrl(zport);
-       }
-
-       /* Load up the new values.  */
-       load_zsregs(zport, zport->regs, irq);
-
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void zs_pm(struct uart_port *uport, unsigned int state,
-                 unsigned int oldstate)
-{
-       struct zs_port *zport = to_zport(uport);
-
-       if (state < 3)
-               zport->regs[5] |= TxENAB;
-       else
-               zport->regs[5] &= ~TxENAB;
-       write_zsreg(zport, R5, zport->regs[5]);
-}
-
-
-static const char *zs_type(struct uart_port *uport)
-{
-       return "Z85C30 SCC";
-}
-
-static void zs_release_port(struct uart_port *uport)
-{
-       iounmap(uport->membase);
-       uport->membase = 0;
-       release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
-}
-
-static int zs_map_port(struct uart_port *uport)
-{
-       if (!uport->membase)
-               uport->membase = ioremap_nocache(uport->mapbase,
-                                                ZS_CHAN_IO_SIZE);
-       if (!uport->membase) {
-               printk(KERN_ERR "zs: Cannot map MMIO\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static int zs_request_port(struct uart_port *uport)
-{
-       int ret;
-
-       if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
-               printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
-               return -EBUSY;
-       }
-       ret = zs_map_port(uport);
-       if (ret) {
-               release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
-               return ret;
-       }
-       return 0;
-}
-
-static void zs_config_port(struct uart_port *uport, int flags)
-{
-       struct zs_port *zport = to_zport(uport);
-
-       if (flags & UART_CONFIG_TYPE) {
-               if (zs_request_port(uport))
-                       return;
-
-               uport->type = PORT_ZS;
-
-               zs_reset(zport);
-       }
-}
-
-static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
-{
-       struct zs_port *zport = to_zport(uport);
-       int ret = 0;
-
-       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
-               ret = -EINVAL;
-       if (ser->irq != uport->irq)
-               ret = -EINVAL;
-       if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
-               ret = -EINVAL;
-       return ret;
-}
-
-
-static struct uart_ops zs_ops = {
-       .tx_empty       = zs_tx_empty,
-       .set_mctrl      = zs_set_mctrl,
-       .get_mctrl      = zs_get_mctrl,
-       .stop_tx        = zs_stop_tx,
-       .start_tx       = zs_start_tx,
-       .stop_rx        = zs_stop_rx,
-       .enable_ms      = zs_enable_ms,
-       .break_ctl      = zs_break_ctl,
-       .startup        = zs_startup,
-       .shutdown       = zs_shutdown,
-       .set_termios    = zs_set_termios,
-       .pm             = zs_pm,
-       .type           = zs_type,
-       .release_port   = zs_release_port,
-       .request_port   = zs_request_port,
-       .config_port    = zs_config_port,
-       .verify_port    = zs_verify_port,
-};
-
-/*
- * Initialize Z85C30 port structures.
- */
-static int __init zs_probe_sccs(void)
-{
-       static int probed;
-       struct zs_parms zs_parms;
-       int chip, side, irq;
-       int n_chips = 0;
-       int i;
-
-       if (probed)
-               return 0;
-
-       irq = dec_interrupt[DEC_IRQ_SCC0];
-       if (irq >= 0) {
-               zs_parms.scc[n_chips] = IOASIC_SCC0;
-               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
-               n_chips++;
-       }
-       irq = dec_interrupt[DEC_IRQ_SCC1];
-       if (irq >= 0) {
-               zs_parms.scc[n_chips] = IOASIC_SCC1;
-               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
-               n_chips++;
-       }
-       if (!n_chips)
-               return -ENXIO;
-
-       probed = 1;
-
-       for (chip = 0; chip < n_chips; chip++) {
-               spin_lock_init(&zs_sccs[chip].zlock);
-               for (side = 0; side < ZS_NUM_CHAN; side++) {
-                       struct zs_port *zport = &zs_sccs[chip].zport[side];
-                       struct uart_port *uport = &zport->port;
-
-                       zport->scc      = &zs_sccs[chip];
-                       zport->clk_mode = 16;
-
-                       uport->irq      = zs_parms.irq[chip];
-                       uport->uartclk  = ZS_CLOCK;
-                       uport->fifosize = 1;
-                       uport->iotype   = UPIO_MEM;
-                       uport->flags    = UPF_BOOT_AUTOCONF;
-                       uport->ops      = &zs_ops;
-                       uport->line     = chip * ZS_NUM_CHAN + side;
-                       uport->mapbase  = dec_kn_slot_base +
-                                         zs_parms.scc[chip] +
-                                         (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
-
-                       for (i = 0; i < ZS_NUM_REGS; i++)
-                               zport->regs[i] = zs_init_regs[i];
-               }
-       }
-
-       return 0;
-}
-
-
-#ifdef CONFIG_SERIAL_ZS_CONSOLE
-static void zs_console_putchar(struct uart_port *uport, int ch)
-{
-       struct zs_port *zport = to_zport(uport);
-       struct zs_scc *scc = zport->scc;
-       int irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       if (zs_transmit_drain(zport, irq))
-               write_zsdata(zport, ch);
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void zs_console_write(struct console *co, const char *s,
-                            unsigned int count)
-{
-       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
-       struct zs_port *zport = &zs_sccs[chip].zport[side];
-       struct zs_scc *scc = zport->scc;
-       unsigned long flags;
-       u8 txint, txenb;
-       int irq;
-
-       /* Disable transmit interrupts and enable the transmitter. */
-       spin_lock_irqsave(&scc->zlock, flags);
-       txint = zport->regs[1];
-       txenb = zport->regs[5];
-       if (txint & TxINT_ENAB) {
-               zport->regs[1] = txint & ~TxINT_ENAB;
-               write_zsreg(zport, R1, zport->regs[1]);
-       }
-       if (!(txenb & TxENAB)) {
-               zport->regs[5] = txenb | TxENAB;
-               write_zsreg(zport, R5, zport->regs[5]);
-       }
-       spin_unlock_irqrestore(&scc->zlock, flags);
-
-       uart_console_write(&zport->port, s, count, zs_console_putchar);
-
-       /* Restore transmit interrupts and the transmitter enable. */
-       spin_lock_irqsave(&scc->zlock, flags);
-       irq = !irqs_disabled_flags(flags);
-       zs_line_drain(zport, irq);
-       if (!(txenb & TxENAB)) {
-               zport->regs[5] &= ~TxENAB;
-               write_zsreg(zport, R5, zport->regs[5]);
-       }
-       if (txint & TxINT_ENAB) {
-               zport->regs[1] |= TxINT_ENAB;
-               write_zsreg(zport, R1, zport->regs[1]);
-       }
-       spin_unlock_irqrestore(&scc->zlock, flags);
-}
-
-/*
- * Setup serial console baud/bits/parity.  We do two things here:
- * - construct a cflag setting for the first uart_open()
- * - initialise the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int __init zs_console_setup(struct console *co, char *options)
-{
-       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
-       struct zs_port *zport = &zs_sccs[chip].zport[side];
-       struct uart_port *uport = &zport->port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-       int ret;
-
-       ret = zs_map_port(uport);
-       if (ret)
-               return ret;
-
-       zs_reset(zport);
-       zs_pm(uport, 0, -1);
-
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       return uart_set_options(uport, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver zs_reg;
-static struct console zs_console = {
-       .name   = "ttyS",
-       .write  = zs_console_write,
-       .device = uart_console_device,
-       .setup  = zs_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-       .data   = &zs_reg,
-};
-
-/*
- *     Register console.
- */
-static int __init zs_serial_console_init(void)
-{
-       int ret;
-
-       ret = zs_probe_sccs();
-       if (ret)
-               return ret;
-       register_console(&zs_console);
-
-       return 0;
-}
-
-console_initcall(zs_serial_console_init);
-
-#define SERIAL_ZS_CONSOLE      &zs_console
-#else
-#define SERIAL_ZS_CONSOLE      NULL
-#endif /* CONFIG_SERIAL_ZS_CONSOLE */
-
-static struct uart_driver zs_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
-       .dev_name               = "ttyS",
-       .major                  = TTY_MAJOR,
-       .minor                  = 64,
-       .nr                     = ZS_NUM_SCCS * ZS_NUM_CHAN,
-       .cons                   = SERIAL_ZS_CONSOLE,
-};
-
-/* zs_init inits the driver. */
-static int __init zs_init(void)
-{
-       int i, ret;
-
-       pr_info("%s%s\n", zs_name, zs_version);
-
-       /* Find out how many Z85C30 SCCs we have.  */
-       ret = zs_probe_sccs();
-       if (ret)
-               return ret;
-
-       ret = uart_register_driver(&zs_reg);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
-               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
-               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
-               struct uart_port *uport = &zport->port;
-
-               if (zport->scc)
-                       uart_add_one_port(&zs_reg, uport);
-       }
-
-       return 0;
-}
-
-static void __exit zs_exit(void)
-{
-       int i;
-
-       for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
-               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
-               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
-               struct uart_port *uport = &zport->port;
-
-               if (zport->scc)
-                       uart_remove_one_port(&zs_reg, uport);
-       }
-
-       uart_unregister_driver(&zs_reg);
-}
-
-module_init(zs_init);
-module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
deleted file mode 100644 (file)
index aa921b5..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
- */
-#ifndef _SERIAL_ZS_H
-#define _SERIAL_ZS_H
-
-#ifdef __KERNEL__
-
-#define ZS_NUM_REGS 16
-
-/*
- * This is our internal structure for each serial port's state.
- */
-struct zs_port {
-       struct zs_scc   *scc;                   /* Containing SCC.  */
-       struct uart_port port;                  /* Underlying UART.  */
-
-       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
-
-       unsigned int    tty_break;              /* Set on BREAK condition.  */
-       int             tx_stopped;             /* Output is suspended.  */
-
-       unsigned int    mctrl;                  /* State of modem lines.  */
-       u8              brk;                    /* BREAK state from RR0.  */
-
-       u8              regs[ZS_NUM_REGS];      /* Channel write registers.  */
-};
-
-/*
- * Per-SCC state for locking and the interrupt handler.
- */
-struct zs_scc {
-       struct zs_port  zport[2];
-       spinlock_t      zlock;
-       atomic_t        irq_guard;
-       int             initialised;
-};
-
-#endif /* __KERNEL__ */
-
-/*
- * Conversion routines to/from brg time constants from/to bits per second.
- */
-#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/*
- * The Zilog register set.
- */
-
-/* Write Register 0 (Command) */
-#define R0             0       /* Register selects */
-#define R1             1
-#define R2             2
-#define R3             3
-#define R4             4
-#define R5             5
-#define R6             6
-#define R7             7
-#define R8             8
-#define R9             9
-#define R10            10
-#define R11            11
-#define R12            12
-#define R13            13
-#define R14            14
-#define R15            15
-
-#define NULLCODE       0       /* Null Code */
-#define POINT_HIGH     0x8     /* Select upper half of registers */
-#define RES_EXT_INT    0x10    /* Reset Ext. Status Interrupts */
-#define SEND_ABORT     0x18    /* HDLC Abort */
-#define RES_RxINT_FC   0x20    /* Reset RxINT on First Character */
-#define RES_Tx_P       0x28    /* Reset TxINT Pending */
-#define ERR_RES                0x30    /* Error Reset */
-#define RES_H_IUS      0x38    /* Reset highest IUS */
-
-#define RES_Rx_CRC     0x40    /* Reset Rx CRC Checker */
-#define RES_Tx_CRC     0x80    /* Reset Tx CRC Checker */
-#define RES_EOM_L      0xC0    /* Reset EOM latch */
-
-/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
-#define EXT_INT_ENAB   0x1     /* Ext Int Enable */
-#define TxINT_ENAB     0x2     /* Tx Int Enable */
-#define PAR_SPEC       0x4     /* Parity is special condition */
-
-#define RxINT_DISAB    0       /* Rx Int Disable */
-#define RxINT_FCERR    0x8     /* Rx Int on First Character Only or Error */
-#define RxINT_ALL      0x10    /* Int on all Rx Characters or error */
-#define RxINT_ERR      0x18    /* Int on error only */
-#define RxINT_MASK     0x18
-
-#define WT_RDY_RT      0x20    /* Wait/Ready on R/T */
-#define WT_FN_RDYFN    0x40    /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB    0x80    /* Wait/Ready Enable */
-
-/* Write Register 2 (Interrupt Vector) */
-
-/* Write Register 3 (Receive Parameters and Control) */
-#define RxENABLE       0x1     /* Rx Enable */
-#define SYNC_L_INH     0x2     /* Sync Character Load Inhibit */
-#define ADD_SM         0x4     /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB     0x8     /* Rx CRC Enable */
-#define ENT_HM         0x10    /* Enter Hunt Mode */
-#define AUTO_ENAB      0x20    /* Auto Enables */
-#define Rx5            0x0     /* Rx 5 Bits/Character */
-#define Rx7            0x40    /* Rx 7 Bits/Character */
-#define Rx6            0x80    /* Rx 6 Bits/Character */
-#define Rx8            0xc0    /* Rx 8 Bits/Character */
-#define RxNBITS_MASK   0xc0
-
-/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
-#define PAR_ENA                0x1     /* Parity Enable */
-#define PAR_EVEN       0x2     /* Parity Even/Odd* */
-
-#define SYNC_ENAB      0       /* Sync Modes Enable */
-#define SB1            0x4     /* 1 stop bit/char */
-#define SB15           0x8     /* 1.5 stop bits/char */
-#define SB2            0xc     /* 2 stop bits/char */
-#define SB_MASK                0xc
-
-#define MONSYNC                0       /* 8 Bit Sync character */
-#define BISYNC         0x10    /* 16 bit sync character */
-#define SDLC           0x20    /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC                0x30    /* External Sync Mode */
-
-#define X1CLK          0x0     /* x1 clock mode */
-#define X16CLK         0x40    /* x16 clock mode */
-#define X32CLK         0x80    /* x32 clock mode */
-#define X64CLK         0xc0    /* x64 clock mode */
-#define XCLK_MASK      0xc0
-
-/* Write Register 5 (Transmit Parameters and Controls) */
-#define TxCRC_ENAB     0x1     /* Tx CRC Enable */
-#define RTS            0x2     /* RTS */
-#define SDLC_CRC       0x4     /* SDLC/CRC-16 */
-#define TxENAB         0x8     /* Tx Enable */
-#define SND_BRK                0x10    /* Send Break */
-#define Tx5            0x0     /* Tx 5 bits (or less)/character */
-#define Tx7            0x20    /* Tx 7 bits/character */
-#define Tx6            0x40    /* Tx 6 bits/character */
-#define Tx8            0x60    /* Tx 8 bits/character */
-#define TxNBITS_MASK   0x60
-#define DTR            0x80    /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (Transmit Buffer) */
-
-/* Write Register 9 (Master Interrupt Control) */
-#define VIS            1       /* Vector Includes Status */
-#define NV             2       /* No Vector */
-#define DLC            4       /* Disable Lower Chain */
-#define MIE            8       /* Master Interrupt Enable */
-#define STATHI         0x10    /* Status high */
-#define SOFTACK                0x20    /* Software Interrupt Acknowledge */
-#define NORESET                0       /* No reset on write to R9 */
-#define CHRB           0x40    /* Reset channel B */
-#define CHRA           0x80    /* Reset channel A */
-#define FHWRES         0xc0    /* Force hardware reset */
-
-/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
-#define BIT6           1       /* 6 bit/8bit sync */
-#define LOOPMODE       2       /* SDLC Loop mode */
-#define ABUNDER                4       /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE       8       /* Mark/flag on idle */
-#define GAOP           0x10    /* Go active on poll */
-#define NRZ            0       /* NRZ mode */
-#define NRZI           0x20    /* NRZI mode */
-#define FM1            0x40    /* FM1 (transition = 1) */
-#define FM0            0x60    /* FM0 (transition = 0) */
-#define CRCPS          0x80    /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode Control) */
-#define TRxCXT         0       /* TRxC = Xtal output */
-#define TRxCTC         1       /* TRxC = Transmit clock */
-#define TRxCBR         2       /* TRxC = BR Generator Output */
-#define TRxCDP         3       /* TRxC = DPLL output */
-#define TRxCOI         4       /* TRxC O/I */
-#define TCRTxCP                0       /* Transmit clock = RTxC pin */
-#define TCTRxCP                8       /* Transmit clock = TRxC pin */
-#define TCBR           0x10    /* Transmit clock = BR Generator output */
-#define TCDPLL         0x18    /* Transmit clock = DPLL output */
-#define RCRTxCP                0       /* Receive clock = RTxC pin */
-#define RCTRxCP                0x20    /* Receive clock = TRxC pin */
-#define RCBR           0x40    /* Receive clock = BR Generator output */
-#define RCDPLL         0x60    /* Receive clock = DPLL output */
-#define RTxCX          0x80    /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
-
-/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
-
-/* Write Register 14 (Miscellaneous Control Bits) */
-#define BRENABL                1       /* Baud rate generator enable */
-#define BRSRC          2       /* Baud rate generator source */
-#define DTRREQ         4       /* DTR/Request function */
-#define AUTOECHO       8       /* Auto Echo */
-#define LOOPBAK                0x10    /* Local loopback */
-#define SEARCH         0x20    /* Enter search mode */
-#define RMC            0x40    /* Reset missing clock */
-#define DISDPLL                0x60    /* Disable DPLL */
-#define SSBR           0x80    /* Set DPLL source = BR generator */
-#define SSRTxC         0xa0    /* Set DPLL source = RTxC */
-#define SFMM           0xc0    /* Set FM mode */
-#define SNRZI          0xe0    /* Set NRZI mode */
-
-/* Write Register 15 (External/Status Interrupt Control) */
-#define WR7P_EN                1       /* WR7 Prime SDLC Feature Enable */
-#define ZCIE           2       /* Zero count IE */
-#define DCDIE          8       /* DCD IE */
-#define SYNCIE         0x10    /* Sync/hunt IE */
-#define CTSIE          0x20    /* CTS IE */
-#define TxUIE          0x40    /* Tx Underrun/EOM IE */
-#define BRKIE          0x80    /* Break/Abort IE */
-
-
-/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
-#define Rx_CH_AV       0x1     /* Rx Character Available */
-#define ZCOUNT         0x2     /* Zero count */
-#define Tx_BUF_EMP     0x4     /* Tx Buffer empty */
-#define DCD            0x8     /* DCD */
-#define SYNC_HUNT      0x10    /* Sync/hunt */
-#define CTS            0x20    /* CTS */
-#define TxEOM          0x40    /* Tx underrun */
-#define BRK_ABRT       0x80    /* Break/Abort */
-
-/* Read Register 1 (Special Receive Condition Status) */
-#define ALL_SNT                0x1     /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3           0x8     /* 0/3 */
-#define RES4           0x4     /* 0/4 */
-#define RES5           0xc     /* 0/5 */
-#define RES6           0x2     /* 0/6 */
-#define RES7           0xa     /* 0/7 */
-#define RES8           0x6     /* 0/8 */
-#define RES18          0xe     /* 1/8 */
-#define RES28          0x0     /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR                0x10    /* Parity Error */
-#define Rx_OVR         0x20    /* Rx Overrun Error */
-#define FRM_ERR                0x40    /* CRC/Framing Error */
-#define END_FR         0x80    /* End of Frame (SDLC) */
-
-/* Read Register 2 (Interrupt Vector (WR2) -- channel A).  */
-
-/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
-
-/* Read Register 3 (Interrupt Pending Bits -- channel A only).  */
-#define CHBEXT         0x1     /* Channel B Ext/Stat IP */
-#define CHBTxIP                0x2     /* Channel B Tx IP */
-#define CHBRxIP                0x4     /* Channel B Rx IP */
-#define CHAEXT         0x8     /* Channel A Ext/Stat IP */
-#define CHATxIP                0x10    /* Channel A Tx IP */
-#define CHARxIP                0x20    /* Channel A Rx IP */
-
-/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
-
-/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
-
-/* Read Register 8 (Receive Data) */
-
-/* Read Register 10 (Miscellaneous Status Bits) */
-#define ONLOOP         2       /* On loop */
-#define LOOPSEND       0x10    /* Loop sending */
-#define CLK2MIS                0x40    /* Two clocks missing */
-#define CLK1MIS                0x80    /* One clock missing */
-
-/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
-
-/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
-
-/* Read Register 15 (External/Status Interrupt Control (WR15)) */
-
-#endif /* _SERIAL_ZS_H */
index de885a0..f33e2dd 100644 (file)
@@ -173,7 +173,8 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
        return 0;
 }
 
-#define VALID(x) (x | 0x80)
+#define SENSE_VALID_FLAG 0x80
+#define VALID(x) (x | SENSE_VALID_FLAG)
 
 static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
        [IRQ_TYPE_EDGE_FALLING] = VALID(0),
@@ -201,7 +202,8 @@ static int intc_set_type(struct irq_data *data, unsigned int type)
        ihp = intc_find_irq(d->sense, d->nr_sense, irq);
        if (ihp) {
                addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
-               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle,
+                                                   value & ~SENSE_VALID_FLAG);
        }
 
        return 0;
index 351d8a3..19752b0 100644 (file)
@@ -7,10 +7,9 @@
 #include <linux/of_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 
-struct awesome_struct {
+struct ce4100_info {
        struct ssp_device ssp;
-       struct platform_device spi_pdev;
-       struct pxa2xx_spi_master spi_pdata;
+       struct platform_device *spi_pdev;
 };
 
 static DEFINE_MUTEX(ssp_lock);
@@ -51,23 +50,15 @@ void pxa_ssp_free(struct ssp_device *ssp)
 }
 EXPORT_SYMBOL_GPL(pxa_ssp_free);
 
-static void plat_dev_release(struct device *dev)
-{
-       struct awesome_struct *as = container_of(dev,
-                       struct awesome_struct, spi_pdev.dev);
-
-       of_device_node_put(&as->spi_pdev.dev);
-}
-
 static int __devinit ce4100_spi_probe(struct pci_dev *dev,
                const struct pci_device_id *ent)
 {
        int ret;
        resource_size_t phys_beg;
        resource_size_t phys_len;
-       struct awesome_struct *spi_info;
+       struct ce4100_info *spi_info;
        struct platform_device *pdev;
-       struct pxa2xx_spi_master *spi_pdata;
+       struct pxa2xx_spi_master spi_pdata;
        struct ssp_device *ssp;
 
        ret = pci_enable_device(dev);
@@ -84,33 +75,30 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev,
                return ret;
        }
 
+       pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
        spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
-       if (!spi_info) {
+       if (!pdev || !spi_info ) {
                ret = -ENOMEM;
-               goto err_kz;
+               goto err_nomem;
        }
-       ssp = &spi_info->ssp;
-       pdev = &spi_info->spi_pdev;
-       spi_pdata =  &spi_info->spi_pdata;
+       memset(&spi_pdata, 0, sizeof(spi_pdata));
+       spi_pdata.num_chipselect = dev->devfn;
 
-       pdev->name = "pxa2xx-spi";
-       pdev->id = dev->devfn;
-       pdev->dev.parent = &dev->dev;
-       pdev->dev.platform_data = &spi_info->spi_pdata;
+       ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
+       if (ret)
+               goto err_nomem;
 
+       pdev->dev.parent = &dev->dev;
 #ifdef CONFIG_OF
        pdev->dev.of_node = dev->dev.of_node;
 #endif
-       pdev->dev.release = plat_dev_release;
-
-       spi_pdata->num_chipselect = dev->devfn;
-
+       ssp = &spi_info->ssp;
        ssp->phys_base = pci_resource_start(dev, 0);
        ssp->mmio_base = ioremap(phys_beg, phys_len);
        if (!ssp->mmio_base) {
                dev_err(&pdev->dev, "failed to ioremap() registers\n");
                ret = -EIO;
-               goto err_remap;
+               goto err_nomem;
        }
        ssp->irq = dev->irq;
        ssp->port_id = pdev->id;
@@ -122,7 +110,7 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev,
 
        pci_set_drvdata(dev, spi_info);
 
-       ret = platform_device_register(pdev);
+       ret = platform_device_add(pdev);
        if (ret)
                goto err_dev_add;
 
@@ -135,27 +123,21 @@ err_dev_add:
        mutex_unlock(&ssp_lock);
        iounmap(ssp->mmio_base);
 
-err_remap:
-       kfree(spi_info);
-
-err_kz:
+err_nomem:
        release_mem_region(phys_beg, phys_len);
-
+       platform_device_put(pdev);
+       kfree(spi_info);
        return ret;
 }
 
 static void __devexit ce4100_spi_remove(struct pci_dev *dev)
 {
-       struct awesome_struct *spi_info;
-       struct platform_device *pdev;
+       struct ce4100_info *spi_info;
        struct ssp_device *ssp;
 
        spi_info = pci_get_drvdata(dev);
-
        ssp = &spi_info->ssp;
-       pdev = &spi_info->spi_pdev;
-
-       platform_device_unregister(pdev);
+       platform_device_unregister(spi_info->spi_pdev);
 
        iounmap(ssp->mmio_base);
        release_mem_region(pci_resource_start(dev, 0),
@@ -171,7 +153,6 @@ static void __devexit ce4100_spi_remove(struct pci_dev *dev)
 }
 
 static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
-
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
        { },
 };
index 56f60c8..2c665fc 100644 (file)
@@ -509,9 +509,11 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
        bytes_done = 0;
 
        while (bytes_done < t->len) {
+               void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL;
+               const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL;
                n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo,
-                                          t->tx_buf + bytes_done,
-                                          t->rx_buf + bytes_done,
+                                          tx_buf,
+                                          rx_buf,
                                           words, bits);
                if (n < 0)
                        break;
index 2d8cc45..42cdaa9 100644 (file)
@@ -82,7 +82,7 @@ config SSB_SDIOHOST
 
 config SSB_SILENT
        bool "No SSB kernel messages"
-       depends on SSB && EMBEDDED
+       depends on SSB && EXPERT
        help
          This option turns off all Sonics Silicon Backplane printks.
          Note that you won't be able to identify problems, once
index c7345db..f853379 100644 (file)
@@ -733,7 +733,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 
        /* Fetch the vendor specific tuples. */
        res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
-                               ssb_pcmcia_do_get_invariants, sprom);
+                               ssb_pcmcia_do_get_invariants, iv);
        if ((res == 0) || (res == -ENOSPC))
                return 0;
 
index 0e298db..29b8ab4 100644 (file)
@@ -360,8 +360,8 @@ int PSSendOps(void *arg)
                status = 1;
                goto complete;
        }
-        len = (firmware->size > MAX_BDADDR_FORMAT_LENGTH)? MAX_BDADDR_FORMAT_LENGTH: firmware->size;
-       memcpy(config_bdaddr, firmware->data,len);
+       len = min(firmware->size, MAX_BDADDR_FORMAT_LENGTH - 1);
+       memcpy(config_bdaddr, firmware->data, len);
        config_bdaddr[len] = '\0';
        write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING);
                A_RELEASE_FIRMWARE(firmware);
index bdd629d..cd8392b 100644 (file)
@@ -209,11 +209,8 @@ static void wl_ops_stop(struct ieee80211_hw *hw)
        struct wl_info *wl = hw->priv;
        ASSERT(wl);
        WL_LOCK(wl);
-       wl_down(wl);
        ieee80211_stop_queues(hw);
        WL_UNLOCK(wl);
-
-       return;
 }
 
 static int
@@ -246,7 +243,14 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 static void
 wl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       return;
+       struct wl_info *wl;
+
+       wl = HW_TO_WL(hw);
+
+       /* put driver in down state */
+       WL_LOCK(wl);
+       wl_down(wl);
+       WL_UNLOCK(wl);
 }
 
 static int
@@ -259,9 +263,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
        switch (type) {
        case NL80211_CHAN_HT20:
        case NL80211_CHAN_NO_HT:
-               WL_LOCK(wl);
                err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value);
-               WL_UNLOCK(wl);
                break;
        case NL80211_CHAN_HT40MINUS:
        case NL80211_CHAN_HT40PLUS:
@@ -281,6 +283,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
        int err = 0;
        int new_int;
 
+       WL_LOCK(wl);
        if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
                WL_NONE("%s: Setting listen interval to %d\n",
                        __func__, conf->listen_interval);
@@ -337,6 +340,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
        }
 
  config_out:
+       WL_UNLOCK(wl);
        return err;
 }
 
@@ -455,13 +459,21 @@ wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
 
 static void wl_ops_sw_scan_start(struct ieee80211_hw *hw)
 {
+       struct wl_info *wl = hw->priv;
        WL_NONE("Scan Start\n");
+       WL_LOCK(wl);
+       wlc_scan_start(wl->wlc);
+       WL_UNLOCK(wl);
        return;
 }
 
 static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw)
 {
+       struct wl_info *wl = hw->priv;
        WL_NONE("Scan Complete\n");
+       WL_LOCK(wl);
+       wlc_scan_stop(wl->wlc);
+       WL_UNLOCK(wl);
        return;
 }
 
@@ -779,7 +791,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs,
        wl_found++;
        return wl;
 
- fail:
+fail:
        wl_free(wl);
 fail1:
        return NULL;
@@ -1090,7 +1102,6 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 }
 
-#ifdef LINUXSTA_PS
 static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct wl_info *wl;
@@ -1105,11 +1116,12 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
                return -ENODEV;
        }
 
+       /* only need to flag hw is down for proper resume */
        WL_LOCK(wl);
-       wl_down(wl);
        wl->pub->hw_up = false;
        WL_UNLOCK(wl);
-       pci_save_state(pdev, wl->pci_psstate);
+
+       pci_save_state(pdev);
        pci_disable_device(pdev);
        return pci_set_power_state(pdev, PCI_D3hot);
 }
@@ -1133,7 +1145,7 @@ static int wl_resume(struct pci_dev *pdev)
        if (err)
                return err;
 
-       pci_restore_state(pdev, wl->pci_psstate);
+       pci_restore_state(pdev);
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1145,13 +1157,12 @@ static int wl_resume(struct pci_dev *pdev)
        if ((val & 0x0000ff00) != 0)
                pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
-       WL_LOCK(wl);
-       err = wl_up(wl);
-       WL_UNLOCK(wl);
-
+       /*
+       *  done. driver will be put in up state
+       *  in wl_ops_add_interface() call.
+       */
        return err;
 }
-#endif                         /* LINUXSTA_PS */
 
 static void wl_remove(struct pci_dev *pdev)
 {
@@ -1184,14 +1195,12 @@ static void wl_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver wl_pci_driver = {
- .name  = "brcm80211",
- .probe = wl_pci_probe,
-#ifdef LINUXSTA_PS
- .suspend = wl_suspend,
- .resume  = wl_resume,
-#endif                         /* LINUXSTA_PS */
- .remove   = __devexit_p(wl_remove),
- .id_table = wl_id_table,
+       .name = "brcm80211",
+       .probe = wl_pci_probe,
+       .suspend = wl_suspend,
+       .resume = wl_resume,
+       .remove = __devexit_p(wl_remove),
+       .id_table = wl_id_table,
 };
 
 /**
index 1d5d01a..e37e805 100644 (file)
@@ -5126,7 +5126,6 @@ wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu,
        fifo = prio2fifo[prio];
 
        ASSERT((uint) skb_headroom(sdu) >= TXOFF);
-       ASSERT(!(sdu->cloned));
        ASSERT(!(sdu->next));
        ASSERT(!(sdu->prev));
        ASSERT(fifo < NFIFO);
@@ -8462,3 +8461,16 @@ static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh,
 
        kfree(qi);
 }
+
+/*
+ * Flag 'scan in progress' to withold dynamic phy calibration
+ */
+void wlc_scan_start(struct wlc_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
+}
+
+void wlc_scan_stop(struct wlc_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
+}
index 146a690..aff4130 100644 (file)
@@ -570,6 +570,8 @@ extern void wlc_enable_mac(struct wlc_info *wlc);
 extern u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate);
 extern u32 wlc_get_rspec_history(struct wlc_bsscfg *cfg);
 extern u32 wlc_get_current_highest_rate(struct wlc_bsscfg *cfg);
+extern void wlc_scan_start(struct wlc_info *wlc);
+extern void wlc_scan_stop(struct wlc_info *wlc);
 
 static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name,
                                    uint *arg)
index aad4732..1502d80 100644 (file)
@@ -439,6 +439,7 @@ config COMEDI_NI_AT_AO
 config COMEDI_NI_ATMIO
        tristate "NI AT-MIO E series ISA-PNP card support"
        depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
        default N
        ---help---
          Enable support for National Instruments AT-MIO E series cards
@@ -1040,6 +1041,8 @@ config COMEDI_NI_PCIDIO
 config COMEDI_NI_PCIMIO
        tristate "NI PCI-MIO-E series and M series support"
        depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
+       select COMEDI_FC
        default N
        ---help---
          Enable support for National Instruments PCI-MIO-E series and M series
@@ -1164,6 +1167,7 @@ config COMEDI_NI_LABPC_CS
 config COMEDI_NI_MIO_CS
        tristate "NI DAQCard E series PCMCIA support"
        depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
        select COMEDI_FC
        default N
        ---help---
@@ -1268,7 +1272,6 @@ config COMEDI_MITE
 config COMEDI_NI_TIO
        tristate "NI general purpose counter support"
        depends on COMEDI_MITE
-       select COMEDI_8255
        default N
        ---help---
          Enable support for National Instruments general purpose counters.
index cd25b24..fd274e9 100644 (file)
@@ -61,8 +61,6 @@
 #define PCI_DAQ_SIZE           4096
 #define PCI_DAQ_SIZE_660X       8192
 
-MODULE_LICENSE("GPL");
-
 struct mite_struct *mite_devices;
 EXPORT_SYMBOL(mite_devices);
 
index 14e716e..54741c9 100644 (file)
@@ -527,3 +527,7 @@ static void __exit driver_ni6527_cleanup_module(void)
 
 module_init(driver_ni6527_init_module);
 module_exit(driver_ni6527_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 8b8e2aa..403fc09 100644 (file)
@@ -871,3 +871,7 @@ static void __exit driver_ni_65xx_cleanup_module(void)
 
 module_init(driver_ni_65xx_init_module);
 module_exit(driver_ni_65xx_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 6612b08..ca2aeaa 100644 (file)
@@ -1421,3 +1421,7 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev,
        };
        return 0;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index e9f034e..d8d91f9 100644 (file)
@@ -384,3 +384,7 @@ static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot)
        mite_list_devices();
        return -EIO;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 4d1868d..0728c3c 100644 (file)
@@ -575,7 +575,8 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
        /* grab our IRQ */
        if (irq) {
                isr_flags = 0;
-               if (thisboard->bustype == pci_bustype)
+               if (thisboard->bustype == pci_bustype
+                   || thisboard->bustype == pcmcia_bustype)
                        isr_flags |= IRQF_SHARED;
                if (request_irq(irq, labpc_interrupt, isr_flags,
                                driver_labpc.driver_name, dev)) {
index 84a15c3..005d2fe 100644 (file)
@@ -1354,3 +1354,7 @@ static void __exit driver_pcidio_cleanup_module(void)
 
 module_init(driver_pcidio_init_module);
 module_exit(driver_pcidio_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 23a3812..9148abd 100644 (file)
@@ -1853,3 +1853,7 @@ static int pcimio_dio_change(struct comedi_device *dev,
 
        return 0;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index b3d05fc..4fb8094 100644 (file)
@@ -368,6 +368,7 @@ static int blkvsc_probe(struct device *device)
                blkdev->gd->first_minor = 0;
        blkdev->gd->fops = &block_ops;
        blkdev->gd->private_data = blkdev;
+       blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
        sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum);
 
        blkvsc_do_inquiry(blkdev);
index df9cd13..0edbe74 100644 (file)
@@ -1279,7 +1279,7 @@ static void netvsc_channel_cb(void *context)
        /* ASSERT(device); */
 
        packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
-                        GFP_KERNEL);
+                        GFP_ATOMIC);
        if (!packet)
                return;
        buffer = packet;
index 0147b40..b41c964 100644 (file)
@@ -236,6 +236,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
        if (status == 1) {
                netif_carrier_on(net);
                netif_wake_queue(net);
+               netif_notify_peers(net);
        } else {
                netif_carrier_off(net);
                netif_stop_queue(net);
@@ -358,7 +359,6 @@ static int netvsc_probe(struct device *device)
 
        /* Set initial state */
        netif_carrier_off(net);
-       netif_stop_queue(net);
 
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = device_ctx;
index deb68c8..b8b54da 100644 (file)
@@ -68,7 +68,7 @@ static ssize_t ad7476_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0);
 
index 6859089..5d85efa 100644 (file)
@@ -68,7 +68,7 @@ static ssize_t ad7887_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7887_show_scale, NULL, 0);
 
index 6309d52..89ccf37 100644 (file)
@@ -432,7 +432,7 @@ static ssize_t ad799x_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, 0);
index e3387cd..0f87eca 100644 (file)
@@ -87,7 +87,7 @@ static ssize_t ad5446_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0);
 
index e38e89d..e2f6d6a 100644 (file)
@@ -874,7 +874,10 @@ static int nc_set_selected_input_dev(u8 value)
                sc_access[3].reg_addr = 0x109;
                sc_access[3].mask = MASK6;
                sc_access[3].value = 0x00;
-               num_val = 4;
+               sc_access[4].reg_addr = 0x104;
+               sc_access[4].value = 0x3C;
+               sc_access[4].mask = 0xff;
+               num_val = 5;
                break;
        default:
                return -EINVAL;
index 6aa312d..2d0263f 100644 (file)
@@ -1,13 +1,37 @@
-The binding between hdpvr and lirc_zilog is currently disabled,
+1. Both ir-kbd-i2c and lirc_zilog provide support for RX events.
+The 'tx_only' lirc_zilog module parameter will allow ir-kbd-i2c
+and lirc_zilog to coexist in the kernel, if the user requires such a set-up.
+However the IR unit will not work well without coordination between the
+two modules.  A shared mutex, for transceiver access locking, needs to be
+supplied by bridge drivers, in struct IR_i2_init_data, to both ir-kbd-i2c
+and lirc_zilog, before they will coexist usefully.  This should be fixed
+before moving out of staging.
+
+2. References and locking need careful examination.  For cx18 and ivtv PCI
+cards, which are not easily "hot unplugged", the imperfect state of reference
+counting and locking is acceptable if not correct.  For USB connected units
+like HD PVR, PVR USB2, HVR-1900, and HVR1950, the likelyhood of an Ooops on
+unplug is probably great.  Proper reference counting and locking needs to be
+implemented before this module is moved out of staging.
+
+3. The binding between hdpvr and lirc_zilog is currently disabled,
 due to an OOPS reported a few years ago when both the hdpvr and cx18
 drivers were loaded in his system. More details can be seen at:
        http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html
 More tests need to be done, in order to fix the reported issue.
 
-There's a conflict between ir-kbd-i2c: Both provide support for RX events.
-Such conflict needs to be fixed, before moving it out of staging.
+4. In addition to providing a shared mutex for transceiver access
+locking, bridge drivers, if able, should provide a chip reset() callback
+to lirc_zilog via struct IR_i2c_init_data.  cx18 and ivtv already have routines
+to perform Z8 chip resets via GPIO manipulations.  This will allow lirc_zilog
+to bring the chip back to normal when it hangs, in the same places the
+original lirc_pvr150 driver code does.  This is not strictly needed, so it
+is not required to move lirc_zilog out of staging.
+
+5. Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
+and installed on Hauppauge products.  When working on either module, developers
+must consider at least the following bridge drivers which mention an IR Rx unit
+at address 0x71 (indicative of a Z8):
 
-The way I2C probe works, it will try to register the driver twice, one
-for RX and another for TX. The logic needs to be fixed to avoid such
-issue.
+       ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134
 
index 0da6b95..235cab0 100644 (file)
@@ -447,6 +447,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 
 exit:
        mutex_unlock(&context->ctx_lock);
+       kfree(data_buf);
 
        return (!retval) ? n_bytes : retval;
 }
index 929ae57..5938616 100644 (file)
@@ -232,6 +232,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
                i++;
        }
        terminate_send(tx_buf[i - 1]);
+       kfree(tx_buf);
        return n;
 }
 
index dfd2c44..3a9c098 100644 (file)
@@ -376,6 +376,7 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
        unsigned long flags;
        int counttimer;
        int *wbuf;
+       ssize_t ret;
 
        if (!is_claimed)
                return -EBUSY;
@@ -393,8 +394,10 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
        if (timer == 0) {
                /* try again if device is ready */
                timer = init_lirc_timer();
-               if (timer == 0)
-                       return -EIO;
+               if (timer == 0) {
+                       ret = -EIO;
+                       goto out;
+               }
        }
 
        /* adjust values from usecs */
@@ -420,7 +423,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
                        if (check_pselecd && (in(1) & LP_PSELECD)) {
                                lirc_off();
                                local_irq_restore(flags);
-                               return -EIO;
+                               ret = -EIO;
+                               goto out;
                        }
                } while (counttimer < wbuf[i]);
                i++;
@@ -436,7 +440,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
                        level = newlevel;
                        if (check_pselecd && (in(1) & LP_PSELECD)) {
                                local_irq_restore(flags);
-                               return -EIO;
+                               ret = -EIO;
+                               goto out;
                        }
                } while (counttimer < wbuf[i]);
                i++;
@@ -445,7 +450,11 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
 #else
        /* place code that handles write without external timer here */
 #endif
-       return n;
+       ret = n;
+out:
+       kfree(wbuf);
+
+       return ret;
 }
 
 static unsigned int lirc_poll(struct file *file, poll_table *wait)
index 998485e..925eabe 100644 (file)
@@ -448,6 +448,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
 exit:
 
        mutex_unlock(&context->ctx_lock);
+       kfree(data_buf);
 
        return (!retval) ? n_bytes : retval;
 }
index 9bcf149..1c3099b 100644 (file)
@@ -966,7 +966,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
        if (n % sizeof(int) || count % 2 == 0)
                return -EINVAL;
        wbuf = memdup_user(buf, n);
-       if (PTR_ERR(wbuf))
+       if (IS_ERR(wbuf))
                return PTR_ERR(wbuf);
        spin_lock_irqsave(&hardware[type].lock, flags);
        if (type == LIRC_IRDEO) {
@@ -981,6 +981,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
        }
        off();
        spin_unlock_irqrestore(&hardware[type].lock, flags);
+       kfree(wbuf);
        return n;
 }
 
index c553ab6..76be7b8 100644 (file)
@@ -330,6 +330,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
        /* enable receiver */
        Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
 #endif
+       kfree(tx_buf);
        return count;
 }
 
index ad29bb1..0aad0d7 100644 (file)
@@ -20,6 +20,9 @@
  *
  * parts are cut&pasted from the lirc_i2c.c driver
  *
+ * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are
+ * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
 #include <media/lirc_dev.h>
 #include <media/lirc.h>
 
-struct IR {
-       struct lirc_driver l;
-
-       /* Device info */
-       struct mutex ir_lock;
-       int open;
-       bool is_hdpvr;
-
+struct IR_rx {
        /* RX device */
-       struct i2c_client c_rx;
-       int have_rx;
+       struct i2c_client *c;
 
        /* RX device buffer & lock */
        struct lirc_buffer buf;
        struct mutex buf_lock;
 
        /* RX polling thread data */
-       struct completion *t_notify;
-       struct completion *t_notify2;
-       int shutdown;
        struct task_struct *task;
 
        /* RX read data */
        unsigned char b[3];
+       bool hdpvr_data_fmt;
+};
 
+struct IR_tx {
        /* TX device */
-       struct i2c_client c_tx;
+       struct i2c_client *c;
+
+       /* TX additional actions needed */
        int need_boot;
-       int have_tx;
+       bool post_tx_ready_poll;
+};
+
+struct IR {
+       struct lirc_driver l;
+
+       struct mutex ir_lock;
+       int open;
+
+       struct i2c_adapter *adapter;
+       struct IR_rx *rx;
+       struct IR_tx *tx;
 };
 
 /* Minor -> data mapping */
+static struct mutex ir_devices_lock;
 static struct IR *ir_devices[MAX_IRCTL_DEVICES];
 
 /* Block size for IR transmitter */
@@ -124,14 +133,11 @@ static struct mutex tx_data_lock;
 #define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
                                        ## args)
 #define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-
-#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX"
-#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX"
+#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args)
 
 /* module parameters */
 static int debug;      /* debug output */
-static int disable_rx; /* disable RX device */
-static int disable_tx; /* disable TX device */
+static int tx_only;    /* only handle the IR Tx function */
 static int minor = -1; /* minor number */
 
 #define dprintk(fmt, args...)                                          \
@@ -150,8 +156,12 @@ static int add_to_buf(struct IR *ir)
        int ret;
        int failures = 0;
        unsigned char sendbuf[1] = { 0 };
+       struct IR_rx *rx = ir->rx;
 
-       if (lirc_buffer_full(&ir->buf)) {
+       if (rx == NULL)
+               return -ENXIO;
+
+       if (lirc_buffer_full(&rx->buf)) {
                dprintk("buffer overflow\n");
                return -EOVERFLOW;
        }
@@ -161,17 +171,25 @@ static int add_to_buf(struct IR *ir)
         * data and we have space
         */
        do {
+               if (kthread_should_stop())
+                       return -ENODATA;
+
                /*
                 * Lock i2c bus for the duration.  RX/TX chips interfere so
                 * this is worth it
                 */
                mutex_lock(&ir->ir_lock);
 
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       return -ENODATA;
+               }
+
                /*
                 * Send random "poll command" (?)  Windows driver does this
                 * and it is a good point to detect chip failure.
                 */
-               ret = i2c_master_send(&ir->c_rx, sendbuf, 1);
+               ret = i2c_master_send(rx->c, sendbuf, 1);
                if (ret != 1) {
                        zilog_error("i2c_master_send failed with %d\n", ret);
                        if (failures >= 3) {
@@ -186,45 +204,53 @@ static int add_to_buf(struct IR *ir)
                                    "trying reset\n");
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (kthread_should_stop()) {
+                               mutex_unlock(&ir->ir_lock);
+                               return -ENODATA;
+                       }
                        schedule_timeout((100 * HZ + 999) / 1000);
-                       ir->need_boot = 1;
+                       ir->tx->need_boot = 1;
 
                        ++failures;
                        mutex_unlock(&ir->ir_lock);
                        continue;
                }
 
-               ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf));
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       return -ENODATA;
+               }
+               ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
                mutex_unlock(&ir->ir_lock);
                if (ret != sizeof(keybuf)) {
                        zilog_error("i2c_master_recv failed with %d -- "
                                    "keeping last read buffer\n", ret);
                } else {
-                       ir->b[0] = keybuf[3];
-                       ir->b[1] = keybuf[4];
-                       ir->b[2] = keybuf[5];
-                       dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+                       rx->b[0] = keybuf[3];
+                       rx->b[1] = keybuf[4];
+                       rx->b[2] = keybuf[5];
+                       dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]);
                }
 
                /* key pressed ? */
-               if (ir->is_hdpvr) {
+               if (rx->hdpvr_data_fmt) {
                        if (got_data && (keybuf[0] == 0x80))
                                return 0;
                        else if (got_data && (keybuf[0] == 0x00))
                                return -ENODATA;
-               } else if ((ir->b[0] & 0x80) == 0)
+               } else if ((rx->b[0] & 0x80) == 0)
                        return got_data ? 0 : -ENODATA;
 
                /* look what we have */
-               code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2);
+               code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2);
 
                codes[0] = (code >> 8) & 0xff;
                codes[1] = code & 0xff;
 
                /* return it */
-               lirc_buffer_write(&ir->buf, codes);
+               lirc_buffer_write(&rx->buf, codes);
                ++got_data;
-       } while (!lirc_buffer_full(&ir->buf));
+       } while (!lirc_buffer_full(&rx->buf));
 
        return 0;
 }
@@ -242,46 +268,35 @@ static int add_to_buf(struct IR *ir)
 static int lirc_thread(void *arg)
 {
        struct IR *ir = arg;
-
-       if (ir->t_notify != NULL)
-               complete(ir->t_notify);
+       struct IR_rx *rx = ir->rx;
 
        dprintk("poll thread started\n");
 
-       do {
-               if (ir->open) {
-                       set_current_state(TASK_INTERRUPTIBLE);
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
 
-                       /*
-                        * This is ~113*2 + 24 + jitter (2*repeat gap +
-                        * code length).  We use this interval as the chip
-                        * resets every time you poll it (bad!).  This is
-                        * therefore just sufficient to catch all of the
-                        * button presses.  It makes the remote much more
-                        * responsive.  You can see the difference by
-                        * running irw and holding down a button.  With
-                        * 100ms, the old polling interval, you'll notice
-                        * breaks in the repeat sequence corresponding to
-                        * lost keypresses.
-                        */
-                       schedule_timeout((260 * HZ) / 1000);
-                       if (ir->shutdown)
-                               break;
-                       if (!add_to_buf(ir))
-                               wake_up_interruptible(&ir->buf.wait_poll);
-               } else {
-                       /* if device not opened so we can sleep half a second */
-                       set_current_state(TASK_INTERRUPTIBLE);
+               /* if device not opened, we can sleep half a second */
+               if (!ir->open) {
                        schedule_timeout(HZ/2);
+                       continue;
                }
-       } while (!ir->shutdown);
-
-       if (ir->t_notify2 != NULL)
-               wait_for_completion(ir->t_notify2);
 
-       ir->task = NULL;
-       if (ir->t_notify != NULL)
-               complete(ir->t_notify);
+               /*
+                * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
+                * We use this interval as the chip resets every time you poll
+                * it (bad!).  This is therefore just sufficient to catch all
+                * of the button presses.  It makes the remote much more
+                * responsive.  You can see the difference by running irw and
+                * holding down a button.  With 100ms, the old polling
+                * interval, you'll notice breaks in the repeat sequence
+                * corresponding to lost keypresses.
+                */
+               schedule_timeout((260 * HZ) / 1000);
+               if (kthread_should_stop())
+                       break;
+               if (!add_to_buf(ir))
+                       wake_up_interruptible(&rx->buf.wait_poll);
+       }
 
        dprintk("poll thread ended\n");
        return 0;
@@ -299,10 +314,10 @@ static int set_use_inc(void *data)
         * this is completely broken code. lirc_unregister_driver()
         * must be possible even when the device is open
         */
-       if (ir->c_rx.addr)
-               i2c_use_client(&ir->c_rx);
-       if (ir->c_tx.addr)
-               i2c_use_client(&ir->c_tx);
+       if (ir->rx != NULL)
+               i2c_use_client(ir->rx->c);
+       if (ir->tx != NULL)
+               i2c_use_client(ir->tx->c);
 
        return 0;
 }
@@ -311,10 +326,10 @@ static void set_use_dec(void *data)
 {
        struct IR *ir = data;
 
-       if (ir->c_rx.addr)
-               i2c_release_client(&ir->c_rx);
-       if (ir->c_tx.addr)
-               i2c_release_client(&ir->c_tx);
+       if (ir->rx)
+               i2c_release_client(ir->rx->c);
+       if (ir->tx)
+               i2c_release_client(ir->tx->c);
        if (ir->l.owner != NULL)
                module_put(ir->l.owner);
 }
@@ -453,7 +468,7 @@ corrupt:
 }
 
 /* send a block of data to the IR TX device */
-static int send_data_block(struct IR *ir, unsigned char *data_block)
+static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
 {
        int i, j, ret;
        unsigned char buf[5];
@@ -467,7 +482,7 @@ static int send_data_block(struct IR *ir, unsigned char *data_block)
                        buf[1 + j] = data_block[i + j];
                dprintk("%02x %02x %02x %02x %02x",
                        buf[0], buf[1], buf[2], buf[3], buf[4]);
-               ret = i2c_master_send(&ir->c_tx, buf, tosend + 1);
+               ret = i2c_master_send(tx->c, buf, tosend + 1);
                if (ret != tosend + 1) {
                        zilog_error("i2c_master_send failed with %d\n", ret);
                        return ret < 0 ? ret : -EFAULT;
@@ -478,38 +493,50 @@ static int send_data_block(struct IR *ir, unsigned char *data_block)
 }
 
 /* send boot data to the IR TX device */
-static int send_boot_data(struct IR *ir)
+static int send_boot_data(struct IR_tx *tx)
 {
-       int ret;
+       int ret, i;
        unsigned char buf[4];
 
        /* send the boot block */
-       ret = send_data_block(ir, tx_data->boot_data);
+       ret = send_data_block(tx, tx_data->boot_data);
        if (ret != 0)
                return ret;
 
-       /* kick it off? */
+       /* Hit the go button to activate the new boot data */
        buf[0] = 0x00;
        buf[1] = 0x20;
-       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       ret = i2c_master_send(tx->c, buf, 2);
        if (ret != 2) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(&ir->c_tx, buf, 1);
+
+       /*
+        * Wait for zilog to settle after hitting go post boot block upload.
+        * Without this delay, the HD-PVR and HVR-1950 both return an -EIO
+        * upon attempting to get firmware revision, and tx probe thus fails.
+        */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
 
        /* Here comes the firmware version... (hopefully) */
-       ret = i2c_master_recv(&ir->c_tx, buf, 4);
+       ret = i2c_master_recv(tx->c, buf, 4);
        if (ret != 4) {
                zilog_error("i2c_master_recv failed with %d\n", ret);
                return 0;
        }
-       if (buf[0] != 0x80) {
-               zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+       if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
+               zilog_error("unexpected IR TX init response: %02x\n", buf[0]);
                return 0;
        }
        zilog_notify("Zilog/Hauppauge IR blaster firmware version "
@@ -543,7 +570,7 @@ static void fw_unload(void)
 }
 
 /* load "firmware" for the IR TX device */
-static int fw_load(struct IR *ir)
+static int fw_load(struct IR_tx *tx)
 {
        int ret;
        unsigned int i;
@@ -558,7 +585,7 @@ static int fw_load(struct IR *ir)
        }
 
        /* Request codeset data file */
-       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev);
+       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c->dev);
        if (ret != 0) {
                zilog_error("firmware haup-ir-blaster.bin not available "
                            "(%d)\n", ret);
@@ -685,20 +712,20 @@ out:
 }
 
 /* initialise the IR TX device */
-static int tx_init(struct IR *ir)
+static int tx_init(struct IR_tx *tx)
 {
        int ret;
 
        /* Load 'firmware' */
-       ret = fw_load(ir);
+       ret = fw_load(tx);
        if (ret != 0)
                return ret;
 
        /* Send boot block */
-       ret = send_boot_data(ir);
+       ret = send_boot_data(tx);
        if (ret != 0)
                return ret;
-       ir->need_boot = 0;
+       tx->need_boot = 0;
 
        /* Looks good */
        return 0;
@@ -714,20 +741,20 @@ static loff_t lseek(struct file *filep, loff_t offset, int orig)
 static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
 {
        struct IR *ir = filep->private_data;
-       unsigned char buf[ir->buf.chunk_size];
+       struct IR_rx *rx = ir->rx;
        int ret = 0, written = 0;
        DECLARE_WAITQUEUE(wait, current);
 
        dprintk("read called\n");
-       if (ir->c_rx.addr == 0)
+       if (rx == NULL)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&ir->buf_lock))
+       if (mutex_lock_interruptible(&rx->buf_lock))
                return -ERESTARTSYS;
 
-       if (n % ir->buf.chunk_size) {
+       if (n % rx->buf.chunk_size) {
                dprintk("read result = -EINVAL\n");
-               mutex_unlock(&ir->buf_lock);
+               mutex_unlock(&rx->buf_lock);
                return -EINVAL;
        }
 
@@ -736,7 +763,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
         * to avoid losing scan code (in case when queue is awaken somewhere
         * between while condition checking and scheduling)
         */
-       add_wait_queue(&ir->buf.wait_poll, &wait);
+       add_wait_queue(&rx->buf.wait_poll, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
 
        /*
@@ -744,7 +771,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
         * mode and 'copy_to_user' is happy, wait for data.
         */
        while (written < n && ret == 0) {
-               if (lirc_buffer_empty(&ir->buf)) {
+               if (lirc_buffer_empty(&rx->buf)) {
                        /*
                         * According to the read(2) man page, 'written' can be
                         * returned as less than 'n', instead of blocking
@@ -764,16 +791,17 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
                        schedule();
                        set_current_state(TASK_INTERRUPTIBLE);
                } else {
-                       lirc_buffer_read(&ir->buf, buf);
+                       unsigned char buf[rx->buf.chunk_size];
+                       lirc_buffer_read(&rx->buf, buf);
                        ret = copy_to_user((void *)outbuf+written, buf,
-                                          ir->buf.chunk_size);
-                       written += ir->buf.chunk_size;
+                                          rx->buf.chunk_size);
+                       written += rx->buf.chunk_size;
                }
        }
 
-       remove_wait_queue(&ir->buf.wait_poll, &wait);
+       remove_wait_queue(&rx->buf.wait_poll, &wait);
        set_current_state(TASK_RUNNING);
-       mutex_unlock(&ir->buf_lock);
+       mutex_unlock(&rx->buf_lock);
 
        dprintk("read result = %s (%d)\n",
                ret ? "-EFAULT" : "OK", ret);
@@ -782,7 +810,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
 }
 
 /* send a keypress to the IR TX device */
-static int send_code(struct IR *ir, unsigned int code, unsigned int key)
+static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 {
        unsigned char data_block[TX_BLOCK_SIZE];
        unsigned char buf[2];
@@ -799,26 +827,34 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
                return ret;
 
        /* Send the data block */
-       ret = send_data_block(ir, data_block);
+       ret = send_data_block(tx, data_block);
        if (ret != 0)
                return ret;
 
        /* Send data block length? */
        buf[0] = 0x00;
        buf[1] = 0x40;
-       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       ret = i2c_master_send(tx->c, buf, 2);
        if (ret != 2) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(&ir->c_tx, buf, 1);
+
+       /* Give the z8 a moment to process data block */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
 
        /* Send finished download? */
-       ret = i2c_master_recv(&ir->c_tx, buf, 1);
+       ret = i2c_master_recv(tx->c, buf, 1);
        if (ret != 1) {
                zilog_error("i2c_master_recv failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
@@ -832,7 +868,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
        /* Send prepare command? */
        buf[0] = 0x00;
        buf[1] = 0x80;
-       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       ret = i2c_master_send(tx->c, buf, 2);
        if (ret != 2) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
@@ -843,7 +879,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
         * last i2c_master_recv always fails with a -5, so for now, we're
         * going to skip this whole mess and say we're done on the HD PVR
         */
-       if (ir->is_hdpvr) {
+       if (!tx->post_tx_ready_poll) {
                dprintk("sent code %u, key %u\n", code, key);
                return 0;
        }
@@ -857,7 +893,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
        for (i = 0; i < 20; ++i) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout((50 * HZ + 999) / 1000);
-               ret = i2c_master_send(&ir->c_tx, buf, 1);
+               ret = i2c_master_send(tx->c, buf, 1);
                if (ret == 1)
                        break;
                dprintk("NAK expected: i2c_master_send "
@@ -870,7 +906,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
        }
 
        /* Seems to be an 'ok' response */
-       i = i2c_master_recv(&ir->c_tx, buf, 1);
+       i = i2c_master_recv(tx->c, buf, 1);
        if (i != 1) {
                zilog_error("i2c_master_recv failed with %d\n", ret);
                return -EFAULT;
@@ -895,10 +931,11 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                          loff_t *ppos)
 {
        struct IR *ir = filep->private_data;
+       struct IR_tx *tx = ir->tx;
        size_t i;
        int failures = 0;
 
-       if (ir->c_tx.addr == 0)
+       if (tx == NULL)
                return -ENODEV;
 
        /* Validate user parameters */
@@ -919,15 +956,15 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                }
 
                /* Send boot data first if required */
-               if (ir->need_boot == 1) {
-                       ret = send_boot_data(ir);
+               if (tx->need_boot == 1) {
+                       ret = send_boot_data(tx);
                        if (ret == 0)
-                               ir->need_boot = 0;
+                               tx->need_boot = 0;
                }
 
                /* Send the code */
                if (ret == 0) {
-                       ret = send_code(ir, (unsigned)command >> 16,
+                       ret = send_code(tx, (unsigned)command >> 16,
                                            (unsigned)command & 0xFFFF);
                        if (ret == -EPROTO) {
                                mutex_unlock(&ir->ir_lock);
@@ -952,7 +989,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                        }
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout((100 * HZ + 999) / 1000);
-                       ir->need_boot = 1;
+                       tx->need_boot = 1;
                        ++failures;
                } else
                        i += sizeof(int);
@@ -969,22 +1006,23 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
 static unsigned int poll(struct file *filep, poll_table *wait)
 {
        struct IR *ir = filep->private_data;
+       struct IR_rx *rx = ir->rx;
        unsigned int ret;
 
        dprintk("poll called\n");
-       if (ir->c_rx.addr == 0)
+       if (rx == NULL)
                return -ENODEV;
 
-       mutex_lock(&ir->buf_lock);
+       mutex_lock(&rx->buf_lock);
 
-       poll_wait(filep, &ir->buf.wait_poll, wait);
+       poll_wait(filep, &rx->buf.wait_poll, wait);
 
        dprintk("poll result = %s\n",
-               lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+               lirc_buffer_empty(&rx->buf) ? "0" : "POLLIN|POLLRDNORM");
 
-       ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+       ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM);
 
-       mutex_unlock(&ir->buf_lock);
+       mutex_unlock(&rx->buf_lock);
        return ret;
 }
 
@@ -994,10 +1032,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        int result;
        unsigned long mode, features = 0;
 
-       if (ir->c_rx.addr != 0)
+       features |= LIRC_CAN_SEND_PULSE;
+       if (ir->rx != NULL)
                features |= LIRC_CAN_REC_LIRCCODE;
-       if (ir->c_tx.addr != 0)
-               features |= LIRC_CAN_SEND_PULSE;
 
        switch (cmd) {
        case LIRC_GET_LENGTH:
@@ -1024,15 +1061,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                        result = -EINVAL;
                break;
        case LIRC_GET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
                result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
                break;
        case LIRC_SET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
                result = get_user(mode, (unsigned long *) arg);
                if (!result && mode != LIRC_MODE_PULSE)
                        return -EINVAL;
@@ -1043,6 +1074,15 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        return result;
 }
 
+/* ir_devices_lock must be held */
+static struct IR *find_ir_device_by_minor(unsigned int minor)
+{
+       if (minor >= MAX_IRCTL_DEVICES)
+               return NULL;
+
+       return ir_devices[minor];
+}
+
 /*
  * Open the IR device.  Get hold of our IR structure and
  * stash it in private_data for the file
@@ -1051,15 +1091,15 @@ static int open(struct inode *node, struct file *filep)
 {
        struct IR *ir;
        int ret;
+       unsigned int minor = MINOR(node->i_rdev);
 
        /* find our IR struct */
-       unsigned minor = MINOR(node->i_rdev);
-       if (minor >= MAX_IRCTL_DEVICES) {
-               dprintk("minor %d: open result = -ENODEV\n",
-                       minor);
+       mutex_lock(&ir_devices_lock);
+       ir = find_ir_device_by_minor(minor);
+       mutex_unlock(&ir_devices_lock);
+
+       if (ir == NULL)
                return -ENODEV;
-       }
-       ir = ir_devices[minor];
 
        /* increment in use count */
        mutex_lock(&ir->ir_lock);
@@ -1106,7 +1146,6 @@ static struct lirc_driver lirc_template = {
 
 static int ir_remove(struct i2c_client *client);
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 #define ID_FLAG_TX     0x01
 #define ID_FLAG_HDPVR  0x02
@@ -1126,7 +1165,6 @@ static struct i2c_driver driver = {
        },
        .probe          = ir_probe,
        .remove         = ir_remove,
-       .command        = ir_command,
        .id_table       = ir_transceiver_id,
 };
 
@@ -1144,214 +1182,253 @@ static const struct file_operations lirc_fops = {
        .release        = close
 };
 
-static int ir_remove(struct i2c_client *client)
+static void destroy_rx_kthread(struct IR_rx *rx)
 {
-       struct IR *ir = i2c_get_clientdata(client);
+       /* end up polling thread */
+       if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) {
+               kthread_stop(rx->task);
+               rx->task = NULL;
+       }
+}
 
-       mutex_lock(&ir->ir_lock);
+/* ir_devices_lock must be held */
+static int add_ir_device(struct IR *ir)
+{
+       int i;
 
-       if (ir->have_rx || ir->have_tx) {
-               DECLARE_COMPLETION(tn);
-               DECLARE_COMPLETION(tn2);
-
-               /* end up polling thread */
-               if (ir->task && !IS_ERR(ir->task)) {
-                       ir->t_notify = &tn;
-                       ir->t_notify2 = &tn2;
-                       ir->shutdown = 1;
-                       wake_up_process(ir->task);
-                       complete(&tn2);
-                       wait_for_completion(&tn);
-                       ir->t_notify = NULL;
-                       ir->t_notify2 = NULL;
+       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+               if (ir_devices[i] == NULL) {
+                       ir_devices[i] = ir;
+                       break;
                }
 
-       } else {
-               mutex_unlock(&ir->ir_lock);
-               zilog_error("%s: detached from something we didn't "
-                           "attach to\n", __func__);
-               return -ENODEV;
+       return i == MAX_IRCTL_DEVICES ? -ENOMEM : i;
+}
+
+/* ir_devices_lock must be held */
+static void del_ir_device(struct IR *ir)
+{
+       int i;
+
+       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+               if (ir_devices[i] == ir) {
+                       ir_devices[i] = NULL;
+                       break;
+               }
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+       struct IR *ir = i2c_get_clientdata(client);
+
+       mutex_lock(&ir_devices_lock);
+
+       if (ir == NULL) {
+               /* We destroyed everything when the first client came through */
+               mutex_unlock(&ir_devices_lock);
+               return 0;
        }
 
-       /* unregister lirc driver */
-       if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
-               lirc_unregister_driver(ir->l.minor);
-               ir_devices[ir->l.minor] = NULL;
+       /* Good-bye LIRC */
+       lirc_unregister_driver(ir->l.minor);
+
+       /* Good-bye Rx */
+       destroy_rx_kthread(ir->rx);
+       if (ir->rx != NULL) {
+               if (ir->rx->buf.fifo_initialized)
+                       lirc_buffer_free(&ir->rx->buf);
+               i2c_set_clientdata(ir->rx->c, NULL);
+               kfree(ir->rx);
        }
 
-       /* free memory */
-       lirc_buffer_free(&ir->buf);
-       mutex_unlock(&ir->ir_lock);
+       /* Good-bye Tx */
+       i2c_set_clientdata(ir->tx->c, NULL);
+       kfree(ir->tx);
+
+       /* Good-bye IR */
+       del_ir_device(ir);
        kfree(ir);
 
+       mutex_unlock(&ir_devices_lock);
        return 0;
 }
 
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+
+/* ir_devices_lock must be held */
+static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter)
 {
+       int i;
        struct IR *ir = NULL;
+
+       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+               if (ir_devices[i] != NULL &&
+                   ir_devices[i]->adapter == adapter) {
+                       ir = ir_devices[i];
+                       break;
+               }
+
+       return ir;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct IR *ir;
        struct i2c_adapter *adap = client->adapter;
-       char buf;
        int ret;
-       int have_rx = 0, have_tx = 0;
+       bool tx_probe = false;
 
-       dprintk("%s: adapter name (%s) nr %d, i2c_device_id name (%s), "
-               "client addr=0x%02x\n",
-               __func__, adap->name, adap->nr, id->name, client->addr);
+       dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n",
+               __func__, id->name, adap->nr, adap->name, client->addr);
 
        /*
-        * FIXME - This probe function probes both the Tx and Rx
-        * addresses of the IR microcontroller.
-        *
-        * However, the I2C subsystem is passing along one I2C client at a
-        * time, based on matches to the ir_transceiver_id[] table above.
-        * The expectation is that each i2c_client address will be probed
-        * individually by drivers so the I2C subsystem can mark all client
-        * addresses as claimed or not.
-        *
-        * This probe routine causes only one of the client addresses, TX or RX,
-        * to be claimed.  This will cause a problem if the I2C subsystem is
-        * subsequently triggered to probe unclaimed clients again.
+        * The IR receiver    is at i2c address 0x71.
+        * The IR transmitter is at i2c address 0x70.
         */
-       /*
-        * The external IR receiver is at i2c address 0x71.
-        * The IR transmitter is at 0x70.
-        */
-       client->addr = 0x70;
 
-       if (!disable_tx) {
-               if (i2c_master_recv(client, &buf, 1) == 1)
-                       have_tx = 1;
-               dprintk("probe 0x70 @ %s: %s\n",
-                       adap->name, have_tx ? "success" : "failed");
-       }
+       if (id->driver_data & ID_FLAG_TX)
+               tx_probe = true;
+       else if (tx_only) /* module option */
+               return -ENXIO;
 
-       if (!disable_rx) {
-               client->addr = 0x71;
-               if (i2c_master_recv(client, &buf, 1) == 1)
-                       have_rx = 1;
-               dprintk("probe 0x71 @ %s: %s\n",
-                       adap->name, have_rx ? "success" : "failed");
-       }
+       zilog_info("probing IR %s on %s (i2c-%d)\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
 
-       if (!(have_rx || have_tx)) {
-               zilog_error("%s: no devices found\n", adap->name);
-               goto out_nodev;
-       }
+       mutex_lock(&ir_devices_lock);
 
-       printk(KERN_INFO "lirc_zilog: chip found with %s\n",
-               have_rx && have_tx ? "RX and TX" :
-                       have_rx ? "RX only" : "TX only");
+       /* Use a single struct IR instance for both the Rx and Tx functions */
+       ir = find_ir_device_by_adapter(adap);
+       if (ir == NULL) {
+               ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+               if (ir == NULL) {
+                       ret = -ENOMEM;
+                       goto out_no_ir;
+               }
+               /* store for use in ir_probe() again, and open() later on */
+               ret = add_ir_device(ir);
+               if (ret)
+                       goto out_free_ir;
+
+               ir->adapter = adap;
+               mutex_init(&ir->ir_lock);
+
+               /* set lirc_dev stuff */
+               memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+               ir->l.minor       = minor; /* module option */
+               ir->l.code_length = 13;
+               ir->l.rbuf        = NULL;
+               ir->l.fops        = &lirc_fops;
+               ir->l.data        = ir;
+               ir->l.dev         = &adap->dev;
+               ir->l.sample_rate = 0;
+       }
 
-       ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+       if (tx_probe) {
+               /* Set up a struct IR_tx instance */
+               ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
+               if (ir->tx == NULL) {
+                       ret = -ENOMEM;
+                       goto out_free_xx;
+               }
 
-       if (!ir)
-               goto out_nomem;
+               ir->tx->c = client;
+               ir->tx->need_boot = 1;
+               ir->tx->post_tx_ready_poll =
+                              (id->driver_data & ID_FLAG_HDPVR) ? false : true;
+       } else {
+               /* Set up a struct IR_rx instance */
+               ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
+               if (ir->rx == NULL) {
+                       ret = -ENOMEM;
+                       goto out_free_xx;
+               }
 
-       ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2);
-       if (ret)
-               goto out_nomem;
+               ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2);
+               if (ret)
+                       goto out_free_xx;
 
-       mutex_init(&ir->ir_lock);
-       mutex_init(&ir->buf_lock);
-       ir->need_boot = 1;
-       ir->is_hdpvr = (id->driver_data & ID_FLAG_HDPVR) ? true : false;
+               mutex_init(&ir->rx->buf_lock);
+               ir->rx->c = client;
+               ir->rx->hdpvr_data_fmt =
+                              (id->driver_data & ID_FLAG_HDPVR) ? true : false;
 
-       memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
-       ir->l.minor = -1;
+               /* set lirc_dev stuff */
+               ir->l.rbuf = &ir->rx->buf;
+       }
 
-       /* I2C attach to device */
        i2c_set_clientdata(client, ir);
 
-       /* initialise RX device */
-       if (have_rx) {
-               DECLARE_COMPLETION(tn);
-               memcpy(&ir->c_rx, client, sizeof(struct i2c_client));
-
-               ir->c_rx.addr = 0x71;
-               strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME,
-                       I2C_NAME_SIZE);
+       /* Proceed only if we have the required Tx and Rx clients ready to go */
+       if (ir->tx == NULL ||
+           (ir->rx == NULL && !tx_only)) {
+               zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on "
+                          "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name,
+                          adap->nr, tx_probe ? "Rx" : "Tx");
+               goto out_ok;
+       }
 
+       /* initialise RX device */
+       if (ir->rx != NULL) {
                /* try to fire up polling thread */
-               ir->t_notify = &tn;
-               ir->task = kthread_run(lirc_thread, ir, "lirc_zilog");
-               if (IS_ERR(ir->task)) {
-                       ret = PTR_ERR(ir->task);
-                       zilog_error("lirc_register_driver: cannot run "
-                                   "poll thread %d\n", ret);
-                       goto err;
+               ir->rx->task = kthread_run(lirc_thread, ir,
+                                          "zilog-rx-i2c-%d", adap->nr);
+               if (IS_ERR(ir->rx->task)) {
+                       ret = PTR_ERR(ir->rx->task);
+                       zilog_error("%s: could not start IR Rx polling thread"
+                                   "\n", __func__);
+                       goto out_free_xx;
                }
-               wait_for_completion(&tn);
-               ir->t_notify = NULL;
-               ir->have_rx = 1;
        }
 
-       /* initialise TX device */
-       if (have_tx) {
-               memcpy(&ir->c_tx, client, sizeof(struct i2c_client));
-               ir->c_tx.addr = 0x70;
-               strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME,
-                       I2C_NAME_SIZE);
-               ir->have_tx = 1;
-       }
-
-       /* set lirc_dev stuff */
-       ir->l.code_length = 13;
-       ir->l.rbuf        = &ir->buf;
-       ir->l.fops        = &lirc_fops;
-       ir->l.data        = ir;
-       ir->l.minor       = minor;
-       ir->l.dev         = &adap->dev;
-       ir->l.sample_rate = 0;
-
        /* register with lirc */
        ir->l.minor = lirc_register_driver(&ir->l);
        if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
-               zilog_error("ir_attach: \"minor\" must be between 0 and %d "
-                           "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor);
+               zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n",
+                           __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
                ret = -EBADRQC;
-               goto err;
+               goto out_free_thread;
        }
 
-       /* store this for getting back in open() later on */
-       ir_devices[ir->l.minor] = ir;
-
        /*
         * if we have the tx device, load the 'firmware'.  We do this
         * after registering with lirc as otherwise hotplug seems to take
         * 10s to create the lirc device.
         */
-       if (have_tx) {
-               /* Special TX init */
-               ret = tx_init(ir);
-               if (ret != 0)
-                       goto err;
-       }
+       ret = tx_init(ir->tx);
+       if (ret != 0)
+               goto out_unregister;
 
+       zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+out_ok:
+       mutex_unlock(&ir_devices_lock);
        return 0;
 
-err:
-       /* undo everything, hopefully... */
-       if (ir->c_rx.addr)
-               ir_remove(&ir->c_rx);
-       if (ir->c_tx.addr)
-               ir_remove(&ir->c_tx);
-       return ret;
-
-out_nodev:
-       zilog_error("no device found\n");
-       return -ENODEV;
-
-out_nomem:
-       zilog_error("memory allocation failure\n");
+out_unregister:
+       lirc_unregister_driver(ir->l.minor);
+out_free_thread:
+       destroy_rx_kthread(ir->rx);
+out_free_xx:
+       if (ir->rx != NULL) {
+               if (ir->rx->buf.fifo_initialized)
+                       lirc_buffer_free(&ir->rx->buf);
+               if (ir->rx->c != NULL)
+                       i2c_set_clientdata(ir->rx->c, NULL);
+               kfree(ir->rx);
+       }
+       if (ir->tx != NULL) {
+               if (ir->tx->c != NULL)
+                       i2c_set_clientdata(ir->tx->c, NULL);
+               kfree(ir->tx);
+       }
+out_free_ir:
+       del_ir_device(ir);
        kfree(ir);
-       return -ENOMEM;
-}
-
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       /* nothing */
-       return 0;
+out_no_ir:
+       zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n",
+                   __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
+                  ret);
+       mutex_unlock(&ir_devices_lock);
+       return ret;
 }
 
 static int __init zilog_init(void)
@@ -1361,6 +1438,7 @@ static int __init zilog_init(void)
        zilog_notify("Zilog/Hauppauge IR driver initializing\n");
 
        mutex_init(&tx_data_lock);
+       mutex_init(&ir_devices_lock);
 
        request_module("firmware_class");
 
@@ -1386,7 +1464,8 @@ module_exit(zilog_exit);
 
 MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
 MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
-             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
+             "Andy Walls");
 MODULE_LICENSE("GPL");
 /* for compat with old name, which isn't all that accurate anymore */
 MODULE_ALIAS("lirc_pvr150");
@@ -1397,8 +1476,5 @@ MODULE_PARM_DESC(minor, "Preferred minor device number");
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Enable debugging messages");
 
-module_param(disable_rx, bool, 0644);
-MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device");
-
-module_param(disable_tx, bool, 0644);
-MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device");
+module_param(tx_only, bool, 0644);
+MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function");
index 23fa049..a2f29d4 100644 (file)
@@ -347,7 +347,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
        if ((!mfd) || (mfd->key != MFD_KEY))
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mfd->fbi, 1);
 
        ret = msm_fb_suspend_sub(mfd);
@@ -358,7 +358,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
                pdev->dev.power.power_state = state;
        }
 
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 #else
@@ -431,11 +431,11 @@ static int msm_fb_resume(struct platform_device *pdev)
        if ((!mfd) || (mfd->key != MFD_KEY))
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        ret = msm_fb_resume_sub(mfd);
        pdev->dev.power.power_state = PMSG_ON;
        fb_set_suspend(mfd->fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        return ret;
 }
index 9f26dc9..56a283d 100644 (file)
@@ -373,17 +373,17 @@ static void dcon_source_switch(struct work_struct *work)
                 *
                 * For now, we just hope..
                 */
-               acquire_console_sem();
+               console_lock();
                ignore_fb_events = 1;
                if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) {
                        ignore_fb_events = 0;
-                       release_console_sem();
+                       console_unlock();
                        printk(KERN_ERR "olpc-dcon:  Failed to enter CPU mode\n");
                        dcon_pending = DCON_SOURCE_DCON;
                        return;
                }
                ignore_fb_events = 0;
-               release_console_sem();
+               console_unlock();
 
                /* And turn off the DCON */
                pdata->set_dconload(1);
@@ -435,12 +435,12 @@ static void dcon_source_switch(struct work_struct *work)
                        }
                }
 
-               acquire_console_sem();
+               console_lock();
                ignore_fb_events = 1;
                if (fb_blank(fbinfo, FB_BLANK_POWERDOWN))
                        printk(KERN_ERR "olpc-dcon:  couldn't blank fb!\n");
                ignore_fb_events = 0;
-               release_console_sem();
+               console_unlock();
 
                printk(KERN_INFO "olpc-dcon: The DCON has control\n");
                break;
index 701561d..236dd36 100644 (file)
@@ -484,8 +484,6 @@ struct net_device *RtmpPhyNetDevInit(struct rt_rtmp_adapter *pAd,
        net_dev->ml_priv = (void *)pAd;
        pAd->net_dev = net_dev;
 
-       netif_stop_queue(net_dev);
-
        return net_dev;
 
 }
index ee68d51..322bf49 100644 (file)
@@ -106,6 +106,7 @@ struct usb_device_id rtusb_usb_id[] = {
        {USB_DEVICE(0x0411, 0x016f)},   /* MelCo.,Inc. WLI-UC-G301N */
        {USB_DEVICE(0x1737, 0x0070)},   /* Linksys WUSB100 */
        {USB_DEVICE(0x1737, 0x0071)},   /* Linksys WUSB600N */
+       {USB_DEVICE(0x1737, 0x0078)},   /* Linksys WUSB100v2 */
        {USB_DEVICE(0x0411, 0x00e8)},   /* Buffalo WLI-UC-G300N */
        {USB_DEVICE(0x050d, 0x815c)},   /* Belkin F5D8053 */
        {USB_DEVICE(0x100D, 0x9031)},   /* Motorola 2770 */
index 32088a6..84be383 100644 (file)
@@ -128,12 +128,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
        u8 *ptmpchar = NULL, *ppayload, *ptr;
        struct tx_desc *ptx_desc;
        u32 txdscp_sz = sizeof(struct tx_desc);
+       u8 ret = _FAIL;
 
        ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw);
        if (pmappedfw && (ulfilelength > 0)) {
                update_fwhdr(&fwhdr, pmappedfw);
                if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
-                       goto exit_fail;
+                       goto firmware_rel;
                fill_fwpriv(padapter, &fwhdr.fwpriv);
                /* firmware check ok */
                maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
@@ -141,7 +142,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
                maxlen += txdscp_sz;
                ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
                if (ptmpchar == NULL)
-                       return _FAIL;
+                       goto firmware_rel;
 
                ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
                            ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
@@ -273,11 +274,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
                        goto exit_fail;
        } else
                goto exit_fail;
-       return _SUCCESS;
+       ret = _SUCCESS;
 
 exit_fail:
        kfree(ptmpchar);
-       return _FAIL;
+firmware_rel:
+       release_firmware((struct firmware *)phfwfile_hdl);
+       return ret;
 }
 
 uint rtl8712_hal_init(struct _adapter *padapter)
index a692ee8..21ce2af 100644 (file)
@@ -47,54 +47,123 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
 static void r871xu_dev_remove(struct usb_interface *pusb_intf);
 
 static struct usb_device_id rtl871x_usb_id_tbl[] = {
-       /*92SU
-        * Realtek */
-       {USB_DEVICE(0x0bda, 0x8171)},
-       {USB_DEVICE(0x0bda, 0x8172)},
+
+/* RTL8188SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8171)},
        {USB_DEVICE(0x0bda, 0x8173)},
-       {USB_DEVICE(0x0bda, 0x8174)},
        {USB_DEVICE(0x0bda, 0x8712)},
        {USB_DEVICE(0x0bda, 0x8713)},
        {USB_DEVICE(0x0bda, 0xC512)},
-       /* Abocom  */
+       /* Abocom */
        {USB_DEVICE(0x07B8, 0x8188)},
+       /* ASUS */
+       {USB_DEVICE(0x0B05, 0x1786)},
+       {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */
+       /* Belkin */
+       {USB_DEVICE(0x050D, 0x945A)},
        /* Corega */
-       {USB_DEVICE(0x07aa, 0x0047)},
-       /* Dlink */
-       {USB_DEVICE(0x07d1, 0x3303)},
-       {USB_DEVICE(0x07d1, 0x3302)},
-       {USB_DEVICE(0x07d1, 0x3300)},
-       /* Dlink for Skyworth */
-       {USB_DEVICE(0x14b2, 0x3300)},
-       {USB_DEVICE(0x14b2, 0x3301)},
-       {USB_DEVICE(0x14b2, 0x3302)},
+       {USB_DEVICE(0x07AA, 0x0047)},
+       /* D-Link */
+       {USB_DEVICE(0x2001, 0x3306)},
+       {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */
+       /* Edimax */
+       {USB_DEVICE(0x7392, 0x7611)},
        /* EnGenius */
        {USB_DEVICE(0x1740, 0x9603)},
-       {USB_DEVICE(0x1740, 0x9605)},
+       /* Hawking */
+       {USB_DEVICE(0x0E66, 0x0016)},
+       /* Hercules */
+       {USB_DEVICE(0x06F8, 0xE034)},
+       {USB_DEVICE(0x06F8, 0xE032)},
+       /* Logitec */
+       {USB_DEVICE(0x0789, 0x0167)},
+       /* PCI */
+       {USB_DEVICE(0x2019, 0xAB28)},
+       {USB_DEVICE(0x2019, 0xED16)},
+       /* Sitecom */
+       {USB_DEVICE(0x0DF6, 0x0057)},
+       {USB_DEVICE(0x0DF6, 0x0045)},
+       {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */
+       {USB_DEVICE(0x0DF6, 0x004B)},
+       {USB_DEVICE(0x0DF6, 0x0063)},
+       /* Sweex */
+       {USB_DEVICE(0x177F, 0x0154)},
+       /* Thinkware */
+       {USB_DEVICE(0x0BDA, 0x5077)},
+       /* Toshiba */
+       {USB_DEVICE(0x1690, 0x0752)},
+       /* - */
+       {USB_DEVICE(0x20F4, 0x646B)},
+       {USB_DEVICE(0x083A, 0xC512)},
+
+/* RTL8191SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8172)},
+       /* Amigo */
+       {USB_DEVICE(0x0EB0, 0x9061)},
+       /* ASUS/EKB */
+       {USB_DEVICE(0x0BDA, 0x8172)},
+       {USB_DEVICE(0x13D3, 0x3323)},
+       {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3342)},
+       /* ASUS/EKBLenovo */
+       {USB_DEVICE(0x13D3, 0x3333)},
+       {USB_DEVICE(0x13D3, 0x3334)},
+       {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */
+       /* ASUS/Media BOX */
+       {USB_DEVICE(0x13D3, 0x3309)},
        /* Belkin */
-       {USB_DEVICE(0x050d, 0x815F)},
-       {USB_DEVICE(0x050d, 0x945A)},
-       {USB_DEVICE(0x050d, 0x845A)},
-       /* Guillemot */
-       {USB_DEVICE(0x06f8, 0xe031)},
+       {USB_DEVICE(0x050D, 0x815F)},
+       /* D-Link */
+       {USB_DEVICE(0x07D1, 0x3302)},
+       {USB_DEVICE(0x07D1, 0x3300)},
+       {USB_DEVICE(0x07D1, 0x3303)},
        /* Edimax */
-       {USB_DEVICE(0x7392, 0x7611)},
        {USB_DEVICE(0x7392, 0x7612)},
-       {USB_DEVICE(0x7392, 0x7622)},
-       /* Sitecom */
-       {USB_DEVICE(0x0DF6, 0x0045)},
+       /* EnGenius */
+       {USB_DEVICE(0x1740, 0x9605)},
+       /* Guillemot */
+       {USB_DEVICE(0x06F8, 0xE031)},
        /* Hawking */
        {USB_DEVICE(0x0E66, 0x0015)},
-       {USB_DEVICE(0x0E66, 0x0016)},
-       {USB_DEVICE(0x0b05, 0x1786)},
-       {USB_DEVICE(0x0b05, 0x1791)},    /* 11n mode disable */
-
+       /* Mediao */
        {USB_DEVICE(0x13D3, 0x3306)},
-       {USB_DEVICE(0x13D3, 0x3309)},
+       /* PCI */
+       {USB_DEVICE(0x2019, 0xED18)},
+       {USB_DEVICE(0x2019, 0x4901)},
+       /* Sitecom */
+       {USB_DEVICE(0x0DF6, 0x0058)},
+       {USB_DEVICE(0x0DF6, 0x0049)},
+       {USB_DEVICE(0x0DF6, 0x004C)},
+       {USB_DEVICE(0x0DF6, 0x0064)},
+       /* Skyworth */
+       {USB_DEVICE(0x14b2, 0x3300)},
+       {USB_DEVICE(0x14b2, 0x3301)},
+       {USB_DEVICE(0x14B2, 0x3302)},
+       /* - */
+       {USB_DEVICE(0x04F2, 0xAFF2)},
+       {USB_DEVICE(0x04F2, 0xAFF5)},
+       {USB_DEVICE(0x04F2, 0xAFF6)},
+       {USB_DEVICE(0x13D3, 0x3339)},
+       {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */
        {USB_DEVICE(0x13D3, 0x3310)},
-       {USB_DEVICE(0x13D3, 0x3311)},    /* 11n mode disable */
        {USB_DEVICE(0x13D3, 0x3325)},
-       {USB_DEVICE(0x083A, 0xC512)},
+
+/* RTL8192SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8174)},
+       {USB_DEVICE(0x0BDA, 0x8174)},
+       /* Belkin */
+       {USB_DEVICE(0x050D, 0x845A)},
+       /* Corega */
+       {USB_DEVICE(0x07AA, 0x0051)},
+       /* Edimax */
+       {USB_DEVICE(0x7392, 0x7622)},
+       /* NEC */
+       {USB_DEVICE(0x0409, 0x02B6)},
        {}
 };
 
@@ -103,8 +172,20 @@ MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl);
 static struct specific_device_id specific_device_id_tbl[] = {
        {.idVendor = 0x0b05, .idProduct = 0x1791,
                 .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x0df6, .idProduct = 0x0059,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3306,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
        {.idVendor = 0x13D3, .idProduct = 0x3311,
                 .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3335,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3336,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3340,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3341,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
        {}
 };
 
index 0bc113c..d007e4a 100644 (file)
@@ -1044,9 +1044,9 @@ static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg)
 
        /* when doing suspend, call fb apis and pci apis */
        if (msg.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                fb_set_suspend(&sfb->fb, 1);
-               release_console_sem();
+               console_unlock();
                retv = pci_save_state(pdev);
                pci_disable_device(pdev);
                retv = pci_choose_state(pdev, msg);
@@ -1105,9 +1105,9 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
 
        smtcfb_setmode(sfb);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(&sfb->fb, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 408bb9b..07a7f54 100644 (file)
@@ -332,7 +332,7 @@ static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
        unsigned long flags;
 
        len = strlen(buf);
-       if (len > 0 || len < 3) {
+       if (len > 0 && len < 3) {
                ch = buf[0];
                if (ch == '\n')
                        ch = '0';
index e8f047e..80183a7 100644 (file)
@@ -986,12 +986,6 @@ static int __devinit synaptics_rmi4_probe
        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,
@@ -1003,15 +997,20 @@ static int __devinit synaptics_rmi4_probe
        if (retval) {
                dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
                                __func__, platformdata->irq_number);
-               goto err_request_irq;
+               goto err_unset_clientdata;
+       }
+
+       retval = input_register_device(rmi4_data->input_dev);
+       if (retval) {
+               dev_err(&client->dev, "%s:input register failed\n", __func__);
+               goto err_free_irq;
        }
 
        return retval;
 
-err_request_irq:
+err_free_irq:
        free_irq(platformdata->irq_number, rmi4_data);
-       input_unregister_device(rmi4_data->input_dev);
-err_input_register:
+err_unset_clientdata:
        i2c_set_clientdata(client, NULL);
 err_query_dev:
        if (platformdata->regulator_en) {
index 5718645..27e0aa8 100644 (file)
@@ -949,7 +949,7 @@ func_end:
  *      Calls the Bridge's CHNL_ISR to determine if this interrupt is ours, then
  *      schedules a DPC to dispatch I/O.
  */
-void io_mbox_msg(u32 msg)
+int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg)
 {
        struct io_mgr *pio_mgr;
        struct dev_object *dev_obj;
@@ -959,9 +959,9 @@ void io_mbox_msg(u32 msg)
        dev_get_io_mgr(dev_obj, &pio_mgr);
 
        if (!pio_mgr)
-               return;
+               return NOTIFY_BAD;
 
-       pio_mgr->intr_val = (u16)msg;
+       pio_mgr->intr_val = (u16)((u32)msg);
        if (pio_mgr->intr_val & MBX_PM_CLASS)
                io_dispatch_pm(pio_mgr);
 
@@ -973,7 +973,7 @@ void io_mbox_msg(u32 msg)
                spin_unlock_irqrestore(&pio_mgr->dpc_lock, flags);
                tasklet_schedule(&pio_mgr->dpc_tasklet);
        }
-       return;
+       return NOTIFY_OK;
 }
 
 /*
index a3b0a18..a3f69f6 100644 (file)
@@ -223,6 +223,10 @@ static struct bridge_drv_interface drv_interface_fxns = {
        bridge_msg_set_queue_id,
 };
 
+static struct notifier_block dsp_mbox_notifier = {
+       .notifier_call = io_mbox_msg,
+};
+
 static inline void flush_all(struct bridge_dev_context *dev_context)
 {
        if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
@@ -553,7 +557,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
                 * Enable Mailbox events and also drain any pending
                 * stale messages.
                 */
-               dev_context->mbox = omap_mbox_get("dsp");
+               dev_context->mbox = omap_mbox_get("dsp", &dsp_mbox_notifier);
                if (IS_ERR(dev_context->mbox)) {
                        dev_context->mbox = NULL;
                        pr_err("%s: Failed to get dsp mailbox handle\n",
@@ -563,8 +567,6 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 
        }
        if (!status) {
-               dev_context->mbox->rxq->callback = (int (*)(void *))io_mbox_msg;
-
 /*PM_IVA2GRPSEL_PER = 0xC0;*/
                temp = readl(resources->dw_per_pm_base + 0xA8);
                temp = (temp & 0xFFFFFF30) | 0xC0;
@@ -685,7 +687,7 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
        /* Disable the mailbox interrupts */
        if (dev_context->mbox) {
                omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
-               omap_mbox_put(dev_context->mbox);
+               omap_mbox_put(dev_context->mbox, &dsp_mbox_notifier);
                dev_context->mbox = NULL;
        }
        /* Reset IVA2 clocks*/
@@ -786,10 +788,7 @@ static int bridge_dev_create(struct bridge_dev_context
 
        pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL);
        if (pt_attrs != NULL) {
-               /* Assuming that we use only DSP's memory map
-                * until 0x4000:0000 , we would need only 1024
-                * L1 enties i.e L1 size = 4K */
-               pt_attrs->l1_size = 0x1000;
+               pt_attrs->l1_size = SZ_16K; /* 4096 entries of 32 bits */
                align_size = pt_attrs->l1_size;
                /* Align sizes are expected to be power of 2 */
                /* we like to get aligned on L1 table size */
index 18aec55..8242c70 100644 (file)
@@ -72,22 +72,17 @@ extern void io_dpc(unsigned long ref_data);
 /*
  *  ======== io_mbox_msg ========
  *  Purpose:
- *      Main interrupt handler for the shared memory Bridge channel manager.
- *      Calls the Bridge's chnlsm_isr to determine if this interrupt is ours,
- *      then schedules a DPC to dispatch I/O.
+ *     Main message handler for the shared memory Bridge channel manager.
+ *     Determine if this message is ours, then schedules a DPC to
+ *     dispatch I/O.
  *  Parameters:
- *      ref_data:   Pointer to the channel manager object for this board.
- *                  Set in an initial call to ISR_Install().
+ *     self:   Pointer to its own notifier_block struct.
+ *     len:    Length of message.
+ *     msg:    Message code received.
  *  Returns:
- *      TRUE if interrupt handled; FALSE otherwise.
- *  Requires:
- *      Must be in locked memory if executing in kernel mode.
- *      Must only call functions which are in locked memory if Kernel mode.
- *      Must only call asynchronous services.
- *      Interrupts are disabled and EOI for this interrupt has been sent.
- *  Ensures:
+ *     NOTIFY_OK if handled; NOTIFY_BAD otherwise.
  */
-void io_mbox_msg(u32 msg);
+int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg);
 
 /*
  *  ======== io_request_chnl ========
index 8fe017c..eb9b9f1 100644 (file)
@@ -1450,29 +1450,55 @@ static struct video_device tm6000_template = {
  * ------------------------------------------------------------------
  */
 
-int tm6000_v4l2_register(struct tm6000_core *dev)
+static struct video_device *vdev_init(struct tm6000_core *dev,
+               const struct video_device
+               *template, const char *type_name)
 {
-       int ret = -1;
        struct video_device *vfd;
 
        vfd = video_device_alloc();
-       if(!vfd) {
+       if (NULL == vfd)
+               return NULL;
+
+       *vfd = *template;
+       vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->release = video_device_release;
+       vfd->debug = tm6000_debug;
+       vfd->lock = &dev->lock;
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+       video_set_drvdata(vfd, dev);
+       return vfd;
+}
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+       int ret = -1;
+
+       dev->vfd = vdev_init(dev, &tm6000_template, "video");
+
+       if (!dev->vfd) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                      dev->name);
                return -ENOMEM;
        }
-       dev->vfd = vfd;
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
 
-       memcpy(dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
-       dev->vfd->debug = tm6000_debug;
-       dev->vfd->lock = &dev->lock;
+       ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
 
-       vfd->v4l2_dev = &dev->v4l2_dev;
-       video_set_drvdata(vfd, dev);
+       if (ret < 0) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                      dev->name);
+               return ret;
+       }
+
+       printk(KERN_INFO "%s: registered device %s\n",
+              dev->name, video_device_node_name(dev->vfd));
 
-       ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
        printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
        return ret;
 }
index 30dbfb6..d732679 100644 (file)
@@ -32,6 +32,7 @@
 
 struct stub_device {
        struct usb_interface *interface;
+       struct usb_device *udev;
        struct list_head list;
 
        struct usbip_device ud;
index b186b5f..a7ce51c 100644 (file)
@@ -258,10 +258,11 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 static void stub_device_reset(struct usbip_device *ud)
 {
        struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        int ret;
 
        usbip_udbg("device reset");
+
        ret = usb_lock_device_for_reset(udev, sdev->interface);
        if (ret < 0) {
                dev_err(&udev->dev, "lock for reset\n");
@@ -309,7 +310,8 @@ static void stub_device_unusable(struct usbip_device *ud)
  *
  * Allocates and initializes a new stub_device struct.
  */
-static struct stub_device *stub_device_alloc(struct usb_interface *interface)
+static struct stub_device *stub_device_alloc(struct usb_device *udev,
+                                            struct usb_interface *interface)
 {
        struct stub_device *sdev;
        int busnum = interface_to_busnum(interface);
@@ -324,7 +326,8 @@ static struct stub_device *stub_device_alloc(struct usb_interface *interface)
                return NULL;
        }
 
-       sdev->interface = interface;
+       sdev->interface = usb_get_intf(interface);
+       sdev->udev = usb_get_dev(udev);
 
        /*
         * devid is defined with devnum when this driver is first allocated.
@@ -450,11 +453,12 @@ static int stub_probe(struct usb_interface *interface,
                        return err;
                }
 
+               usb_get_intf(interface);
                return 0;
        }
 
        /* ok. this is my device. */
-       sdev = stub_device_alloc(interface);
+       sdev = stub_device_alloc(udev, interface);
        if (!sdev)
                return -ENOMEM;
 
@@ -476,6 +480,8 @@ static int stub_probe(struct usb_interface *interface,
                dev_err(&interface->dev, "create sysfs files for %s\n",
                        udev_busid);
                usb_set_intfdata(interface, NULL);
+               usb_put_intf(interface);
+
                busid_priv->interf_count = 0;
 
                busid_priv->sdev = NULL;
@@ -545,6 +551,7 @@ static void stub_disconnect(struct usb_interface *interface)
        if (busid_priv->interf_count > 1) {
                busid_priv->interf_count--;
                shutdown_busid(busid_priv);
+               usb_put_intf(interface);
                return;
        }
 
@@ -554,6 +561,9 @@ static void stub_disconnect(struct usb_interface *interface)
        /* 1. shutdown the current connection */
        shutdown_busid(busid_priv);
 
+       usb_put_dev(sdev->udev);
+       usb_put_intf(interface);
+
        /* 3. free sdev */
        busid_priv->sdev = NULL;
        stub_device_free(sdev);
index 3de6fd2..ae6ac82 100644 (file)
@@ -364,7 +364,7 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
 
 static int get_pipe(struct stub_device *sdev, int epnum, int dir)
 {
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        struct usb_host_endpoint *ep;
        struct usb_endpoint_descriptor *epd = NULL;
 
@@ -484,7 +484,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
        int ret;
        struct stub_priv *priv;
        struct usbip_device *ud = &sdev->ud;
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
 
 
index 41a1fe5..afc3b1a 100644 (file)
@@ -100,9 +100,6 @@ struct vhci_hcd {
         * But, the index of this array begins from 0.
         */
        struct vhci_device vdev[VHCI_NPORTS];
-
-       /* vhci_device which has not been assiged its address yet */
-       int pending_port;
 };
 
 
@@ -119,6 +116,9 @@ void rh_port_disconnect(int rhport);
 void vhci_rx_loop(struct usbip_task *ut);
 void vhci_tx_loop(struct usbip_task *ut);
 
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
+                                           __u32 seqnum);
+
 #define hardware               (&the_controller->pdev.dev)
 
 static inline struct vhci_device *port_to_vdev(__u32 port)
index 08bd26a..a35fe61 100644 (file)
@@ -138,8 +138,6 @@ void rh_port_connect(int rhport, enum usb_device_speed speed)
         * the_controller->vdev[rhport].ud.status = VDEV_CONNECT;
         * spin_unlock(&the_controller->vdev[rhport].ud.lock); */
 
-       the_controller->pending_port = rhport;
-
        spin_unlock_irqrestore(&the_controller->lock, flags);
 
        usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
@@ -559,6 +557,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        struct device *dev = &urb->dev->dev;
        int ret = 0;
        unsigned long flags;
+       struct vhci_device *vdev;
 
        usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
                    hcd, urb, mem_flags);
@@ -574,6 +573,18 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                return urb->status;
        }
 
+       vdev = port_to_vdev(urb->dev->portnum-1);
+
+       /* refuse enqueue for dead connection */
+       spin_lock(&vdev->ud.lock);
+       if (vdev->ud.status == VDEV_ST_NULL || vdev->ud.status == VDEV_ST_ERROR) {
+               usbip_uerr("enqueue for inactive port %d\n", vdev->rhport);
+               spin_unlock(&vdev->ud.lock);
+               spin_unlock_irqrestore(&the_controller->lock, flags);
+               return -ENODEV;
+       }
+       spin_unlock(&vdev->ud.lock);
+
        ret = usb_hcd_link_urb_to_ep(hcd, urb);
        if (ret)
                goto no_need_unlink;
@@ -592,8 +603,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                __u8 type = usb_pipetype(urb->pipe);
                struct usb_ctrlrequest *ctrlreq =
                                (struct usb_ctrlrequest *) urb->setup_packet;
-               struct vhci_device *vdev =
-                               port_to_vdev(the_controller->pending_port);
 
                if (type != PIPE_CONTROL || !ctrlreq) {
                        dev_err(dev, "invalid request to devnum 0\n");
@@ -607,7 +616,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                        dev_info(dev, "SetAddress Request (%d) to port %d\n",
                                 ctrlreq->wValue, vdev->rhport);
 
-                       vdev->udev = urb->dev;
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
 
                        spin_lock(&vdev->ud.lock);
                        vdev->ud.status = VDEV_ST_USED;
@@ -627,8 +638,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                                                "Get_Descriptor to device 0 "
                                                "(get max pipe size)\n");
 
-                       /* FIXME: reference count? (usb_get_dev()) */
-                       vdev->udev = urb->dev;
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
                        goto out;
 
                default:
@@ -805,7 +817,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        return 0;
 }
 
-
 static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
 {
        struct vhci_unlink *unlink, *tmp;
@@ -813,11 +824,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
        spin_lock(&vdev->priv_lock);
 
        list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+               usbip_uinfo("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
                list_del(&unlink->list);
                kfree(unlink);
        }
 
        list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+               struct urb *urb;
+
+               /* give back URB of unanswered unlink request */
+               usbip_uinfo("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
+
+               urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+               if (!urb) {
+                       usbip_uinfo("the urb (seqnum %lu) was already given back\n",
+                                                       unlink->unlink_seqnum);
+                       list_del(&unlink->list);
+                       kfree(unlink);
+                       continue;
+               }
+
+               urb->status = -ENODEV;
+
+               spin_lock(&the_controller->lock);
+               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+               spin_unlock(&the_controller->lock);
+
+               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
                list_del(&unlink->list);
                kfree(unlink);
        }
@@ -887,6 +921,10 @@ static void vhci_device_reset(struct usbip_device *ud)
        vdev->speed  = 0;
        vdev->devid  = 0;
 
+       if (vdev->udev)
+               usb_put_dev(vdev->udev);
+       vdev->udev = NULL;
+
        ud->tcp_socket = NULL;
 
        ud->status = VDEV_ST_NULL;
index 8147d72..bf69914 100644 (file)
 #include "vhci.h"
 
 
-/* get URB from transmitted urb queue */
-static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
+/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
                                            __u32 seqnum)
 {
        struct vhci_priv *priv, *tmp;
        struct urb *urb = NULL;
        int status;
 
-       spin_lock(&vdev->priv_lock);
-
        list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
                if (priv->seqnum == seqnum) {
                        urb = priv->urb;
@@ -63,8 +61,6 @@ static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
                }
        }
 
-       spin_unlock(&vdev->priv_lock);
-
        return urb;
 }
 
@@ -74,9 +70,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
        struct usbip_device *ud = &vdev->ud;
        struct urb *urb;
 
+       spin_lock(&vdev->priv_lock);
 
        urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
 
+       spin_unlock(&vdev->priv_lock);
 
        if (!urb) {
                usbip_uerr("cannot find a urb of seqnum %u\n",
@@ -161,7 +159,12 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
                return;
        }
 
+       spin_lock(&vdev->priv_lock);
+
        urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+
+       spin_unlock(&vdev->priv_lock);
+
        if (!urb) {
                /*
                 * I get the result of a unlink request. But, it seems that I
@@ -190,6 +193,19 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
        return;
 }
 
+static int vhci_priv_tx_empty(struct vhci_device *vdev)
+{
+       int empty = 0;
+
+       spin_lock(&vdev->priv_lock);
+
+       empty = list_empty(&vdev->priv_rx);
+
+       spin_unlock(&vdev->priv_lock);
+
+       return empty;
+}
+
 /* recv a pdu */
 static void vhci_rx_pdu(struct usbip_device *ud)
 {
@@ -202,11 +218,29 @@ static void vhci_rx_pdu(struct usbip_device *ud)
 
        memset(&pdu, 0, sizeof(pdu));
 
-
        /* 1. receive a pdu header */
        ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+       if (ret < 0) {
+               if (ret == -ECONNRESET)
+                       usbip_uinfo("connection reset by peer\n");
+               else if (ret == -EAGAIN) {
+                       /* ignore if connection was idle */
+                       if (vhci_priv_tx_empty(vdev))
+                               return;
+                       usbip_uinfo("connection timed out with pending urbs\n");
+               } else if (ret != -ERESTARTSYS)
+                       usbip_uinfo("xmit failed %d\n", ret);
+
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               return;
+       }
+       if (ret == 0) {
+               usbip_uinfo("connection closed");
+               usbip_event_add(ud, VDEV_EVENT_DOWN);
+               return;
+       }
        if (ret != sizeof(pdu)) {
-               usbip_uerr("receiving pdu failed! size is %d, should be %d\n",
+               usbip_uerr("received pdu size is %d, should be %d\n",
                                        ret, (unsigned int)sizeof(pdu));
                usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers
deleted file mode 100644 (file)
index e69de29..0000000
index 7016fdd..e19b932 100644 (file)
@@ -3954,8 +3954,8 @@ void XGI_GetCRT2ResInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
 unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo)
 {
 
-       if ((((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA))
-                       && (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */
+       if ((pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+                       (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */
                return 1;
 
        return 0;
@@ -8773,7 +8773,7 @@ unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 
        if (pVBInfo->IF_DEF_LVDS == 0) {
                CRT2Index = CRT2Index >> 6; /*  for LCD */
-               if (((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA)) { /*301b*/
+               if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b*/
                        if (pVBInfo->LCDResInfo != Panel1024x768)
                                VCLKIndex = LCDXlat2VCLK[CRT2Index];
                        else
index 5415712..4bd8cbd 100644 (file)
@@ -227,6 +227,7 @@ static int zram_read(struct zram *zram, struct bio *bio)
 
                if (zram_test_flag(zram, index, ZRAM_ZERO)) {
                        handle_zero_page(page);
+                       index++;
                        continue;
                }
 
@@ -235,12 +236,14 @@ static int zram_read(struct zram *zram, struct bio *bio)
                        pr_debug("Read before write: sector=%lu, size=%u",
                                (ulong)(bio->bi_sector), bio->bi_size);
                        /* Do nothing */
+                       index++;
                        continue;
                }
 
                /* Page is stored uncompressed since it's incompressible */
                if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
                        handle_uncompressed_page(zram, page, index);
+                       index++;
                        continue;
                }
 
@@ -320,6 +323,7 @@ static int zram_write(struct zram *zram, struct bio *bio)
                        mutex_unlock(&zram->lock);
                        zram_stat_inc(&zram->stats.pages_zero);
                        zram_set_flag(zram, index, ZRAM_ZERO);
+                       index++;
                        continue;
                }
 
index 5cfd708..973bb19 100644 (file)
@@ -13,8 +13,7 @@ target_core_mod-y             := target_core_configfs.o \
                                   target_core_transport.o \
                                   target_core_cdb.o \
                                   target_core_ua.o \
-                                  target_core_rd.o \
-                                  target_core_mib.o
+                                  target_core_rd.o
 
 obj-$(CONFIG_TARGET_CORE)      += target_core_mod.o
 
index 2764510..caf8dc1 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/parser.h>
 #include <linux/syscalls.h>
 #include <linux/configfs.h>
-#include <linux/proc_fs.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_device.h>
@@ -1971,13 +1970,35 @@ static void target_core_dev_release(struct config_item *item)
 {
        struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
                                struct se_subsystem_dev, se_dev_group);
-       struct config_group *dev_cg;
-
-       if (!(se_dev))
-               return;
+       struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
+       struct se_subsystem_api *t = hba->transport;
+       struct config_group *dev_cg = &se_dev->se_dev_group;
 
-       dev_cg = &se_dev->se_dev_group;
        kfree(dev_cg->default_groups);
+       /*
+        * This pointer will set when the storage is enabled with:
+        *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+        */
+       if (se_dev->se_dev_ptr) {
+               printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
+                       "virtual_device() for se_dev_ptr: %p\n",
+                       se_dev->se_dev_ptr);
+
+               se_free_virtual_device(se_dev->se_dev_ptr, hba);
+       } else {
+               /*
+                * Release struct se_subsystem_dev->se_dev_su_ptr..
+                */
+               printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
+                       "device() for se_dev_su_ptr: %p\n",
+                       se_dev->se_dev_su_ptr);
+
+               t->free_device(se_dev->se_dev_su_ptr);
+       }
+
+       printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
+                       "_dev_t: %p\n", se_dev);
+       kfree(se_dev);
 }
 
 static ssize_t target_core_dev_show(struct config_item *item,
@@ -2140,7 +2161,16 @@ static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = {
        NULL,
 };
 
+static void target_core_alua_lu_gp_release(struct config_item *item)
+{
+       struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item),
+                       struct t10_alua_lu_gp, lu_gp_group);
+
+       core_alua_free_lu_gp(lu_gp);
+}
+
 static struct configfs_item_operations target_core_alua_lu_gp_ops = {
+       .release                = target_core_alua_lu_gp_release,
        .show_attribute         = target_core_alua_lu_gp_attr_show,
        .store_attribute        = target_core_alua_lu_gp_attr_store,
 };
@@ -2191,9 +2221,11 @@ static void target_core_alua_drop_lu_gp(
        printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit"
                " Group: core/alua/lu_gps/%s, ID: %hu\n",
                config_item_name(item), lu_gp->lu_gp_id);
-
+       /*
+        * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release()
+        * -> target_core_alua_lu_gp_release()
+        */
        config_item_put(item);
-       core_alua_free_lu_gp(lu_gp);
 }
 
 static struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
@@ -2549,7 +2581,16 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
        NULL,
 };
 
+static void target_core_alua_tg_pt_gp_release(struct config_item *item)
+{
+       struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item),
+                       struct t10_alua_tg_pt_gp, tg_pt_gp_group);
+
+       core_alua_free_tg_pt_gp(tg_pt_gp);
+}
+
 static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
+       .release                = target_core_alua_tg_pt_gp_release,
        .show_attribute         = target_core_alua_tg_pt_gp_attr_show,
        .store_attribute        = target_core_alua_tg_pt_gp_attr_store,
 };
@@ -2602,9 +2643,11 @@ static void target_core_alua_drop_tg_pt_gp(
        printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port"
                " Group: alua/tg_pt_gps/%s, ID: %hu\n",
                config_item_name(item), tg_pt_gp->tg_pt_gp_id);
-
+       /*
+        * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release()
+        * -> target_core_alua_tg_pt_gp_release().
+        */
        config_item_put(item);
-       core_alua_free_tg_pt_gp(tg_pt_gp);
 }
 
 static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
@@ -2771,13 +2814,11 @@ static void target_core_drop_subdev(
        struct se_subsystem_api *t;
        struct config_item *df_item;
        struct config_group *dev_cg, *tg_pt_gp_cg;
-       int i, ret;
+       int i;
 
        hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
 
-       if (mutex_lock_interruptible(&hba->hba_access_mutex))
-               goto out;
-
+       mutex_lock(&hba->hba_access_mutex);
        t = hba->transport;
 
        spin_lock(&se_global->g_device_lock);
@@ -2791,7 +2832,10 @@ static void target_core_drop_subdev(
                config_item_put(df_item);
        }
        kfree(tg_pt_gp_cg->default_groups);
-       core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+       /*
+        * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp
+        * directly from target_core_alua_tg_pt_gp_release().
+        */
        T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
 
        dev_cg = &se_dev->se_dev_group;
@@ -2800,38 +2844,12 @@ static void target_core_drop_subdev(
                dev_cg->default_groups[i] = NULL;
                config_item_put(df_item);
        }
-
-       config_item_put(item);
        /*
-        * This pointer will set when the storage is enabled with:
-        * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+        * The releasing of se_dev and associated se_dev->se_dev_ptr is done
+        * from target_core_dev_item_ops->release() ->target_core_dev_release().
         */
-       if (se_dev->se_dev_ptr) {
-               printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
-                       "virtual_device() for se_dev_ptr: %p\n",
-                               se_dev->se_dev_ptr);
-
-               ret = se_free_virtual_device(se_dev->se_dev_ptr, hba);
-               if (ret < 0)
-                       goto hba_out;
-       } else {
-               /*
-                * Release struct se_subsystem_dev->se_dev_su_ptr..
-                */
-               printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
-                       "device() for se_dev_su_ptr: %p\n",
-                       se_dev->se_dev_su_ptr);
-
-               t->free_device(se_dev->se_dev_su_ptr);
-       }
-
-       printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
-               "_dev_t: %p\n", se_dev);
-
-hba_out:
+       config_item_put(item);
        mutex_unlock(&hba->hba_access_mutex);
-out:
-       kfree(se_dev);
 }
 
 static struct configfs_group_operations target_core_hba_group_ops = {
@@ -2914,6 +2932,13 @@ SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR);
 
 CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group);
 
+static void target_core_hba_release(struct config_item *item)
+{
+       struct se_hba *hba = container_of(to_config_group(item),
+                               struct se_hba, hba_group);
+       core_delete_hba(hba);
+}
+
 static struct configfs_attribute *target_core_hba_attrs[] = {
        &target_core_hba_hba_info.attr,
        &target_core_hba_hba_mode.attr,
@@ -2921,6 +2946,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = {
 };
 
 static struct configfs_item_operations target_core_hba_item_ops = {
+       .release                = target_core_hba_release,
        .show_attribute         = target_core_hba_attr_show,
        .store_attribute        = target_core_hba_attr_store,
 };
@@ -2997,10 +3023,11 @@ static void target_core_call_delhbafromtarget(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_hba *hba = item_to_hba(item);
-
+       /*
+        * core_delete_hba() is called from target_core_hba_item_ops->release()
+        * -> target_core_hba_release()
+        */
        config_item_put(item);
-       core_delete_hba(hba);
 }
 
 static struct configfs_group_operations target_core_group_ops = {
@@ -3022,7 +3049,6 @@ static int target_core_init_configfs(void)
        struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
        struct config_group *lu_gp_cg = NULL;
        struct configfs_subsystem *subsys;
-       struct proc_dir_entry *scsi_target_proc = NULL;
        struct t10_alua_lu_gp *lu_gp;
        int ret;
 
@@ -3128,21 +3154,10 @@ static int target_core_init_configfs(void)
        if (core_dev_setup_virtual_lun0() < 0)
                goto out;
 
-       scsi_target_proc = proc_mkdir("scsi_target", 0);
-       if (!(scsi_target_proc)) {
-               printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n");
-               goto out;
-       }
-       ret = init_scsi_target_mib();
-       if (ret < 0)
-               goto out;
-
        return 0;
 
 out:
        configfs_unregister_subsystem(subsys);
-       if (scsi_target_proc)
-               remove_proc_entry("scsi_target", 0);
        core_dev_release_virtual_lun0();
        rd_module_exit();
 out_global:
@@ -3178,8 +3193,7 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(lu_gp_cg->default_groups);
-       core_alua_free_lu_gp(se_global->default_lu_gp);
-       se_global->default_lu_gp = NULL;
+       lu_gp_cg->default_groups = NULL;
 
        alua_cg = &se_global->alua_group;
        for (i = 0; alua_cg->default_groups[i]; i++) {
@@ -3188,6 +3202,7 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(alua_cg->default_groups);
+       alua_cg->default_groups = NULL;
 
        hba_cg = &se_global->target_core_hbagroup;
        for (i = 0; hba_cg->default_groups[i]; i++) {
@@ -3196,20 +3211,20 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(hba_cg->default_groups);
-
-       for (i = 0; subsys->su_group.default_groups[i]; i++) {
-               item = &subsys->su_group.default_groups[i]->cg_item;
-               subsys->su_group.default_groups[i] = NULL;
-               config_item_put(item);
-       }
+       hba_cg->default_groups = NULL;
+       /*
+        * We expect subsys->su_group.default_groups to be released
+        * by configfs subsystem provider logic..
+        */
+       configfs_unregister_subsystem(subsys);
        kfree(subsys->su_group.default_groups);
 
-       configfs_unregister_subsystem(subsys);
+       core_alua_free_lu_gp(se_global->default_lu_gp);
+       se_global->default_lu_gp = NULL;
+
        printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric"
                        " Infrastructure\n");
 
-       remove_scsi_target_mib();
-       remove_proc_entry("scsi_target", 0);
        core_dev_release_virtual_lun0();
        rd_module_exit();
        release_se_global();
index 317ce58..5da051a 100644 (file)
@@ -373,11 +373,11 @@ int core_update_device_list_for_node(
                /*
                 * deve->se_lun_acl will be NULL for demo-mode created LUNs
                 * that have not been explictly concerted to MappedLUNs ->
-                * struct se_lun_acl.
+                * struct se_lun_acl, but we remove deve->alua_port_list from
+                * port->sep_alua_list. This also means that active UAs and
+                * NodeACL context specific PR metadata for demo-mode
+                * MappedLUN *deve will be released below..
                 */
-               if (!(deve->se_lun_acl))
-                       return 0;
-
                spin_lock_bh(&port->sep_alua_lock);
                list_del(&deve->alua_port_list);
                spin_unlock_bh(&port->sep_alua_lock);
@@ -395,12 +395,14 @@ int core_update_device_list_for_node(
                                printk(KERN_ERR "struct se_dev_entry->se_lun_acl"
                                        " already set for demo mode -> explict"
                                        " LUN ACL transition\n");
+                               spin_unlock_irq(&nacl->device_list_lock);
                                return -1;
                        }
                        if (deve->se_lun != lun) {
                                printk(KERN_ERR "struct se_dev_entry->se_lun does"
                                        " match passed struct se_lun for demo mode"
                                        " -> explict LUN ACL transition\n");
+                               spin_unlock_irq(&nacl->device_list_lock);
                                return -1;
                        }
                        deve->se_lun_acl = lun_acl;
@@ -865,9 +867,6 @@ static void se_dev_stop(struct se_device *dev)
                }
        }
        spin_unlock(&hba->device_lock);
-
-       while (atomic_read(&hba->dev_mib_access_count))
-               cpu_relax();
 }
 
 int se_dev_check_online(struct se_device *dev)
index 32b148d..b65d1c8 100644 (file)
@@ -214,12 +214,22 @@ TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR);
 
 CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group);
 
+static void target_fabric_mappedlun_release(struct config_item *item)
+{
+       struct se_lun_acl *lacl = container_of(to_config_group(item),
+                               struct se_lun_acl, se_lun_group);
+       struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
+
+       core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
 static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
        &target_fabric_mappedlun_write_protect.attr,
        NULL,
 };
 
 static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
+       .release                = target_fabric_mappedlun_release,
        .show_attribute         = target_fabric_mappedlun_attr_show,
        .store_attribute        = target_fabric_mappedlun_attr_store,
        .allow_link             = target_fabric_mappedlun_link,
@@ -337,15 +347,21 @@ static void target_fabric_drop_mappedlun(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_lun_acl *lacl = container_of(to_config_group(item),
-                       struct se_lun_acl, se_lun_group);
-       struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
-
        config_item_put(item);
-       core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
+static void target_fabric_nacl_base_release(struct config_item *item)
+{
+       struct se_node_acl *se_nacl = container_of(to_config_group(item),
+                       struct se_node_acl, acl_group);
+       struct se_portal_group *se_tpg = se_nacl->se_tpg;
+       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_nodeacl(se_nacl);
 }
 
 static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
+       .release                = target_fabric_nacl_base_release,
        .show_attribute         = target_fabric_nacl_base_attr_show,
        .store_attribute        = target_fabric_nacl_base_attr_store,
 };
@@ -404,9 +420,6 @@ static void target_fabric_drop_nodeacl(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_portal_group *se_tpg = container_of(group,
-                       struct se_portal_group, tpg_acl_group);
-       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
        struct se_node_acl *se_nacl = container_of(to_config_group(item),
                        struct se_node_acl, acl_group);
        struct config_item *df_item;
@@ -419,9 +432,10 @@ static void target_fabric_drop_nodeacl(
                nacl_cg->default_groups[i] = NULL;
                config_item_put(df_item);
        }
-
+       /*
+        * struct se_node_acl free is done in target_fabric_nacl_base_release()
+        */
        config_item_put(item);
-       tf->tf_ops.fabric_drop_nodeacl(se_nacl);
 }
 
 static struct configfs_group_operations target_fabric_nacl_group_ops = {
@@ -437,7 +451,18 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL);
 
 CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group);
 
+static void target_fabric_np_base_release(struct config_item *item)
+{
+       struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
+                               struct se_tpg_np, tpg_np_group);
+       struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent;
+       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_np(se_tpg_np);
+}
+
 static struct configfs_item_operations target_fabric_np_base_item_ops = {
+       .release                = target_fabric_np_base_release,
        .show_attribute         = target_fabric_np_base_attr_show,
        .store_attribute        = target_fabric_np_base_attr_store,
 };
@@ -466,6 +491,7 @@ static struct config_group *target_fabric_make_np(
        if (!(se_tpg_np) || IS_ERR(se_tpg_np))
                return ERR_PTR(-EINVAL);
 
+       se_tpg_np->tpg_np_parent = se_tpg;
        config_group_init_type_name(&se_tpg_np->tpg_np_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit);
 
@@ -476,14 +502,10 @@ static void target_fabric_drop_np(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_portal_group *se_tpg = container_of(group,
-                               struct se_portal_group, tpg_np_group);
-       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
-       struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
-                               struct se_tpg_np, tpg_np_group);
-
+       /*
+        * struct se_tpg_np is released via target_fabric_np_base_release()
+        */
        config_item_put(item);
-       tf->tf_ops.fabric_drop_np(se_tpg_np);
 }
 
 static struct configfs_group_operations target_fabric_np_group_ops = {
@@ -814,7 +836,18 @@ TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
  */
 CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group);
 
+static void target_fabric_tpg_release(struct config_item *item)
+{
+       struct se_portal_group *se_tpg = container_of(to_config_group(item),
+                       struct se_portal_group, tpg_group);
+       struct se_wwn *wwn = se_tpg->se_tpg_wwn;
+       struct target_fabric_configfs *tf = wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_tpg(se_tpg);
+}
+
 static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
+       .release                = target_fabric_tpg_release,
        .show_attribute         = target_fabric_tpg_attr_show,
        .store_attribute        = target_fabric_tpg_attr_store,
 };
@@ -872,8 +905,6 @@ static void target_fabric_drop_tpg(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
-       struct target_fabric_configfs *tf = wwn->wwn_tf;
        struct se_portal_group *se_tpg = container_of(to_config_group(item),
                                struct se_portal_group, tpg_group);
        struct config_group *tpg_cg = &se_tpg->tpg_group;
@@ -890,15 +921,28 @@ static void target_fabric_drop_tpg(
        }
 
        config_item_put(item);
-       tf->tf_ops.fabric_drop_tpg(se_tpg);
 }
 
+static void target_fabric_release_wwn(struct config_item *item)
+{
+       struct se_wwn *wwn = container_of(to_config_group(item),
+                               struct se_wwn, wwn_group);
+       struct target_fabric_configfs *tf = wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_wwn(wwn);
+}
+
+static struct configfs_item_operations target_fabric_tpg_item_ops = {
+       .release        = target_fabric_release_wwn,
+};
+
 static struct configfs_group_operations target_fabric_tpg_group_ops = {
        .make_group     = target_fabric_make_tpg,
        .drop_item      = target_fabric_drop_tpg,
 };
 
-TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL);
+TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops,
+               NULL);
 
 /* End of tfc_tpg_cit */
 
@@ -932,13 +976,7 @@ static void target_fabric_drop_wwn(
        struct config_group *group,
        struct config_item *item)
 {
-       struct target_fabric_configfs *tf = container_of(group,
-                               struct target_fabric_configfs, tf_group);
-       struct se_wwn *wwn = container_of(to_config_group(item),
-                               struct se_wwn, wwn_group);
-
        config_item_put(item);
-       tf->tf_ops.fabric_drop_wwn(wwn);
 }
 
 static struct configfs_group_operations target_fabric_wwn_group_ops = {
index c6e0d75..67f0c09 100644 (file)
@@ -154,7 +154,7 @@ static struct se_device *iblock_create_virtdevice(
 
        bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
                                FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
-       if (!(bd))
+       if (IS_ERR(bd))
                goto failed;
        /*
         * Setup the local scope queue_limits from struct request_queue->limits
@@ -220,8 +220,10 @@ static void iblock_free_device(void *p)
 {
        struct iblock_dev *ib_dev = p;
 
-       blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
-       bioset_free(ib_dev->ibd_bio_set);
+       if (ib_dev->ibd_bd != NULL)
+               blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+       if (ib_dev->ibd_bio_set != NULL)
+               bioset_free(ib_dev->ibd_bio_set);
        kfree(ib_dev);
 }
 
diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c
deleted file mode 100644 (file)
index d5a48aa..0000000
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*******************************************************************************
- * Filename:  target_core_mib.c
- *
- * Copyright (c) 2006-2007 SBE, Inc.  All Rights Reserved.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
- *
- * Nicholas A. Bellinger <nab@linux-iscsi.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ******************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/version.h>
-#include <generated/utsrelease.h>
-#include <linux/utsname.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/blkdev.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
-#include <target/target_core_configfs.h>
-
-#include "target_core_hba.h"
-#include "target_core_mib.h"
-
-/* SCSI mib table index */
-static struct scsi_index_table scsi_index_table;
-
-#ifndef INITIAL_JIFFIES
-#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
-#endif
-
-/* SCSI Instance Table */
-#define SCSI_INST_SW_INDEX             1
-#define SCSI_TRANSPORT_INDEX           1
-
-#define NONE           "None"
-#define ISPRINT(a)   ((a >= ' ') && (a <= '~'))
-
-static inline int list_is_first(const struct list_head *list,
-                               const struct list_head *head)
-{
-       return list->prev == head;
-}
-
-static void *locate_hba_start(
-       struct seq_file *seq,
-       loff_t *pos)
-{
-       spin_lock(&se_global->g_device_lock);
-       return seq_list_start(&se_global->g_se_dev_list, *pos);
-}
-
-static void *locate_hba_next(
-       struct seq_file *seq,
-       void *v,
-       loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_dev_list, pos);
-}
-
-static void locate_hba_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock(&se_global->g_device_lock);
-}
-
-/****************************************************************************
- * SCSI MIB Tables
- ****************************************************************************/
-
-/*
- * SCSI Instance Table
- */
-static void *scsi_inst_seq_start(
-       struct seq_file *seq,
-       loff_t *pos)
-{
-       spin_lock(&se_global->hba_lock);
-       return seq_list_start(&se_global->g_hba_list, *pos);
-}
-
-static void *scsi_inst_seq_next(
-       struct seq_file *seq,
-       void *v,
-       loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_hba_list, pos);
-}
-
-static void scsi_inst_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock(&se_global->hba_lock);
-}
-
-static int scsi_inst_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba = list_entry(v, struct se_hba, hba_list);
-
-       if (list_is_first(&hba->hba_list, &se_global->g_hba_list))
-               seq_puts(seq, "inst sw_indx\n");
-
-       seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX);
-       seq_printf(seq, "plugin: %s version: %s\n",
-                       hba->transport->name, TARGET_CORE_VERSION);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_inst_seq_ops = {
-       .start  = scsi_inst_seq_start,
-       .next   = scsi_inst_seq_next,
-       .stop   = scsi_inst_seq_stop,
-       .show   = scsi_inst_seq_show
-};
-
-static int scsi_inst_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_inst_seq_ops);
-}
-
-static const struct file_operations scsi_inst_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_inst_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Device Table
- */
-static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_dev_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_dev_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       char str[28];
-       int k;
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst indx role ports\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       seq_printf(seq, "%u %u %s %u\n", hba->hba_index,
-                  dev->dev_index, "Target", dev->dev_port_count);
-
-       memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
-
-       /* vendor */
-       for (k = 0; k < 8; k++)
-               str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ?
-                               DEV_T10_WWN(dev)->vendor[k] : 0x20;
-       str[k] = 0x20;
-
-       /* model */
-       for (k = 0; k < 16; k++)
-               str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ?
-                               DEV_T10_WWN(dev)->model[k] : 0x20;
-       str[k + 9] = 0;
-
-       seq_printf(seq, "dev_alias: %s\n", str);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_dev_seq_ops = {
-       .start  = scsi_dev_seq_start,
-       .next   = scsi_dev_seq_next,
-       .stop   = scsi_dev_seq_stop,
-       .show   = scsi_dev_seq_show
-};
-
-static int scsi_dev_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_dev_seq_ops);
-}
-
-static const struct file_operations scsi_dev_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_dev_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Port Table
- */
-static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_port_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *sep, *sep_tmp;
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx role busy_count\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       /* FIXME: scsiPortBusyStatuses count */
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
-               seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index,
-                       dev->dev_index, sep->sep_index, "Device",
-                       dev->dev_index, 0);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_port_seq_ops = {
-       .start  = scsi_port_seq_start,
-       .next   = scsi_port_seq_next,
-       .stop   = scsi_port_seq_stop,
-       .show   = scsi_port_seq_show
-};
-
-static int scsi_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_port_seq_ops);
-}
-
-static const struct file_operations scsi_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Transport Table
- */
-static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_transport_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_transport_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *se, *se_tmp;
-       struct se_portal_group *tpg;
-       struct t10_wwn *wwn;
-       char buf[64];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx dev_name\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       wwn = DEV_T10_WWN(dev);
-
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) {
-               tpg = se->sep_tpg;
-               sprintf(buf, "scsiTransport%s",
-                               TPG_TFO(tpg)->get_fabric_name());
-
-               seq_printf(seq, "%u %s %u %s+%s\n",
-                       hba->hba_index, /* scsiTransportIndex */
-                       buf,  /* scsiTransportType */
-                       (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ?
-                       TPG_TFO(tpg)->tpg_get_inst_index(tpg) :
-                       0,
-                       TPG_TFO(tpg)->tpg_get_wwn(tpg),
-                       (strlen(wwn->unit_serial)) ?
-                       /* scsiTransportDevName */
-                       wwn->unit_serial : wwn->vendor);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_transport_seq_ops = {
-       .start  = scsi_transport_seq_start,
-       .next   = scsi_transport_seq_next,
-       .stop   = scsi_transport_seq_stop,
-       .show   = scsi_transport_seq_show
-};
-
-static int scsi_transport_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_transport_seq_ops);
-}
-
-static const struct file_operations scsi_transport_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_transport_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Target Device Table
- */
-static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-
-#define LU_COUNT       1  /* for now */
-static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       int non_accessible_lus = 0;
-       char status[16];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst indx num_LUs status non_access_LUs"
-                       " resets\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       switch (dev->dev_status) {
-       case TRANSPORT_DEVICE_ACTIVATED:
-               strcpy(status, "activated");
-               break;
-       case TRANSPORT_DEVICE_DEACTIVATED:
-               strcpy(status, "deactivated");
-               non_accessible_lus = 1;
-               break;
-       case TRANSPORT_DEVICE_SHUTDOWN:
-               strcpy(status, "shutdown");
-               non_accessible_lus = 1;
-               break;
-       case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
-       case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
-               strcpy(status, "offline");
-               non_accessible_lus = 1;
-               break;
-       default:
-               sprintf(status, "unknown(%d)", dev->dev_status);
-               non_accessible_lus = 1;
-       }
-
-       seq_printf(seq, "%u %u %u %s %u %u\n",
-                  hba->hba_index, dev->dev_index, LU_COUNT,
-                  status, non_accessible_lus, dev->num_resets);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_tgt_dev_seq_ops = {
-       .start  = scsi_tgt_dev_seq_start,
-       .next   = scsi_tgt_dev_seq_next,
-       .stop   = scsi_tgt_dev_seq_stop,
-       .show   = scsi_tgt_dev_seq_show
-};
-
-static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_tgt_dev_seq_ops);
-}
-
-static const struct file_operations scsi_tgt_dev_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_tgt_dev_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Target Port Table
- */
-static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *sep, *sep_tmp;
-       struct se_portal_group *tpg;
-       u32 rx_mbytes, tx_mbytes;
-       unsigned long long num_cmds;
-       char buf[64];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx name port_index in_cmds"
-                       " write_mbytes read_mbytes hs_in_cmds\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
-               tpg = sep->sep_tpg;
-               sprintf(buf, "%sPort#",
-                       TPG_TFO(tpg)->get_fabric_name());
-
-               seq_printf(seq, "%u %u %u %s%d %s%s%d ",
-                    hba->hba_index,
-                    dev->dev_index,
-                    sep->sep_index,
-                    buf, sep->sep_index,
-                    TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+",
-                    TPG_TFO(tpg)->tpg_get_tag(tpg));
-
-               spin_lock(&sep->sep_lun->lun_sep_lock);
-               num_cmds = sep->sep_stats.cmd_pdus;
-               rx_mbytes = (sep->sep_stats.rx_data_octets >> 20);
-               tx_mbytes = (sep->sep_stats.tx_data_octets >> 20);
-               spin_unlock(&sep->sep_lun->lun_sep_lock);
-
-               seq_printf(seq, "%llu %u %u %u\n", num_cmds,
-                       rx_mbytes, tx_mbytes, 0);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_tgt_port_seq_ops = {
-       .start  = scsi_tgt_port_seq_start,
-       .next   = scsi_tgt_port_seq_next,
-       .stop   = scsi_tgt_port_seq_stop,
-       .show   = scsi_tgt_port_seq_show
-};
-
-static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_tgt_port_seq_ops);
-}
-
-static const struct file_operations scsi_tgt_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_tgt_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Authorized Initiator Table:
- * It contains the SCSI Initiators authorized to be attached to one of the
- * local Target ports.
- * Iterates through all active TPGs and extracts the info from the ACLs
- */
-static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       spin_lock_bh(&se_global->se_tpg_lock);
-       return seq_list_start(&se_global->g_se_tpg_list, *pos);
-}
-
-static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v,
-                                        loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_tpg_list, pos);
-}
-
-static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock_bh(&se_global->se_tpg_lock);
-}
-
-static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
-                                               se_tpg_list);
-       struct se_dev_entry *deve;
-       struct se_lun *lun;
-       struct se_node_acl *se_nacl;
-       int j;
-
-       if (list_is_first(&se_tpg->se_tpg_list,
-                         &se_global->g_se_tpg_list))
-               seq_puts(seq, "inst dev port indx dev_or_port intr_name "
-                        "map_indx att_count num_cmds read_mbytes "
-                        "write_mbytes hs_num_cmds creation_time row_status\n");
-
-       if (!(se_tpg))
-               return 0;
-
-       spin_lock(&se_tpg->acl_node_lock);
-       list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) {
-
-               atomic_inc(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               spin_unlock(&se_tpg->acl_node_lock);
-
-               spin_lock_irq(&se_nacl->device_list_lock);
-               for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
-                       deve = &se_nacl->device_list[j];
-                       if (!(deve->lun_flags &
-                                       TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
-                           (!deve->se_lun))
-                               continue;
-                       lun = deve->se_lun;
-                       if (!lun->lun_se_dev)
-                               continue;
-
-                       seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u"
-                                       " %u %s\n",
-                               /* scsiInstIndex */
-                               (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
-                               TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
-                               0,
-                               /* scsiDeviceIndex */
-                               lun->lun_se_dev->dev_index,
-                               /* scsiAuthIntrTgtPortIndex */
-                               TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
-                               /* scsiAuthIntrIndex */
-                               se_nacl->acl_index,
-                               /* scsiAuthIntrDevOrPort */
-                               1,
-                               /* scsiAuthIntrName */
-                               se_nacl->initiatorname[0] ?
-                                       se_nacl->initiatorname : NONE,
-                               /* FIXME: scsiAuthIntrLunMapIndex */
-                               0,
-                               /* scsiAuthIntrAttachedTimes */
-                               deve->attach_count,
-                               /* scsiAuthIntrOutCommands */
-                               deve->total_cmds,
-                               /* scsiAuthIntrReadMegaBytes */
-                               (u32)(deve->read_bytes >> 20),
-                               /* scsiAuthIntrWrittenMegaBytes */
-                               (u32)(deve->write_bytes >> 20),
-                               /* FIXME: scsiAuthIntrHSOutCommands */
-                               0,
-                               /* scsiAuthIntrLastCreation */
-                               (u32)(((u32)deve->creation_time -
-                                           INITIAL_JIFFIES) * 100 / HZ),
-                               /* FIXME: scsiAuthIntrRowStatus */
-                               "Ready");
-               }
-               spin_unlock_irq(&se_nacl->device_list_lock);
-
-               spin_lock(&se_tpg->acl_node_lock);
-               atomic_dec(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_dec();
-       }
-       spin_unlock(&se_tpg->acl_node_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_auth_intr_seq_ops = {
-       .start  = scsi_auth_intr_seq_start,
-       .next   = scsi_auth_intr_seq_next,
-       .stop   = scsi_auth_intr_seq_stop,
-       .show   = scsi_auth_intr_seq_show
-};
-
-static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_auth_intr_seq_ops);
-}
-
-static const struct file_operations scsi_auth_intr_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_auth_intr_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Attached Initiator Port Table:
- * It lists the SCSI Initiators attached to one of the local Target ports.
- * Iterates through all active TPGs and use active sessions from each TPG
- * to list the info fo this table.
- */
-static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       spin_lock_bh(&se_global->se_tpg_lock);
-       return seq_list_start(&se_global->g_se_tpg_list, *pos);
-}
-
-static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v,
-                                        loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_tpg_list, pos);
-}
-
-static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock_bh(&se_global->se_tpg_lock);
-}
-
-static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
-                                               se_tpg_list);
-       struct se_dev_entry *deve;
-       struct se_lun *lun;
-       struct se_node_acl *se_nacl;
-       struct se_session *se_sess;
-       unsigned char buf[64];
-       int j;
-
-       if (list_is_first(&se_tpg->se_tpg_list,
-                         &se_global->g_se_tpg_list))
-               seq_puts(seq, "inst dev port indx port_auth_indx port_name"
-                       " port_ident\n");
-
-       if (!(se_tpg))
-               return 0;
-
-       spin_lock(&se_tpg->session_lock);
-       list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
-               if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) ||
-                   (!se_sess->se_node_acl) ||
-                   (!se_sess->se_node_acl->device_list))
-                       continue;
-
-               atomic_inc(&se_sess->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               se_nacl = se_sess->se_node_acl;
-               atomic_inc(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               spin_unlock(&se_tpg->session_lock);
-
-               spin_lock_irq(&se_nacl->device_list_lock);
-               for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
-                       deve = &se_nacl->device_list[j];
-                       if (!(deve->lun_flags &
-                                       TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
-                          (!deve->se_lun))
-                               continue;
-
-                       lun = deve->se_lun;
-                       if (!lun->lun_se_dev)
-                               continue;
-
-                       memset(buf, 0, 64);
-                       if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL)
-                               TPG_TFO(se_tpg)->sess_get_initiator_sid(
-                                       se_sess, (unsigned char *)&buf[0], 64);
-
-                       seq_printf(seq, "%u %u %u %u %u %s+i+%s\n",
-                               /* scsiInstIndex */
-                               (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
-                               TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
-                               0,
-                               /* scsiDeviceIndex */
-                               lun->lun_se_dev->dev_index,
-                               /* scsiPortIndex */
-                               TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
-                               /* scsiAttIntrPortIndex */
-                               (TPG_TFO(se_tpg)->sess_get_index != NULL) ?
-                               TPG_TFO(se_tpg)->sess_get_index(se_sess) :
-                               0,
-                               /* scsiAttIntrPortAuthIntrIdx */
-                               se_nacl->acl_index,
-                               /* scsiAttIntrPortName */
-                               se_nacl->initiatorname[0] ?
-                                       se_nacl->initiatorname : NONE,
-                               /* scsiAttIntrPortIdentifier */
-                               buf);
-               }
-               spin_unlock_irq(&se_nacl->device_list_lock);
-
-               spin_lock(&se_tpg->session_lock);
-               atomic_dec(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_dec();
-               atomic_dec(&se_sess->mib_ref_count);
-               smp_mb__after_atomic_dec();
-       }
-       spin_unlock(&se_tpg->session_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_att_intr_port_seq_ops = {
-       .start  = scsi_att_intr_port_seq_start,
-       .next   = scsi_att_intr_port_seq_next,
-       .stop   = scsi_att_intr_port_seq_stop,
-       .show   = scsi_att_intr_port_seq_show
-};
-
-static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_att_intr_port_seq_ops);
-}
-
-static const struct file_operations scsi_att_intr_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_att_intr_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Logical Unit Table
- */
-static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_lu_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-#define SCSI_LU_INDEX          1
-static int scsi_lu_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       int j;
-       char str[28];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst dev indx LUN lu_name vend prod rev"
-               " dev_type status state-bit num_cmds read_mbytes"
-               " write_mbytes resets full_stat hs_num_cmds creation_time\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       /* Fix LU state, if we can read it from the device */
-       seq_printf(seq, "%u %u %u %llu %s", hba->hba_index,
-                       dev->dev_index, SCSI_LU_INDEX,
-                       (unsigned long long)0, /* FIXME: scsiLuDefaultLun */
-                       (strlen(DEV_T10_WWN(dev)->unit_serial)) ?
-                       /* scsiLuWwnName */
-                       (char *)&DEV_T10_WWN(dev)->unit_serial[0] :
-                       "None");
-
-       memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
-       /* scsiLuVendorId */
-       for (j = 0; j < 8; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ?
-                       DEV_T10_WWN(dev)->vendor[j] : 0x20;
-       str[8] = 0;
-       seq_printf(seq, " %s", str);
-
-       /* scsiLuProductId */
-       for (j = 0; j < 16; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ?
-                       DEV_T10_WWN(dev)->model[j] : 0x20;
-       str[16] = 0;
-       seq_printf(seq, " %s", str);
-
-       /* scsiLuRevisionId */
-       for (j = 0; j < 4; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ?
-                       DEV_T10_WWN(dev)->revision[j] : 0x20;
-       str[4] = 0;
-       seq_printf(seq, " %s", str);
-
-       seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n",
-               /* scsiLuPeripheralType */
-                  TRANSPORT(dev)->get_device_type(dev),
-                  (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ?
-               "available" : "notavailable", /* scsiLuStatus */
-               "exposed",      /* scsiLuState */
-               (unsigned long long)dev->num_cmds,
-               /* scsiLuReadMegaBytes */
-               (u32)(dev->read_bytes >> 20),
-               /* scsiLuWrittenMegaBytes */
-               (u32)(dev->write_bytes >> 20),
-               dev->num_resets, /* scsiLuInResets */
-               0, /* scsiLuOutTaskSetFullStatus */
-               0, /* scsiLuHSInCommands */
-               (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) *
-                                                       100 / HZ));
-
-       return 0;
-}
-
-static const struct seq_operations scsi_lu_seq_ops = {
-       .start  = scsi_lu_seq_start,
-       .next   = scsi_lu_seq_next,
-       .stop   = scsi_lu_seq_stop,
-       .show   = scsi_lu_seq_show
-};
-
-static int scsi_lu_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_lu_seq_ops);
-}
-
-static const struct file_operations scsi_lu_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_lu_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/****************************************************************************/
-
-/*
- * Remove proc fs entries
- */
-void remove_scsi_target_mib(void)
-{
-       remove_proc_entry("scsi_target/mib/scsi_inst", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_dev", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_transport", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_lu", NULL);
-       remove_proc_entry("scsi_target/mib", NULL);
-}
-
-/*
- * Create proc fs entries for the mib tables
- */
-int init_scsi_target_mib(void)
-{
-       struct proc_dir_entry *dir_entry;
-       struct proc_dir_entry *scsi_inst_entry;
-       struct proc_dir_entry *scsi_dev_entry;
-       struct proc_dir_entry *scsi_port_entry;
-       struct proc_dir_entry *scsi_transport_entry;
-       struct proc_dir_entry *scsi_tgt_dev_entry;
-       struct proc_dir_entry *scsi_tgt_port_entry;
-       struct proc_dir_entry *scsi_auth_intr_entry;
-       struct proc_dir_entry *scsi_att_intr_port_entry;
-       struct proc_dir_entry *scsi_lu_entry;
-
-       dir_entry = proc_mkdir("scsi_target/mib", NULL);
-       if (!(dir_entry)) {
-               printk(KERN_ERR "proc_mkdir() failed.\n");
-               return -1;
-       }
-
-       scsi_inst_entry =
-               create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL);
-       if (scsi_inst_entry)
-               scsi_inst_entry->proc_fops = &scsi_inst_seq_fops;
-       else
-               goto error;
-
-       scsi_dev_entry =
-               create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL);
-       if (scsi_dev_entry)
-               scsi_dev_entry->proc_fops = &scsi_dev_seq_fops;
-       else
-               goto error;
-
-       scsi_port_entry =
-               create_proc_entry("scsi_target/mib/scsi_port", 0, NULL);
-       if (scsi_port_entry)
-               scsi_port_entry->proc_fops = &scsi_port_seq_fops;
-       else
-               goto error;
-
-       scsi_transport_entry =
-               create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL);
-       if (scsi_transport_entry)
-               scsi_transport_entry->proc_fops = &scsi_transport_seq_fops;
-       else
-               goto error;
-
-       scsi_tgt_dev_entry =
-               create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL);
-       if (scsi_tgt_dev_entry)
-               scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops;
-       else
-               goto error;
-
-       scsi_tgt_port_entry =
-               create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL);
-       if (scsi_tgt_port_entry)
-               scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops;
-       else
-               goto error;
-
-       scsi_auth_intr_entry =
-               create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL);
-       if (scsi_auth_intr_entry)
-               scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops;
-       else
-               goto error;
-
-       scsi_att_intr_port_entry =
-             create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL);
-       if (scsi_att_intr_port_entry)
-               scsi_att_intr_port_entry->proc_fops =
-                               &scsi_att_intr_port_seq_fops;
-       else
-               goto error;
-
-       scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL);
-       if (scsi_lu_entry)
-               scsi_lu_entry->proc_fops = &scsi_lu_seq_fops;
-       else
-               goto error;
-
-       return 0;
-
-error:
-       printk(KERN_ERR "create_proc_entry() failed.\n");
-       remove_scsi_target_mib();
-       return -1;
-}
-
-/*
- * Initialize the index table for allocating unique row indexes to various mib
- * tables
- */
-void init_scsi_index_table(void)
-{
-       memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
-       spin_lock_init(&scsi_index_table.lock);
-}
-
-/*
- * Allocate a new row index for the entry type specified
- */
-u32 scsi_get_new_index(scsi_index_t type)
-{
-       u32 new_index;
-
-       if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
-               printk(KERN_ERR "Invalid index type %d\n", type);
-               return -1;
-       }
-
-       spin_lock(&scsi_index_table.lock);
-       new_index = ++scsi_index_table.scsi_mib_index[type];
-       if (new_index == 0)
-               new_index = ++scsi_index_table.scsi_mib_index[type];
-       spin_unlock(&scsi_index_table.lock);
-
-       return new_index;
-}
-EXPORT_SYMBOL(scsi_get_new_index);
diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h
deleted file mode 100644 (file)
index 2772046..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef TARGET_CORE_MIB_H
-#define TARGET_CORE_MIB_H
-
-typedef enum {
-       SCSI_INST_INDEX,
-       SCSI_DEVICE_INDEX,
-       SCSI_AUTH_INTR_INDEX,
-       SCSI_INDEX_TYPE_MAX
-} scsi_index_t;
-
-struct scsi_index_table {
-       spinlock_t      lock;
-       u32             scsi_mib_index[SCSI_INDEX_TYPE_MAX];
-} ____cacheline_aligned;
-
-/* SCSI Port stats */
-struct scsi_port_stats {
-       u64     cmd_pdus;
-       u64     tx_data_octets;
-       u64     rx_data_octets;
-} ____cacheline_aligned;
-
-extern int init_scsi_target_mib(void);
-extern void remove_scsi_target_mib(void);
-extern void init_scsi_index_table(void);
-extern u32 scsi_get_new_index(scsi_index_t);
-
-#endif   /*** TARGET_CORE_MIB_H ***/
index 742d246..f2a0847 100644 (file)
@@ -462,8 +462,8 @@ static struct se_device *pscsi_create_type_disk(
         */
        bd = blkdev_get_by_path(se_dev->se_dev_udev_path,
                                FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);
-       if (!(bd)) {
-               printk("pSCSI: blkdev_get_by_path() failed\n");
+       if (IS_ERR(bd)) {
+               printk(KERN_ERR "pSCSI: blkdev_get_by_path() failed\n");
                scsi_device_put(sd);
                return NULL;
        }
index abfa81a..c26f674 100644 (file)
@@ -275,7 +275,6 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
        spin_lock_init(&acl->device_list_lock);
        spin_lock_init(&acl->nacl_sess_lock);
        atomic_set(&acl->acl_pr_ref_count, 0);
-       atomic_set(&acl->mib_ref_count, 0);
        acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg);
        snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
        acl->se_tpg = tpg;
@@ -318,12 +317,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl)
                cpu_relax();
 }
 
-void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl)
-{
-       while (atomic_read(&nacl->mib_ref_count) != 0)
-               cpu_relax();
-}
-
 void core_tpg_clear_object_luns(struct se_portal_group *tpg)
 {
        int i, ret;
@@ -480,7 +473,6 @@ int core_tpg_del_initiator_node_acl(
        spin_unlock_bh(&tpg->session_lock);
 
        core_tpg_wait_for_nacl_pr_ref(acl);
-       core_tpg_wait_for_mib_ref(acl);
        core_clear_initiator_node_from_tpg(acl, tpg);
        core_free_device_list_for_node(acl, tpg);
 
@@ -701,6 +693,8 @@ EXPORT_SYMBOL(core_tpg_register);
 
 int core_tpg_deregister(struct se_portal_group *se_tpg)
 {
+       struct se_node_acl *nacl, *nacl_tmp;
+
        printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group"
                " for endpoint: %s Portal Tag %u\n",
                (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
@@ -714,6 +708,25 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
 
        while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)
                cpu_relax();
+       /*
+        * Release any remaining demo-mode generated se_node_acl that have
+        * not been released because of TFO->tpg_check_demo_mode_cache() == 1
+        * in transport_deregister_session().
+        */
+       spin_lock_bh(&se_tpg->acl_node_lock);
+       list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list,
+                       acl_list) {
+               list_del(&nacl->acl_list);
+               se_tpg->num_node_acls--;
+               spin_unlock_bh(&se_tpg->acl_node_lock);
+
+               core_tpg_wait_for_nacl_pr_ref(nacl);
+               core_free_device_list_for_node(nacl, se_tpg);
+               TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, nacl);
+
+               spin_lock_bh(&se_tpg->acl_node_lock);
+       }
+       spin_unlock_bh(&se_tpg->acl_node_lock);
 
        if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
                core_tpg_release_virtual_lun0(se_tpg);
index 28b6292..236e22d 100644 (file)
@@ -379,6 +379,40 @@ void release_se_global(void)
        se_global = NULL;
 }
 
+/* SCSI statistics table index */
+static struct scsi_index_table scsi_index_table;
+
+/*
+ * Initialize the index table for allocating unique row indexes to various mib
+ * tables.
+ */
+void init_scsi_index_table(void)
+{
+       memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
+       spin_lock_init(&scsi_index_table.lock);
+}
+
+/*
+ * Allocate a new row index for the entry type specified
+ */
+u32 scsi_get_new_index(scsi_index_t type)
+{
+       u32 new_index;
+
+       if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
+               printk(KERN_ERR "Invalid index type %d\n", type);
+               return -EINVAL;
+       }
+
+       spin_lock(&scsi_index_table.lock);
+       new_index = ++scsi_index_table.scsi_mib_index[type];
+       if (new_index == 0)
+               new_index = ++scsi_index_table.scsi_mib_index[type];
+       spin_unlock(&scsi_index_table.lock);
+
+       return new_index;
+}
+
 void transport_init_queue_obj(struct se_queue_obj *qobj)
 {
        atomic_set(&qobj->queue_cnt, 0);
@@ -437,7 +471,6 @@ struct se_session *transport_init_session(void)
        }
        INIT_LIST_HEAD(&se_sess->sess_list);
        INIT_LIST_HEAD(&se_sess->sess_acl_list);
-       atomic_set(&se_sess->mib_ref_count, 0);
 
        return se_sess;
 }
@@ -546,12 +579,6 @@ void transport_deregister_session(struct se_session *se_sess)
                transport_free_session(se_sess);
                return;
        }
-       /*
-        * Wait for possible reference in drivers/target/target_core_mib.c:
-        * scsi_att_intr_port_seq_show()
-        */
-       while (atomic_read(&se_sess->mib_ref_count) != 0)
-               cpu_relax();
 
        spin_lock_bh(&se_tpg->session_lock);
        list_del(&se_sess->sess_list);
@@ -574,7 +601,6 @@ void transport_deregister_session(struct se_session *se_sess)
                                spin_unlock_bh(&se_tpg->acl_node_lock);
 
                                core_tpg_wait_for_nacl_pr_ref(se_nacl);
-                               core_tpg_wait_for_mib_ref(se_nacl);
                                core_free_device_list_for_node(se_nacl, se_tpg);
                                TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg,
                                                se_nacl);
@@ -4827,6 +4853,8 @@ static int transport_do_se_mem_map(
 
                return ret;
        }
+
+       BUG_ON(list_empty(se_mem_list));
        /*
         * This is the normal path for all normal non BIDI and BIDI-COMMAND
         * WRITE payloads..  If we need to do BIDI READ passthrough for
@@ -5008,7 +5036,9 @@ transport_map_control_cmd_to_task(struct se_cmd *cmd)
                struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
                u32 se_mem_cnt = 0, task_offset = 0;
 
-               BUG_ON(list_empty(cmd->t_task->t_mem_list));
+               if (!list_empty(T_TASK(cmd)->t_mem_list))
+                       se_mem = list_entry(T_TASK(cmd)->t_mem_list->next,
+                                       struct se_mem, se_list);
 
                ret = transport_do_se_mem_map(dev, task,
                                cmd->t_task->t_mem_list, NULL, se_mem,
index f7a5dba..bf7c687 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig THERMAL
        tristate "Generic Thermal sysfs driver"
-       depends on NET
        help
          Generic Thermal Sysfs driver offers a generic mechanism for
          thermal management. Usually it's made up of one or more thermal
index 7d0e63c..713b7ea 100644 (file)
@@ -62,20 +62,6 @@ static DEFINE_MUTEX(thermal_list_lock);
 
 static unsigned int thermal_event_seqnum;
 
-static struct genl_family thermal_event_genl_family = {
-       .id = GENL_ID_GENERATE,
-       .name = THERMAL_GENL_FAMILY_NAME,
-       .version = THERMAL_GENL_VERSION,
-       .maxattr = THERMAL_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group thermal_event_mcgrp = {
-       .name = THERMAL_GENL_MCAST_GROUP_NAME,
-};
-
-static int genetlink_init(void);
-static void genetlink_exit(void);
-
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
        int err;
@@ -1225,6 +1211,18 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
 EXPORT_SYMBOL(thermal_zone_device_unregister);
 
+#ifdef CONFIG_NET
+static struct genl_family thermal_event_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .name = THERMAL_GENL_FAMILY_NAME,
+       .version = THERMAL_GENL_VERSION,
+       .maxattr = THERMAL_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group thermal_event_mcgrp = {
+       .name = THERMAL_GENL_MCAST_GROUP_NAME,
+};
+
 int generate_netlink_event(u32 orig, enum events event)
 {
        struct sk_buff *skb;
@@ -1301,6 +1299,15 @@ static int genetlink_init(void)
        return result;
 }
 
+static void genetlink_exit(void)
+{
+       genl_unregister_family(&thermal_event_genl_family);
+}
+#else /* !CONFIG_NET */
+static inline int genetlink_init(void) { return 0; }
+static inline void genetlink_exit(void) {}
+#endif /* !CONFIG_NET */
+
 static int __init thermal_init(void)
 {
        int result = 0;
@@ -1316,11 +1323,6 @@ static int __init thermal_init(void)
        return result;
 }
 
-static void genetlink_exit(void)
-{
-       genl_unregister_family(&thermal_event_genl_family);
-}
-
 static void __exit thermal_exit(void)
 {
        class_unregister(&thermal_class);
index c43ef48..3962772 100644 (file)
@@ -9,3 +9,5 @@ obj-$(CONFIG_N_GSM)             += n_gsm.o
 obj-$(CONFIG_R3964)            += n_r3964.o
 
 obj-y                          += vt/
+obj-$(CONFIG_HVC_DRIVER)       += hvc/
+obj-y                          += serial/
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
new file mode 100644 (file)
index 0000000..d79e7e9
--- /dev/null
@@ -0,0 +1,12 @@
+obj-$(CONFIG_HVC_CONSOLE)      += hvc_vio.o hvsi.o
+obj-$(CONFIG_HVC_ISERIES)      += hvc_iseries.o
+obj-$(CONFIG_HVC_RTAS)         += hvc_rtas.o
+obj-$(CONFIG_HVC_TILE)         += hvc_tile.o
+obj-$(CONFIG_HVC_DCC)          += hvc_dcc.o
+obj-$(CONFIG_HVC_BEAT)         += hvc_beat.o
+obj-$(CONFIG_HVC_DRIVER)       += hvc_console.o
+obj-$(CONFIG_HVC_IRQ)          += hvc_irq.o
+obj-$(CONFIG_HVC_XEN)          += hvc_xen.o
+obj-$(CONFIG_HVC_IUCV)         += hvc_iucv.o
+obj-$(CONFIG_HVC_UDBG)         += hvc_udbg.o
+obj-$(CONFIG_HVCS)             += hvcs.o
diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c
new file mode 100644 (file)
index 0000000..5fe4631
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Beat hypervisor console driver
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/char/hvc_rtas.c:
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/hvconsole.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
+extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
+
+struct hvc_struct *hvc_beat_dev = NULL;
+
+/* bug: only one queue is available regardless of vtermno */
+static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
+{
+       static unsigned char q[sizeof(unsigned long) * 2]
+               __attribute__((aligned(sizeof(unsigned long))));
+       static int qlen = 0;
+       u64 got;
+
+again:
+       if (qlen) {
+               if (qlen > cnt) {
+                       memcpy(buf, q, cnt);
+                       qlen -= cnt;
+                       memmove(q + cnt, q, qlen);
+                       return cnt;
+               } else {        /* qlen <= cnt */
+                       int     r;
+
+                       memcpy(buf, q, qlen);
+                       r = qlen;
+                       qlen = 0;
+                       return r;
+               }
+       }
+       if (beat_get_term_char(vtermno, &got,
+               ((u64 *)q), ((u64 *)q) + 1) == 0) {
+               qlen = got;
+               goto again;
+       }
+       return 0;
+}
+
+static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
+{
+       unsigned long kb[2];
+       int rest, nlen;
+
+       for (rest = cnt; rest > 0; rest -= nlen) {
+               nlen = (rest > 16) ? 16 : rest;
+               memcpy(kb, buf, nlen);
+               beat_put_term_char(vtermno, nlen, kb[0], kb[1]);
+               buf += nlen;
+       }
+       return cnt;
+}
+
+static const struct hv_ops hvc_beat_get_put_ops = {
+       .get_chars = hvc_beat_get_chars,
+       .put_chars = hvc_beat_put_chars,
+};
+
+static int hvc_beat_useit = 1;
+
+static int hvc_beat_config(char *p)
+{
+       hvc_beat_useit = simple_strtoul(p, NULL, 0);
+       return 0;
+}
+
+static int __init hvc_beat_console_init(void)
+{
+       if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
+               hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
+       }
+       return 0;
+}
+
+/* temp */
+static int __init hvc_beat_init(void)
+{
+       struct hvc_struct *hp;
+
+       if (!firmware_has_feature(FW_FEATURE_BEAT))
+               return -ENODEV;
+
+       hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+       hvc_beat_dev = hp;
+       return 0;
+}
+
+static void __exit hvc_beat_exit(void)
+{
+       if (hvc_beat_dev)
+               hvc_remove(hvc_beat_dev);
+}
+
+module_init(hvc_beat_init);
+module_exit(hvc_beat_exit);
+
+__setup("hvc_beat=", hvc_beat_config);
+
+console_initcall(hvc_beat_console_init);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
new file mode 100644 (file)
index 0000000..e9cba13
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Additional Author(s):
+ *  Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/kbd_kern.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/major.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+
+#include "hvc_console.h"
+
+#define HVC_MAJOR      229
+#define HVC_MINOR      0
+
+/*
+ * Wait this long per iteration while trying to push buffered data to the
+ * hypervisor before allowing the tty to complete a close operation.
+ */
+#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
+
+/*
+ * These sizes are most efficient for vio, because they are the
+ * native transfer size. We could make them selectable in the
+ * future to better deal with backends that want other buffer sizes.
+ */
+#define N_OUTBUF       16
+#define N_INBUF                16
+
+#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
+
+static struct tty_driver *hvc_driver;
+static struct task_struct *hvc_task;
+
+/* Picks up late kicks after list walk but before schedule() */
+static int hvc_kicked;
+
+static int hvc_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
+#endif
+
+/* dynamic list of hvc_struct instances */
+static LIST_HEAD(hvc_structs);
+
+/*
+ * Protect the list of hvc_struct instances from inserts and removals during
+ * list traversal.
+ */
+static DEFINE_SPINLOCK(hvc_structs_lock);
+
+/*
+ * This value is used to assign a tty->index value to a hvc_struct based
+ * upon order of exposure via hvc_probe(), when we can not match it to
+ * a console candidate registered with hvc_instantiate().
+ */
+static int last_hvc = -1;
+
+/*
+ * Do not call this function with either the hvc_structs_lock or the hvc_struct
+ * lock held.  If successful, this function increments the kref reference
+ * count against the target hvc_struct so it should be released when finished.
+ */
+static struct hvc_struct *hvc_get_by_index(int index)
+{
+       struct hvc_struct *hp;
+       unsigned long flags;
+
+       spin_lock(&hvc_structs_lock);
+
+       list_for_each_entry(hp, &hvc_structs, next) {
+               spin_lock_irqsave(&hp->lock, flags);
+               if (hp->index == index) {
+                       kref_get(&hp->kref);
+                       spin_unlock_irqrestore(&hp->lock, flags);
+                       spin_unlock(&hvc_structs_lock);
+                       return hp;
+               }
+               spin_unlock_irqrestore(&hp->lock, flags);
+       }
+       hp = NULL;
+
+       spin_unlock(&hvc_structs_lock);
+       return hp;
+}
+
+
+/*
+ * Initial console vtermnos for console API usage prior to full console
+ * initialization.  Any vty adapter outside this range will not have usable
+ * console interfaces but can still be used as a tty device.  This has to be
+ * static because kmalloc will not work during early console init.
+ */
+static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
+       {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
+
+/*
+ * Console APIs, NOT TTY.  These APIs are available immediately when
+ * hvc_console_setup() finds adapters.
+ */
+
+static void hvc_console_print(struct console *co, const char *b,
+                             unsigned count)
+{
+       char c[N_OUTBUF] __ALIGNED__;
+       unsigned i = 0, n = 0;
+       int r, donecr = 0, index = co->index;
+
+       /* Console access attempt outside of acceptable console range. */
+       if (index >= MAX_NR_HVC_CONSOLES)
+               return;
+
+       /* This console adapter was removed so it is not usable. */
+       if (vtermnos[index] == -1)
+               return;
+
+       while (count > 0 || i > 0) {
+               if (count > 0 && i < sizeof(c)) {
+                       if (b[n] == '\n' && !donecr) {
+                               c[i++] = '\r';
+                               donecr = 1;
+                       } else {
+                               c[i++] = b[n++];
+                               donecr = 0;
+                               --count;
+                       }
+               } else {
+                       r = cons_ops[index]->put_chars(vtermnos[index], c, i);
+                       if (r <= 0) {
+                               /* throw away chars on error */
+                               i = 0;
+                       } else if (r > 0) {
+                               i -= r;
+                               if (i > 0)
+                                       memmove(c, c+r, i);
+                       }
+               }
+       }
+}
+
+static struct tty_driver *hvc_console_device(struct console *c, int *index)
+{
+       if (vtermnos[c->index] == -1)
+               return NULL;
+
+       *index = c->index;
+       return hvc_driver;
+}
+
+static int __init hvc_console_setup(struct console *co, char *options)
+{
+       if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
+               return -ENODEV;
+
+       if (vtermnos[co->index] == -1)
+               return -ENODEV;
+
+       return 0;
+}
+
+static struct console hvc_console = {
+       .name           = "hvc",
+       .write          = hvc_console_print,
+       .device         = hvc_console_device,
+       .setup          = hvc_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+/*
+ * Early console initialization.  Precedes driver initialization.
+ *
+ * (1) we are first, and the user specified another driver
+ * -- index will remain -1
+ * (2) we are first and the user specified no driver
+ * -- index will be set to 0, then we will fail setup.
+ * (3)  we are first and the user specified our driver
+ * -- index will be set to user specified driver, and we will fail
+ * (4) we are after driver, and this initcall will register us
+ * -- if the user didn't specify a driver then the console will match
+ *
+ * Note that for cases 2 and 3, we will match later when the io driver
+ * calls hvc_instantiate() and call register again.
+ */
+static int __init hvc_console_init(void)
+{
+       register_console(&hvc_console);
+       return 0;
+}
+console_initcall(hvc_console_init);
+
+/* callback when the kboject ref count reaches zero. */
+static void destroy_hvc_struct(struct kref *kref)
+{
+       struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+       unsigned long flags;
+
+       spin_lock(&hvc_structs_lock);
+
+       spin_lock_irqsave(&hp->lock, flags);
+       list_del(&(hp->next));
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       spin_unlock(&hvc_structs_lock);
+
+       kfree(hp);
+}
+
+/*
+ * hvc_instantiate() is an early console discovery method which locates
+ * consoles * prior to the vio subsystem discovering them.  Hotplugged
+ * vty adapters do NOT get an hvc_instantiate() callback since they
+ * appear after early console init.
+ */
+int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
+{
+       struct hvc_struct *hp;
+
+       if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
+               return -1;
+
+       if (vtermnos[index] != -1)
+               return -1;
+
+       /* make sure no no tty has been registered in this index */
+       hp = hvc_get_by_index(index);
+       if (hp) {
+               kref_put(&hp->kref, destroy_hvc_struct);
+               return -1;
+       }
+
+       vtermnos[index] = vtermno;
+       cons_ops[index] = ops;
+
+       /* reserve all indices up to and including this index */
+       if (last_hvc < index)
+               last_hvc = index;
+
+       /* if this index is what the user requested, then register
+        * now (setup won't fail at this point).  It's ok to just
+        * call register again if previously .setup failed.
+        */
+       if (index == hvc_console.index)
+               register_console(&hvc_console);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hvc_instantiate);
+
+/* Wake the sleeping khvcd */
+void hvc_kick(void)
+{
+       hvc_kicked = 1;
+       wake_up_process(hvc_task);
+}
+EXPORT_SYMBOL_GPL(hvc_kick);
+
+static void hvc_unthrottle(struct tty_struct *tty)
+{
+       hvc_kick();
+}
+
+/*
+ * The TTY interface won't be used until after the vio layer has exposed the vty
+ * adapter to the kernel.
+ */
+static int hvc_open(struct tty_struct *tty, struct file * filp)
+{
+       struct hvc_struct *hp;
+       unsigned long flags;
+       int rc = 0;
+
+       /* Auto increments kref reference if found. */
+       if (!(hp = hvc_get_by_index(tty->index)))
+               return -ENODEV;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       /* Check and then increment for fast path open. */
+       if (hp->count++ > 0) {
+               tty_kref_get(tty);
+               spin_unlock_irqrestore(&hp->lock, flags);
+               hvc_kick();
+               return 0;
+       } /* else count == 0 */
+
+       tty->driver_data = hp;
+
+       hp->tty = tty_kref_get(tty);
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (hp->ops->notifier_add)
+               rc = hp->ops->notifier_add(hp, hp->data);
+
+       /*
+        * If the notifier fails we return an error.  The tty layer
+        * will call hvc_close() after a failed open but we don't want to clean
+        * up there so we'll clean up here and clear out the previously set
+        * tty fields and return the kref reference.
+        */
+       if (rc) {
+               spin_lock_irqsave(&hp->lock, flags);
+               hp->tty = NULL;
+               spin_unlock_irqrestore(&hp->lock, flags);
+               tty_kref_put(tty);
+               tty->driver_data = NULL;
+               kref_put(&hp->kref, destroy_hvc_struct);
+               printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
+       }
+       /* Force wakeup of the polling thread */
+       hvc_kick();
+
+       return rc;
+}
+
+static void hvc_close(struct tty_struct *tty, struct file * filp)
+{
+       struct hvc_struct *hp;
+       unsigned long flags;
+
+       if (tty_hung_up_p(filp))
+               return;
+
+       /*
+        * No driver_data means that this close was issued after a failed
+        * hvc_open by the tty layer's release_dev() function and we can just
+        * exit cleanly because the kref reference wasn't made.
+        */
+       if (!tty->driver_data)
+               return;
+
+       hp = tty->driver_data;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       if (--hp->count == 0) {
+               /* We are done with the tty pointer now. */
+               hp->tty = NULL;
+               spin_unlock_irqrestore(&hp->lock, flags);
+
+               if (hp->ops->notifier_del)
+                       hp->ops->notifier_del(hp, hp->data);
+
+               /* cancel pending tty resize work */
+               cancel_work_sync(&hp->tty_resize);
+
+               /*
+                * Chain calls chars_in_buffer() and returns immediately if
+                * there is no buffered data otherwise sleeps on a wait queue
+                * waking periodically to check chars_in_buffer().
+                */
+               tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
+       } else {
+               if (hp->count < 0)
+                       printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
+                               hp->vtermno, hp->count);
+               spin_unlock_irqrestore(&hp->lock, flags);
+       }
+
+       tty_kref_put(tty);
+       kref_put(&hp->kref, destroy_hvc_struct);
+}
+
+static void hvc_hangup(struct tty_struct *tty)
+{
+       struct hvc_struct *hp = tty->driver_data;
+       unsigned long flags;
+       int temp_open_count;
+
+       if (!hp)
+               return;
+
+       /* cancel pending tty resize work */
+       cancel_work_sync(&hp->tty_resize);
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       /*
+        * The N_TTY line discipline has problems such that in a close vs
+        * open->hangup case this can be called after the final close so prevent
+        * that from happening for now.
+        */
+       if (hp->count <= 0) {
+               spin_unlock_irqrestore(&hp->lock, flags);
+               return;
+       }
+
+       temp_open_count = hp->count;
+       hp->count = 0;
+       hp->n_outbuf = 0;
+       hp->tty = NULL;
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (hp->ops->notifier_hangup)
+               hp->ops->notifier_hangup(hp, hp->data);
+
+       while(temp_open_count) {
+               --temp_open_count;
+               tty_kref_put(tty);
+               kref_put(&hp->kref, destroy_hvc_struct);
+       }
+}
+
+/*
+ * Push buffered characters whether they were just recently buffered or waiting
+ * on a blocked hypervisor.  Call this function with hp->lock held.
+ */
+static int hvc_push(struct hvc_struct *hp)
+{
+       int n;
+
+       n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
+       if (n <= 0) {
+               if (n == 0) {
+                       hp->do_wakeup = 1;
+                       return 0;
+               }
+               /* throw away output on error; this happens when
+                  there is no session connected to the vterm. */
+               hp->n_outbuf = 0;
+       } else
+               hp->n_outbuf -= n;
+       if (hp->n_outbuf > 0)
+               memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
+       else
+               hp->do_wakeup = 1;
+
+       return n;
+}
+
+static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       struct hvc_struct *hp = tty->driver_data;
+       unsigned long flags;
+       int rsize, written = 0;
+
+       /* This write was probably executed during a tty close. */
+       if (!hp)
+               return -EPIPE;
+
+       if (hp->count <= 0)
+               return -EIO;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       /* Push pending writes */
+       if (hp->n_outbuf > 0)
+               hvc_push(hp);
+
+       while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
+               if (rsize > count)
+                       rsize = count;
+               memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
+               count -= rsize;
+               buf += rsize;
+               hp->n_outbuf += rsize;
+               written += rsize;
+               hvc_push(hp);
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       /*
+        * Racy, but harmless, kick thread if there is still pending data.
+        */
+       if (hp->n_outbuf)
+               hvc_kick();
+
+       return written;
+}
+
+/**
+ * hvc_set_winsz() - Resize the hvc tty terminal window.
+ * @work:      work structure.
+ *
+ * The routine shall not be called within an atomic context because it
+ * might sleep.
+ *
+ * Locking:    hp->lock
+ */
+static void hvc_set_winsz(struct work_struct *work)
+{
+       struct hvc_struct *hp;
+       unsigned long hvc_flags;
+       struct tty_struct *tty;
+       struct winsize ws;
+
+       hp = container_of(work, struct hvc_struct, tty_resize);
+
+       spin_lock_irqsave(&hp->lock, hvc_flags);
+       if (!hp->tty) {
+               spin_unlock_irqrestore(&hp->lock, hvc_flags);
+               return;
+       }
+       ws  = hp->ws;
+       tty = tty_kref_get(hp->tty);
+       spin_unlock_irqrestore(&hp->lock, hvc_flags);
+
+       tty_do_resize(tty, &ws);
+       tty_kref_put(tty);
+}
+
+/*
+ * This is actually a contract between the driver and the tty layer outlining
+ * how much write room the driver can guarantee will be sent OR BUFFERED.  This
+ * driver MUST honor the return value.
+ */
+static int hvc_write_room(struct tty_struct *tty)
+{
+       struct hvc_struct *hp = tty->driver_data;
+
+       if (!hp)
+               return -1;
+
+       return hp->outbuf_size - hp->n_outbuf;
+}
+
+static int hvc_chars_in_buffer(struct tty_struct *tty)
+{
+       struct hvc_struct *hp = tty->driver_data;
+
+       if (!hp)
+               return 0;
+       return hp->n_outbuf;
+}
+
+/*
+ * timeout will vary between the MIN and MAX values defined here.  By default
+ * and during console activity we will use a default MIN_TIMEOUT of 10.  When
+ * the console is idle, we increase the timeout value on each pass through
+ * msleep until we reach the max.  This may be noticeable as a brief (average
+ * one second) delay on the console before the console responds to input when
+ * there has been no input for some time.
+ */
+#define MIN_TIMEOUT            (10)
+#define MAX_TIMEOUT            (2000)
+static u32 timeout = MIN_TIMEOUT;
+
+#define HVC_POLL_READ  0x00000001
+#define HVC_POLL_WRITE 0x00000002
+
+int hvc_poll(struct hvc_struct *hp)
+{
+       struct tty_struct *tty;
+       int i, n, poll_mask = 0;
+       char buf[N_INBUF] __ALIGNED__;
+       unsigned long flags;
+       int read_total = 0;
+       int written_total = 0;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       /* Push pending writes */
+       if (hp->n_outbuf > 0)
+               written_total = hvc_push(hp);
+
+       /* Reschedule us if still some write pending */
+       if (hp->n_outbuf > 0) {
+               poll_mask |= HVC_POLL_WRITE;
+               /* If hvc_push() was not able to write, sleep a few msecs */
+               timeout = (written_total) ? 0 : MIN_TIMEOUT;
+       }
+
+       /* No tty attached, just skip */
+       tty = tty_kref_get(hp->tty);
+       if (tty == NULL)
+               goto bail;
+
+       /* Now check if we can get data (are we throttled ?) */
+       if (test_bit(TTY_THROTTLED, &tty->flags))
+               goto throttled;
+
+       /* If we aren't notifier driven and aren't throttled, we always
+        * request a reschedule
+        */
+       if (!hp->irq_requested)
+               poll_mask |= HVC_POLL_READ;
+
+       /* Read data if any */
+       for (;;) {
+               int count = tty_buffer_request_room(tty, N_INBUF);
+
+               /* If flip is full, just reschedule a later read */
+               if (count == 0) {
+                       poll_mask |= HVC_POLL_READ;
+                       break;
+               }
+
+               n = hp->ops->get_chars(hp->vtermno, buf, count);
+               if (n <= 0) {
+                       /* Hangup the tty when disconnected from host */
+                       if (n == -EPIPE) {
+                               spin_unlock_irqrestore(&hp->lock, flags);
+                               tty_hangup(tty);
+                               spin_lock_irqsave(&hp->lock, flags);
+                       } else if ( n == -EAGAIN ) {
+                               /*
+                                * Some back-ends can only ensure a certain min
+                                * num of bytes read, which may be > 'count'.
+                                * Let the tty clear the flip buff to make room.
+                                */
+                               poll_mask |= HVC_POLL_READ;
+                       }
+                       break;
+               }
+               for (i = 0; i < n; ++i) {
+#ifdef CONFIG_MAGIC_SYSRQ
+                       if (hp->index == hvc_console.index) {
+                               /* Handle the SysRq Hack */
+                               /* XXX should support a sequence */
+                               if (buf[i] == '\x0f') { /* ^O */
+                                       /* if ^O is pressed again, reset
+                                        * sysrq_pressed and flip ^O char */
+                                       sysrq_pressed = !sysrq_pressed;
+                                       if (sysrq_pressed)
+                                               continue;
+                               } else if (sysrq_pressed) {
+                                       handle_sysrq(buf[i]);
+                                       sysrq_pressed = 0;
+                                       continue;
+                               }
+                       }
+#endif /* CONFIG_MAGIC_SYSRQ */
+                       tty_insert_flip_char(tty, buf[i], 0);
+               }
+
+               read_total += n;
+       }
+ throttled:
+       /* Wakeup write queue if necessary */
+       if (hp->do_wakeup) {
+               hp->do_wakeup = 0;
+               tty_wakeup(tty);
+       }
+ bail:
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (read_total) {
+               /* Activity is occurring, so reset the polling backoff value to
+                  a minimum for performance. */
+               timeout = MIN_TIMEOUT;
+
+               tty_flip_buffer_push(tty);
+       }
+       if (tty)
+               tty_kref_put(tty);
+
+       return poll_mask;
+}
+EXPORT_SYMBOL_GPL(hvc_poll);
+
+/**
+ * __hvc_resize() - Update terminal window size information.
+ * @hp:                HVC console pointer
+ * @ws:                Terminal window size structure
+ *
+ * Stores the specified window size information in the hvc structure of @hp.
+ * The function schedule the tty resize update.
+ *
+ * Locking:    Locking free; the function MUST be called holding hp->lock
+ */
+void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
+{
+       hp->ws = ws;
+       schedule_work(&hp->tty_resize);
+}
+EXPORT_SYMBOL_GPL(__hvc_resize);
+
+/*
+ * This kthread is either polling or interrupt driven.  This is determined by
+ * calling hvc_poll() who determines whether a console adapter support
+ * interrupts.
+ */
+static int khvcd(void *unused)
+{
+       int poll_mask;
+       struct hvc_struct *hp;
+
+       set_freezable();
+       do {
+               poll_mask = 0;
+               hvc_kicked = 0;
+               try_to_freeze();
+               wmb();
+               if (!cpus_are_in_xmon()) {
+                       spin_lock(&hvc_structs_lock);
+                       list_for_each_entry(hp, &hvc_structs, next) {
+                               poll_mask |= hvc_poll(hp);
+                       }
+                       spin_unlock(&hvc_structs_lock);
+               } else
+                       poll_mask |= HVC_POLL_READ;
+               if (hvc_kicked)
+                       continue;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!hvc_kicked) {
+                       if (poll_mask == 0)
+                               schedule();
+                       else {
+                               if (timeout < MAX_TIMEOUT)
+                                       timeout += (timeout >> 6) + 1;
+
+                               msleep_interruptible(timeout);
+                       }
+               }
+               __set_current_state(TASK_RUNNING);
+       } while (!kthread_should_stop());
+
+       return 0;
+}
+
+static const struct tty_operations hvc_ops = {
+       .open = hvc_open,
+       .close = hvc_close,
+       .write = hvc_write,
+       .hangup = hvc_hangup,
+       .unthrottle = hvc_unthrottle,
+       .write_room = hvc_write_room,
+       .chars_in_buffer = hvc_chars_in_buffer,
+};
+
+struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
+                            const struct hv_ops *ops,
+                            int outbuf_size)
+{
+       struct hvc_struct *hp;
+       int i;
+
+       /* We wait until a driver actually comes along */
+       if (!hvc_driver) {
+               int err = hvc_init();
+               if (err)
+                       return ERR_PTR(err);
+       }
+
+       hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
+                       GFP_KERNEL);
+       if (!hp)
+               return ERR_PTR(-ENOMEM);
+
+       hp->vtermno = vtermno;
+       hp->data = data;
+       hp->ops = ops;
+       hp->outbuf_size = outbuf_size;
+       hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
+
+       kref_init(&hp->kref);
+
+       INIT_WORK(&hp->tty_resize, hvc_set_winsz);
+       spin_lock_init(&hp->lock);
+       spin_lock(&hvc_structs_lock);
+
+       /*
+        * find index to use:
+        * see if this vterm id matches one registered for console.
+        */
+       for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
+               if (vtermnos[i] == hp->vtermno &&
+                   cons_ops[i] == hp->ops)
+                       break;
+
+       /* no matching slot, just use a counter */
+       if (i >= MAX_NR_HVC_CONSOLES)
+               i = ++last_hvc;
+
+       hp->index = i;
+
+       list_add_tail(&(hp->next), &hvc_structs);
+       spin_unlock(&hvc_structs_lock);
+
+       return hp;
+}
+EXPORT_SYMBOL_GPL(hvc_alloc);
+
+int hvc_remove(struct hvc_struct *hp)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       tty = tty_kref_get(hp->tty);
+
+       if (hp->index < MAX_NR_HVC_CONSOLES)
+               vtermnos[hp->index] = -1;
+
+       /* Don't whack hp->irq because tty_hangup() will need to free the irq. */
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       /*
+        * We 'put' the instance that was grabbed when the kref instance
+        * was initialized using kref_init().  Let the last holder of this
+        * kref cause it to be removed, which will probably be the tty_vhangup
+        * below.
+        */
+       kref_put(&hp->kref, destroy_hvc_struct);
+
+       /*
+        * This function call will auto chain call hvc_hangup.
+        */
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hvc_remove);
+
+/* Driver initialization: called as soon as someone uses hvc_alloc(). */
+static int hvc_init(void)
+{
+       struct tty_driver *drv;
+       int err;
+
+       /* We need more than hvc_count adapters due to hotplug additions. */
+       drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
+       if (!drv) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       drv->owner = THIS_MODULE;
+       drv->driver_name = "hvc";
+       drv->name = "hvc";
+       drv->major = HVC_MAJOR;
+       drv->minor_start = HVC_MINOR;
+       drv->type = TTY_DRIVER_TYPE_SYSTEM;
+       drv->init_termios = tty_std_termios;
+       drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+       tty_set_operations(drv, &hvc_ops);
+
+       /* Always start the kthread because there can be hotplug vty adapters
+        * added later. */
+       hvc_task = kthread_run(khvcd, NULL, "khvcd");
+       if (IS_ERR(hvc_task)) {
+               printk(KERN_ERR "Couldn't create kthread for console.\n");
+               err = PTR_ERR(hvc_task);
+               goto put_tty;
+       }
+
+       err = tty_register_driver(drv);
+       if (err) {
+               printk(KERN_ERR "Couldn't register hvc console driver\n");
+               goto stop_thread;
+       }
+
+       /*
+        * Make sure tty is fully registered before allowing it to be
+        * found by hvc_console_device.
+        */
+       smp_mb();
+       hvc_driver = drv;
+       return 0;
+
+stop_thread:
+       kthread_stop(hvc_task);
+       hvc_task = NULL;
+put_tty:
+       put_tty_driver(drv);
+out:
+       return err;
+}
+
+/* This isn't particularly necessary due to this being a console driver
+ * but it is nice to be thorough.
+ */
+static void __exit hvc_exit(void)
+{
+       if (hvc_driver) {
+               kthread_stop(hvc_task);
+
+               tty_unregister_driver(hvc_driver);
+               /* return tty_struct instances allocated in hvc_init(). */
+               put_tty_driver(hvc_driver);
+               unregister_console(&hvc_console);
+       }
+}
+module_exit(hvc_exit);
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
new file mode 100644 (file)
index 0000000..54381eb
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * hvc_console.h
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author(s):
+ *     Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * hvc_console header information:
+ *      moved here from arch/powerpc/include/asm/hvconsole.h
+ *      and drivers/char/hvc_console.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef HVC_CONSOLE_H
+#define HVC_CONSOLE_H
+#include <linux/kref.h>
+#include <linux/tty.h>
+#include <linux/spinlock.h>
+
+/*
+ * This is the max number of console adapters that can/will be found as
+ * console devices on first stage console init.  Any number beyond this range
+ * can't be used as a console device but is still a valid tty device.
+ */
+#define MAX_NR_HVC_CONSOLES    16
+
+/*
+ * The Linux TTY code does not support dynamic addition of tty derived devices
+ * so we need to know how many tty devices we might need when space is allocated
+ * for the tty device.  Since this driver supports hotplug of vty adapters we
+ * need to make sure we have enough allocated.
+ */
+#define HVC_ALLOC_TTY_ADAPTERS 8
+
+struct hvc_struct {
+       spinlock_t lock;
+       int index;
+       struct tty_struct *tty;
+       int count;
+       int do_wakeup;
+       char *outbuf;
+       int outbuf_size;
+       int n_outbuf;
+       uint32_t vtermno;
+       const struct hv_ops *ops;
+       int irq_requested;
+       int data;
+       struct winsize ws;
+       struct work_struct tty_resize;
+       struct list_head next;
+       struct kref kref; /* ref count & hvc_struct lifetime */
+};
+
+/* implemented by a low level driver */
+struct hv_ops {
+       int (*get_chars)(uint32_t vtermno, char *buf, int count);
+       int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+
+       /* Callbacks for notification. Called in open, close and hangup */
+       int (*notifier_add)(struct hvc_struct *hp, int irq);
+       void (*notifier_del)(struct hvc_struct *hp, int irq);
+       void (*notifier_hangup)(struct hvc_struct *hp, int irq);
+};
+
+/* Register a vterm and a slot index for use as a console (console_init) */
+extern int hvc_instantiate(uint32_t vtermno, int index,
+                          const struct hv_ops *ops);
+
+/* register a vterm for hvc tty operation (module_init or hotplug add) */
+extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data,
+                                    const struct hv_ops *ops, int outbuf_size);
+/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
+extern int hvc_remove(struct hvc_struct *hp);
+
+/* data available */
+int hvc_poll(struct hvc_struct *hp);
+void hvc_kick(void);
+
+/* Resize hvc tty terminal window */
+extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws);
+
+static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       __hvc_resize(hp, ws);
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+/* default notifier for irq based notification */
+extern int notifier_add_irq(struct hvc_struct *hp, int data);
+extern void notifier_del_irq(struct hvc_struct *hp, int data);
+extern void notifier_hangup_irq(struct hvc_struct *hp, int data);
+
+
+#if defined(CONFIG_XMON) && defined(CONFIG_SMP)
+#include <asm/xmon.h>
+#else
+static inline int cpus_are_in_xmon(void)
+{
+       return 0;
+}
+#endif
+
+#endif // HVC_CONSOLE_H
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
new file mode 100644 (file)
index 0000000..6470f63
--- /dev/null
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+
+#include "hvc_console.h"
+
+/* DCC Status Bits */
+#define DCC_STATUS_RX          (1 << 30)
+#define DCC_STATUS_TX          (1 << 29)
+
+static inline u32 __dcc_getstatus(void)
+{
+       u32 __ret;
+
+       asm("mrc p14, 0, %0, c0, c1, 0  @ read comms ctrl reg"
+               : "=r" (__ret) : : "cc");
+
+       return __ret;
+}
+
+
+#if defined(CONFIG_CPU_V7)
+static inline char __dcc_getchar(void)
+{
+       char __c;
+
+       asm("get_wait:  mrc p14, 0, pc, c0, c1, 0                          \n\
+                       bne get_wait                                       \n\
+                       mrc p14, 0, %0, c0, c5, 0       @ read comms data reg"
+               : "=r" (__c) : : "cc");
+
+       return __c;
+}
+#else
+static inline char __dcc_getchar(void)
+{
+       char __c;
+
+       asm("mrc p14, 0, %0, c0, c5, 0  @ read comms data reg"
+               : "=r" (__c));
+
+       return __c;
+}
+#endif
+
+#if defined(CONFIG_CPU_V7)
+static inline void __dcc_putchar(char c)
+{
+       asm("put_wait:  mrc p14, 0, pc, c0, c1, 0                 \n\
+                       bcs put_wait                              \n\
+                       mcr p14, 0, %0, c0, c5, 0                   "
+       : : "r" (c) : "cc");
+}
+#else
+static inline void __dcc_putchar(char c)
+{
+       asm("mcr p14, 0, %0, c0, c5, 0  @ write a char"
+               : /* no output register */
+               : "r" (c));
+}
+#endif
+
+static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               while (__dcc_getstatus() & DCC_STATUS_TX)
+                       cpu_relax();
+
+               __dcc_putchar((char)(buf[i] & 0xFF));
+       }
+
+       return count;
+}
+
+static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
+{
+       int i;
+
+       for (i = 0; i < count; ++i) {
+               int c = -1;
+
+               if (__dcc_getstatus() & DCC_STATUS_RX)
+                       c = __dcc_getchar();
+               if (c < 0)
+                       break;
+               buf[i] = c;
+       }
+
+       return i;
+}
+
+static const struct hv_ops hvc_dcc_get_put_ops = {
+       .get_chars = hvc_dcc_get_chars,
+       .put_chars = hvc_dcc_put_chars,
+};
+
+static int __init hvc_dcc_console_init(void)
+{
+       hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+       return 0;
+}
+console_initcall(hvc_dcc_console_init);
+
+static int __init hvc_dcc_init(void)
+{
+       hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+       return 0;
+}
+device_initcall(hvc_dcc_init);
diff --git a/drivers/tty/hvc/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c
new file mode 100644 (file)
index 0000000..2623e17
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright IBM Corp. 2001,2008
+ *
+ * This file contains the IRQ specific code for hvc_console
+ *
+ */
+
+#include <linux/interrupt.h>
+
+#include "hvc_console.h"
+
+static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
+{
+       /* if hvc_poll request a repoll, then kick the hvcd thread */
+       if (hvc_poll(dev_instance))
+               hvc_kick();
+       return IRQ_HANDLED;
+}
+
+/*
+ * For IRQ based systems these callbacks can be used
+ */
+int notifier_add_irq(struct hvc_struct *hp, int irq)
+{
+       int rc;
+
+       if (!irq) {
+               hp->irq_requested = 0;
+               return 0;
+       }
+       rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
+                          "hvc_console", hp);
+       if (!rc)
+               hp->irq_requested = 1;
+       return rc;
+}
+
+void notifier_del_irq(struct hvc_struct *hp, int irq)
+{
+       if (!hp->irq_requested)
+               return;
+       free_irq(irq, hp);
+       hp->irq_requested = 0;
+}
+
+void notifier_hangup_irq(struct hvc_struct *hp, int irq)
+{
+       notifier_del_irq(hp, irq);
+}
diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c
new file mode 100644 (file)
index 0000000..21c5495
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * iSeries vio driver interface to hvc_console.c
+ *
+ * This code is based heavily on hvc_vio.c and viocons.c
+ *
+ * Copyright (C) 2006 Stephen Rothwell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/console.h>
+
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+#include <asm/firmware.h>
+#include <asm/iseries/vio.h>
+#include <asm/iseries/hv_call.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_lp_event.h>
+
+#include "hvc_console.h"
+
+#define VTTY_PORTS 10
+
+static DEFINE_SPINLOCK(consolelock);
+static DEFINE_SPINLOCK(consoleloglock);
+
+static const char hvc_driver_name[] = "hvc_console";
+
+#define IN_BUF_SIZE    200
+
+/*
+ * Our port information.
+ */
+static struct port_info {
+       HvLpIndex lp;
+       u64 seq;        /* sequence number of last HV send */
+       u64 ack;        /* last ack from HV */
+       struct hvc_struct *hp;
+       int in_start;
+       int in_end;
+       unsigned char in_buf[IN_BUF_SIZE];
+} port_info[VTTY_PORTS] = {
+       [ 0 ... VTTY_PORTS - 1 ] = {
+               .lp = HvLpIndexInvalid
+       }
+};
+
+#define viochar_is_console(pi) ((pi) == &port_info[0])
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+       {"serial", "IBM,iSeries-vty"},
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static void hvlog(char *fmt, ...)
+{
+       int i;
+       unsigned long flags;
+       va_list args;
+       static char buf[256];
+
+       spin_lock_irqsave(&consoleloglock, flags);
+       va_start(args, fmt);
+       i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
+       va_end(args);
+       buf[i++] = '\r';
+       HvCall_writeLogBuffer(buf, i);
+       spin_unlock_irqrestore(&consoleloglock, flags);
+}
+
+/*
+ * Initialize the common fields in a charLpEvent
+ */
+static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
+{
+       struct HvLpEvent *hev = &viochar->event;
+
+       memset(viochar, 0, sizeof(struct viocharlpevent));
+
+       hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
+               HV_LP_EVENT_INT;
+       hev->xType = HvLpEvent_Type_VirtualIo;
+       hev->xSubtype = viomajorsubtype_chario | viochardata;
+       hev->xSourceLp = HvLpConfig_getLpIndex();
+       hev->xTargetLp = lp;
+       hev->xSizeMinus1 = sizeof(struct viocharlpevent);
+       hev->xSourceInstanceId = viopath_sourceinst(lp);
+       hev->xTargetInstanceId = viopath_targetinst(lp);
+}
+
+static int get_chars(uint32_t vtermno, char *buf, int count)
+{
+       struct port_info *pi;
+       int n = 0;
+       unsigned long flags;
+
+       if (vtermno >= VTTY_PORTS)
+               return -EINVAL;
+       if (count == 0)
+               return 0;
+
+       pi = &port_info[vtermno];
+       spin_lock_irqsave(&consolelock, flags);
+
+       if (pi->in_end == 0)
+               goto done;
+
+       n = pi->in_end - pi->in_start;
+       if (n > count)
+               n = count;
+       memcpy(buf, &pi->in_buf[pi->in_start], n);
+       pi->in_start += n;
+       if (pi->in_start == pi->in_end) {
+               pi->in_start = 0;
+               pi->in_end = 0;
+       }
+done:
+       spin_unlock_irqrestore(&consolelock, flags);
+       return n;
+}
+
+static int put_chars(uint32_t vtermno, const char *buf, int count)
+{
+       struct viocharlpevent *viochar;
+       struct port_info *pi;
+       HvLpEvent_Rc hvrc;
+       unsigned long flags;
+       int sent = 0;
+
+       if (vtermno >= VTTY_PORTS)
+               return -EINVAL;
+
+       pi = &port_info[vtermno];
+
+       spin_lock_irqsave(&consolelock, flags);
+
+       if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
+               HvCall_writeLogBuffer(buf, count);
+               sent = count;
+               goto done;
+       }
+
+       viochar = vio_get_event_buffer(viomajorsubtype_chario);
+       if (viochar == NULL) {
+               hvlog("\n\rviocons: Can't get viochar buffer.");
+               goto done;
+       }
+
+       while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
+               int len;
+
+               len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
+
+               if (viochar_is_console(pi))
+                       HvCall_writeLogBuffer(buf, len);
+
+               init_data_event(viochar, pi->lp);
+
+               viochar->len = len;
+               viochar->event.xCorrelationToken = pi->seq++;
+               viochar->event.xSizeMinus1 =
+                       offsetof(struct viocharlpevent, data) + len;
+
+               memcpy(viochar->data, buf, len);
+
+               hvrc = HvCallEvent_signalLpEvent(&viochar->event);
+               if (hvrc)
+                       hvlog("\n\rerror sending event! return code %d\n\r",
+                               (int)hvrc);
+               sent += len;
+               count -= len;
+               buf += len;
+       }
+
+       vio_free_event_buffer(viomajorsubtype_chario, viochar);
+done:
+       spin_unlock_irqrestore(&consolelock, flags);
+       return sent;
+}
+
+static const struct hv_ops hvc_get_put_ops = {
+       .get_chars = get_chars,
+       .put_chars = put_chars,
+       .notifier_add = notifier_add_irq,
+       .notifier_del = notifier_del_irq,
+       .notifier_hangup = notifier_hangup_irq,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+                       const struct vio_device_id *id)
+{
+       struct hvc_struct *hp;
+       struct port_info *pi;
+
+       /* probed with invalid parameters. */
+       if (!vdev || !id)
+               return -EPERM;
+
+       if (vdev->unit_address >= VTTY_PORTS)
+               return -ENODEV;
+
+       pi = &port_info[vdev->unit_address];
+
+       hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
+                       VIOCHAR_MAX_DATA);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+       pi->hp = hp;
+       dev_set_drvdata(&vdev->dev, pi);
+
+       return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+       struct port_info *pi = dev_get_drvdata(&vdev->dev);
+       struct hvc_struct *hp = pi->hp;
+
+       return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+       .id_table       = hvc_driver_table,
+       .probe          = hvc_vio_probe,
+       .remove         = __devexit_p(hvc_vio_remove),
+       .driver         = {
+               .name   = hvc_driver_name,
+               .owner  = THIS_MODULE,
+       }
+};
+
+static void hvc_open_event(struct HvLpEvent *event)
+{
+       unsigned long flags;
+       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+       u8 port = cevent->virtual_device;
+       struct port_info *pi;
+       int reject = 0;
+
+       if (hvlpevent_is_ack(event)) {
+               if (port >= VTTY_PORTS)
+                       return;
+
+               spin_lock_irqsave(&consolelock, flags);
+
+               pi = &port_info[port];
+               if (event->xRc == HvLpEvent_Rc_Good) {
+                       pi->seq = pi->ack = 0;
+                       /*
+                        * This line allows connections from the primary
+                        * partition but once one is connected from the
+                        * primary partition nothing short of a reboot
+                        * of linux will allow access from the hosting
+                        * partition again without a required iSeries fix.
+                        */
+                       pi->lp = event->xTargetLp;
+               }
+
+               spin_unlock_irqrestore(&consolelock, flags);
+               if (event->xRc != HvLpEvent_Rc_Good)
+                       printk(KERN_WARNING
+                              "hvc: handle_open_event: event->xRc == (%d).\n",
+                              event->xRc);
+
+               if (event->xCorrelationToken != 0) {
+                       atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
+                       atomic_set(aptr, 1);
+               } else
+                       printk(KERN_WARNING
+                              "hvc: weird...got open ack without atomic\n");
+               return;
+       }
+
+       /* This had better require an ack, otherwise complain */
+       if (!hvlpevent_need_ack(event)) {
+               printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
+               return;
+       }
+
+       spin_lock_irqsave(&consolelock, flags);
+
+       /* Make sure this is a good virtual tty */
+       if (port >= VTTY_PORTS) {
+               event->xRc = HvLpEvent_Rc_SubtypeError;
+               cevent->subtype_result_code = viorc_openRejected;
+               /*
+                * Flag state here since we can't printk while holding
+                * the consolelock spinlock.
+                */
+               reject = 1;
+       } else {
+               pi = &port_info[port];
+               if ((pi->lp != HvLpIndexInvalid) &&
+                               (pi->lp != event->xSourceLp)) {
+                       /*
+                        * If this is tty is already connected to a different
+                        * partition, fail.
+                        */
+                       event->xRc = HvLpEvent_Rc_SubtypeError;
+                       cevent->subtype_result_code = viorc_openRejected;
+                       reject = 2;
+               } else {
+                       pi->lp = event->xSourceLp;
+                       event->xRc = HvLpEvent_Rc_Good;
+                       cevent->subtype_result_code = viorc_good;
+                       pi->seq = pi->ack = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&consolelock, flags);
+
+       if (reject == 1)
+               printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
+       else if (reject == 2)
+               printk(KERN_WARNING "hvc: open rejected: console in exclusive "
+                               "use by another partition.\n");
+
+       /* Return the acknowledgement */
+       HvCallEvent_ackLpEvent(event);
+}
+
+/*
+ * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
+ * virtual console should never actually issue a close event to the hypervisor
+ * because the virtual console never goes away.  A close event coming from the
+ * hypervisor simply means that there are no client consoles connected to the
+ * virtual console.
+ */
+static void hvc_close_event(struct HvLpEvent *event)
+{
+       unsigned long flags;
+       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+       u8 port = cevent->virtual_device;
+
+       if (!hvlpevent_is_int(event)) {
+               printk(KERN_WARNING
+                       "hvc: got unexpected close acknowledgement\n");
+               return;
+       }
+
+       if (port >= VTTY_PORTS) {
+               printk(KERN_WARNING
+                       "hvc: close message from invalid virtual device.\n");
+               return;
+       }
+
+       /* For closes, just mark the console partition invalid */
+       spin_lock_irqsave(&consolelock, flags);
+
+       if (port_info[port].lp == event->xSourceLp)
+               port_info[port].lp = HvLpIndexInvalid;
+
+       spin_unlock_irqrestore(&consolelock, flags);
+}
+
+static void hvc_data_event(struct HvLpEvent *event)
+{
+       unsigned long flags;
+       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+       struct port_info *pi;
+       int n;
+       u8 port = cevent->virtual_device;
+
+       if (port >= VTTY_PORTS) {
+               printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
+                               port);
+               return;
+       }
+       if (cevent->len == 0)
+               return;
+
+       /*
+        * Change 05/01/2003 - Ryan Arnold: If a partition other than
+        * the current exclusive partition tries to send us data
+        * events then just drop them on the floor because we don't
+        * want his stinking data.  He isn't authorized to receive
+        * data because he wasn't the first one to get the console,
+        * therefore he shouldn't be allowed to send data either.
+        * This will work without an iSeries fix.
+        */
+       pi = &port_info[port];
+       if (pi->lp != event->xSourceLp)
+               return;
+
+       spin_lock_irqsave(&consolelock, flags);
+
+       n = IN_BUF_SIZE - pi->in_end;
+       if (n > cevent->len)
+               n = cevent->len;
+       if (n > 0) {
+               memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
+               pi->in_end += n;
+       }
+       spin_unlock_irqrestore(&consolelock, flags);
+       if (n == 0)
+               printk(KERN_WARNING "hvc: input buffer overflow\n");
+}
+
+static void hvc_ack_event(struct HvLpEvent *event)
+{
+       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+       unsigned long flags;
+       u8 port = cevent->virtual_device;
+
+       if (port >= VTTY_PORTS) {
+               printk(KERN_WARNING "hvc: data on invalid virtual device\n");
+               return;
+       }
+
+       spin_lock_irqsave(&consolelock, flags);
+       port_info[port].ack = event->xCorrelationToken;
+       spin_unlock_irqrestore(&consolelock, flags);
+}
+
+static void hvc_config_event(struct HvLpEvent *event)
+{
+       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+
+       if (cevent->data[0] == 0x01)
+               printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
+                      cevent->data[1], cevent->data[2],
+                      cevent->data[3], cevent->data[4]);
+       else
+               printk(KERN_WARNING "hvc: unknown config event\n");
+}
+
+static void hvc_handle_event(struct HvLpEvent *event)
+{
+       int charminor;
+
+       if (event == NULL)
+               return;
+
+       charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
+       switch (charminor) {
+       case viocharopen:
+               hvc_open_event(event);
+               break;
+       case viocharclose:
+               hvc_close_event(event);
+               break;
+       case viochardata:
+               hvc_data_event(event);
+               break;
+       case viocharack:
+               hvc_ack_event(event);
+               break;
+       case viocharconfig:
+               hvc_config_event(event);
+               break;
+       default:
+               if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
+                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
+                       HvCallEvent_ackLpEvent(event);
+               }
+       }
+}
+
+static int __init send_open(HvLpIndex remoteLp, void *sem)
+{
+       return HvCallEvent_signalLpEventFast(remoteLp,
+                       HvLpEvent_Type_VirtualIo,
+                       viomajorsubtype_chario | viocharopen,
+                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+                       viopath_sourceinst(remoteLp),
+                       viopath_targetinst(remoteLp),
+                       (u64)(unsigned long)sem, VIOVERSION << 16,
+                       0, 0, 0, 0);
+}
+
+static int __init hvc_vio_init(void)
+{
+       atomic_t wait_flag;
+       int rc;
+
+       if (!firmware_has_feature(FW_FEATURE_ISERIES))
+               return -EIO;
+
+       /* +2 for fudge */
+       rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
+                       viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
+       if (rc)
+               printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
+
+       if (viopath_hostLp == HvLpIndexInvalid)
+               vio_set_hostlp();
+
+       /*
+        * And if the primary is not the same as the hosting LP, open to the
+        * hosting lp
+        */
+       if ((viopath_hostLp != HvLpIndexInvalid) &&
+           (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
+               printk(KERN_INFO "hvc: open path to hosting (%d)\n",
+                               viopath_hostLp);
+               rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
+                               VIOCHAR_WINDOW + 2);    /* +2 for fudge */
+               if (rc)
+                       printk(KERN_WARNING
+                               "error opening to partition %d: %d\n",
+                               viopath_hostLp, rc);
+       }
+
+       if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
+               printk(KERN_WARNING
+                       "hvc: error seting handler for console events!\n");
+
+       /*
+        * First, try to open the console to the hosting lp.
+        * Wait on a semaphore for the response.
+        */
+       atomic_set(&wait_flag, 0);
+       if ((viopath_isactive(viopath_hostLp)) &&
+           (send_open(viopath_hostLp, &wait_flag) == 0)) {
+               printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
+               while (atomic_read(&wait_flag) == 0)
+                       mb();
+               atomic_set(&wait_flag, 0);
+       }
+
+       /*
+        * If we don't have an active console, try the primary
+        */
+       if ((!viopath_isactive(port_info[0].lp)) &&
+           (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
+           (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
+               printk(KERN_INFO "hvc: opening console to primary partition\n");
+               while (atomic_read(&wait_flag) == 0)
+                       mb();
+       }
+
+       /* Register as a vio device to receive callbacks */
+       rc = vio_register_driver(&hvc_vio_driver);
+
+       return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void __exit hvc_vio_exit(void)
+{
+       vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int __init hvc_find_vtys(void)
+{
+       struct device_node *vty;
+       int num_found = 0;
+
+       for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+                       vty = of_find_node_by_name(vty, "vty")) {
+               const uint32_t *vtermno;
+
+               /* We have statically defined space for only a certain number
+                * of console adapters.
+                */
+               if ((num_found >= MAX_NR_HVC_CONSOLES) ||
+                               (num_found >= VTTY_PORTS)) {
+                       of_node_put(vty);
+                       break;
+               }
+
+               vtermno = of_get_property(vty, "reg", NULL);
+               if (!vtermno)
+                       continue;
+
+               if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
+                       continue;
+
+               if (num_found == 0)
+                       add_preferred_console("hvc", 0, NULL);
+               hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+               ++num_found;
+       }
+
+       return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
new file mode 100644 (file)
index 0000000..c3425bb
--- /dev/null
@@ -0,0 +1,1337 @@
+/*
+ * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
+ *
+ * This HVC device driver provides terminal access using
+ * z/VM IUCV communication paths.
+ *
+ * Copyright IBM Corp. 2008, 2009
+ *
+ * Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+#define KMSG_COMPONENT         "hvc_iucv"
+#define pr_fmt(fmt)            KMSG_COMPONENT ": " fmt
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/ebcdic.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mempool.h>
+#include <linux/moduleparam.h>
+#include <linux/tty.h>
+#include <linux/wait.h>
+#include <net/iucv/iucv.h>
+
+#include "hvc_console.h"
+
+
+/* General device driver settings */
+#define HVC_IUCV_MAGIC         0xc9e4c3e5
+#define MAX_HVC_IUCV_LINES     HVC_ALLOC_TTY_ADAPTERS
+#define MEMPOOL_MIN_NR         (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4)
+
+/* IUCV TTY message  */
+#define MSG_VERSION            0x02    /* Message version */
+#define MSG_TYPE_ERROR         0x01    /* Error message */
+#define MSG_TYPE_TERMENV       0x02    /* Terminal environment variable */
+#define MSG_TYPE_TERMIOS       0x04    /* Terminal IO struct update */
+#define MSG_TYPE_WINSIZE       0x08    /* Terminal window size update */
+#define MSG_TYPE_DATA          0x10    /* Terminal data */
+
+struct iucv_tty_msg {
+       u8      version;                /* Message version */
+       u8      type;                   /* Message type */
+#define MSG_MAX_DATALEN                ((u16)(~0))
+       u16     datalen;                /* Payload length */
+       u8      data[];                 /* Payload buffer */
+} __attribute__((packed));
+#define MSG_SIZE(s)            ((s) + offsetof(struct iucv_tty_msg, data))
+
+enum iucv_state_t {
+       IUCV_DISCONN    = 0,
+       IUCV_CONNECTED  = 1,
+       IUCV_SEVERED    = 2,
+};
+
+enum tty_state_t {
+       TTY_CLOSED      = 0,
+       TTY_OPENED      = 1,
+};
+
+struct hvc_iucv_private {
+       struct hvc_struct       *hvc;           /* HVC struct reference */
+       u8                      srv_name[8];    /* IUCV service name (ebcdic) */
+       unsigned char           is_console;     /* Linux console usage flag */
+       enum iucv_state_t       iucv_state;     /* IUCV connection status */
+       enum tty_state_t        tty_state;      /* TTY status */
+       struct iucv_path        *path;          /* IUCV path pointer */
+       spinlock_t              lock;           /* hvc_iucv_private lock */
+#define SNDBUF_SIZE            (PAGE_SIZE)     /* must be < MSG_MAX_DATALEN */
+       void                    *sndbuf;        /* send buffer            */
+       size_t                  sndbuf_len;     /* length of send buffer  */
+#define QUEUE_SNDBUF_DELAY     (HZ / 25)
+       struct delayed_work     sndbuf_work;    /* work: send iucv msg(s) */
+       wait_queue_head_t       sndbuf_waitq;   /* wait for send completion */
+       struct list_head        tty_outqueue;   /* outgoing IUCV messages */
+       struct list_head        tty_inqueue;    /* incoming IUCV messages */
+       struct device           *dev;           /* device structure */
+};
+
+struct iucv_tty_buffer {
+       struct list_head        list;   /* list pointer */
+       struct iucv_message     msg;    /* store an IUCV message */
+       size_t                  offset; /* data buffer offset */
+       struct iucv_tty_msg     *mbuf;  /* buffer to store input/output data */
+};
+
+/* IUCV callback handler */
+static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]);
+static void hvc_iucv_path_severed(struct iucv_path *, u8[16]);
+static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *);
+static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *);
+
+
+/* Kernel module parameter: use one terminal device as default */
+static unsigned long hvc_iucv_devices = 1;
+
+/* Array of allocated hvc iucv tty lines... */
+static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
+#define IUCV_HVC_CON_IDX       (0)
+/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
+#define MAX_VMID_FILTER                (500)
+static size_t hvc_iucv_filter_size;
+static void *hvc_iucv_filter;
+static const char *hvc_iucv_filter_string;
+static DEFINE_RWLOCK(hvc_iucv_filter_lock);
+
+/* Kmem cache and mempool for iucv_tty_buffer elements */
+static struct kmem_cache *hvc_iucv_buffer_cache;
+static mempool_t *hvc_iucv_mempool;
+
+/* IUCV handler callback functions */
+static struct iucv_handler hvc_iucv_handler = {
+       .path_pending  = hvc_iucv_path_pending,
+       .path_severed  = hvc_iucv_path_severed,
+       .message_complete = hvc_iucv_msg_complete,
+       .message_pending  = hvc_iucv_msg_pending,
+};
+
+
+/**
+ * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance.
+ * @num:       The HVC virtual terminal number (vtermno)
+ *
+ * This function returns the struct hvc_iucv_private instance that corresponds
+ * to the HVC virtual terminal number specified as parameter @num.
+ */
+struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
+{
+       if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))
+               return NULL;
+       return hvc_iucv_table[num - HVC_IUCV_MAGIC];
+}
+
+/**
+ * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element.
+ * @size:      Size of the internal buffer used to store data.
+ * @flags:     Memory allocation flags passed to mempool.
+ *
+ * This function allocates a new struct iucv_tty_buffer element and, optionally,
+ * allocates an internal data buffer with the specified size @size.
+ * The internal data buffer is always allocated with GFP_DMA which is
+ * required for receiving and sending data with IUCV.
+ * Note: The total message size arises from the internal buffer size and the
+ *      members of the iucv_tty_msg structure.
+ * The function returns NULL if memory allocation has failed.
+ */
+static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
+{
+       struct iucv_tty_buffer *bufp;
+
+       bufp = mempool_alloc(hvc_iucv_mempool, flags);
+       if (!bufp)
+               return NULL;
+       memset(bufp, 0, sizeof(*bufp));
+
+       if (size > 0) {
+               bufp->msg.length = MSG_SIZE(size);
+               bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA);
+               if (!bufp->mbuf) {
+                       mempool_free(bufp, hvc_iucv_mempool);
+                       return NULL;
+               }
+               bufp->mbuf->version = MSG_VERSION;
+               bufp->mbuf->type    = MSG_TYPE_DATA;
+               bufp->mbuf->datalen = (u16) size;
+       }
+       return bufp;
+}
+
+/**
+ * destroy_tty_buffer() - destroy struct iucv_tty_buffer element.
+ * @bufp:      Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL.
+ */
+static void destroy_tty_buffer(struct iucv_tty_buffer *bufp)
+{
+       kfree(bufp->mbuf);
+       mempool_free(bufp, hvc_iucv_mempool);
+}
+
+/**
+ * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element.
+ * @list:      List containing struct iucv_tty_buffer elements.
+ */
+static void destroy_tty_buffer_list(struct list_head *list)
+{
+       struct iucv_tty_buffer *ent, *next;
+
+       list_for_each_entry_safe(ent, next, list, list) {
+               list_del(&ent->list);
+               destroy_tty_buffer(ent);
+       }
+}
+
+/**
+ * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer.
+ * @priv:              Pointer to struct hvc_iucv_private
+ * @buf:               HVC buffer for writing received terminal data.
+ * @count:             HVC buffer size.
+ * @has_more_data:     Pointer to an int variable.
+ *
+ * The function picks up pending messages from the input queue and receives
+ * the message data that is then written to the specified buffer @buf.
+ * If the buffer size @count is less than the data message size, the
+ * message is kept on the input queue and @has_more_data is set to 1.
+ * If all message data has been written, the message is removed from
+ * the input queue.
+ *
+ * The function returns the number of bytes written to the terminal, zero if
+ * there are no pending data messages available or if there is no established
+ * IUCV path.
+ * If the IUCV path has been severed, then -EPIPE is returned to cause a
+ * hang up (that is issued by the HVC layer).
+ */
+static int hvc_iucv_write(struct hvc_iucv_private *priv,
+                         char *buf, int count, int *has_more_data)
+{
+       struct iucv_tty_buffer *rb;
+       int written;
+       int rc;
+
+       /* immediately return if there is no IUCV connection */
+       if (priv->iucv_state == IUCV_DISCONN)
+               return 0;
+
+       /* if the IUCV path has been severed, return -EPIPE to inform the
+        * HVC layer to hang up the tty device. */
+       if (priv->iucv_state == IUCV_SEVERED)
+               return -EPIPE;
+
+       /* check if there are pending messages */
+       if (list_empty(&priv->tty_inqueue))
+               return 0;
+
+       /* receive an iucv message and flip data to the tty (ldisc) */
+       rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list);
+
+       written = 0;
+       if (!rb->mbuf) { /* message not yet received ... */
+               /* allocate mem to store msg data; if no memory is available
+                * then leave the buffer on the list and re-try later */
+               rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA);
+               if (!rb->mbuf)
+                       return -ENOMEM;
+
+               rc = __iucv_message_receive(priv->path, &rb->msg, 0,
+                                           rb->mbuf, rb->msg.length, NULL);
+               switch (rc) {
+               case 0: /* Successful       */
+                       break;
+               case 2: /* No message found */
+               case 9: /* Message purged   */
+                       break;
+               default:
+                       written = -EIO;
+               }
+               /* remove buffer if an error has occured or received data
+                * is not correct */
+               if (rc || (rb->mbuf->version != MSG_VERSION) ||
+                         (rb->msg.length    != MSG_SIZE(rb->mbuf->datalen)))
+                       goto out_remove_buffer;
+       }
+
+       switch (rb->mbuf->type) {
+       case MSG_TYPE_DATA:
+               written = min_t(int, rb->mbuf->datalen - rb->offset, count);
+               memcpy(buf, rb->mbuf->data + rb->offset, written);
+               if (written < (rb->mbuf->datalen - rb->offset)) {
+                       rb->offset += written;
+                       *has_more_data = 1;
+                       goto out_written;
+               }
+               break;
+
+       case MSG_TYPE_WINSIZE:
+               if (rb->mbuf->datalen != sizeof(struct winsize))
+                       break;
+               /* The caller must ensure that the hvc is locked, which
+                * is the case when called from hvc_iucv_get_chars() */
+               __hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
+               break;
+
+       case MSG_TYPE_ERROR:    /* ignored ... */
+       case MSG_TYPE_TERMENV:  /* ignored ... */
+       case MSG_TYPE_TERMIOS:  /* ignored ... */
+               break;
+       }
+
+out_remove_buffer:
+       list_del(&rb->list);
+       destroy_tty_buffer(rb);
+       *has_more_data = !list_empty(&priv->tty_inqueue);
+
+out_written:
+       return written;
+}
+
+/**
+ * hvc_iucv_get_chars() - HVC get_chars operation.
+ * @vtermno:   HVC virtual terminal number.
+ * @buf:       Pointer to a buffer to store data
+ * @count:     Size of buffer available for writing
+ *
+ * The HVC thread calls this method to read characters from the back-end.
+ * If an IUCV communication path has been established, pending IUCV messages
+ * are received and data is copied into buffer @buf up to @count bytes.
+ *
+ * Locking:    The routine gets called under an irqsave() spinlock; and
+ *             the routine locks the struct hvc_iucv_private->lock to call
+ *             helper functions.
+ */
+static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
+{
+       struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
+       int written;
+       int has_more_data;
+
+       if (count <= 0)
+               return 0;
+
+       if (!priv)
+               return -ENODEV;
+
+       spin_lock(&priv->lock);
+       has_more_data = 0;
+       written = hvc_iucv_write(priv, buf, count, &has_more_data);
+       spin_unlock(&priv->lock);
+
+       /* if there are still messages on the queue... schedule another run */
+       if (has_more_data)
+               hvc_kick();
+
+       return written;
+}
+
+/**
+ * hvc_iucv_queue() - Buffer terminal data for sending.
+ * @priv:      Pointer to struct hvc_iucv_private instance.
+ * @buf:       Buffer containing data to send.
+ * @count:     Size of buffer and amount of data to send.
+ *
+ * The function queues data for sending. To actually send the buffered data,
+ * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY).
+ * The function returns the number of data bytes that has been buffered.
+ *
+ * If the device is not connected, data is ignored and the function returns
+ * @count.
+ * If the buffer is full, the function returns 0.
+ * If an existing IUCV communicaton path has been severed, -EPIPE is returned
+ * (that can be passed to HVC layer to cause a tty hangup).
+ */
+static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf,
+                         int count)
+{
+       size_t len;
+
+       if (priv->iucv_state == IUCV_DISCONN)
+               return count;                   /* ignore data */
+
+       if (priv->iucv_state == IUCV_SEVERED)
+               return -EPIPE;
+
+       len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len);
+       if (!len)
+               return 0;
+
+       memcpy(priv->sndbuf + priv->sndbuf_len, buf, len);
+       priv->sndbuf_len += len;
+
+       if (priv->iucv_state == IUCV_CONNECTED)
+               schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY);
+
+       return len;
+}
+
+/**
+ * hvc_iucv_send() - Send an IUCV message containing terminal data.
+ * @priv:      Pointer to struct hvc_iucv_private instance.
+ *
+ * If an IUCV communication path has been established, the buffered output data
+ * is sent via an IUCV message and the number of bytes sent is returned.
+ * Returns 0 if there is no established IUCV communication path or
+ * -EPIPE if an existing IUCV communicaton path has been severed.
+ */
+static int hvc_iucv_send(struct hvc_iucv_private *priv)
+{
+       struct iucv_tty_buffer *sb;
+       int rc, len;
+
+       if (priv->iucv_state == IUCV_SEVERED)
+               return -EPIPE;
+
+       if (priv->iucv_state == IUCV_DISCONN)
+               return -EIO;
+
+       if (!priv->sndbuf_len)
+               return 0;
+
+       /* allocate internal buffer to store msg data and also compute total
+        * message length */
+       sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC);
+       if (!sb)
+               return -ENOMEM;
+
+       memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len);
+       sb->mbuf->datalen = (u16) priv->sndbuf_len;
+       sb->msg.length = MSG_SIZE(sb->mbuf->datalen);
+
+       list_add_tail(&sb->list, &priv->tty_outqueue);
+
+       rc = __iucv_message_send(priv->path, &sb->msg, 0, 0,
+                                (void *) sb->mbuf, sb->msg.length);
+       if (rc) {
+               /* drop the message here; however we might want to handle
+                * 0x03 (msg limit reached) by trying again... */
+               list_del(&sb->list);
+               destroy_tty_buffer(sb);
+       }
+       len = priv->sndbuf_len;
+       priv->sndbuf_len = 0;
+
+       return len;
+}
+
+/**
+ * hvc_iucv_sndbuf_work() - Send buffered data over IUCV
+ * @work:      Work structure.
+ *
+ * This work queue function sends buffered output data over IUCV and,
+ * if not all buffered data could be sent, reschedules itself.
+ */
+static void hvc_iucv_sndbuf_work(struct work_struct *work)
+{
+       struct hvc_iucv_private *priv;
+
+       priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work);
+       if (!priv)
+               return;
+
+       spin_lock_bh(&priv->lock);
+       hvc_iucv_send(priv);
+       spin_unlock_bh(&priv->lock);
+}
+
+/**
+ * hvc_iucv_put_chars() - HVC put_chars operation.
+ * @vtermno:   HVC virtual terminal number.
+ * @buf:       Pointer to an buffer to read data from
+ * @count:     Size of buffer available for reading
+ *
+ * The HVC thread calls this method to write characters to the back-end.
+ * The function calls hvc_iucv_queue() to queue terminal data for sending.
+ *
+ * Locking:    The method gets called under an irqsave() spinlock; and
+ *             locks struct hvc_iucv_private->lock.
+ */
+static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
+{
+       struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
+       int queued;
+
+       if (count <= 0)
+               return 0;
+
+       if (!priv)
+               return -ENODEV;
+
+       spin_lock(&priv->lock);
+       queued = hvc_iucv_queue(priv, buf, count);
+       spin_unlock(&priv->lock);
+
+       return queued;
+}
+
+/**
+ * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time.
+ * @hp:        Pointer to the HVC device (struct hvc_struct)
+ * @id:        Additional data (originally passed to hvc_alloc): the index of an struct
+ *     hvc_iucv_private instance.
+ *
+ * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private
+ * instance that is derived from @id. Always returns 0.
+ *
+ * Locking:    struct hvc_iucv_private->lock, spin_lock_bh
+ */
+static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id)
+{
+       struct hvc_iucv_private *priv;
+
+       priv = hvc_iucv_get_private(id);
+       if (!priv)
+               return 0;
+
+       spin_lock_bh(&priv->lock);
+       priv->tty_state = TTY_OPENED;
+       spin_unlock_bh(&priv->lock);
+
+       return 0;
+}
+
+/**
+ * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance.
+ * @priv:      Pointer to the struct hvc_iucv_private instance.
+ */
+static void hvc_iucv_cleanup(struct hvc_iucv_private *priv)
+{
+       destroy_tty_buffer_list(&priv->tty_outqueue);
+       destroy_tty_buffer_list(&priv->tty_inqueue);
+
+       priv->tty_state = TTY_CLOSED;
+       priv->iucv_state = IUCV_DISCONN;
+
+       priv->sndbuf_len = 0;
+}
+
+/**
+ * tty_outqueue_empty() - Test if the tty outq is empty
+ * @priv:      Pointer to struct hvc_iucv_private instance.
+ */
+static inline int tty_outqueue_empty(struct hvc_iucv_private *priv)
+{
+       int rc;
+
+       spin_lock_bh(&priv->lock);
+       rc = list_empty(&priv->tty_outqueue);
+       spin_unlock_bh(&priv->lock);
+
+       return rc;
+}
+
+/**
+ * flush_sndbuf_sync() - Flush send buffer and wait for completion
+ * @priv:      Pointer to struct hvc_iucv_private instance.
+ *
+ * The routine cancels a pending sndbuf work, calls hvc_iucv_send()
+ * to flush any buffered terminal output data and waits for completion.
+ */
+static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
+{
+       int sync_wait;
+
+       cancel_delayed_work_sync(&priv->sndbuf_work);
+
+       spin_lock_bh(&priv->lock);
+       hvc_iucv_send(priv);            /* force sending buffered data */
+       sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */
+       spin_unlock_bh(&priv->lock);
+
+       if (sync_wait)
+               wait_event_timeout(priv->sndbuf_waitq,
+                                  tty_outqueue_empty(priv), HZ/10);
+}
+
+/**
+ * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up
+ * @priv:      Pointer to hvc_iucv_private structure
+ *
+ * This routine severs an existing IUCV communication path and hangs
+ * up the underlying HVC terminal device.
+ * The hang-up occurs only if an IUCV communication path is established;
+ * otherwise there is no need to hang up the terminal device.
+ *
+ * The IUCV HVC hang-up is separated into two steps:
+ * 1. After the IUCV path has been severed, the iucv_state is set to
+ *    IUCV_SEVERED.
+ * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the
+ *    IUCV_SEVERED state causes the tty hang-up in the HVC layer.
+ *
+ * If the tty has not yet been opened, clean up the hvc_iucv_private
+ * structure to allow re-connects.
+ * If the tty has been opened, let get_chars() return -EPIPE to signal
+ * the HVC layer to hang up the tty and, if so, wake up the HVC thread
+ * to call get_chars()...
+ *
+ * Special notes on hanging up a HVC terminal instantiated as console:
+ * Hang-up:    1. do_tty_hangup() replaces file ops (= hung_up_tty_fops)
+ *             2. do_tty_hangup() calls tty->ops->close() for console_filp
+ *                     => no hangup notifier is called by HVC (default)
+ *             2. hvc_close() returns because of tty_hung_up_p(filp)
+ *                     => no delete notifier is called!
+ * Finally, the back-end is not being notified, thus, the tty session is
+ * kept active (TTY_OPEN) to be ready for re-connects.
+ *
+ * Locking:    spin_lock(&priv->lock) w/o disabling bh
+ */
+static void hvc_iucv_hangup(struct hvc_iucv_private *priv)
+{
+       struct iucv_path *path;
+
+       path = NULL;
+       spin_lock(&priv->lock);
+       if (priv->iucv_state == IUCV_CONNECTED) {
+               path = priv->path;
+               priv->path = NULL;
+               priv->iucv_state = IUCV_SEVERED;
+               if (priv->tty_state == TTY_CLOSED)
+                       hvc_iucv_cleanup(priv);
+               else
+                       /* console is special (see above) */
+                       if (priv->is_console) {
+                               hvc_iucv_cleanup(priv);
+                               priv->tty_state = TTY_OPENED;
+                       } else
+                               hvc_kick();
+       }
+       spin_unlock(&priv->lock);
+
+       /* finally sever path (outside of priv->lock due to lock ordering) */
+       if (path) {
+               iucv_path_sever(path, NULL);
+               iucv_path_free(path);
+       }
+}
+
+/**
+ * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups.
+ * @hp:                Pointer to the HVC device (struct hvc_struct)
+ * @id:                Additional data (originally passed to hvc_alloc):
+ *             the index of an struct hvc_iucv_private instance.
+ *
+ * This routine notifies the HVC back-end that a tty hangup (carrier loss,
+ * virtual or otherwise) has occured.
+ * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup())
+ * to keep an existing IUCV communication path established.
+ * (Background: vhangup() is called from user space (by getty or login) to
+ *             disable writing to the tty by other applications).
+ * If the tty has been opened and an established IUCV path has been severed
+ * (we caused the tty hangup), the function calls hvc_iucv_cleanup().
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
+{
+       struct hvc_iucv_private *priv;
+
+       priv = hvc_iucv_get_private(id);
+       if (!priv)
+               return;
+
+       flush_sndbuf_sync(priv);
+
+       spin_lock_bh(&priv->lock);
+       /* NOTE: If the hangup was scheduled by ourself (from the iucv
+        *       path_servered callback [IUCV_SEVERED]), we have to clean up
+        *       our structure and to set state to TTY_CLOSED.
+        *       If the tty was hung up otherwise (e.g. vhangup()), then we
+        *       ignore this hangup and keep an established IUCV path open...
+        *       (...the reason is that we are not able to connect back to the
+        *       client if we disconnect on hang up) */
+       priv->tty_state = TTY_CLOSED;
+
+       if (priv->iucv_state == IUCV_SEVERED)
+               hvc_iucv_cleanup(priv);
+       spin_unlock_bh(&priv->lock);
+}
+
+/**
+ * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
+ * @hp:                Pointer to the HVC device (struct hvc_struct)
+ * @id:                Additional data (originally passed to hvc_alloc):
+ *             the index of an struct hvc_iucv_private instance.
+ *
+ * This routine notifies the HVC back-end that the last tty device fd has been
+ * closed.  The function calls hvc_iucv_cleanup() to clean up the struct
+ * hvc_iucv_private instance.
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
+{
+       struct hvc_iucv_private *priv;
+       struct iucv_path        *path;
+
+       priv = hvc_iucv_get_private(id);
+       if (!priv)
+               return;
+
+       flush_sndbuf_sync(priv);
+
+       spin_lock_bh(&priv->lock);
+       path = priv->path;              /* save reference to IUCV path */
+       priv->path = NULL;
+       hvc_iucv_cleanup(priv);
+       spin_unlock_bh(&priv->lock);
+
+       /* sever IUCV path outside of priv->lock due to lock ordering of:
+        * priv->lock <--> iucv_table_lock */
+       if (path) {
+               iucv_path_sever(path, NULL);
+               iucv_path_free(path);
+       }
+}
+
+/**
+ * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID
+ * @ipvmid:    Originating z/VM user ID (right padded with blanks)
+ *
+ * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise
+ * non-zero.
+ */
+static int hvc_iucv_filter_connreq(u8 ipvmid[8])
+{
+       size_t i;
+
+       /* Note: default policy is ACCEPT if no filter is set */
+       if (!hvc_iucv_filter_size)
+               return 0;
+
+       for (i = 0; i < hvc_iucv_filter_size; i++)
+               if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8))
+                       return 0;
+       return 1;
+}
+
+/**
+ * hvc_iucv_path_pending() - IUCV handler to process a connection request.
+ * @path:      Pending path (struct iucv_path)
+ * @ipvmid:    z/VM system identifier of originator
+ * @ipuser:    User specified data for this path
+ *             (AF_IUCV: port/service name and originator port)
+ *
+ * The function uses the @ipuser data to determine if the pending path belongs
+ * to a terminal managed by this device driver.
+ * If the path belongs to this driver, ensure that the terminal is not accessed
+ * multiple times (only one connection to a terminal is allowed).
+ * If the terminal is not yet connected, the pending path is accepted and is
+ * associated to the appropriate struct hvc_iucv_private instance.
+ *
+ * Returns 0 if @path belongs to a terminal managed by the this device driver;
+ * otherwise returns -ENODEV in order to dispatch this path to other handlers.
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static int hvc_iucv_path_pending(struct iucv_path *path,
+                                 u8 ipvmid[8], u8 ipuser[16])
+{
+       struct hvc_iucv_private *priv;
+       u8 nuser_data[16];
+       u8 vm_user_id[9];
+       int i, rc;
+
+       priv = NULL;
+       for (i = 0; i < hvc_iucv_devices; i++)
+               if (hvc_iucv_table[i] &&
+                   (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) {
+                       priv = hvc_iucv_table[i];
+                       break;
+               }
+       if (!priv)
+               return -ENODEV;
+
+       /* Enforce that ipvmid is allowed to connect to us */
+       read_lock(&hvc_iucv_filter_lock);
+       rc = hvc_iucv_filter_connreq(ipvmid);
+       read_unlock(&hvc_iucv_filter_lock);
+       if (rc) {
+               iucv_path_sever(path, ipuser);
+               iucv_path_free(path);
+               memcpy(vm_user_id, ipvmid, 8);
+               vm_user_id[8] = 0;
+               pr_info("A connection request from z/VM user ID %s "
+                       "was refused\n", vm_user_id);
+               return 0;
+       }
+
+       spin_lock(&priv->lock);
+
+       /* If the terminal is already connected or being severed, then sever
+        * this path to enforce that there is only ONE established communication
+        * path per terminal. */
+       if (priv->iucv_state != IUCV_DISCONN) {
+               iucv_path_sever(path, ipuser);
+               iucv_path_free(path);
+               goto out_path_handled;
+       }
+
+       /* accept path */
+       memcpy(nuser_data, ipuser + 8, 8);  /* remote service (for af_iucv) */
+       memcpy(nuser_data + 8, ipuser, 8);  /* local service  (for af_iucv) */
+       path->msglim = 0xffff;              /* IUCV MSGLIMIT */
+       path->flags &= ~IUCV_IPRMDATA;      /* TODO: use IUCV_IPRMDATA */
+       rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv);
+       if (rc) {
+               iucv_path_sever(path, ipuser);
+               iucv_path_free(path);
+               goto out_path_handled;
+       }
+       priv->path = path;
+       priv->iucv_state = IUCV_CONNECTED;
+
+       /* flush buffered output data... */
+       schedule_delayed_work(&priv->sndbuf_work, 5);
+
+out_path_handled:
+       spin_unlock(&priv->lock);
+       return 0;
+}
+
+/**
+ * hvc_iucv_path_severed() - IUCV handler to process a path sever.
+ * @path:      Pending path (struct iucv_path)
+ * @ipuser:    User specified data for this path
+ *             (AF_IUCV: port/service name and originator port)
+ *
+ * This function calls the hvc_iucv_hangup() function for the
+ * respective IUCV HVC terminal.
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
+{
+       struct hvc_iucv_private *priv = path->private;
+
+       hvc_iucv_hangup(priv);
+}
+
+/**
+ * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message.
+ * @path:      Pending path (struct iucv_path)
+ * @msg:       Pointer to the IUCV message
+ *
+ * The function puts an incoming message on the input queue for later
+ * processing (by hvc_iucv_get_chars() / hvc_iucv_write()).
+ * If the tty has not yet been opened, the message is rejected.
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_msg_pending(struct iucv_path *path,
+                                struct iucv_message *msg)
+{
+       struct hvc_iucv_private *priv = path->private;
+       struct iucv_tty_buffer *rb;
+
+       /* reject messages that exceed max size of iucv_tty_msg->datalen */
+       if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) {
+               iucv_message_reject(path, msg);
+               return;
+       }
+
+       spin_lock(&priv->lock);
+
+       /* reject messages if tty has not yet been opened */
+       if (priv->tty_state == TTY_CLOSED) {
+               iucv_message_reject(path, msg);
+               goto unlock_return;
+       }
+
+       /* allocate tty buffer to save iucv msg only */
+       rb = alloc_tty_buffer(0, GFP_ATOMIC);
+       if (!rb) {
+               iucv_message_reject(path, msg);
+               goto unlock_return;     /* -ENOMEM */
+       }
+       rb->msg = *msg;
+
+       list_add_tail(&rb->list, &priv->tty_inqueue);
+
+       hvc_kick();     /* wake up hvc thread */
+
+unlock_return:
+       spin_unlock(&priv->lock);
+}
+
+/**
+ * hvc_iucv_msg_complete() - IUCV handler to process message completion
+ * @path:      Pending path (struct iucv_path)
+ * @msg:       Pointer to the IUCV message
+ *
+ * The function is called upon completion of message delivery to remove the
+ * message from the outqueue. Additional delivery information can be found
+ * msg->audit: rejected messages (0x040000 (IPADRJCT)), and
+ *            purged messages   (0x010000 (IPADPGNR)).
+ *
+ * Locking:    struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_msg_complete(struct iucv_path *path,
+                                 struct iucv_message *msg)
+{
+       struct hvc_iucv_private *priv = path->private;
+       struct iucv_tty_buffer  *ent, *next;
+       LIST_HEAD(list_remove);
+
+       spin_lock(&priv->lock);
+       list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list)
+               if (ent->msg.id == msg->id) {
+                       list_move(&ent->list, &list_remove);
+                       break;
+               }
+       wake_up(&priv->sndbuf_waitq);
+       spin_unlock(&priv->lock);
+       destroy_tty_buffer_list(&list_remove);
+}
+
+/**
+ * hvc_iucv_pm_freeze() - Freeze PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Sever an established IUCV communication path and
+ * trigger a hang-up of the underlying HVC terminal.
+ */
+static int hvc_iucv_pm_freeze(struct device *dev)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+
+       local_bh_disable();
+       hvc_iucv_hangup(priv);
+       local_bh_enable();
+
+       return 0;
+}
+
+/**
+ * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Wake up the HVC thread to trigger hang-up and respective
+ * HVC back-end notifier invocations.
+ */
+static int hvc_iucv_pm_restore_thaw(struct device *dev)
+{
+       hvc_kick();
+       return 0;
+}
+
+
+/* HVC operations */
+static const struct hv_ops hvc_iucv_ops = {
+       .get_chars = hvc_iucv_get_chars,
+       .put_chars = hvc_iucv_put_chars,
+       .notifier_add = hvc_iucv_notifier_add,
+       .notifier_del = hvc_iucv_notifier_del,
+       .notifier_hangup = hvc_iucv_notifier_hangup,
+};
+
+/* Suspend / resume device operations */
+static const struct dev_pm_ops hvc_iucv_pm_ops = {
+       .freeze   = hvc_iucv_pm_freeze,
+       .thaw     = hvc_iucv_pm_restore_thaw,
+       .restore  = hvc_iucv_pm_restore_thaw,
+};
+
+/* IUCV HVC device driver */
+static struct device_driver hvc_iucv_driver = {
+       .name = KMSG_COMPONENT,
+       .bus  = &iucv_bus,
+       .pm   = &hvc_iucv_pm_ops,
+};
+
+/**
+ * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
+ * @id:                        hvc_iucv_table index
+ * @is_console:                Flag if the instance is used as Linux console
+ *
+ * This function allocates a new hvc_iucv_private structure and stores
+ * the instance in hvc_iucv_table at index @id.
+ * Returns 0 on success; otherwise non-zero.
+ */
+static int __init hvc_iucv_alloc(int id, unsigned int is_console)
+{
+       struct hvc_iucv_private *priv;
+       char name[9];
+       int rc;
+
+       priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       spin_lock_init(&priv->lock);
+       INIT_LIST_HEAD(&priv->tty_outqueue);
+       INIT_LIST_HEAD(&priv->tty_inqueue);
+       INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work);
+       init_waitqueue_head(&priv->sndbuf_waitq);
+
+       priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!priv->sndbuf) {
+               kfree(priv);
+               return -ENOMEM;
+       }
+
+       /* set console flag */
+       priv->is_console = is_console;
+
+       /* allocate hvc device */
+       priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /*             PAGE_SIZE */
+                             HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
+       if (IS_ERR(priv->hvc)) {
+               rc = PTR_ERR(priv->hvc);
+               goto out_error_hvc;
+       }
+
+       /* notify HVC thread instead of using polling */
+       priv->hvc->irq_requested = 1;
+
+       /* setup iucv related information */
+       snprintf(name, 9, "lnxhvc%-2d", id);
+       memcpy(priv->srv_name, name, 8);
+       ASCEBC(priv->srv_name, 8);
+
+       /* create and setup device */
+       priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
+       if (!priv->dev) {
+               rc = -ENOMEM;
+               goto out_error_dev;
+       }
+       dev_set_name(priv->dev, "hvc_iucv%d", id);
+       dev_set_drvdata(priv->dev, priv);
+       priv->dev->bus = &iucv_bus;
+       priv->dev->parent = iucv_root;
+       priv->dev->driver = &hvc_iucv_driver;
+       priv->dev->release = (void (*)(struct device *)) kfree;
+       rc = device_register(priv->dev);
+       if (rc) {
+               put_device(priv->dev);
+               goto out_error_dev;
+       }
+
+       hvc_iucv_table[id] = priv;
+       return 0;
+
+out_error_dev:
+       hvc_remove(priv->hvc);
+out_error_hvc:
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
+
+       return rc;
+}
+
+/**
+ * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances
+ */
+static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
+{
+       hvc_remove(priv->hvc);
+       device_unregister(priv->dev);
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
+}
+
+/**
+ * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID
+ * @filter:    String containing a comma-separated list of z/VM user IDs
+ */
+static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
+{
+       const char *nextdelim, *residual;
+       size_t len;
+
+       nextdelim = strchr(filter, ',');
+       if (nextdelim) {
+               len = nextdelim - filter;
+               residual = nextdelim + 1;
+       } else {
+               len = strlen(filter);
+               residual = filter + len;
+       }
+
+       if (len == 0)
+               return ERR_PTR(-EINVAL);
+
+       /* check for '\n' (if called from sysfs) */
+       if (filter[len - 1] == '\n')
+               len--;
+
+       if (len > 8)
+               return ERR_PTR(-EINVAL);
+
+       /* pad with blanks and save upper case version of user ID */
+       memset(dest, ' ', 8);
+       while (len--)
+               dest[len] = toupper(filter[len]);
+       return residual;
+}
+
+/**
+ * hvc_iucv_setup_filter() - Set up z/VM user ID filter
+ * @filter:    String consisting of a comma-separated list of z/VM user IDs
+ *
+ * The function parses the @filter string and creates an array containing
+ * the list of z/VM user ID filter entries.
+ * Return code 0 means success, -EINVAL if the filter is syntactically
+ * incorrect, -ENOMEM if there was not enough memory to allocate the
+ * filter list array, or -ENOSPC if too many z/VM user IDs have been specified.
+ */
+static int hvc_iucv_setup_filter(const char *val)
+{
+       const char *residual;
+       int err;
+       size_t size, count;
+       void *array, *old_filter;
+
+       count = strlen(val);
+       if (count == 0 || (count == 1 && val[0] == '\n')) {
+               size  = 0;
+               array = NULL;
+               goto out_replace_filter;        /* clear filter */
+       }
+
+       /* count user IDs in order to allocate sufficient memory */
+       size = 1;
+       residual = val;
+       while ((residual = strchr(residual, ',')) != NULL) {
+               residual++;
+               size++;
+       }
+
+       /* check if the specified list exceeds the filter limit */
+       if (size > MAX_VMID_FILTER)
+               return -ENOSPC;
+
+       array = kzalloc(size * 8, GFP_KERNEL);
+       if (!array)
+               return -ENOMEM;
+
+       count = size;
+       residual = val;
+       while (*residual && count) {
+               residual = hvc_iucv_parse_filter(residual,
+                                                array + ((size - count) * 8));
+               if (IS_ERR(residual)) {
+                       err = PTR_ERR(residual);
+                       kfree(array);
+                       goto out_err;
+               }
+               count--;
+       }
+
+out_replace_filter:
+       write_lock_bh(&hvc_iucv_filter_lock);
+       old_filter = hvc_iucv_filter;
+       hvc_iucv_filter_size = size;
+       hvc_iucv_filter = array;
+       write_unlock_bh(&hvc_iucv_filter_lock);
+       kfree(old_filter);
+
+       err = 0;
+out_err:
+       return err;
+}
+
+/**
+ * param_set_vmidfilter() - Set z/VM user ID filter parameter
+ * @val:       String consisting of a comma-separated list of z/VM user IDs
+ * @kp:                Kernel parameter pointing to hvc_iucv_filter array
+ *
+ * The function sets up the z/VM user ID filter specified as comma-separated
+ * list of user IDs in @val.
+ * Note: If it is called early in the boot process, @val is stored and
+ *      parsed later in hvc_iucv_init().
+ */
+static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
+{
+       int rc;
+
+       if (!MACHINE_IS_VM || !hvc_iucv_devices)
+               return -ENODEV;
+
+       if (!val)
+               return -EINVAL;
+
+       rc = 0;
+       if (slab_is_available())
+               rc = hvc_iucv_setup_filter(val);
+       else
+               hvc_iucv_filter_string = val;   /* defer... */
+       return rc;
+}
+
+/**
+ * param_get_vmidfilter() - Get z/VM user ID filter
+ * @buffer:    Buffer to store z/VM user ID filter,
+ *             (buffer size assumption PAGE_SIZE)
+ * @kp:                Kernel parameter pointing to the hvc_iucv_filter array
+ *
+ * The function stores the filter as a comma-separated list of z/VM user IDs
+ * in @buffer. Typically, sysfs routines call this function for attr show.
+ */
+static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
+{
+       int rc;
+       size_t index, len;
+       void *start, *end;
+
+       if (!MACHINE_IS_VM || !hvc_iucv_devices)
+               return -ENODEV;
+
+       rc = 0;
+       read_lock_bh(&hvc_iucv_filter_lock);
+       for (index = 0; index < hvc_iucv_filter_size; index++) {
+               start = hvc_iucv_filter + (8 * index);
+               end   = memchr(start, ' ', 8);
+               len   = (end) ? end - start : 8;
+               memcpy(buffer + rc, start, len);
+               rc += len;
+               buffer[rc++] = ',';
+       }
+       read_unlock_bh(&hvc_iucv_filter_lock);
+       if (rc)
+               buffer[--rc] = '\0';    /* replace last comma and update rc */
+       return rc;
+}
+
+#define param_check_vmidfilter(name, p) __param_check(name, p, void)
+
+static struct kernel_param_ops param_ops_vmidfilter = {
+       .set = param_set_vmidfilter,
+       .get = param_get_vmidfilter,
+};
+
+/**
+ * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
+ */
+static int __init hvc_iucv_init(void)
+{
+       int rc;
+       unsigned int i;
+
+       if (!hvc_iucv_devices)
+               return -ENODEV;
+
+       if (!MACHINE_IS_VM) {
+               pr_notice("The z/VM IUCV HVC device driver cannot "
+                          "be used without z/VM\n");
+               rc = -ENODEV;
+               goto out_error;
+       }
+
+       if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) {
+               pr_err("%lu is not a valid value for the hvc_iucv= "
+                       "kernel parameter\n", hvc_iucv_devices);
+               rc = -EINVAL;
+               goto out_error;
+       }
+
+       /* register IUCV HVC device driver */
+       rc = driver_register(&hvc_iucv_driver);
+       if (rc)
+               goto out_error;
+
+       /* parse hvc_iucv_allow string and create z/VM user ID filter list */
+       if (hvc_iucv_filter_string) {
+               rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
+               switch (rc) {
+               case 0:
+                       break;
+               case -ENOMEM:
+                       pr_err("Allocating memory failed with "
+                               "reason code=%d\n", 3);
+                       goto out_error;
+               case -EINVAL:
+                       pr_err("hvc_iucv_allow= does not specify a valid "
+                               "z/VM user ID list\n");
+                       goto out_error;
+               case -ENOSPC:
+                       pr_err("hvc_iucv_allow= specifies too many "
+                               "z/VM user IDs\n");
+                       goto out_error;
+               default:
+                       goto out_error;
+               }
+       }
+
+       hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,
+                                          sizeof(struct iucv_tty_buffer),
+                                          0, 0, NULL);
+       if (!hvc_iucv_buffer_cache) {
+               pr_err("Allocating memory failed with reason code=%d\n", 1);
+               rc = -ENOMEM;
+               goto out_error;
+       }
+
+       hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR,
+                                                   hvc_iucv_buffer_cache);
+       if (!hvc_iucv_mempool) {
+               pr_err("Allocating memory failed with reason code=%d\n", 2);
+               kmem_cache_destroy(hvc_iucv_buffer_cache);
+               rc = -ENOMEM;
+               goto out_error;
+       }
+
+       /* register the first terminal device as console
+        * (must be done before allocating hvc terminal devices) */
+       rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops);
+       if (rc) {
+               pr_err("Registering HVC terminal device as "
+                      "Linux console failed\n");
+               goto out_error_memory;
+       }
+
+       /* allocate hvc_iucv_private structs */
+       for (i = 0; i < hvc_iucv_devices; i++) {
+               rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0);
+               if (rc) {
+                       pr_err("Creating a new HVC terminal device "
+                               "failed with error code=%d\n", rc);
+                       goto out_error_hvc;
+               }
+       }
+
+       /* register IUCV callback handler */
+       rc = iucv_register(&hvc_iucv_handler, 0);
+       if (rc) {
+               pr_err("Registering IUCV handlers failed with error code=%d\n",
+                       rc);
+               goto out_error_hvc;
+       }
+
+       return 0;
+
+out_error_hvc:
+       for (i = 0; i < hvc_iucv_devices; i++)
+               if (hvc_iucv_table[i])
+                       hvc_iucv_destroy(hvc_iucv_table[i]);
+out_error_memory:
+       mempool_destroy(hvc_iucv_mempool);
+       kmem_cache_destroy(hvc_iucv_buffer_cache);
+out_error:
+       if (hvc_iucv_filter)
+               kfree(hvc_iucv_filter);
+       hvc_iucv_devices = 0; /* ensure that we do not provide any device */
+       return rc;
+}
+
+/**
+ * hvc_iucv_config() - Parsing of hvc_iucv=  kernel command line parameter
+ * @val:       Parameter value (numeric)
+ */
+static int __init hvc_iucv_config(char *val)
+{
+        return strict_strtoul(val, 10, &hvc_iucv_devices);
+}
+
+
+device_initcall(hvc_iucv_init);
+__setup("hvc_iucv=", hvc_iucv_config);
+core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640);
diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c
new file mode 100644 (file)
index 0000000..61c4a61
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * IBM RTAS driver interface to hvc_console.c
+ *
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * Author(s): Maximino Augilar <IBM STI Design Center>
+ *         : Ryan S. Arnold <rsa@us.ibm.com>
+ *         : Utz Bacher <utz.bacher@de.ibm.com>
+ *         : David Woodhouse <dwmw2@infradead.org>
+ *
+ *    inspired by drivers/char/hvc_console.c
+ *    written by Anton Blanchard and Paul Mackerras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/irq.h>
+#include <asm/rtas.h>
+#include "hvc_console.h"
+
+#define hvc_rtas_cookie 0x67781e15
+struct hvc_struct *hvc_rtas_dev;
+
+static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
+static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
+
+static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
+               int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i]))
+                       break;
+       }
+
+       return i;
+}
+
+static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
+{
+       int i, c;
+
+       for (i = 0; i < count; i++) {
+               if (rtas_call(rtascons_get_char_token, 0, 2, &c))
+                       break;
+
+               buf[i] = c;
+       }
+
+       return i;
+}
+
+static const struct hv_ops hvc_rtas_get_put_ops = {
+       .get_chars = hvc_rtas_read_console,
+       .put_chars = hvc_rtas_write_console,
+};
+
+static int __init hvc_rtas_init(void)
+{
+       struct hvc_struct *hp;
+
+       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+               rtascons_put_char_token = rtas_token("put-term-char");
+       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+               return -EIO;
+
+       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+               rtascons_get_char_token = rtas_token("get-term-char");
+       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+               return -EIO;
+
+       BUG_ON(hvc_rtas_dev);
+
+       /* Allocate an hvc_struct for the console device we instantiated
+        * earlier.  Save off hp so that we can return it on exit */
+       hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+
+       hvc_rtas_dev = hp;
+
+       return 0;
+}
+module_init(hvc_rtas_init);
+
+/* This will tear down the tty portion of the driver */
+static void __exit hvc_rtas_exit(void)
+{
+       /* Really the fun isn't over until the worker thread breaks down and
+        * the tty cleans up */
+       if (hvc_rtas_dev)
+               hvc_remove(hvc_rtas_dev);
+}
+module_exit(hvc_rtas_exit);
+
+/* This will happen prior to module init.  There is no tty at this time? */
+static int __init hvc_rtas_console_init(void)
+{
+       rtascons_put_char_token = rtas_token("put-term-char");
+       if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+               return -EIO;
+
+       rtascons_get_char_token = rtas_token("get-term-char");
+       if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+               return -EIO;
+
+       hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops);
+       add_preferred_console("hvc", 0, NULL);
+
+       return 0;
+}
+console_initcall(hvc_rtas_console_init);
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
new file mode 100644 (file)
index 0000000..7a84a05
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   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.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Tilera TILE Processor hypervisor console
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <hv/hypervisor.h>
+
+#include "hvc_console.h"
+
+static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
+{
+       return hv_console_write((HV_VirtAddr)buf, count);
+}
+
+static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
+{
+       int i, c;
+
+       for (i = 0; i < count; ++i) {
+               c = hv_console_read_if_ready();
+               if (c < 0)
+                       break;
+               buf[i] = c;
+       }
+
+       return i;
+}
+
+static const struct hv_ops hvc_tile_get_put_ops = {
+       .get_chars = hvc_tile_get_chars,
+       .put_chars = hvc_tile_put_chars,
+};
+
+static int __init hvc_tile_console_init(void)
+{
+       extern void disable_early_printk(void);
+       hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
+       add_preferred_console("hvc", 0, NULL);
+       disable_early_printk();
+       return 0;
+}
+console_initcall(hvc_tile_console_init);
+
+static int __init hvc_tile_init(void)
+{
+       struct hvc_struct *s;
+       s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+       return IS_ERR(s) ? PTR_ERR(s) : 0;
+}
+device_initcall(hvc_tile_init);
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
new file mode 100644 (file)
index 0000000..b0957e6
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * udbg interface to hvc_console.c
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+
+#include <asm/udbg.h>
+
+#include "hvc_console.h"
+
+struct hvc_struct *hvc_udbg_dev;
+
+static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++)
+               udbg_putc(buf[i]);
+
+       return i;
+}
+
+static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
+{
+       int i, c;
+
+       if (!udbg_getc_poll)
+               return 0;
+
+       for (i = 0; i < count; i++) {
+               if ((c = udbg_getc_poll()) == -1)
+                       break;
+               buf[i] = c;
+       }
+
+       return i;
+}
+
+static const struct hv_ops hvc_udbg_ops = {
+       .get_chars = hvc_udbg_get,
+       .put_chars = hvc_udbg_put,
+};
+
+static int __init hvc_udbg_init(void)
+{
+       struct hvc_struct *hp;
+
+       BUG_ON(hvc_udbg_dev);
+
+       hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+
+       hvc_udbg_dev = hp;
+
+       return 0;
+}
+module_init(hvc_udbg_init);
+
+static void __exit hvc_udbg_exit(void)
+{
+       if (hvc_udbg_dev)
+               hvc_remove(hvc_udbg_dev);
+}
+module_exit(hvc_udbg_exit);
+
+static int __init hvc_udbg_console_init(void)
+{
+       hvc_instantiate(0, 0, &hvc_udbg_ops);
+       add_preferred_console("hvc", 0, NULL);
+
+       return 0;
+}
+console_initcall(hvc_udbg_console_init);
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
new file mode 100644 (file)
index 0000000..5e2f52b
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * vio driver interface to hvc_console.c
+ *
+ * This code was moved here to allow the remaing code to be reused as a
+ * generic polling mode with semi-reliable transport driver core to the
+ * console and tty subsystems.
+ *
+ *
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Additional Author(s):
+ *  Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+static const char hvc_driver_name[] = "hvc_console";
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+       {"serial", "hvterm1"},
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
+{
+       unsigned long got;
+       int i;
+
+       /*
+        * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion
+        * so we play safe and avoid the situation where got > count which could
+        * overload the flip buffer.
+        */
+       if (count < SIZE_VIO_GET_CHARS)
+               return -EAGAIN;
+
+       got = hvc_get_chars(vtermno, buf, count);
+
+       /*
+        * Work around a HV bug where it gives us a null
+        * after every \r.  -- paulus
+        */
+       for (i = 1; i < got; ++i) {
+               if (buf[i] == 0 && buf[i-1] == '\r') {
+                       --got;
+                       if (i < got)
+                               memmove(&buf[i], &buf[i+1],
+                                       got - i);
+               }
+       }
+       return got;
+}
+
+static const struct hv_ops hvc_get_put_ops = {
+       .get_chars = filtered_get_chars,
+       .put_chars = hvc_put_chars,
+       .notifier_add = notifier_add_irq,
+       .notifier_del = notifier_del_irq,
+       .notifier_hangup = notifier_hangup_irq,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+                               const struct vio_device_id *id)
+{
+       struct hvc_struct *hp;
+
+       /* probed with invalid parameters. */
+       if (!vdev || !id)
+               return -EPERM;
+
+       hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
+                       MAX_VIO_PUT_CHARS);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+       dev_set_drvdata(&vdev->dev, hp);
+
+       return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+       struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
+
+       return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+       .id_table       = hvc_driver_table,
+       .probe          = hvc_vio_probe,
+       .remove         = __devexit_p(hvc_vio_remove),
+       .driver         = {
+               .name   = hvc_driver_name,
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init hvc_vio_init(void)
+{
+       int rc;
+
+       if (firmware_has_feature(FW_FEATURE_ISERIES))
+               return -EIO;
+
+       /* Register as a vio device to receive callbacks */
+       rc = vio_register_driver(&hvc_vio_driver);
+
+       return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void __exit hvc_vio_exit(void)
+{
+       vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int hvc_find_vtys(void)
+{
+       struct device_node *vty;
+       int num_found = 0;
+
+       for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+                       vty = of_find_node_by_name(vty, "vty")) {
+               const uint32_t *vtermno;
+
+               /* We have statically defined space for only a certain number
+                * of console adapters.
+                */
+               if (num_found >= MAX_NR_HVC_CONSOLES) {
+                       of_node_put(vty);
+                       break;
+               }
+
+               vtermno = of_get_property(vty, "reg", NULL);
+               if (!vtermno)
+                       continue;
+
+               if (of_device_is_compatible(vty, "hvterm1")) {
+                       hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+                       ++num_found;
+               }
+       }
+
+       return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
new file mode 100644 (file)
index 0000000..3740e32
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE   0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static unsigned long console_pfn = ~0ul;
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+       if (console_pfn == ~0ul)
+               return mfn_to_virt(xen_start_info->console.domU.mfn);
+       else
+               return __va(console_pfn << PAGE_SHIFT);
+}
+
+static inline void notify_daemon(void)
+{
+       /* Use evtchn: this is called early, before irq is set up. */
+       notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int __write_console(const char *data, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int sent = 0;
+
+       cons = intf->out_cons;
+       prod = intf->out_prod;
+       mb();                   /* update queue values before going on */
+       BUG_ON((prod - cons) > sizeof(intf->out));
+
+       while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+               intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+       wmb();                  /* write ring before updating pointer */
+       intf->out_prod = prod;
+
+       if (sent)
+               notify_daemon();
+       return sent;
+}
+
+static int domU_write_console(uint32_t vtermno, const char *data, int len)
+{
+       int ret = len;
+
+       /*
+        * Make sure the whole buffer is emitted, polling if
+        * necessary.  We don't ever want to rely on the hvc daemon
+        * because the most interesting console output is when the
+        * kernel is crippled.
+        */
+       while (len) {
+               int sent = __write_console(data, len);
+               
+               data += sent;
+               len -= sent;
+
+               if (unlikely(len))
+                       HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
+       }
+
+       return ret;
+}
+
+static int domU_read_console(uint32_t vtermno, char *buf, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int recv = 0;
+
+       cons = intf->in_cons;
+       prod = intf->in_prod;
+       mb();                   /* get pointers before reading ring */
+       BUG_ON((prod - cons) > sizeof(intf->in));
+
+       while (cons != prod && recv < len)
+               buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+       mb();                   /* read ring before consuming */
+       intf->in_cons = cons;
+
+       notify_daemon();
+       return recv;
+}
+
+static struct hv_ops domU_hvc_ops = {
+       .get_chars = domU_read_console,
+       .put_chars = domU_write_console,
+       .notifier_add = notifier_add_irq,
+       .notifier_del = notifier_del_irq,
+       .notifier_hangup = notifier_hangup_irq,
+};
+
+static int dom0_read_console(uint32_t vtermno, char *buf, int len)
+{
+       return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
+}
+
+/*
+ * Either for a dom0 to write to the system console, or a domU with a
+ * debug version of Xen
+ */
+static int dom0_write_console(uint32_t vtermno, const char *str, int len)
+{
+       int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
+       if (rc < 0)
+               return 0;
+
+       return len;
+}
+
+static struct hv_ops dom0_hvc_ops = {
+       .get_chars = dom0_read_console,
+       .put_chars = dom0_write_console,
+       .notifier_add = notifier_add_irq,
+       .notifier_del = notifier_del_irq,
+       .notifier_hangup = notifier_hangup_irq,
+};
+
+static int __init xen_hvc_init(void)
+{
+       struct hvc_struct *hp;
+       struct hv_ops *ops;
+
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       if (xen_initial_domain()) {
+               ops = &dom0_hvc_ops;
+               xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
+       } else {
+               if (!xen_start_info->console.domU.evtchn)
+                       return -ENODEV;
+
+               ops = &domU_hvc_ops;
+               xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+       }
+       if (xencons_irq < 0)
+               xencons_irq = 0; /* NO_IRQ */
+
+       hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256);
+       if (IS_ERR(hp))
+               return PTR_ERR(hp);
+
+       hvc = hp;
+
+       console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn);
+
+       return 0;
+}
+
+void xen_console_resume(void)
+{
+       if (xencons_irq)
+               rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
+}
+
+static void __exit xen_hvc_fini(void)
+{
+       if (hvc)
+               hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+       struct hv_ops *ops;
+
+       if (!xen_pv_domain())
+               return 0;
+
+       if (xen_initial_domain())
+               ops = &dom0_hvc_ops;
+       else
+               ops = &domU_hvc_ops;
+
+       hvc_instantiate(HVC_COOKIE, 0, ops);
+       return 0;
+}
+
+module_init(xen_hvc_init);
+module_exit(xen_hvc_fini);
+console_initcall(xen_cons_init);
+
+#ifdef CONFIG_EARLY_PRINTK
+static void xenboot_write_console(struct console *console, const char *string,
+                                 unsigned len)
+{
+       unsigned int linelen, off = 0;
+       const char *pos;
+
+       dom0_write_console(0, string, len);
+
+       if (xen_initial_domain())
+               return;
+
+       domU_write_console(0, "(early) ", 8);
+       while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+               linelen = pos-string+off;
+               if (off + linelen > len)
+                       break;
+               domU_write_console(0, string+off, linelen);
+               domU_write_console(0, "\r\n", 2);
+               off += linelen + 1;
+       }
+       if (off < len)
+               domU_write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+       .name           = "xenboot",
+       .write          = xenboot_write_console,
+       .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
+};
+#endif /* CONFIG_EARLY_PRINTK */
+
+void xen_raw_console_write(const char *str)
+{
+       dom0_write_console(0, str, strlen(str));
+}
+
+void xen_raw_printk(const char *fmt, ...)
+{
+       static char buf[512];
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       xen_raw_console_write(buf);
+}
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
new file mode 100644 (file)
index 0000000..bedc6c1
--- /dev/null
@@ -0,0 +1,1604 @@
+/*
+ * IBM eServer Hypervisor Virtual Console Server Device Driver
+ * Copyright (C) 2003, 2004 IBM Corp.
+ *  Ryan S. Arnold (rsa@us.ibm.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Author(s) :  Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This is the device driver for the IBM Hypervisor Virtual Console Server,
+ * "hvcs".  The IBM hvcs provides a tty driver interface to allow Linux
+ * user space applications access to the system consoles of logically
+ * partitioned operating systems, e.g. Linux, running on the same partitioned
+ * Power5 ppc64 system.  Physical hardware consoles per partition are not
+ * practical on this hardware so system consoles are accessed by this driver
+ * using inter-partition firmware interfaces to virtual terminal devices.
+ *
+ * A vty is known to the HMC as a "virtual serial server adapter".  It is a
+ * virtual terminal device that is created by firmware upon partition creation
+ * to act as a partitioned OS's console device.
+ *
+ * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64
+ * Linux system upon their creation by the HMC or their exposure during boot.
+ * The non-user interactive backend of this driver is implemented as a vio
+ * device driver so that it can receive notification of vty-server lifetimes
+ * after it registers with the vio bus to handle vty-server probe and remove
+ * callbacks.
+ *
+ * Many vty-servers can be configured to connect to one vty, but a vty can
+ * only be actively connected to by a single vty-server, in any manner, at one
+ * time.  If the HMC is currently hosting the console for a target Linux
+ * partition; attempts to open the tty device to the partition's console using
+ * the hvcs on any partition will return -EBUSY with every open attempt until
+ * the HMC frees the connection between its vty-server and the desired
+ * partition's vty device.  Conversely, a vty-server may only be connected to
+ * a single vty at one time even though it may have several configured vty
+ * partner possibilities.
+ *
+ * Firmware does not provide notification of vty partner changes to this
+ * driver.  This means that an HMC Super Admin may add or remove partner vtys
+ * from a vty-server's partner list but the changes will not be signaled to
+ * the vty-server.  Firmware only notifies the driver when a vty-server is
+ * added or removed from the system.  To compensate for this deficiency, this
+ * driver implements a sysfs update attribute which provides a method for
+ * rescanning partner information upon a user's request.
+ *
+ * Each vty-server, prior to being exposed to this driver is reference counted
+ * using the 2.6 Linux kernel kref construct.
+ *
+ * For direction on installation and usage of this driver please reference
+ * Documentation/powerpc/hvcs.txt.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/hvconsole.h>
+#include <asm/hvcserver.h>
+#include <asm/uaccess.h>
+#include <asm/vio.h>
+
+/*
+ * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00).
+ * Removed braces around single statements following conditionals.  Removed '=
+ * 0' after static int declarations since these default to zero.  Removed
+ * list_for_each_safe() and replaced with list_for_each_entry() in
+ * hvcs_get_by_index().  The 'safe' version is un-needed now that the driver is
+ * using spinlocks.  Changed spin_lock_irqsave() to spin_lock() when locking
+ * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int
+ * handler.  Initialized hvcs_structs_lock and hvcs_pi_lock to
+ * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init().
+ * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the
+ * list traversals from a deletion.  Removed '= NULL' from pointer declaration
+ * statements since they are initialized NULL by default.  Removed wmb()
+ * instances from hvcs_try_write().  They probably aren't needed with locking in
+ * place.  Added check and cleanup for hvcs_pi_buff = kmalloc() in
+ * hvcs_module_init().  Exposed hvcs_struct.index via a sysfs attribute so that
+ * the coupling between /dev/hvcs* and a vty-server can be automatically
+ * determined.  Moved kobject_put() in hvcs_open outside of the
+ * spin_unlock_irqrestore().
+ *
+ * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it
+ * align with how the tty layer always assigns the lowest index available.  This
+ * change resulted in a list of ints that denotes which indexes are available.
+ * Device additions and removals use the new hvcs_get_index() and
+ * hvcs_return_index() helper functions.  The list is created with
+ * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list().
+ * Without these fixes hotplug vty-server adapter support goes crazy with this
+ * driver if the user removes a vty-server adapter.  Moved free_irq() outside of
+ * the hvcs_final_close() function in order to get it out of the spinlock.
+ * Rearranged hvcs_close().  Cleaned up some printks and did some housekeeping
+ * on the changelog.  Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from
+ * arch/powerepc/include/asm/hvcserver.h
+ *
+ * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to
+ * prevent possible lockup with realtime scheduling as similarily pointed out by
+ * akpm in hvc_console.  Changed resulted in the removal of hvcs_final_close()
+ * to reorder cleanup operations and prevent discarding of pending data during
+ * an hvcs_close().  Removed spinlock protection of hvcs_struct data members in
+ * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed.
+ */
+
+#define HVCS_DRIVER_VERSION "1.3.3"
+
+MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
+MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HVCS_DRIVER_VERSION);
+
+/*
+ * Wait this long per iteration while trying to push buffered data to the
+ * hypervisor before allowing the tty to complete a close operation.
+ */
+#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
+
+/*
+ * Since the Linux TTY code does not currently (2-04-2004) support dynamic
+ * addition of tty derived devices and we shouldn't allocate thousands of
+ * tty_device pointers when the number of vty-server & vty partner connections
+ * will most often be much lower than this, we'll arbitrarily allocate
+ * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we
+ * register the tty_driver. This can be overridden using an insmod parameter.
+ */
+#define HVCS_DEFAULT_SERVER_ADAPTERS   64
+
+/*
+ * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device
+ * nodes as a sanity check.  Theoretically there can be over 1 Billion
+ * vty-server & vty partner connections.
+ */
+#define HVCS_MAX_SERVER_ADAPTERS       1024
+
+/*
+ * We let Linux assign us a major number and we start the minors at zero.  There
+ * is no intuitive mapping between minor number and the target vty-server
+ * adapter except that each new vty-server adapter is always assigned to the
+ * smallest minor number available.
+ */
+#define HVCS_MINOR_START       0
+
+/*
+ * The hcall interface involves putting 8 chars into each of two registers.
+ * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c)
+ * by casting char[16] to long[2].  It would work without __ALIGNED__, but a 
+ * little (tiny) bit slower because an unaligned load is slower than aligned 
+ * load.
+ */
+#define __ALIGNED__    __attribute__((__aligned__(8)))
+
+/*
+ * How much data can firmware send with each hvc_put_chars()?  Maybe this
+ * should be moved into an architecture specific area.
+ */
+#define HVCS_BUFF_LEN  16
+
+/*
+ * This is the maximum amount of data we'll let the user send us (hvcs_write) at
+ * once in a chunk as a sanity check.
+ */
+#define HVCS_MAX_FROM_USER     4096
+
+/*
+ * Be careful when adding flags to this line discipline.  Don't add anything
+ * that will cause echoing or we'll go into recursive loop echoing chars back
+ * and forth with the console drivers.
+ */
+static struct ktermios hvcs_tty_termios = {
+       .c_iflag = IGNBRK | IGNPAR,
+       .c_oflag = OPOST,
+       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+       .c_cc = INIT_C_CC,
+       .c_ispeed = 38400,
+       .c_ospeed = 38400
+};
+
+/*
+ * This value is used to take the place of a command line parameter when the
+ * module is inserted.  It starts as -1 and stays as such if the user doesn't
+ * specify a module insmod parameter.  If they DO specify one then it is set to
+ * the value of the integer passed in.
+ */
+static int hvcs_parm_num_devs = -1;
+module_param(hvcs_parm_num_devs, int, 0);
+
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
+       = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
+
+/* Status of partner info rescan triggered via sysfs. */
+static int hvcs_rescan_status;
+
+static struct tty_driver *hvcs_tty_driver;
+
+/*
+ * In order to be somewhat sane this driver always associates the hvcs_struct
+ * index element with the numerically equal tty->index.  This means that a
+ * hotplugged vty-server adapter will always map to the lowest index valued
+ * device node.  If vty-servers were hotplug removed from the system and then
+ * new ones added the new vty-server may have the largest slot number of all
+ * the vty-server adapters in the partition but it may have the lowest dev node
+ * index of all the adapters due to the hole left by the hotplug removed
+ * adapter.  There are a set of functions provided to get the lowest index for
+ * a new device as well as return the index to the list.  This list is allocated
+ * with a number of elements equal to the number of device nodes requested when
+ * the module was inserted.
+ */
+static int *hvcs_index_list;
+
+/*
+ * How large is the list?  This is kept for traversal since the list is
+ * dynamically created.
+ */
+static int hvcs_index_count;
+
+/*
+ * Used by the khvcsd to pick up I/O operations when the kernel_thread is
+ * already awake but potentially shifted to TASK_INTERRUPTIBLE state.
+ */
+static int hvcs_kicked;
+
+/*
+ * Use by the kthread construct for task operations like waking the sleeping
+ * thread and stopping the kthread.
+ */
+static struct task_struct *hvcs_task;
+
+/*
+ * We allocate this for the use of all of the hvcs_structs when they fetch
+ * partner info.
+ */
+static unsigned long *hvcs_pi_buff;
+
+/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */
+static DEFINE_SPINLOCK(hvcs_pi_lock);
+
+/* One vty-server per hvcs_struct */
+struct hvcs_struct {
+       spinlock_t lock;
+
+       /*
+        * This index identifies this hvcs device as the complement to a
+        * specific tty index.
+        */
+       unsigned int index;
+
+       struct tty_struct *tty;
+       int open_count;
+
+       /*
+        * Used to tell the driver kernel_thread what operations need to take
+        * place upon this hvcs_struct instance.
+        */
+       int todo_mask;
+
+       /*
+        * This buffer is required so that when hvcs_write_room() reports that
+        * it can send HVCS_BUFF_LEN characters that it will buffer the full
+        * HVCS_BUFF_LEN characters if need be.  This is essential for opost
+        * writes since they do not do high level buffering and expect to be
+        * able to send what the driver commits to sending buffering
+        * [e.g. tab to space conversions in n_tty.c opost()].
+        */
+       char buffer[HVCS_BUFF_LEN];
+       int chars_in_buffer;
+
+       /*
+        * Any variable below the kref is valid before a tty is connected and
+        * stays valid after the tty is disconnected.  These shouldn't be
+        * whacked until the koject refcount reaches zero though some entries
+        * may be changed via sysfs initiatives.
+        */
+       struct kref kref; /* ref count & hvcs_struct lifetime */
+       int connected; /* is the vty-server currently connected to a vty? */
+       uint32_t p_unit_address; /* partner unit address */
+       uint32_t p_partition_ID; /* partner partition ID */
+       char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
+       struct list_head next; /* list management */
+       struct vio_dev *vdev;
+};
+
+/* Required to back map a kref to its containing object */
+#define from_kref(k) container_of(k, struct hvcs_struct, kref)
+
+static LIST_HEAD(hvcs_structs);
+static DEFINE_SPINLOCK(hvcs_structs_lock);
+
+static void hvcs_unthrottle(struct tty_struct *tty);
+static void hvcs_throttle(struct tty_struct *tty);
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
+
+static int hvcs_write(struct tty_struct *tty,
+               const unsigned char *buf, int count);
+static int hvcs_write_room(struct tty_struct *tty);
+static int hvcs_chars_in_buffer(struct tty_struct *tty);
+
+static int hvcs_has_pi(struct hvcs_struct *hvcsd);
+static void hvcs_set_pi(struct hvcs_partner_info *pi,
+               struct hvcs_struct *hvcsd);
+static int hvcs_get_pi(struct hvcs_struct *hvcsd);
+static int hvcs_rescan_devices_list(void);
+
+static int hvcs_partner_connect(struct hvcs_struct *hvcsd);
+static void hvcs_partner_free(struct hvcs_struct *hvcsd);
+
+static int hvcs_enable_device(struct hvcs_struct *hvcsd,
+               uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
+
+static int hvcs_open(struct tty_struct *tty, struct file *filp);
+static void hvcs_close(struct tty_struct *tty, struct file *filp);
+static void hvcs_hangup(struct tty_struct * tty);
+
+static int __devinit hvcs_probe(struct vio_dev *dev,
+               const struct vio_device_id *id);
+static int __devexit hvcs_remove(struct vio_dev *dev);
+static int __init hvcs_module_init(void);
+static void __exit hvcs_module_exit(void);
+
+#define HVCS_SCHED_READ        0x00000001
+#define HVCS_QUICK_READ        0x00000002
+#define HVCS_TRY_WRITE 0x00000004
+#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ)
+
+static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
+{
+       return dev_get_drvdata(&viod->dev);
+}
+/* The sysfs interface for the driver and devices */
+
+static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%X\n", hvcsd->p_unit_address);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);
+
+static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);
+
+static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf,
+               size_t count)
+{
+       /*
+        * Don't need this feature at the present time because firmware doesn't
+        * yet support multiple partners.
+        */
+       printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n");
+       return -EPERM;
+}
+
+static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+
+static DEVICE_ATTR(current_vty,
+       S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);
+
+static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf,
+               size_t count)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+
+       /* writing a '0' to this sysfs entry will result in the disconnect. */
+       if (simple_strtol(buf, NULL, 0) != 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       if (hvcsd->open_count > 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               printk(KERN_INFO "HVCS: vterm state unchanged.  "
+                               "The hvcs device node is still in use.\n");
+               return -EPERM;
+       }
+
+       if (hvcsd->connected == 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               printk(KERN_INFO "HVCS: vterm state unchanged. The"
+                               " vty-server is not connected to a vty.\n");
+               return -EPERM;
+       }
+
+       hvcs_partner_free(hvcsd);
+       printk(KERN_INFO "HVCS: Closed vty-server@%X and"
+                       " partner vty@%X:%d connection.\n",
+                       hvcsd->vdev->unit_address,
+                       hvcsd->p_unit_address,
+                       (uint32_t)hvcsd->p_partition_ID);
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return count;
+}
+
+static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%d\n", hvcsd->connected);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR,
+               hvcs_vterm_state_show, hvcs_vterm_state_store);
+
+static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%d\n", hvcsd->index);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+
+static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
+
+static struct attribute *hvcs_attrs[] = {
+       &dev_attr_partner_vtys.attr,
+       &dev_attr_partner_clcs.attr,
+       &dev_attr_current_vty.attr,
+       &dev_attr_vterm_state.attr,
+       &dev_attr_index.attr,
+       NULL,
+};
+
+static struct attribute_group hvcs_attr_group = {
+       .attrs = hvcs_attrs,
+};
+
+static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf)
+{
+       /* A 1 means it is updating, a 0 means it is done updating */
+       return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
+}
+
+static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf,
+               size_t count)
+{
+       if ((simple_strtol(buf, NULL, 0) != 1)
+               && (hvcs_rescan_status != 0))
+               return -EINVAL;
+
+       hvcs_rescan_status = 1;
+       printk(KERN_INFO "HVCS: rescanning partner info for all"
+               " vty-servers.\n");
+       hvcs_rescan_devices_list();
+       hvcs_rescan_status = 0;
+       return count;
+}
+
+static DRIVER_ATTR(rescan,
+       S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store);
+
+static void hvcs_kick(void)
+{
+       hvcs_kicked = 1;
+       wmb();
+       wake_up_process(hvcs_task);
+}
+
+static void hvcs_unthrottle(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       hvcs_kick();
+}
+
+static void hvcs_throttle(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       vio_disable_interrupts(hvcsd->vdev);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+/*
+ * If the device is being removed we don't have to worry about this interrupt
+ * handler taking any further interrupts because they are disabled which means
+ * the hvcs_struct will always be valid in this handler.
+ */
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
+{
+       struct hvcs_struct *hvcsd = dev_instance;
+
+       spin_lock(&hvcsd->lock);
+       vio_disable_interrupts(hvcsd->vdev);
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock(&hvcsd->lock);
+       hvcs_kick();
+
+       return IRQ_HANDLED;
+}
+
+/* This function must be called with the hvcsd->lock held */
+static void hvcs_try_write(struct hvcs_struct *hvcsd)
+{
+       uint32_t unit_address = hvcsd->vdev->unit_address;
+       struct tty_struct *tty = hvcsd->tty;
+       int sent;
+
+       if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
+               /* won't send partial writes */
+               sent = hvc_put_chars(unit_address,
+                               &hvcsd->buffer[0],
+                               hvcsd->chars_in_buffer );
+               if (sent > 0) {
+                       hvcsd->chars_in_buffer = 0;
+                       /* wmb(); */
+                       hvcsd->todo_mask &= ~(HVCS_TRY_WRITE);
+                       /* wmb(); */
+
+                       /*
+                        * We are still obligated to deliver the data to the
+                        * hypervisor even if the tty has been closed because
+                        * we commited to delivering it.  But don't try to wake
+                        * a non-existent tty.
+                        */
+                       if (tty) {
+                               tty_wakeup(tty);
+                       }
+               }
+       }
+}
+
+static int hvcs_io(struct hvcs_struct *hvcsd)
+{
+       uint32_t unit_address;
+       struct tty_struct *tty;
+       char buf[HVCS_BUFF_LEN] __ALIGNED__;
+       unsigned long flags;
+       int got = 0;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       unit_address = hvcsd->vdev->unit_address;
+       tty = hvcsd->tty;
+
+       hvcs_try_write(hvcsd);
+
+       if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
+               hvcsd->todo_mask &= ~(HVCS_READ_MASK);
+               goto bail;
+       } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
+               goto bail;
+
+       /* remove the read masks */
+       hvcsd->todo_mask &= ~(HVCS_READ_MASK);
+
+       if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
+               got = hvc_get_chars(unit_address,
+                               &buf[0],
+                               HVCS_BUFF_LEN);
+               tty_insert_flip_string(tty, buf, got);
+       }
+
+       /* Give the TTY time to process the data we just sent. */
+       if (got)
+               hvcsd->todo_mask |= HVCS_QUICK_READ;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       /* This is synch because tty->low_latency == 1 */
+       if(got)
+               tty_flip_buffer_push(tty);
+
+       if (!got) {
+               /* Do this _after_ the flip_buffer_push */
+               spin_lock_irqsave(&hvcsd->lock, flags);
+               vio_enable_interrupts(hvcsd->vdev);
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+       }
+
+       return hvcsd->todo_mask;
+
+ bail:
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return hvcsd->todo_mask;
+}
+
+static int khvcsd(void *unused)
+{
+       struct hvcs_struct *hvcsd;
+       int hvcs_todo_mask;
+
+       __set_current_state(TASK_RUNNING);
+
+       do {
+               hvcs_todo_mask = 0;
+               hvcs_kicked = 0;
+               wmb();
+
+               spin_lock(&hvcs_structs_lock);
+               list_for_each_entry(hvcsd, &hvcs_structs, next) {
+                       hvcs_todo_mask |= hvcs_io(hvcsd);
+               }
+               spin_unlock(&hvcs_structs_lock);
+
+               /*
+                * If any of the hvcs adapters want to try a write or quick read
+                * don't schedule(), yield a smidgen then execute the hvcs_io
+                * thread again for those that want the write.
+                */
+                if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) {
+                       yield();
+                       continue;
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!hvcs_kicked)
+                       schedule();
+               __set_current_state(TASK_RUNNING);
+       } while (!kthread_should_stop());
+
+       return 0;
+}
+
+static struct vio_device_id hvcs_driver_table[] __devinitdata= {
+       {"serial-server", "hvterm2"},
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
+
+static void hvcs_return_index(int index)
+{
+       /* Paranoia check */
+       if (!hvcs_index_list)
+               return;
+       if (index < 0 || index >= hvcs_index_count)
+               return;
+       if (hvcs_index_list[index] == -1)
+               return;
+       else
+               hvcs_index_list[index] = -1;
+}
+
+/* callback when the kref ref count reaches zero */
+static void destroy_hvcs_struct(struct kref *kref)
+{
+       struct hvcs_struct *hvcsd = from_kref(kref);
+       struct vio_dev *vdev;
+       unsigned long flags;
+
+       spin_lock(&hvcs_structs_lock);
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       /* the list_del poisons the pointers */
+       list_del(&(hvcsd->next));
+
+       if (hvcsd->connected == 1) {
+               hvcs_partner_free(hvcsd);
+               printk(KERN_INFO "HVCS: Closed vty-server@%X and"
+                               " partner vty@%X:%d connection.\n",
+                               hvcsd->vdev->unit_address,
+                               hvcsd->p_unit_address,
+                               (uint32_t)hvcsd->p_partition_ID);
+       }
+       printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n",
+                       hvcsd->vdev->unit_address);
+
+       vdev = hvcsd->vdev;
+       hvcsd->vdev = NULL;
+
+       hvcsd->p_unit_address = 0;
+       hvcsd->p_partition_ID = 0;
+       hvcs_return_index(hvcsd->index);
+       memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       spin_unlock(&hvcs_structs_lock);
+
+       sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
+
+       kfree(hvcsd);
+}
+
+static int hvcs_get_index(void)
+{
+       int i;
+       /* Paranoia check */
+       if (!hvcs_index_list) {
+               printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n");
+               return -EFAULT;
+       }
+       /* Find the numerically lowest first free index. */
+       for(i = 0; i < hvcs_index_count; i++) {
+               if (hvcs_index_list[i] == -1) {
+                       hvcs_index_list[i] = 0;
+                       return i;
+               }
+       }
+       return -1;
+}
+
+static int __devinit hvcs_probe(
+       struct vio_dev *dev,
+       const struct vio_device_id *id)
+{
+       struct hvcs_struct *hvcsd;
+       int index;
+       int retval;
+
+       if (!dev || !id) {
+               printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
+               return -EPERM;
+       }
+
+       /* early to avoid cleanup on failure */
+       index = hvcs_get_index();
+       if (index < 0) {
+               return -EFAULT;
+       }
+
+       hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
+       if (!hvcsd)
+               return -ENODEV;
+
+
+       spin_lock_init(&hvcsd->lock);
+       /* Automatically incs the refcount the first time */
+       kref_init(&hvcsd->kref);
+
+       hvcsd->vdev = dev;
+       dev_set_drvdata(&dev->dev, hvcsd);
+
+       hvcsd->index = index;
+
+       /* hvcsd->index = ++hvcs_struct_count; */
+       hvcsd->chars_in_buffer = 0;
+       hvcsd->todo_mask = 0;
+       hvcsd->connected = 0;
+
+       /*
+        * This will populate the hvcs_struct's partner info fields for the
+        * first time.
+        */
+       if (hvcs_get_pi(hvcsd)) {
+               printk(KERN_ERR "HVCS: Failed to fetch partner"
+                       " info for vty-server@%X on device probe.\n",
+                       hvcsd->vdev->unit_address);
+       }
+
+       /*
+        * If a user app opens a tty that corresponds to this vty-server before
+        * the hvcs_struct has been added to the devices list then the user app
+        * will get -ENODEV.
+        */
+       spin_lock(&hvcs_structs_lock);
+       list_add_tail(&(hvcsd->next), &hvcs_structs);
+       spin_unlock(&hvcs_structs_lock);
+
+       retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
+       if (retval) {
+               printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
+                      hvcsd->vdev->unit_address);
+               return retval;
+       }
+
+       printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
+
+       /*
+        * DON'T enable interrupts here because there is no user to receive the
+        * data.
+        */
+       return 0;
+}
+
+static int __devexit hvcs_remove(struct vio_dev *dev)
+{
+       struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       if (!hvcsd)
+               return -ENODEV;
+
+       /* By this time the vty-server won't be getting any more interrupts */
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       tty = hvcsd->tty;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       /*
+        * Let the last holder of this object cause it to be removed, which
+        * would probably be tty_hangup below.
+        */
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
+
+       /*
+        * The hangup is a scheduled function which will auto chain call
+        * hvcs_hangup.  The tty should always be valid at this time unless a
+        * simultaneous tty close already cleaned up the hvcs_struct.
+        */
+       if (tty)
+               tty_hangup(tty);
+
+       printk(KERN_INFO "HVCS: vty-server@%X removed from the"
+                       " vio bus.\n", dev->unit_address);
+       return 0;
+};
+
+static struct vio_driver hvcs_vio_driver = {
+       .id_table       = hvcs_driver_table,
+       .probe          = hvcs_probe,
+       .remove         = __devexit_p(hvcs_remove),
+       .driver         = {
+               .name   = hvcs_driver_name,
+               .owner  = THIS_MODULE,
+       }
+};
+
+/* Only called from hvcs_get_pi please */
+static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd)
+{
+       int clclength;
+
+       hvcsd->p_unit_address = pi->unit_address;
+       hvcsd->p_partition_ID  = pi->partition_ID;
+       clclength = strlen(&pi->location_code[0]);
+       if (clclength > HVCS_CLC_LENGTH)
+               clclength = HVCS_CLC_LENGTH;
+
+       /* copy the null-term char too */
+       strncpy(&hvcsd->p_location_code[0],
+                       &pi->location_code[0], clclength + 1);
+}
+
+/*
+ * Traverse the list and add the partner info that is found to the hvcs_struct
+ * struct entry. NOTE: At this time I know that partner info will return a
+ * single entry but in the future there may be multiple partner info entries per
+ * vty-server and you'll want to zero out that list and reset it.  If for some
+ * reason you have an old version of this driver but there IS more than one
+ * partner info then hvcsd->p_* will hold the last partner info data from the
+ * firmware query.  A good way to update this code would be to replace the three
+ * partner info fields in hvcs_struct with a list of hvcs_partner_info
+ * instances.
+ *
+ * This function must be called with the hvcsd->lock held.
+ */
+static int hvcs_get_pi(struct hvcs_struct *hvcsd)
+{
+       struct hvcs_partner_info *pi;
+       uint32_t unit_address = hvcsd->vdev->unit_address;
+       struct list_head head;
+       int retval;
+
+       spin_lock(&hvcs_pi_lock);
+       if (!hvcs_pi_buff) {
+               spin_unlock(&hvcs_pi_lock);
+               return -EFAULT;
+       }
+       retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff);
+       spin_unlock(&hvcs_pi_lock);
+       if (retval) {
+               printk(KERN_ERR "HVCS: Failed to fetch partner"
+                       " info for vty-server@%x.\n", unit_address);
+               return retval;
+       }
+
+       /* nixes the values if the partner vty went away */
+       hvcsd->p_unit_address = 0;
+       hvcsd->p_partition_ID = 0;
+
+       list_for_each_entry(pi, &head, node)
+               hvcs_set_pi(pi, hvcsd);
+
+       hvcs_free_partner_info(&head);
+       return 0;
+}
+
+/*
+ * This function is executed by the driver "rescan" sysfs entry.  It shouldn't
+ * be executed elsewhere, in order to prevent deadlock issues.
+ */
+static int hvcs_rescan_devices_list(void)
+{
+       struct hvcs_struct *hvcsd;
+       unsigned long flags;
+
+       spin_lock(&hvcs_structs_lock);
+
+       list_for_each_entry(hvcsd, &hvcs_structs, next) {
+               spin_lock_irqsave(&hvcsd->lock, flags);
+               hvcs_get_pi(hvcsd);
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+       }
+
+       spin_unlock(&hvcs_structs_lock);
+
+       return 0;
+}
+
+/*
+ * Farm this off into its own function because it could be more complex once
+ * multiple partners support is added. This function should be called with
+ * the hvcsd->lock held.
+ */
+static int hvcs_has_pi(struct hvcs_struct *hvcsd)
+{
+       if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID))
+               return 0;
+       return 1;
+}
+
+/*
+ * NOTE: It is possible that the super admin removed a partner vty and then
+ * added a different vty as the new partner.
+ *
+ * This function must be called with the hvcsd->lock held.
+ */
+static int hvcs_partner_connect(struct hvcs_struct *hvcsd)
+{
+       int retval;
+       unsigned int unit_address = hvcsd->vdev->unit_address;
+
+       /*
+        * If there wasn't any pi when the device was added it doesn't meant
+        * there isn't any now.  This driver isn't notified when a new partner
+        * vty is added to a vty-server so we discover changes on our own.
+        * Please see comments in hvcs_register_connection() for justification
+        * of this bizarre code.
+        */
+       retval = hvcs_register_connection(unit_address,
+                       hvcsd->p_partition_ID,
+                       hvcsd->p_unit_address);
+       if (!retval) {
+               hvcsd->connected = 1;
+               return 0;
+       } else if (retval != -EINVAL)
+               return retval;
+
+       /*
+        * As per the spec re-get the pi and try again if -EINVAL after the
+        * first connection attempt.
+        */
+       if (hvcs_get_pi(hvcsd))
+               return -ENOMEM;
+
+       if (!hvcs_has_pi(hvcsd))
+               return -ENODEV;
+
+       retval = hvcs_register_connection(unit_address,
+                       hvcsd->p_partition_ID,
+                       hvcsd->p_unit_address);
+       if (retval != -EINVAL) {
+               hvcsd->connected = 1;
+               return retval;
+       }
+
+       /*
+        * EBUSY is the most likely scenario though the vty could have been
+        * removed or there really could be an hcall error due to the parameter
+        * data but thanks to ambiguous firmware return codes we can't really
+        * tell.
+        */
+       printk(KERN_INFO "HVCS: vty-server or partner"
+                       " vty is busy.  Try again later.\n");
+       return -EBUSY;
+}
+
+/* This function must be called with the hvcsd->lock held */
+static void hvcs_partner_free(struct hvcs_struct *hvcsd)
+{
+       int retval;
+       do {
+               retval = hvcs_free_connection(hvcsd->vdev->unit_address);
+       } while (retval == -EBUSY);
+       hvcsd->connected = 0;
+}
+
+/* This helper function must be called WITHOUT the hvcsd->lock held */
+static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
+               unsigned int irq, struct vio_dev *vdev)
+{
+       unsigned long flags;
+       int rc;
+
+       /*
+        * It is possible that the vty-server was removed between the time that
+        * the conn was registered and now.
+        */
+       if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
+                               IRQF_DISABLED, "ibmhvcs", hvcsd))) {
+               /*
+                * It is possible the vty-server was removed after the irq was
+                * requested but before we have time to enable interrupts.
+                */
+               if (vio_enable_interrupts(vdev) == H_SUCCESS)
+                       return 0;
+               else {
+                       printk(KERN_ERR "HVCS: int enable failed for"
+                                       " vty-server@%X.\n", unit_address);
+                       free_irq(irq, hvcsd);
+               }
+       } else
+               printk(KERN_ERR "HVCS: irq req failed for"
+                               " vty-server@%X.\n", unit_address);
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       hvcs_partner_free(hvcsd);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       return rc;
+
+}
+
+/*
+ * This always increments the kref ref count if the call is successful.
+ * Please remember to dec when you are done with the instance.
+ *
+ * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
+ * calling this function or you will get deadlock.
+ */
+static struct hvcs_struct *hvcs_get_by_index(int index)
+{
+       struct hvcs_struct *hvcsd = NULL;
+       unsigned long flags;
+
+       spin_lock(&hvcs_structs_lock);
+       /* We can immediately discard OOB requests */
+       if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
+               list_for_each_entry(hvcsd, &hvcs_structs, next) {
+                       spin_lock_irqsave(&hvcsd->lock, flags);
+                       if (hvcsd->index == index) {
+                               kref_get(&hvcsd->kref);
+                               spin_unlock_irqrestore(&hvcsd->lock, flags);
+                               spin_unlock(&hvcs_structs_lock);
+                               return hvcsd;
+                       }
+                       spin_unlock_irqrestore(&hvcsd->lock, flags);
+               }
+               hvcsd = NULL;
+       }
+
+       spin_unlock(&hvcs_structs_lock);
+       return hvcsd;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+       struct hvcs_struct *hvcsd;
+       int rc, retval = 0;
+       unsigned long flags;
+       unsigned int irq;
+       struct vio_dev *vdev;
+       unsigned long unit_address;
+
+       if (tty->driver_data)
+               goto fast_open;
+
+       /*
+        * Is there a vty-server that shares the same index?
+        * This function increments the kref index.
+        */
+       if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+               printk(KERN_WARNING "HVCS: open failed, no device associated"
+                               " with tty->index %d.\n", tty->index);
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       if (hvcsd->connected == 0)
+               if ((retval = hvcs_partner_connect(hvcsd)))
+                       goto error_release;
+
+       hvcsd->open_count = 1;
+       hvcsd->tty = tty;
+       tty->driver_data = hvcsd;
+
+       memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
+
+       /*
+        * Save these in the spinlock for the enable operations that need them
+        * outside of the spinlock.
+        */
+       irq = hvcsd->vdev->irq;
+       vdev = hvcsd->vdev;
+       unit_address = hvcsd->vdev->unit_address;
+
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       /*
+        * This must be done outside of the spinlock because it requests irqs
+        * and will grab the spinlock and free the connection if it fails.
+        */
+       if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
+               printk(KERN_WARNING "HVCS: enable device failed.\n");
+               return rc;
+       }
+
+       goto open_success;
+
+fast_open:
+       hvcsd = tty->driver_data;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       kref_get(&hvcsd->kref);
+       hvcsd->open_count++;
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+open_success:
+       hvcs_kick();
+
+       printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
+               hvcsd->vdev->unit_address );
+
+       return 0;
+
+error_release:
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
+
+       printk(KERN_WARNING "HVCS: partner connect failed.\n");
+       return retval;
+}
+
+static void hvcs_close(struct tty_struct *tty, struct file *filp)
+{
+       struct hvcs_struct *hvcsd;
+       unsigned long flags;
+       int irq = NO_IRQ;
+
+       /*
+        * Is someone trying to close the file associated with this device after
+        * we have hung up?  If so tty->driver_data wouldn't be valid.
+        */
+       if (tty_hung_up_p(filp))
+               return;
+
+       /*
+        * No driver_data means that this close was probably issued after a
+        * failed hvcs_open by the tty layer's release_dev() api and we can just
+        * exit cleanly.
+        */
+       if (!tty->driver_data)
+               return;
+
+       hvcsd = tty->driver_data;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       if (--hvcsd->open_count == 0) {
+
+               vio_disable_interrupts(hvcsd->vdev);
+
+               /*
+                * NULL this early so that the kernel_thread doesn't try to
+                * execute any operations on the TTY even though it is obligated
+                * to deliver any pending I/O to the hypervisor.
+                */
+               hvcsd->tty = NULL;
+
+               irq = hvcsd->vdev->irq;
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+               tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
+
+               /*
+                * This line is important because it tells hvcs_open that this
+                * device needs to be re-configured the next time hvcs_open is
+                * called.
+                */
+               tty->driver_data = NULL;
+
+               free_irq(irq, hvcsd);
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
+               return;
+       } else if (hvcsd->open_count < 0) {
+               printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
+                               " is missmanaged.\n",
+               hvcsd->vdev->unit_address, hvcsd->open_count);
+       }
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       kref_put(&hvcsd->kref, destroy_hvcs_struct);
+}
+
+static void hvcs_hangup(struct tty_struct * tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+       int temp_open_count;
+       int irq = NO_IRQ;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       /* Preserve this so that we know how many kref refs to put */
+       temp_open_count = hvcsd->open_count;
+
+       /*
+        * Don't kref put inside the spinlock because the destruction
+        * callback may use the spinlock and it may get called before the
+        * spinlock has been released.
+        */
+       vio_disable_interrupts(hvcsd->vdev);
+
+       hvcsd->todo_mask = 0;
+
+       /* I don't think the tty needs the hvcs_struct pointer after a hangup */
+       hvcsd->tty->driver_data = NULL;
+       hvcsd->tty = NULL;
+
+       hvcsd->open_count = 0;
+
+       /* This will drop any buffered data on the floor which is OK in a hangup
+        * scenario. */
+       memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
+       hvcsd->chars_in_buffer = 0;
+
+       irq = hvcsd->vdev->irq;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       free_irq(irq, hvcsd);
+
+       /*
+        * We need to kref_put() for every open_count we have since the
+        * tty_hangup() function doesn't invoke a close per open connection on a
+        * non-console device.
+        */
+       while(temp_open_count) {
+               --temp_open_count;
+               /*
+                * The final put will trigger destruction of the hvcs_struct.
+                * NOTE:  If this hangup was signaled from user space then the
+                * final put will never happen.
+                */
+               kref_put(&hvcsd->kref, destroy_hvcs_struct);
+       }
+}
+
+/*
+ * NOTE: This is almost always from_user since user level apps interact with the
+ * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by
+ * hvcs_remove (which removes the target device and executes tty_hangup()) that
+ * tty_hangup will allow hvcs_write time to complete execution before it
+ * terminates our device.
+ */
+static int hvcs_write(struct tty_struct *tty,
+               const unsigned char *buf, int count)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned int unit_address;
+       const unsigned char *charbuf;
+       unsigned long flags;
+       int total_sent = 0;
+       int tosend = 0;
+       int result = 0;
+
+       /*
+        * If they don't check the return code off of their open they may
+        * attempt this even if there is no connected device.
+        */
+       if (!hvcsd)
+               return -ENODEV;
+
+       /* Reasonable size to prevent user level flooding */
+       if (count > HVCS_MAX_FROM_USER) {
+               printk(KERN_WARNING "HVCS write: count being truncated to"
+                               " HVCS_MAX_FROM_USER.\n");
+               count = HVCS_MAX_FROM_USER;
+       }
+
+       charbuf = buf;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       /*
+        * Somehow an open succedded but the device was removed or the
+        * connection terminated between the vty-server and partner vty during
+        * the middle of a write operation?  This is a crummy place to do this
+        * but we want to keep it all in the spinlock.
+        */
+       if (hvcsd->open_count <= 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               return -ENODEV;
+       }
+
+       unit_address = hvcsd->vdev->unit_address;
+
+       while (count > 0) {
+               tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer));
+               /*
+                * No more space, this probably means that the last call to
+                * hvcs_write() didn't succeed and the buffer was filled up.
+                */
+               if (!tosend)
+                       break;
+
+               memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer],
+                               &charbuf[total_sent],
+                               tosend);
+
+               hvcsd->chars_in_buffer += tosend;
+
+               result = 0;
+
+               /*
+                * If this is true then we don't want to try writing to the
+                * hypervisor because that is the kernel_threads job now.  We'll
+                * just add to the buffer.
+                */
+               if (!(hvcsd->todo_mask & HVCS_TRY_WRITE))
+                       /* won't send partial writes */
+                       result = hvc_put_chars(unit_address,
+                                       &hvcsd->buffer[0],
+                                       hvcsd->chars_in_buffer);
+
+               /*
+                * Since we know we have enough room in hvcsd->buffer for
+                * tosend we record that it was sent regardless of whether the
+                * hypervisor actually took it because we have it buffered.
+                */
+               total_sent+=tosend;
+               count-=tosend;
+               if (result == 0) {
+                       hvcsd->todo_mask |= HVCS_TRY_WRITE;
+                       hvcs_kick();
+                       break;
+               }
+
+               hvcsd->chars_in_buffer = 0;
+               /*
+                * Test after the chars_in_buffer reset otherwise this could
+                * deadlock our writes if hvc_put_chars fails.
+                */
+               if (result < 0)
+                       break;
+       }
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       if (result == -1)
+               return -EIO;
+       else
+               return total_sent;
+}
+
+/*
+ * This is really asking how much can we guarentee that we can send or that we
+ * absolutely WILL BUFFER if we can't send it.  This driver MUST honor the
+ * return value, hence the reason for hvcs_struct buffering.
+ */
+static int hvcs_write_room(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+
+       if (!hvcsd || hvcsd->open_count <= 0)
+               return 0;
+
+       return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
+}
+
+static int hvcs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+
+       return hvcsd->chars_in_buffer;
+}
+
+static const struct tty_operations hvcs_ops = {
+       .open = hvcs_open,
+       .close = hvcs_close,
+       .hangup = hvcs_hangup,
+       .write = hvcs_write,
+       .write_room = hvcs_write_room,
+       .chars_in_buffer = hvcs_chars_in_buffer,
+       .unthrottle = hvcs_unthrottle,
+       .throttle = hvcs_throttle,
+};
+
+static int hvcs_alloc_index_list(int n)
+{
+       int i;
+
+       hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
+       if (!hvcs_index_list)
+               return -ENOMEM;
+       hvcs_index_count = n;
+       for (i = 0; i < hvcs_index_count; i++)
+               hvcs_index_list[i] = -1;
+       return 0;
+}
+
+static void hvcs_free_index_list(void)
+{
+       /* Paranoia check to be thorough. */
+       kfree(hvcs_index_list);
+       hvcs_index_list = NULL;
+       hvcs_index_count = 0;
+}
+
+static int __init hvcs_module_init(void)
+{
+       int rc;
+       int num_ttys_to_alloc;
+
+       printk(KERN_INFO "Initializing %s\n", hvcs_driver_string);
+
+       /* Has the user specified an overload with an insmod param? */
+       if (hvcs_parm_num_devs <= 0 ||
+               (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) {
+               num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS;
+       } else
+               num_ttys_to_alloc = hvcs_parm_num_devs;
+
+       hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
+       if (!hvcs_tty_driver)
+               return -ENOMEM;
+
+       if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
+               rc = -ENOMEM;
+               goto index_fail;
+       }
+
+       hvcs_tty_driver->owner = THIS_MODULE;
+
+       hvcs_tty_driver->driver_name = hvcs_driver_name;
+       hvcs_tty_driver->name = hvcs_device_node;
+
+       /*
+        * We'll let the system assign us a major number, indicated by leaving
+        * it blank.
+        */
+
+       hvcs_tty_driver->minor_start = HVCS_MINOR_START;
+       hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+
+       /*
+        * We role our own so that we DONT ECHO.  We can't echo because the
+        * device we are connecting to already echoes by default and this would
+        * throw us into a horrible recursive echo-echo-echo loop.
+        */
+       hvcs_tty_driver->init_termios = hvcs_tty_termios;
+       hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+
+       tty_set_operations(hvcs_tty_driver, &hvcs_ops);
+
+       /*
+        * The following call will result in sysfs entries that denote the
+        * dynamically assigned major and minor numbers for our devices.
+        */
+       if (tty_register_driver(hvcs_tty_driver)) {
+               printk(KERN_ERR "HVCS: registration as a tty driver failed.\n");
+               rc = -EIO;
+               goto register_fail;
+       }
+
+       hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!hvcs_pi_buff) {
+               rc = -ENOMEM;
+               goto buff_alloc_fail;
+       }
+
+       hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
+       if (IS_ERR(hvcs_task)) {
+               printk(KERN_ERR "HVCS: khvcsd creation failed.  Driver not loaded.\n");
+               rc = -EIO;
+               goto kthread_fail;
+       }
+
+       rc = vio_register_driver(&hvcs_vio_driver);
+       if (rc) {
+               printk(KERN_ERR "HVCS: can't register vio driver\n");
+               goto vio_fail;
+       }
+
+       /*
+        * This needs to be done AFTER the vio_register_driver() call or else
+        * the kobjects won't be initialized properly.
+        */
+       rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
+       if (rc) {
+               printk(KERN_ERR "HVCS: sysfs attr create failed\n");
+               goto attr_fail;
+       }
+
+       printk(KERN_INFO "HVCS: driver module inserted.\n");
+
+       return 0;
+
+attr_fail:
+       vio_unregister_driver(&hvcs_vio_driver);
+vio_fail:
+       kthread_stop(hvcs_task);
+kthread_fail:
+       kfree(hvcs_pi_buff);
+buff_alloc_fail:
+       tty_unregister_driver(hvcs_tty_driver);
+register_fail:
+       hvcs_free_index_list();
+index_fail:
+       put_tty_driver(hvcs_tty_driver);
+       hvcs_tty_driver = NULL;
+       return rc;
+}
+
+static void __exit hvcs_module_exit(void)
+{
+       /*
+        * This driver receives hvcs_remove callbacks for each device upon
+        * module removal.
+        */
+
+       /*
+        * This synchronous operation  will wake the khvcsd kthread if it is
+        * asleep and will return when khvcsd has terminated.
+        */
+       kthread_stop(hvcs_task);
+
+       spin_lock(&hvcs_pi_lock);
+       kfree(hvcs_pi_buff);
+       hvcs_pi_buff = NULL;
+       spin_unlock(&hvcs_pi_lock);
+
+       driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
+
+       vio_unregister_driver(&hvcs_vio_driver);
+
+       tty_unregister_driver(hvcs_tty_driver);
+
+       hvcs_free_index_list();
+
+       put_tty_driver(hvcs_tty_driver);
+
+       printk(KERN_INFO "HVCS: driver module removed.\n");
+}
+
+module_init(hvcs_module_init);
+module_exit(hvcs_module_exit);
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
new file mode 100644 (file)
index 0000000..67a75a5
--- /dev/null
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (C) 2004 Hollis Blanchard <hollisb@us.ibm.com>, IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS
+ * and the service processor on IBM pSeries servers. On these servers, there
+ * are no serial ports under the OS's control, and sometimes there is no other
+ * console available either. However, the service processor has two standard
+ * serial ports, so this over-complicated protocol allows the OS to control
+ * those ports by proxy.
+ *
+ * Besides data, the procotol supports the reading/writing of the serial
+ * port's DTR line, and the reading of the CD line. This is to allow the OS to
+ * control a modem attached to the service processor's serial port. Note that
+ * the OS cannot change the speed of the port through this protocol.
+ */
+
+#undef DEBUG
+
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/hvcall.h>
+#include <asm/hvconsole.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+#include <asm/vio.h>
+#include <asm/param.h>
+
+#define HVSI_MAJOR     229
+#define HVSI_MINOR     128
+#define MAX_NR_HVSI_CONSOLES 4
+
+#define HVSI_TIMEOUT (5*HZ)
+#define HVSI_VERSION 1
+#define HVSI_MAX_PACKET 256
+#define HVSI_MAX_READ 16
+#define HVSI_MAX_OUTGOING_DATA 12
+#define N_OUTBUF 12
+
+/*
+ * we pass data via two 8-byte registers, so we would like our char arrays
+ * properly aligned for those loads.
+ */
+#define __ALIGNED__    __attribute__((__aligned__(sizeof(long))))
+
+struct hvsi_struct {
+       struct delayed_work writer;
+       struct work_struct handshaker;
+       wait_queue_head_t emptyq; /* woken when outbuf is emptied */
+       wait_queue_head_t stateq; /* woken when HVSI state changes */
+       spinlock_t lock;
+       int index;
+       struct tty_struct *tty;
+       int count;
+       uint8_t throttle_buf[128];
+       uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
+       /* inbuf is for packet reassembly. leave a little room for leftovers. */
+       uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ];
+       uint8_t *inbuf_end;
+       int n_throttle;
+       int n_outbuf;
+       uint32_t vtermno;
+       uint32_t virq;
+       atomic_t seqno; /* HVSI packet sequence number */
+       uint16_t mctrl;
+       uint8_t state;  /* HVSI protocol state */
+       uint8_t flags;
+#ifdef CONFIG_MAGIC_SYSRQ
+       uint8_t sysrq;
+#endif /* CONFIG_MAGIC_SYSRQ */
+};
+static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES];
+
+static struct tty_driver *hvsi_driver;
+static int hvsi_count;
+static int (*hvsi_wait)(struct hvsi_struct *hp, int state);
+
+enum HVSI_PROTOCOL_STATE {
+       HVSI_CLOSED,
+       HVSI_WAIT_FOR_VER_RESPONSE,
+       HVSI_WAIT_FOR_VER_QUERY,
+       HVSI_OPEN,
+       HVSI_WAIT_FOR_MCTRL_RESPONSE,
+       HVSI_FSP_DIED,
+};
+#define HVSI_CONSOLE 0x1
+
+#define VS_DATA_PACKET_HEADER           0xff
+#define VS_CONTROL_PACKET_HEADER        0xfe
+#define VS_QUERY_PACKET_HEADER          0xfd
+#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc
+
+/* control verbs */
+#define VSV_SET_MODEM_CTL    1 /* to service processor only */
+#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */
+#define VSV_CLOSE_PROTOCOL   3
+
+/* query verbs */
+#define VSV_SEND_VERSION_NUMBER 1
+#define VSV_SEND_MODEM_CTL_STATUS 2
+
+/* yes, these masks are not consecutive. */
+#define HVSI_TSDTR 0x01
+#define HVSI_TSCD  0x20
+
+struct hvsi_header {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+} __attribute__((packed));
+
+struct hvsi_data {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint8_t  data[HVSI_MAX_OUTGOING_DATA];
+} __attribute__((packed));
+
+struct hvsi_control {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+       /* optional depending on verb: */
+       uint32_t word;
+       uint32_t mask;
+} __attribute__((packed));
+
+struct hvsi_query {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+} __attribute__((packed));
+
+struct hvsi_query_response {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+       uint16_t query_seqno;
+       union {
+               uint8_t  version;
+               uint32_t mctrl_word;
+       } u;
+} __attribute__((packed));
+
+
+
+static inline int is_console(struct hvsi_struct *hp)
+{
+       return hp->flags & HVSI_CONSOLE;
+}
+
+static inline int is_open(struct hvsi_struct *hp)
+{
+       /* if we're waiting for an mctrl then we're already open */
+       return (hp->state == HVSI_OPEN)
+                       || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE);
+}
+
+static inline void print_state(struct hvsi_struct *hp)
+{
+#ifdef DEBUG
+       static const char *state_names[] = {
+               "HVSI_CLOSED",
+               "HVSI_WAIT_FOR_VER_RESPONSE",
+               "HVSI_WAIT_FOR_VER_QUERY",
+               "HVSI_OPEN",
+               "HVSI_WAIT_FOR_MCTRL_RESPONSE",
+               "HVSI_FSP_DIED",
+       };
+       const char *name = (hp->state < ARRAY_SIZE(state_names))
+               ? state_names[hp->state] : "UNKNOWN";
+
+       pr_debug("hvsi%i: state = %s\n", hp->index, name);
+#endif /* DEBUG */
+}
+
+static inline void __set_state(struct hvsi_struct *hp, int state)
+{
+       hp->state = state;
+       print_state(hp);
+       wake_up_all(&hp->stateq);
+}
+
+static inline void set_state(struct hvsi_struct *hp, int state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       __set_state(hp, state);
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static inline int len_packet(const uint8_t *packet)
+{
+       return (int)((struct hvsi_header *)packet)->len;
+}
+
+static inline int is_header(const uint8_t *packet)
+{
+       struct hvsi_header *header = (struct hvsi_header *)packet;
+       return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER;
+}
+
+static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet)
+{
+       if (hp->inbuf_end < packet + sizeof(struct hvsi_header))
+               return 0; /* don't even have the packet header */
+
+       if (hp->inbuf_end < (packet + len_packet(packet)))
+               return 0; /* don't have the rest of the packet */
+
+       return 1;
+}
+
+/* shift remaining bytes in packetbuf down */
+static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to)
+{
+       int remaining = (int)(hp->inbuf_end - read_to);
+
+       pr_debug("%s: %i chars remain\n", __func__, remaining);
+
+       if (read_to != hp->inbuf)
+               memmove(hp->inbuf, read_to, remaining);
+
+       hp->inbuf_end = hp->inbuf + remaining;
+}
+
+#ifdef DEBUG
+#define dbg_dump_packet(packet) dump_packet(packet)
+#define dbg_dump_hex(data, len) dump_hex(data, len)
+#else
+#define dbg_dump_packet(packet) do { } while (0)
+#define dbg_dump_hex(data, len) do { } while (0)
+#endif
+
+static void dump_hex(const uint8_t *data, int len)
+{
+       int i;
+
+       printk("    ");
+       for (i=0; i < len; i++)
+               printk("%.2x", data[i]);
+
+       printk("\n    ");
+       for (i=0; i < len; i++) {
+               if (isprint(data[i]))
+                       printk("%c", data[i]);
+               else
+                       printk(".");
+       }
+       printk("\n");
+}
+
+static void dump_packet(uint8_t *packet)
+{
+       struct hvsi_header *header = (struct hvsi_header *)packet;
+
+       printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len,
+                       header->seqno);
+
+       dump_hex(packet, header->len);
+}
+
+static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
+{
+       unsigned long got;
+
+       got = hvc_get_chars(hp->vtermno, buf, count);
+
+       return got;
+}
+
+static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
+       struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
+{
+       struct hvsi_control *header = (struct hvsi_control *)packet;
+
+       switch (header->verb) {
+               case VSV_MODEM_CTL_UPDATE:
+                       if ((header->word & HVSI_TSCD) == 0) {
+                               /* CD went away; no more connection */
+                               pr_debug("hvsi%i: CD dropped\n", hp->index);
+                               hp->mctrl &= TIOCM_CD;
+                               /* If userland hasn't done an open(2) yet, hp->tty is NULL. */
+                               if (hp->tty && !(hp->tty->flags & CLOCAL))
+                                       *to_hangup = hp->tty;
+                       }
+                       break;
+               case VSV_CLOSE_PROTOCOL:
+                       pr_debug("hvsi%i: service processor came back\n", hp->index);
+                       if (hp->state != HVSI_CLOSED) {
+                               *to_handshake = hp;
+                       }
+                       break;
+               default:
+                       printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ",
+                               hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+}
+
+static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet)
+{
+       struct hvsi_query_response *resp = (struct hvsi_query_response *)packet;
+
+       switch (hp->state) {
+               case HVSI_WAIT_FOR_VER_RESPONSE:
+                       __set_state(hp, HVSI_WAIT_FOR_VER_QUERY);
+                       break;
+               case HVSI_WAIT_FOR_MCTRL_RESPONSE:
+                       hp->mctrl = 0;
+                       if (resp->u.mctrl_word & HVSI_TSDTR)
+                               hp->mctrl |= TIOCM_DTR;
+                       if (resp->u.mctrl_word & HVSI_TSCD)
+                               hp->mctrl |= TIOCM_CD;
+                       __set_state(hp, HVSI_OPEN);
+                       break;
+               default:
+                       printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+}
+
+/* respond to service processor's version query */
+static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno)
+{
+       struct hvsi_query_response packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_QUERY_RESPONSE_PACKET_HEADER;
+       packet.len = sizeof(struct hvsi_query_response);
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.verb = VSV_SEND_VERSION_NUMBER;
+       packet.u.version = HVSI_VERSION;
+       packet.query_seqno = query_seqno+1;
+
+       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't send query response!\n",
+                       hp->index);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
+{
+       struct hvsi_query *query = (struct hvsi_query *)packet;
+
+       switch (hp->state) {
+               case HVSI_WAIT_FOR_VER_QUERY:
+                       hvsi_version_respond(hp, query->seqno);
+                       __set_state(hp, HVSI_OPEN);
+                       break;
+               default:
+                       printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+}
+
+static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+{
+       int i;
+
+       for (i=0; i < len; i++) {
+               char c = buf[i];
+#ifdef CONFIG_MAGIC_SYSRQ
+               if (c == '\0') {
+                       hp->sysrq = 1;
+                       continue;
+               } else if (hp->sysrq) {
+                       handle_sysrq(c);
+                       hp->sysrq = 0;
+                       continue;
+               }
+#endif /* CONFIG_MAGIC_SYSRQ */
+               tty_insert_flip_char(hp->tty, c, 0);
+       }
+}
+
+/*
+ * We could get 252 bytes of data at once here. But the tty layer only
+ * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow
+ * it. Accordingly we won't send more than 128 bytes at a time to the flip
+ * buffer, which will give the tty buffer a chance to throttle us. Should the
+ * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be
+ * revisited.
+ */
+#define TTY_THRESHOLD_THROTTLE 128
+static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+               const uint8_t *packet)
+{
+       const struct hvsi_header *header = (const struct hvsi_header *)packet;
+       const uint8_t *data = packet + sizeof(struct hvsi_header);
+       int datalen = header->len - sizeof(struct hvsi_header);
+       int overflow = datalen - TTY_THRESHOLD_THROTTLE;
+
+       pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
+
+       if (datalen == 0)
+               return NULL;
+
+       if (overflow > 0) {
+               pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
+               datalen = TTY_THRESHOLD_THROTTLE;
+       }
+
+       hvsi_insert_chars(hp, data, datalen);
+
+       if (overflow > 0) {
+               /*
+                * we still have more data to deliver, so we need to save off the
+                * overflow and send it later
+                */
+               pr_debug("%s: deferring overflow\n", __func__);
+               memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
+               hp->n_throttle = overflow;
+       }
+
+       return hp->tty;
+}
+
+/*
+ * Returns true/false indicating data successfully read from hypervisor.
+ * Used both to get packets for tty connections and to advance the state
+ * machine during console handshaking (in which case tty = NULL and we ignore
+ * incoming data).
+ */
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
+               struct tty_struct **hangup, struct hvsi_struct **handshake)
+{
+       uint8_t *packet = hp->inbuf;
+       int chunklen;
+
+       *flip = NULL;
+       *hangup = NULL;
+       *handshake = NULL;
+
+       chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
+       if (chunklen == 0) {
+               pr_debug("%s: 0-length read\n", __func__);
+               return 0;
+       }
+
+       pr_debug("%s: got %i bytes\n", __func__, chunklen);
+       dbg_dump_hex(hp->inbuf_end, chunklen);
+
+       hp->inbuf_end += chunklen;
+
+       /* handle all completed packets */
+       while ((packet < hp->inbuf_end) && got_packet(hp, packet)) {
+               struct hvsi_header *header = (struct hvsi_header *)packet;
+
+               if (!is_header(packet)) {
+                       printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index);
+                       /* skip bytes until we find a header or run out of data */
+                       while ((packet < hp->inbuf_end) && (!is_header(packet)))
+                               packet++;
+                       continue;
+               }
+
+               pr_debug("%s: handling %i-byte packet\n", __func__,
+                               len_packet(packet));
+               dbg_dump_packet(packet);
+
+               switch (header->type) {
+                       case VS_DATA_PACKET_HEADER:
+                               if (!is_open(hp))
+                                       break;
+                               if (hp->tty == NULL)
+                                       break; /* no tty buffer to put data in */
+                               *flip = hvsi_recv_data(hp, packet);
+                               break;
+                       case VS_CONTROL_PACKET_HEADER:
+                               hvsi_recv_control(hp, packet, hangup, handshake);
+                               break;
+                       case VS_QUERY_RESPONSE_PACKET_HEADER:
+                               hvsi_recv_response(hp, packet);
+                               break;
+                       case VS_QUERY_PACKET_HEADER:
+                               hvsi_recv_query(hp, packet);
+                               break;
+                       default:
+                               printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n",
+                                               hp->index, header->type);
+                               dump_packet(packet);
+                               break;
+               }
+
+               packet += len_packet(packet);
+
+               if (*hangup || *handshake) {
+                       pr_debug("%s: hangup or handshake\n", __func__);
+                       /*
+                        * we need to send the hangup now before receiving any more data.
+                        * If we get "data, hangup, data", we can't deliver the second
+                        * data before the hangup.
+                        */
+                       break;
+               }
+       }
+
+       compact_inbuf(hp, packet);
+
+       return 1;
+}
+
+static void hvsi_send_overflow(struct hvsi_struct *hp)
+{
+       pr_debug("%s: delivering %i bytes overflow\n", __func__,
+                       hp->n_throttle);
+
+       hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+       hp->n_throttle = 0;
+}
+
+/*
+ * must get all pending data because we only get an irq on empty->non-empty
+ * transition
+ */
+static irqreturn_t hvsi_interrupt(int irq, void *arg)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)arg;
+       struct tty_struct *flip;
+       struct tty_struct *hangup;
+       struct hvsi_struct *handshake;
+       unsigned long flags;
+       int again = 1;
+
+       pr_debug("%s\n", __func__);
+
+       while (again) {
+               spin_lock_irqsave(&hp->lock, flags);
+               again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
+               spin_unlock_irqrestore(&hp->lock, flags);
+
+               /*
+                * we have to call tty_flip_buffer_push() and tty_hangup() outside our
+                * spinlock. But we also have to keep going until we've read all the
+                * available data.
+                */
+
+               if (flip) {
+                       /* there was data put in the tty flip buffer */
+                       tty_flip_buffer_push(flip);
+                       flip = NULL;
+               }
+
+               if (hangup) {
+                       tty_hangup(hangup);
+               }
+
+               if (handshake) {
+                       pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
+                       schedule_work(&handshake->handshaker);
+               }
+       }
+
+       spin_lock_irqsave(&hp->lock, flags);
+       if (hp->tty && hp->n_throttle
+                       && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
+               /* we weren't hung up and we weren't throttled, so we can deliver the
+                * rest now */
+               flip = hp->tty;
+               hvsi_send_overflow(hp);
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (flip) {
+               tty_flip_buffer_push(flip);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* for boot console, before the irq handler is running */
+static int __init poll_for_state(struct hvsi_struct *hp, int state)
+{
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+
+       for (;;) {
+               hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */
+
+               if (hp->state == state)
+                       return 0;
+
+               mdelay(5);
+               if (time_after(jiffies, end_jiffies))
+                       return -EIO;
+       }
+}
+
+/* wait for irq handler to change our state */
+static int wait_for_state(struct hvsi_struct *hp, int state)
+{
+       int ret = 0;
+
+       if (!wait_event_timeout(hp->stateq, (hp->state == state), HVSI_TIMEOUT))
+               ret = -EIO;
+
+       return ret;
+}
+
+static int hvsi_query(struct hvsi_struct *hp, uint16_t verb)
+{
+       struct hvsi_query packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_QUERY_PACKET_HEADER;
+       packet.len = sizeof(struct hvsi_query);
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.verb = verb;
+
+       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index,
+                       wrote);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hvsi_get_mctrl(struct hvsi_struct *hp)
+{
+       int ret;
+
+       set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE);
+       hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS);
+
+       ret = hvsi_wait(hp, HVSI_OPEN);
+       if (ret < 0) {
+               printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index);
+               set_state(hp, HVSI_OPEN);
+               return ret;
+       }
+
+       pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl);
+
+       return 0;
+}
+
+/* note that we can only set DTR */
+static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl)
+{
+       struct hvsi_control packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_CONTROL_PACKET_HEADER,
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = sizeof(struct hvsi_control);
+       packet.verb = VSV_SET_MODEM_CTL;
+       packet.mask = HVSI_TSDTR;
+
+       if (mctrl & TIOCM_DTR)
+               packet.word = HVSI_TSDTR;
+
+       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void hvsi_drain_input(struct hvsi_struct *hp)
+{
+       uint8_t buf[HVSI_MAX_READ] __ALIGNED__;
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+
+       while (time_before(end_jiffies, jiffies))
+               if (0 == hvsi_read(hp, buf, HVSI_MAX_READ))
+                       break;
+}
+
+static int hvsi_handshake(struct hvsi_struct *hp)
+{
+       int ret;
+
+       /*
+        * We could have a CLOSE or other data waiting for us before we even try
+        * to open; try to throw it all away so we don't get confused. (CLOSE
+        * is the first message sent up the pipe when the FSP comes online. We
+        * need to distinguish between "it came up a while ago and we're the first
+        * user" and "it was just reset before it saw our handshake packet".)
+        */
+       hvsi_drain_input(hp);
+
+       set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE);
+       ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER);
+       if (ret < 0) {
+               printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index);
+               return ret;
+       }
+
+       ret = hvsi_wait(hp, HVSI_OPEN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void hvsi_handshaker(struct work_struct *work)
+{
+       struct hvsi_struct *hp =
+               container_of(work, struct hvsi_struct, handshaker);
+
+       if (hvsi_handshake(hp) >= 0)
+               return;
+
+       printk(KERN_ERR "hvsi%i: re-handshaking failed\n", hp->index);
+       if (is_console(hp)) {
+               /*
+                * ttys will re-attempt the handshake via hvsi_open, but
+                * the console will not.
+                */
+               printk(KERN_ERR "hvsi%i: lost console!\n", hp->index);
+       }
+}
+
+static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count)
+{
+       struct hvsi_data packet __ALIGNED__;
+       int ret;
+
+       BUG_ON(count > HVSI_MAX_OUTGOING_DATA);
+
+       packet.type = VS_DATA_PACKET_HEADER;
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = count + sizeof(struct hvsi_header);
+       memcpy(&packet.data, buf, count);
+
+       ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (ret == packet.len) {
+               /* return the number of chars written, not the packet length */
+               return count;
+       }
+       return ret; /* return any errors */
+}
+
+static void hvsi_close_protocol(struct hvsi_struct *hp)
+{
+       struct hvsi_control packet __ALIGNED__;
+
+       packet.type = VS_CONTROL_PACKET_HEADER;
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = 6;
+       packet.verb = VSV_CLOSE_PROTOCOL;
+
+       pr_debug("%s: sending %i bytes\n", __func__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+}
+
+static int hvsi_open(struct tty_struct *tty, struct file *filp)
+{
+       struct hvsi_struct *hp;
+       unsigned long flags;
+       int line = tty->index;
+       int ret;
+
+       pr_debug("%s\n", __func__);
+
+       if (line < 0 || line >= hvsi_count)
+               return -ENODEV;
+       hp = &hvsi_ports[line];
+
+       tty->driver_data = hp;
+
+       mb();
+       if (hp->state == HVSI_FSP_DIED)
+               return -EIO;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       hp->tty = tty;
+       hp->count++;
+       atomic_set(&hp->seqno, 0);
+       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (is_console(hp))
+               return 0; /* this has already been handshaked as the console */
+
+       ret = hvsi_handshake(hp);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name);
+               return ret;
+       }
+
+       ret = hvsi_get_mctrl(hp);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name);
+               return ret;
+       }
+
+       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: couldn't set DTR\n", tty->name);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* wait for hvsi_write_worker to empty hp->outbuf */
+static void hvsi_flush_output(struct hvsi_struct *hp)
+{
+       wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);
+
+       /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
+       cancel_delayed_work_sync(&hp->writer);
+       flush_work_sync(&hp->handshaker);
+
+       /*
+        * it's also possible that our timeout expired and hvsi_write_worker
+        * didn't manage to push outbuf. poof.
+        */
+       hp->n_outbuf = 0;
+}
+
+static void hvsi_close(struct tty_struct *tty, struct file *filp)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       if (tty_hung_up_p(filp))
+               return;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       if (--hp->count == 0) {
+               hp->tty = NULL;
+               hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
+
+               /* only close down connection if it is not the console */
+               if (!is_console(hp)) {
+                       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */
+                       __set_state(hp, HVSI_CLOSED);
+                       /*
+                        * any data delivered to the tty layer after this will be
+                        * discarded (except for XON/XOFF)
+                        */
+                       tty->closing = 1;
+
+                       spin_unlock_irqrestore(&hp->lock, flags);
+
+                       /* let any existing irq handlers finish. no more will start. */
+                       synchronize_irq(hp->virq);
+
+                       /* hvsi_write_worker will re-schedule until outbuf is empty. */
+                       hvsi_flush_output(hp);
+
+                       /* tell FSP to stop sending data */
+                       hvsi_close_protocol(hp);
+
+                       /*
+                        * drain anything FSP is still in the middle of sending, and let
+                        * hvsi_handshake drain the rest on the next open.
+                        */
+                       hvsi_drain_input(hp);
+
+                       spin_lock_irqsave(&hp->lock, flags);
+               }
+       } else if (hp->count < 0)
+               printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
+                      hp - hvsi_ports, hp->count);
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static void hvsi_hangup(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       unsigned long flags;
+
+       pr_debug("%s\n", __func__);
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       hp->count = 0;
+       hp->n_outbuf = 0;
+       hp->tty = NULL;
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+/* called with hp->lock held */
+static void hvsi_push(struct hvsi_struct *hp)
+{
+       int n;
+
+       if (hp->n_outbuf <= 0)
+               return;
+
+       n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
+       if (n > 0) {
+               /* success */
+               pr_debug("%s: wrote %i chars\n", __func__, n);
+               hp->n_outbuf = 0;
+       } else if (n == -EIO) {
+               __set_state(hp, HVSI_FSP_DIED);
+               printk(KERN_ERR "hvsi%i: service processor died\n", hp->index);
+       }
+}
+
+/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */
+static void hvsi_write_worker(struct work_struct *work)
+{
+       struct hvsi_struct *hp =
+               container_of(work, struct hvsi_struct, writer.work);
+       unsigned long flags;
+#ifdef DEBUG
+       static long start_j = 0;
+
+       if (start_j == 0)
+               start_j = jiffies;
+#endif /* DEBUG */
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
+
+       if (!is_open(hp)) {
+               /*
+                * We could have a non-open connection if the service processor died
+                * while we were busily scheduling ourselves. In that case, it could
+                * be minutes before the service processor comes back, so only try
+                * again once a second.
+                */
+               schedule_delayed_work(&hp->writer, HZ);
+               goto out;
+       }
+
+       hvsi_push(hp);
+       if (hp->n_outbuf > 0)
+               schedule_delayed_work(&hp->writer, 10);
+       else {
+#ifdef DEBUG
+               pr_debug("%s: outbuf emptied after %li jiffies\n", __func__,
+                               jiffies - start_j);
+               start_j = 0;
+#endif /* DEBUG */
+               wake_up_all(&hp->emptyq);
+               tty_wakeup(hp->tty);
+       }
+
+out:
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static int hvsi_write_room(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+
+       return N_OUTBUF - hp->n_outbuf;
+}
+
+static int hvsi_chars_in_buffer(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+
+       return hp->n_outbuf;
+}
+
+static int hvsi_write(struct tty_struct *tty,
+                    const unsigned char *buf, int count)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       const char *source = buf;
+       unsigned long flags;
+       int total = 0;
+       int origcount = count;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
+
+       if (!is_open(hp)) {
+               /* we're either closing or not yet open; don't accept data */
+               pr_debug("%s: not open\n", __func__);
+               goto out;
+       }
+
+       /*
+        * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf
+        * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
+        * will see there is no room in outbuf and return.
+        */
+       while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
+               int chunksize = min(count, hvsi_write_room(hp->tty));
+
+               BUG_ON(hp->n_outbuf < 0);
+               memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
+               hp->n_outbuf += chunksize;
+
+               total += chunksize;
+               source += chunksize;
+               count -= chunksize;
+               hvsi_push(hp);
+       }
+
+       if (hp->n_outbuf > 0) {
+               /*
+                * we weren't able to write it all to the hypervisor.
+                * schedule another push attempt.
+                */
+               schedule_delayed_work(&hp->writer, 10);
+       }
+
+out:
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (total != origcount)
+               pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount,
+                       total);
+
+       return total;
+}
+
+/*
+ * I have never seen throttle or unthrottle called, so this little throttle
+ * buffering scheme may or may not work.
+ */
+static void hvsi_throttle(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+
+       pr_debug("%s\n", __func__);
+
+       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
+}
+
+static void hvsi_unthrottle(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       unsigned long flags;
+       int shouldflip = 0;
+
+       pr_debug("%s\n", __func__);
+
+       spin_lock_irqsave(&hp->lock, flags);
+       if (hp->n_throttle) {
+               hvsi_send_overflow(hp);
+               shouldflip = 1;
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (shouldflip)
+               tty_flip_buffer_push(hp->tty);
+
+       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
+}
+
+static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+
+       hvsi_get_mctrl(hp);
+       return hp->mctrl;
+}
+
+static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       unsigned long flags;
+       uint16_t new_mctrl;
+
+       /* we can only alter DTR */
+       clear &= TIOCM_DTR;
+       set &= TIOCM_DTR;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       new_mctrl = (hp->mctrl & ~clear) | set;
+
+       if (hp->mctrl != new_mctrl) {
+               hvsi_set_mctrl(hp, new_mctrl);
+               hp->mctrl = new_mctrl;
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       return 0;
+}
+
+
+static const struct tty_operations hvsi_ops = {
+       .open = hvsi_open,
+       .close = hvsi_close,
+       .write = hvsi_write,
+       .hangup = hvsi_hangup,
+       .write_room = hvsi_write_room,
+       .chars_in_buffer = hvsi_chars_in_buffer,
+       .throttle = hvsi_throttle,
+       .unthrottle = hvsi_unthrottle,
+       .tiocmget = hvsi_tiocmget,
+       .tiocmset = hvsi_tiocmset,
+};
+
+static int __init hvsi_init(void)
+{
+       int i;
+
+       hvsi_driver = alloc_tty_driver(hvsi_count);
+       if (!hvsi_driver)
+               return -ENOMEM;
+
+       hvsi_driver->owner = THIS_MODULE;
+       hvsi_driver->driver_name = "hvsi";
+       hvsi_driver->name = "hvsi";
+       hvsi_driver->major = HVSI_MAJOR;
+       hvsi_driver->minor_start = HVSI_MINOR;
+       hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+       hvsi_driver->init_termios = tty_std_termios;
+       hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+       hvsi_driver->init_termios.c_ispeed = 9600;
+       hvsi_driver->init_termios.c_ospeed = 9600;
+       hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(hvsi_driver, &hvsi_ops);
+
+       for (i=0; i < hvsi_count; i++) {
+               struct hvsi_struct *hp = &hvsi_ports[i];
+               int ret = 1;
+
+               ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp);
+               if (ret)
+                       printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
+                               hp->virq, ret);
+       }
+       hvsi_wait = wait_for_state; /* irqs active now */
+
+       if (tty_register_driver(hvsi_driver))
+               panic("Couldn't register hvsi console driver\n");
+
+       printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count);
+
+       return 0;
+}
+device_initcall(hvsi_init);
+
+/***** console (not tty) code: *****/
+
+static void hvsi_console_print(struct console *console, const char *buf,
+               unsigned int count)
+{
+       struct hvsi_struct *hp = &hvsi_ports[console->index];
+       char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__;
+       unsigned int i = 0, n = 0;
+       int ret, donecr = 0;
+
+       mb();
+       if (!is_open(hp))
+               return;
+
+       /*
+        * ugh, we have to translate LF -> CRLF ourselves, in place.
+        * copied from hvc_console.c:
+        */
+       while (count > 0 || i > 0) {
+               if (count > 0 && i < sizeof(c)) {
+                       if (buf[n] == '\n' && !donecr) {
+                               c[i++] = '\r';
+                               donecr = 1;
+                       } else {
+                               c[i++] = buf[n++];
+                               donecr = 0;
+                               --count;
+                       }
+               } else {
+                       ret = hvsi_put_chars(hp, c, i);
+                       if (ret < 0)
+                               i = 0;
+                       i -= ret;
+               }
+       }
+}
+
+static struct tty_driver *hvsi_console_device(struct console *console,
+       int *index)
+{
+       *index = console->index;
+       return hvsi_driver;
+}
+
+static int __init hvsi_console_setup(struct console *console, char *options)
+{
+       struct hvsi_struct *hp;
+       int ret;
+
+       if (console->index < 0 || console->index >= hvsi_count)
+               return -1;
+       hp = &hvsi_ports[console->index];
+
+       /* give the FSP a chance to change the baud rate when we re-open */
+       hvsi_close_protocol(hp);
+
+       ret = hvsi_handshake(hp);
+       if (ret < 0)
+               return ret;
+
+       ret = hvsi_get_mctrl(hp);
+       if (ret < 0)
+               return ret;
+
+       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
+       if (ret < 0)
+               return ret;
+
+       hp->flags |= HVSI_CONSOLE;
+
+       return 0;
+}
+
+static struct console hvsi_console = {
+       .name           = "hvsi",
+       .write          = hvsi_console_print,
+       .device         = hvsi_console_device,
+       .setup          = hvsi_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+static int __init hvsi_console_init(void)
+{
+       struct device_node *vty;
+
+       hvsi_wait = poll_for_state; /* no irqs yet; must poll */
+
+       /* search device tree for vty nodes */
+       for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol");
+                       vty != NULL;
+                       vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
+               struct hvsi_struct *hp;
+               const uint32_t *vtermno, *irq;
+
+               vtermno = of_get_property(vty, "reg", NULL);
+               irq = of_get_property(vty, "interrupts", NULL);
+               if (!vtermno || !irq)
+                       continue;
+
+               if (hvsi_count >= MAX_NR_HVSI_CONSOLES) {
+                       of_node_put(vty);
+                       break;
+               }
+
+               hp = &hvsi_ports[hvsi_count];
+               INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker);
+               INIT_WORK(&hp->handshaker, hvsi_handshaker);
+               init_waitqueue_head(&hp->emptyq);
+               init_waitqueue_head(&hp->stateq);
+               spin_lock_init(&hp->lock);
+               hp->index = hvsi_count;
+               hp->inbuf_end = hp->inbuf;
+               hp->state = HVSI_CLOSED;
+               hp->vtermno = *vtermno;
+               hp->virq = irq_create_mapping(NULL, irq[0]);
+               if (hp->virq == NO_IRQ) {
+                       printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
+                               __func__, irq[0]);
+                       continue;
+               }
+
+               hvsi_count++;
+       }
+
+       if (hvsi_count)
+               register_console(&hvsi_console);
+       return 0;
+}
+console_initcall(hvsi_console_init);
index 44b8412..aa2e5d3 100644 (file)
@@ -2414,6 +2414,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
 
        gsm->initiator = c->initiator;
        gsm->mru = c->mru;
+       gsm->mtu = c->mtu;
        gsm->encoding = c->encapsulation;
        gsm->adaption = c->adaption;
        gsm->n2 = c->n2;
index 47d3228..52fc0c9 100644 (file)
@@ -581,8 +581,9 @@ 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;
+       int ret = 0;
        struct n_hdlc_buf *rbuf;
+       DECLARE_WAITQUEUE(wait, current);
 
        if (debuglevel >= DEBUG_LEVEL_INFO)     
                printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
@@ -598,57 +599,55 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
                return -EFAULT;
        }
 
-       tty_lock();
+       add_wait_queue(&tty->read_wait, &wait);
 
        for (;;) {
                if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                       tty_unlock();
-                       return -EIO;
+                       ret = -EIO;
+                       break;
                }
+               if (tty_hung_up_p(file))
+                       break;
 
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-                        tty != n_hdlc->tty) {
-                       tty_unlock();
-                       return 0;
-               }
+               set_current_state(TASK_INTERRUPTIBLE);
 
                rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (rbuf)
+               if (rbuf) {
+                       if (rbuf->count > nr) {
+                               /* too large for caller's buffer */
+                               ret = -EOVERFLOW;
+                       } else {
+                               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                                       ret = -EFAULT;
+                               else
+                                       ret = rbuf->count;
+                       }
+
+                       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);
                        break;
+               }
                        
                /* no data */
                if (file->f_flags & O_NONBLOCK) {
-                       tty_unlock();
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       break;
                }
-                       
-               interruptible_sleep_on (&tty->read_wait);
+
+               schedule();
+
                if (signal_pending(current)) {
-                       tty_unlock();
-                       return -EINTR;
+                       ret = -EINTR;
+                       break;
                }
        }
-               
-       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();
+
+       remove_wait_queue(&tty->read_wait, &wait);
+       __set_current_state(TASK_RUNNING);
+
        return ret;
        
 }      /* end of n_hdlc_tty_read() */
@@ -691,14 +690,15 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                count = maxframe;
        }
        
-       tty_lock();
-
        add_wait_queue(&tty->write_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
+
+       for (;;) {
+               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))) {
+               tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+               if (tbuf)
+                       break;
+
                if (file->f_flags & O_NONBLOCK) {
                        error = -EAGAIN;
                        break;
@@ -719,7 +719,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                }
        }
 
-       set_current_state(TASK_RUNNING);
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tty->write_wait, &wait);
 
        if (!error) {           
@@ -731,7 +731,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                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() */
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
new file mode 100644 (file)
index 0000000..d89aa38
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * linux/drivers/serial/21285.c
+ *
+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+ *
+ * Based on drivers/char/serial.c
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/dec21285.h>
+#include <mach/hardware.h>
+
+#define BAUD_BASE              (mem_fclk_21285/64)
+
+#define SERIAL_21285_NAME      "ttyFB"
+#define SERIAL_21285_MAJOR     204
+#define SERIAL_21285_MINOR     4
+
+#define RXSTAT_DUMMY_READ      0x80000000
+#define RXSTAT_FRAME           (1 << 0)
+#define RXSTAT_PARITY          (1 << 1)
+#define RXSTAT_OVERRUN         (1 << 2)
+#define RXSTAT_ANYERR          (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
+
+#define H_UBRLCR_BREAK         (1 << 0)
+#define H_UBRLCR_PARENB                (1 << 1)
+#define H_UBRLCR_PAREVN                (1 << 2)
+#define H_UBRLCR_STOPB         (1 << 3)
+#define H_UBRLCR_FIFO          (1 << 4)
+
+static const char serial21285_name[] = "Footbridge UART";
+
+#define tx_enabled(port)       ((port)->unused[0])
+#define rx_enabled(port)       ((port)->unused[1])
+
+/*
+ * The documented expression for selecting the divisor is:
+ *  BAUD_BASE / baud - 1
+ * However, typically BAUD_BASE is not divisible by baud, so
+ * we want to select the divisor that gives us the minimum
+ * error.  Therefore, we want:
+ *  int(BAUD_BASE / baud - 0.5) ->
+ *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
+ *  int((BAUD_BASE - (baud >> 1)) / baud)
+ */
+
+static void serial21285_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               disable_irq_nosync(IRQ_CONTX);
+               tx_enabled(port) = 0;
+       }
+}
+
+static void serial21285_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(IRQ_CONTX);
+               tx_enabled(port) = 1;
+       }
+}
+
+static void serial21285_stop_rx(struct uart_port *port)
+{
+       if (rx_enabled(port)) {
+               disable_irq_nosync(IRQ_CONRX);
+               rx_enabled(port) = 0;
+       }
+}
+
+static void serial21285_enable_ms(struct uart_port *port)
+{
+}
+
+static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, flag, rxs, max_count = 256;
+
+       status = *CSR_UARTFLG;
+       while (!(status & 0x10) && max_count--) {
+               ch = *CSR_UARTDR;
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
+               if (unlikely(rxs & RXSTAT_ANYERR)) {
+                       if (rxs & RXSTAT_PARITY)
+                               port->icount.parity++;
+                       else if (rxs & RXSTAT_FRAME)
+                               port->icount.frame++;
+                       if (rxs & RXSTAT_OVERRUN)
+                               port->icount.overrun++;
+
+                       rxs &= port->read_status_mask;
+
+                       if (rxs & RXSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (rxs & RXSTAT_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
+
+               status = *CSR_UARTFLG;
+       }
+       tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count = 256;
+
+       if (port->x_char) {
+               *CSR_UARTDR = port->x_char;
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               serial21285_stop_tx(port);
+               goto out;
+       }
+
+       do {
+               *CSR_UARTDR = xmit->buf[xmit->tail];
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               serial21285_stop_tx(port);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial21285_tx_empty(struct uart_port *port)
+{
+       return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
+}
+
+/* no modem control lines */
+static unsigned int serial21285_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void serial21285_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int h_lcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+       h_lcr = *CSR_H_UBRLCR;
+       if (break_state)
+               h_lcr |= H_UBRLCR_BREAK;
+       else
+               h_lcr &= ~H_UBRLCR_BREAK;
+       *CSR_H_UBRLCR = h_lcr;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int serial21285_startup(struct uart_port *port)
+{
+       int ret;
+
+       tx_enabled(port) = 1;
+       rx_enabled(port) = 1;
+
+       ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
+                         serial21285_name, port);
+       if (ret == 0) {
+               ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
+                                 serial21285_name, port);
+               if (ret)
+                       free_irq(IRQ_CONRX, port);
+       }
+
+       return ret;
+}
+
+static void serial21285_shutdown(struct uart_port *port)
+{
+       free_irq(IRQ_CONTX, port);
+       free_irq(IRQ_CONRX, port);
+}
+
+static void
+serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
+                       struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, quot, h_lcr, b;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       /*
+        * We don't support BREAK character recognition.
+        */
+       termios->c_iflag &= ~(IGNBRK | BRKINT);
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+       b = port->uartclk / (16 * quot);
+       tty_termios_encode_baud_rate(termios, b, b);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               h_lcr = 0x00;
+               break;
+       case CS6:
+               h_lcr = 0x20;
+               break;
+       case CS7:
+               h_lcr = 0x40;
+               break;
+       default: /* CS8 */
+               h_lcr = 0x60;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               h_lcr |= H_UBRLCR_STOPB;
+       if (termios->c_cflag & PARENB) {
+               h_lcr |= H_UBRLCR_PARENB;
+               if (!(termios->c_cflag & PARODD))
+                       h_lcr |= H_UBRLCR_PAREVN;
+       }
+
+       if (port->fifosize)
+               h_lcr |= H_UBRLCR_FIFO;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = RXSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RXSTAT_OVERRUN;
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+       quot -= 1;
+
+       *CSR_UARTCON = 0;
+       *CSR_L_UBRLCR = quot & 0xff;
+       *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
+       *CSR_H_UBRLCR = h_lcr;
+       *CSR_UARTCON = 1;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *serial21285_type(struct uart_port *port)
+{
+       return port->type == PORT_21285 ? "DC21285" : NULL;
+}
+
+static void serial21285_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, 32);
+}
+
+static int serial21285_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, 32, serial21285_name)
+                        != NULL ? 0 : -EBUSY;
+}
+
+static void serial21285_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
+               port->type = PORT_21285;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
+               ret = -EINVAL;
+       if (ser->irq != NO_IRQ)
+               ret = -EINVAL;
+       if (ser->baud_base != port->uartclk / 16)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops serial21285_ops = {
+       .tx_empty       = serial21285_tx_empty,
+       .get_mctrl      = serial21285_get_mctrl,
+       .set_mctrl      = serial21285_set_mctrl,
+       .stop_tx        = serial21285_stop_tx,
+       .start_tx       = serial21285_start_tx,
+       .stop_rx        = serial21285_stop_rx,
+       .enable_ms      = serial21285_enable_ms,
+       .break_ctl      = serial21285_break_ctl,
+       .startup        = serial21285_startup,
+       .shutdown       = serial21285_shutdown,
+       .set_termios    = serial21285_set_termios,
+       .type           = serial21285_type,
+       .release_port   = serial21285_release_port,
+       .request_port   = serial21285_request_port,
+       .config_port    = serial21285_config_port,
+       .verify_port    = serial21285_verify_port,
+};
+
+static struct uart_port serial21285_port = {
+       .mapbase        = 0x42000160,
+       .iotype         = UPIO_MEM,
+       .irq            = NO_IRQ,
+       .fifosize       = 16,
+       .ops            = &serial21285_ops,
+       .flags          = UPF_BOOT_AUTOCONF,
+};
+
+static void serial21285_setup_ports(void)
+{
+       serial21285_port.uartclk = mem_fclk_21285 / 4;
+}
+
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+static void serial21285_console_putchar(struct uart_port *port, int ch)
+{
+       while (*CSR_UARTFLG & 0x20)
+               barrier();
+       *CSR_UARTDR = ch;
+}
+
+static void
+serial21285_console_write(struct console *co, const char *s,
+                         unsigned int count)
+{
+       uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
+}
+
+static void __init
+serial21285_get_options(struct uart_port *port, int *baud,
+                       int *parity, int *bits)
+{
+       if (*CSR_UARTCON == 1) {
+               unsigned int tmp;
+
+               tmp = *CSR_H_UBRLCR;
+               switch (tmp & 0x60) {
+               case 0x00:
+                       *bits = 5;
+                       break;
+               case 0x20:
+                       *bits = 6;
+                       break;
+               case 0x40:
+                       *bits = 7;
+                       break;
+               default:
+               case 0x60:
+                       *bits = 8;
+                       break;
+               }
+
+               if (tmp & H_UBRLCR_PARENB) {
+                       *parity = 'o';
+                       if (tmp & H_UBRLCR_PAREVN)
+                               *parity = 'e';
+               }
+
+               tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
+
+               *baud = port->uartclk / (16 * (tmp + 1));
+       }
+}
+
+static int __init serial21285_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &serial21285_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (machine_is_personal_server())
+               baud = 57600;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               serial21285_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver serial21285_reg;
+
+static struct console serial21285_console =
+{
+       .name           = SERIAL_21285_NAME,
+       .write          = serial21285_console_write,
+       .device         = uart_console_device,
+       .setup          = serial21285_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial21285_reg,
+};
+
+static int __init rs285_console_init(void)
+{
+       serial21285_setup_ports();
+       register_console(&serial21285_console);
+       return 0;
+}
+console_initcall(rs285_console_init);
+
+#define SERIAL_21285_CONSOLE   &serial21285_console
+#else
+#define SERIAL_21285_CONSOLE   NULL
+#endif
+
+static struct uart_driver serial21285_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyFB",
+       .dev_name               = "ttyFB",
+       .major                  = SERIAL_21285_MAJOR,
+       .minor                  = SERIAL_21285_MINOR,
+       .nr                     = 1,
+       .cons                   = SERIAL_21285_CONSOLE,
+};
+
+static int __init serial21285_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: 21285 driver\n");
+
+       serial21285_setup_ports();
+
+       ret = uart_register_driver(&serial21285_reg);
+       if (ret == 0)
+               uart_add_one_port(&serial21285_reg, &serial21285_port);
+
+       return ret;
+}
+
+static void __exit serial21285_exit(void)
+{
+       uart_remove_one_port(&serial21285_reg, &serial21285_port);
+       uart_unregister_driver(&serial21285_reg);
+}
+
+module_init(serial21285_init);
+module_exit(serial21285_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
+MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
new file mode 100644 (file)
index 0000000..de0160e
--- /dev/null
@@ -0,0 +1,1471 @@
+/* 68328serial.c: Serial port driver for 68328 microcontroller
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ * Copyright (C) 2002-2003  David McCullough   <davidm@snapgear.com>
+ * Copyright (C) 2002       Greg Ungerer       <gerg@snapgear.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ * Multiple UART support        Daniel Potts <danielp@cse.unsw.edu.au>
+ * Power management support     Daniel Potts <danielp@cse.unsw.edu.au>
+ * VZ Second Serial Port enable Phil Wilshire
+ * 2.4/2.5 port                 David McCullough
+ */
+
+#include <asm/dbg.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/reboot.h>
+#include <linux/keyboard.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+/* (es) */
+/* note: perhaps we can murge these files, so that you can just
+ *      define 1 of them, and they can sort that out for themselves
+ */
+#if defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#else
+#if defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#else
+#include <asm/MC68328.h>
+#endif /* CONFIG_M68VZ328 */
+#endif /* CONFIG_M68EZ328 */
+
+#include "68328serial.h"
+
+/* Turn off usage of real serial interrupt code, to "support" Copilot */
+#ifdef CONFIG_XCOPILOT_BUGS
+#undef USE_INTS
+#else
+#define USE_INTS
+#endif
+
+static struct m68k_serial m68k_soft[NR_PORTS];
+
+static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+
+struct tty_struct m68k_ttys;
+struct m68k_serial *m68k_consinfo = 0;
+
+#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+
+struct tty_driver *serial_driver;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_ISR_PASS_LIMIT 256
+
+static void change_speed(struct m68k_serial *info);
+
+/*
+ *     Setup for console. Argument comes from the boot command line.
+ */
+
+/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
+#ifdef CONFIG_M68VZ328
+#define CONSOLE_BAUD_RATE      19200
+#define DEFAULT_CBAUD          B19200
+#endif
+
+
+#ifndef CONSOLE_BAUD_RATE
+#define        CONSOLE_BAUD_RATE       9600
+#define        DEFAULT_CBAUD           B9600
+#endif
+
+
+static int m68328_console_initted = 0;
+static int m68328_console_baud    = CONSOLE_BAUD_RATE;
+static int m68328_console_cbaud   = DEFAULT_CBAUD;
+
+
+static inline int serial_paranoia_check(struct m68k_serial *info,
+                                       char *name, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct %s in %s\n";
+       static const char *badinfo =
+               "Warning: null m68k_serial for %s in %s\n";
+
+       if (!info) {
+               printk(badinfo, name, routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, name, routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 0 };
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
+{
+       if (set) {
+               /* set the RTS/CTS line */
+       } else {
+               /* clear it */
+       }
+       return;
+}
+
+/* Utility routines */
+static inline int get_baud(struct m68k_serial *ss)
+{
+       unsigned long result = 115200;
+       unsigned short int baud = uart_addr[ss->line].ubaud;
+       if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
+       result >>= GET_FIELD(baud, UBAUD_DIVIDE);
+
+       return result;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       uart->ustcnt &= ~USTCNT_TXEN;
+       local_irq_restore(flags);
+}
+
+static int rs_put_char(char ch)
+{
+        int flags, loops = 0;
+
+        local_irq_save(flags);
+
+       while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
+               loops++;
+               udelay(5);
+        }
+
+       UTX_TXDATA = ch;
+        udelay(5);
+        local_irq_restore(flags);
+        return 1;
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_start"))
+               return;
+       
+       local_irq_save(flags);
+       if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
+#ifdef USE_INTS
+               uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+               uart->ustcnt |= USTCNT_TXEN;
+#endif
+       }
+       local_irq_restore(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+       /* Drop into the debugger */
+}
+
+static void status_handle(struct m68k_serial *info, unsigned short status)
+{
+#if 0
+       if(status & DCD) {
+               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
+                  ((info->curregs[3] & AUTO_ENAB)==0)) {
+                       info->curregs[3] |= AUTO_ENAB;
+                       info->pendregs[3] |= AUTO_ENAB;
+                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+               }
+       } else {
+               if((info->curregs[3] & AUTO_ENAB)) {
+                       info->curregs[3] &= ~AUTO_ENAB;
+                       info->pendregs[3] &= ~AUTO_ENAB;
+                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+               }
+       }
+#endif
+       /* If this is console input and this is a
+        * 'break asserted' status change interrupt
+        * see if we can drop into the debugger
+        */
+       if((status & URX_BREAK) && info->break_abort)
+               batten_down_hatches();
+       return;
+}
+
+static void receive_chars(struct m68k_serial *info, unsigned short rx)
+{
+       struct tty_struct *tty = info->tty;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned char ch, flag;
+
+       /*
+        * This do { } while() loop will get ALL chars out of Rx FIFO 
+         */
+#ifndef CONFIG_XCOPILOT_BUGS
+       do {
+#endif 
+               ch = GET_FIELD(rx, URX_RXDATA);
+       
+               if(info->is_cons) {
+                       if(URX_BREAK & rx) { /* whee, break received */
+                               status_handle(info, rx);
+                               return;
+#ifdef CONFIG_MAGIC_SYSRQ
+                       } else if (ch == 0x10) { /* ^P */
+                               show_state();
+                               show_free_areas();
+                               show_buffers();
+/*                             show_net_buffers(); */
+                               return;
+                       } else if (ch == 0x12) { /* ^R */
+                               emergency_restart();
+                               return;
+#endif /* CONFIG_MAGIC_SYSRQ */
+                       }
+               }
+
+               if(!tty)
+                       goto clear_and_exit;
+               
+               flag = TTY_NORMAL;
+
+               if(rx & URX_PARITY_ERROR) {
+                       flag = TTY_PARITY;
+                       status_handle(info, rx);
+               } else if(rx & URX_OVRUN) {
+                       flag = TTY_OVERRUN;
+                       status_handle(info, rx);
+               } else if(rx & URX_FRAME_ERROR) {
+                       flag = TTY_FRAME;
+                       status_handle(info, rx);
+               }
+               tty_insert_flip_char(tty, ch, flag);
+#ifndef CONFIG_XCOPILOT_BUGS
+       } while((rx = uart->urx.w) & URX_DATA_READY);
+#endif
+
+       tty_schedule_flip(tty);
+
+clear_and_exit:
+       return;
+}
+
+static void transmit_chars(struct m68k_serial *info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+
+       if (info->x_char) {
+               /* Send next char */
+               uart->utx.b.txdata = info->x_char;
+               info->x_char = 0;
+               goto clear_and_return;
+       }
+
+       if((info->xmit_cnt <= 0) || info->tty->stopped) {
+               /* That's peculiar... TX ints off */
+               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+               goto clear_and_return;
+       }
+
+       /* Send char */
+       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+       info->xmit_cnt--;
+
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               schedule_work(&info->tqueue);
+
+       if(info->xmit_cnt <= 0) {
+               /* All done for now... TX ints off */
+               uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+               goto clear_and_return;
+       }
+
+clear_and_return:
+       /* Clear interrupt (should be auto)*/
+       return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+irqreturn_t rs_interrupt(int irq, void *dev_id)
+{
+       struct m68k_serial *info = dev_id;
+       m68328_uart *uart;
+       unsigned short rx;
+       unsigned short tx;
+
+       uart = &uart_addr[info->line];
+       rx = uart->urx.w;
+
+#ifdef USE_INTS
+       tx = uart->utx.w;
+
+       if (rx & URX_DATA_READY) receive_chars(info, rx);
+       if (tx & UTX_TX_AVAIL)   transmit_chars(info);
+#else
+       receive_chars(info, rx);                
+#endif
+       return IRQ_HANDLED;
+}
+
+static void do_softint(struct work_struct *work)
+{
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+#if 0
+       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               tty_wakeup(tty);
+       }
+#endif   
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(struct work_struct *work)
+{
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+
+static int startup(struct m68k_serial * info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+       
+       if (info->flags & S_INITIALIZED)
+               return 0;
+
+       if (!info->xmit_buf) {
+               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
+               if (!info->xmit_buf)
+                       return -ENOMEM;
+       }
+
+       local_irq_save(flags);
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+
+       uart->ustcnt = USTCNT_UEN;
+       info->xmit_fifo_size = 1;
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
+       (void)uart->urx.w;
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+#ifdef USE_INTS
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | 
+                 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
+#else
+       uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
+#endif
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * and set the speed of the serial port
+        */
+
+       change_speed(info);
+
+       info->flags |= S_INITIALIZED;
+       local_irq_restore(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct m68k_serial * info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long   flags;
+
+       uart->ustcnt = 0; /* All off! */
+       if (!(info->flags & S_INITIALIZED))
+               return;
+
+       local_irq_save(flags);
+       
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = 0;
+       }
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       
+       info->flags &= ~S_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+struct {
+       int divisor, prescale;
+}
+#ifndef CONFIG_M68VZ328
+ hw_baud_table[18] = {
+       {0,0}, /* 0 */
+       {0,0}, /* 50 */
+       {0,0}, /* 75 */
+       {0,0}, /* 110 */
+       {0,0}, /* 134 */
+       {0,0}, /* 150 */
+       {0,0}, /* 200 */
+       {7,0x26}, /* 300 */
+       {6,0x26}, /* 600 */
+       {5,0x26}, /* 1200 */
+       {0,0}, /* 1800 */
+       {4,0x26}, /* 2400 */
+       {3,0x26}, /* 4800 */
+       {2,0x26}, /* 9600 */
+       {1,0x26}, /* 19200 */
+       {0,0x26}, /* 38400 */
+       {1,0x38}, /* 57600 */
+       {0,0x38}, /* 115200 */
+};
+#else
+ hw_baud_table[18] = {
+                 {0,0}, /* 0 */
+                 {0,0}, /* 50 */
+                 {0,0}, /* 75 */
+                 {0,0}, /* 110 */
+                 {0,0}, /* 134 */
+                 {0,0}, /* 150 */
+                 {0,0}, /* 200 */
+                 {0,0}, /* 300 */
+                 {7,0x26}, /* 600 */
+                 {6,0x26}, /* 1200 */
+                 {0,0}, /* 1800 */
+                 {5,0x26}, /* 2400 */
+                 {4,0x26}, /* 4800 */
+                 {3,0x26}, /* 9600 */
+                 {2,0x26}, /* 19200 */
+                 {1,0x26}, /* 38400 */
+                 {0,0x26}, /* 57600 */
+                 {1,0x38}, /* 115200 */
+}; 
+#endif
+/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct m68k_serial *info)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned short port;
+       unsigned short ustcnt;
+       unsigned cflag;
+       int     i;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+
+       ustcnt = uart->ustcnt;
+       uart->ustcnt = ustcnt & ~USTCNT_TXEN;
+
+       i = cflag & CBAUD;
+        if (i & CBAUDEX) {
+                i = (i & ~CBAUDEX) + B38400;
+        }
+
+       info->baud = baud_table[i];
+       uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+
+       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+       
+       if ((cflag & CSIZE) == CS8)
+               ustcnt |= USTCNT_8_7;
+               
+       if (cflag & CSTOPB)
+               ustcnt |= USTCNT_STOP;
+
+       if (cflag & PARENB)
+               ustcnt |= USTCNT_PARITYEN;
+       if (cflag & PARODD)
+               ustcnt |= USTCNT_ODD_EVEN;
+       
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       if (cflag & CRTSCTS) {
+               uart->utx.w &= ~ UTX_NOCTS;
+       } else {
+               uart->utx.w |= UTX_NOCTS;
+       }
+#endif
+
+       ustcnt |= USTCNT_TXEN;
+       
+       uart->ustcnt = ustcnt;
+       return;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+       int left;               /* Output no more than that */
+       unsigned long flags;
+       struct m68k_serial *info = &m68k_soft[0];
+       char c;
+
+       if (info == 0) return;
+       if (info->xmit_buf == 0) return;
+
+       local_irq_save(flags);
+       left = info->xmit_cnt;
+       while (left != 0) {
+               c = info->xmit_buf[info->xmit_tail];
+               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+               local_irq_restore(flags);
+
+               rs_put_char(c);
+
+               local_irq_save(flags);
+               left = min(info->xmit_cnt, left-1);
+       }
+
+       /* Last character is being transmitted now (hopefully). */
+       udelay(5);
+
+       local_irq_restore(flags);
+       return;
+}
+
+/*
+ * m68k_console_print is registered for printk.
+ */
+void console_print_68328(const char *p)
+{
+       char c;
+       
+       while((c=*(p++)) != 0) {
+               if(c == '\n')
+                       rs_put_char('\r');
+               rs_put_char(c);
+       }
+
+       /* Comment this if you want to have a strict interrupt-driven output */
+       rs_fair_output();
+
+       return;
+}
+
+static void rs_set_ldisc(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
+               return;
+
+       info->is_cons = (tty->termios->c_line == N_TTY);
+       
+       printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
+               return;
+#ifndef USE_INTS
+       for(;;) {
+#endif
+
+       /* Enable transmitter */
+       local_irq_save(flags);
+
+       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+                       !info->xmit_buf) {
+               local_irq_restore(flags);
+               return;
+       }
+
+#ifdef USE_INTS
+       uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+       uart->ustcnt |= USTCNT_TXEN;
+#endif
+
+#ifdef USE_INTS
+       if (uart->utx.w & UTX_TX_AVAIL) {
+#else
+       if (1) {
+#endif
+               /* Send char */
+               uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+       }
+
+#ifndef USE_INTS
+       while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+       }
+#endif
+       local_irq_restore(flags);
+}
+
+extern void console_printn(const char * b, int count);
+
+static int rs_write(struct tty_struct * tty,
+                   const unsigned char *buf, int count)
+{
+       int     c, total = 0;
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->name, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf)
+               return 0;
+
+       local_save_flags(flags);
+       while (1) {
+               local_irq_disable();            
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
+               local_irq_restore(flags);
+
+               if (c <= 0)
+                       break;
+
+               memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+               local_irq_disable();
+               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt += c;
+               local_irq_restore(flags);
+               buf += c;
+               count -= c;
+               total += c;
+       }
+
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+               /* Enable transmitter */
+               local_irq_disable();            
+#ifndef USE_INTS
+               while(info->xmit_cnt) {
+#endif
+
+               uart->ustcnt |= USTCNT_TXEN;
+#ifdef USE_INTS
+               uart->ustcnt |= USTCNT_TX_INTR_MASK;
+#else
+               while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+#endif
+               if (uart->utx.w & UTX_TX_AVAIL) {
+                       uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+                       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+                       info->xmit_cnt--;
+               }
+
+#ifndef USE_INTS
+               }
+#endif
+               local_irq_restore(flags);
+       }
+
+       return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       int     ret;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
+               return 0;
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
+               return 0;
+       return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       unsigned long flags;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
+               return;
+       local_irq_save(flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       local_irq_restore(flags);
+       tty_wakeup(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               info->x_char = STOP_CHAR(tty);
+
+       /* Turn off RTS line (do this atomic) */
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       info->x_char = START_CHAR(tty);
+       }
+
+       /* Assert RTS line (do this atomic) */
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct m68k_serial * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+  
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = info->port;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_serial_info(struct m68k_serial * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct m68k_serial old_info;
+       int                     retval = 0;
+
+       if (!new_info)
+               return -EFAULT;
+       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+               return -EFAULT;
+       old_info = *info;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((new_serial.baud_base != info->baud_base) ||
+                   (new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~S_USR_MASK) !=
+                    (info->flags & ~S_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~S_USR_MASK) |
+                              (new_serial.flags & S_USR_MASK));
+               info->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~S_FLAGS) |
+                       (new_serial.flags & S_FLAGS));
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+       retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
+{
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       m68328_uart *uart = &uart_addr[info->line];
+#endif
+       unsigned char status;
+       unsigned long flags;
+
+       local_irq_save(flags);
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+       status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
+#else
+       status = 0;
+#endif
+       local_irq_restore(flags);
+       return put_user(status, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(struct m68k_serial * info, unsigned int duration)
+{
+       m68328_uart *uart = &uart_addr[info->line];
+        unsigned long flags;
+        if (!info->port)
+                return;
+        local_irq_save(flags);
+#ifdef USE_INTS        
+       uart->utx.w |= UTX_SEND_BREAK;
+       msleep_interruptible(duration);
+       uart->utx.w &= ~UTX_SEND_BREAK;
+#endif         
+        local_irq_restore(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       int retval;
+
+       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (!arg)
+                               send_break(info, 250);  /* 1/4 second */
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       send_break(info, arg ? arg*(100) : 250);
+                       return 0;
+               case TIOCGSERIAL:
+                       return get_serial_info(info,
+                                      (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+               case TIOCSERGSTRUCT:
+                       if (copy_to_user((struct m68k_serial *) arg,
+                                   info, sizeof(struct m68k_serial)))
+                               return -EFAULT;
+                       return 0;
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+       change_speed(info);
+
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+       
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       m68328_uart *uart = &uart_addr[info->line];
+       unsigned long flags;
+
+       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+               return;
+       
+       local_irq_save(flags);
+       
+       if (tty_hung_up_p(filp)) {
+               local_irq_restore(flags);
+               return;
+       }
+       
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk("rs_close: bad serial port count for ttyS%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               local_irq_restore(flags);
+               return;
+       }
+       info->flags |= S_CLOSING;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != S_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+
+       uart->ustcnt &= ~USTCNT_RXEN;
+       uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
+
+       shutdown(info);
+       rs_flush_buffer(tty);
+               
+       tty_ldisc_flush(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = NULL;
+#warning "This is not and has never been valid so fix it"      
+#if 0
+       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+               if (tty->ldisc.close)
+                       (tty->ldisc.close)(tty);
+               tty->ldisc = ldiscs[N_TTY];
+               tty->termios->c_line = N_TTY;
+               if (tty->ldisc.open)
+                       (tty->ldisc.open)(tty);
+       }
+#endif 
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+       struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
+               return;
+       
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~S_NORMAL_ACTIVE;
+       info->tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct m68k_serial *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (info->flags & S_CLOSING) {
+               interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & S_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+       
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR))) {
+               info->flags |= S_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL)
+               do_clocal = 1;
+
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+
+       info->count--;
+       info->blocked_open++;
+       while (1) {
+               local_irq_disable();
+               m68k_rtsdtr(info, 1);
+               local_irq_enable();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & S_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & S_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & S_CLOSING) && do_clocal)
+                       break;
+                if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               info->count++;
+       info->blocked_open--;
+
+       if (retval)
+               return retval;
+       info->flags |= S_NORMAL_ACTIVE;
+       return 0;
+}      
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its S structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct m68k_serial      *info;
+       int                     retval, line;
+
+       line = tty->index;
+       
+       if (line >= NR_PORTS || line < 0) /* we have exactly one */
+               return -ENODEV;
+
+       info = &m68k_soft[line];
+
+       if (serial_paranoia_check(info, tty->name, "rs_open"))
+               return -ENODEV;
+
+       info->count++;
+       tty->driver_data = info;
+       info->tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       return block_til_ready(tty, filp, info);
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk("MC68328 serial driver version 1.00\n");
+}
+
+static const struct tty_operations rs_ops = {
+       .open = rs_open,
+       .close = rs_close,
+       .write = rs_write,
+       .flush_chars = rs_flush_chars,
+       .write_room = rs_write_room,
+       .chars_in_buffer = rs_chars_in_buffer,
+       .flush_buffer = rs_flush_buffer,
+       .ioctl = rs_ioctl,
+       .throttle = rs_throttle,
+       .unthrottle = rs_unthrottle,
+       .set_termios = rs_set_termios,
+       .stop = rs_stop,
+       .start = rs_start,
+       .hangup = rs_hangup,
+       .set_ldisc = rs_set_ldisc,
+};
+
+/* rs_init inits the driver */
+static int __init
+rs68328_init(void)
+{
+       int flags, i;
+       struct m68k_serial *info;
+
+       serial_driver = alloc_tty_driver(NR_PORTS);
+       if (!serial_driver)
+               return -ENOMEM;
+
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       /* SPARC: Not all of this is exactly right for us. */
+       
+       serial_driver->name = "ttyS";
+       serial_driver->major = TTY_MAJOR;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag = 
+                       m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(serial_driver, &rs_ops);
+
+       if (tty_register_driver(serial_driver)) {
+               put_tty_driver(serial_driver);
+               printk(KERN_ERR "Couldn't register serial driver\n");
+               return -ENOMEM;
+       }
+
+       local_irq_save(flags);
+
+       for(i=0;i<NR_PORTS;i++) {
+
+           info = &m68k_soft[i];
+           info->magic = SERIAL_MAGIC;
+           info->port = (int) &uart_addr[i];
+           info->tty = NULL;
+           info->irq = uart_irqs[i];
+           info->custom_divisor = 16;
+           info->close_delay = 50;
+           info->closing_wait = 3000;
+           info->x_char = 0;
+           info->event = 0;
+           info->count = 0;
+           info->blocked_open = 0;
+           INIT_WORK(&info->tqueue, do_softint);
+           INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
+           init_waitqueue_head(&info->open_wait);
+           init_waitqueue_head(&info->close_wait);
+           info->line = i;
+           info->is_cons = 1; /* Means shortcuts work */
+           
+           printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, 
+                  info->port, info->irq);
+           printk(" is a builtin MC68328 UART\n");
+           
+#ifdef CONFIG_M68VZ328
+               if (i > 0 )
+                       PJSEL &= 0xCF;  /* PSW enable second port output */
+#endif
+
+           if (request_irq(uart_irqs[i],
+                           rs_interrupt,
+                           IRQF_DISABLED,
+                           "M68328_UART", info))
+                panic("Unable to attach 68328 serial interrupt\n");
+       }
+       local_irq_restore(flags);
+       return 0;
+}
+
+module_init(rs68328_init);
+
+
+
+static void m68328_set_baud(void)
+{
+       unsigned short ustcnt;
+       int     i;
+
+       ustcnt = USTCNT;
+       USTCNT = ustcnt & ~USTCNT_TXEN;
+
+again:
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
+               if (baud_table[i] == m68328_console_baud)
+                       break;
+       if (i >= ARRAY_SIZE(baud_table)) {
+               m68328_console_baud = 9600;
+               goto again;
+       }
+
+       UBAUD = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+               PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+       ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+       ustcnt |= USTCNT_8_7;
+       ustcnt |= USTCNT_TXEN;
+       USTCNT = ustcnt;
+       m68328_console_initted = 1;
+       return;
+}
+
+
+int m68328_console_setup(struct console *cp, char *arg)
+{
+       int             i, n = CONSOLE_BAUD_RATE;
+
+       if (!cp)
+               return(-1);
+
+       if (arg)
+               n = simple_strtoul(arg,NULL,0);
+
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
+               if (baud_table[i] == n)
+                       break;
+       if (i < ARRAY_SIZE(baud_table)) {
+               m68328_console_baud = n;
+               m68328_console_cbaud = 0;
+               if (i > 15) {
+                       m68328_console_cbaud |= CBAUDEX;
+                       i -= 15;
+               }
+               m68328_console_cbaud |= i;
+       }
+
+       m68328_set_baud(); /* make sure baud rate changes */
+       return(0);
+}
+
+
+static struct tty_driver *m68328_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return serial_driver;
+}
+
+
+void m68328_console_write (struct console *co, const char *str,
+                          unsigned int count)
+{
+       if (!m68328_console_initted)
+               m68328_set_baud();
+    while (count--) {
+        if (*str == '\n')
+           rs_put_char('\r');
+        rs_put_char( *str++ );
+    }
+}
+
+
+static struct console m68328_driver = {
+       .name           = "ttyS",
+       .write          = m68328_console_write,
+       .device         = m68328_console_device,
+       .setup          = m68328_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+
+static int __init m68328_console_init(void)
+{
+       register_console(&m68328_driver);
+       return 0;
+}
+
+console_initcall(m68328_console_init);
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h
new file mode 100644 (file)
index 0000000..664ceb0
--- /dev/null
@@ -0,0 +1,188 @@
+/* 68328serial.h: Definitions for the mc68328 serial driver.
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ */
+
+#ifndef _MC683XX_SERIAL_H
+#define _MC683XX_SERIAL_H
+
+
+struct serial_struct {
+       int     type;
+       int     line;
+       int     port;
+       int     irq;
+       int     flags;
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     baud_base;
+       unsigned short  close_delay;
+       char    reserved_char[2];
+       int     hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+       int     reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define S_CLOSING_WAIT_INF     0
+#define S_CLOSING_WAIT_NONE    65535
+
+/*
+ * Definitions for S_struct (and serial_struct) flags field
+ */
+#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define S_FOURPORT  0x0002     /* Set OU1, OUT2 per AST Fourport settings */
+#define S_SAK  0x0004  /* Secure Attention Key (Orange book) */
+#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define S_SPD_MASK     0x0030
+#define S_SPD_HI       0x0010  /* Use 56000 instead of 38400 bps */
+
+#define S_SPD_VHI      0x0020  /* Use 115200 instead of 38400 bps */
+#define S_SPD_CUST     0x0030  /* Use user-specified divisor */
+
+#define S_SKIP_TEST    0x0040 /* Skip UART test during autoconfiguration */
+#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define S_FLAGS        0x0FFF  /* Possible legal S flags */
+#define S_USR_MASK 0x0430      /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define S_INITIALIZED  0x80000000 /* Serial port was initialized */
+#define S_CALLOUT_ACTIVE       0x40000000 /* Call out device is active */
+#define S_NORMAL_ACTIVE        0x20000000 /* Normal device is active */
+#define S_BOOT_AUTOCONF        0x10000000 /* Autoconfigure port on bootup */
+#define S_CLOSING              0x08000000 /* Serial port is closing */
+#define S_CTS_FLOW             0x04000000 /* Do CTS flow control */
+#define S_CHECK_CD             0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to 
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ *                                  -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
+
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real  328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ *                                  -- Vladimir Gurevich
+ */
+
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
+
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct m68k_serial {
+       char soft_carrier;  /* Use soft carrier on this channel */
+       char break_abort;   /* Is serial console in, so process brk/abrt */
+       char is_cons;       /* Is this our console. */
+
+       /* We need to know the current clock divisor
+        * to read the bps rate the chip has currently
+        * loaded.
+        */
+       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+       int baud;
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+       int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     xmit_fifo_size;
+       int                     custom_divisor;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+       int                     xmit_cnt;
+       struct work_struct      tqueue;
+       struct work_struct      tqueue_hangup;
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+/* 
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
+#define UART_IRQ_DEFNS {UART_IRQ_NUM}
+
+#endif /* __KERNEL__ */
+#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c
new file mode 100644 (file)
index 0000000..bc21eea
--- /dev/null
@@ -0,0 +1,2979 @@
+/*
+ *  UART driver for 68360 CPM SCC or SMC
+ *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
+ *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
+ *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *
+ * I used the serial.c driver as the framework for this driver.
+ * Give credit to those guys.
+ * The original code was written for the MBX860 board.  I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs, but this has never been tested, nor is it complete.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ *     int rs_360_init(void);
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serialP.h> 
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/m68360.h>
+#include <asm/commproc.h>
+
+#ifdef CONFIG_KGDB
+extern void breakpoint(void);
+extern void set_debug_traps(void);
+extern int  kgdb_output_string (const char* s, unsigned int count);
+#endif
+
+
+/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
+#include <linux/console.h>
+#include <linux/jiffies.h>
+
+/* this defines the index into rs_table for the port to use
+ */
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT     1 /* ie SMC2 - note USE_SMC2 must be defined */
+#endif
+/* #endif */
+
+#if 0
+/* SCC2 for console
+ */
+#undef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT     2
+#endif
+
+
+#define TX_WAKEUP      ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.03";
+
+static struct tty_driver *serial_driver;
+int serial_console_setup(struct console *co, char *options);
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+  
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs.  For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
+ * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
+ * a flag indicating SCC or SMC, and the number is used as an index into
+ * the CPM parameter area for this device.
+ * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
+ * not currently used.  I should probably use it to indicate the port
+ * type of SMC or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num    hub6
+#define NUM_IS_SCC     ((int)0x00010000)
+#define PORT_NUM(P)    ((P) & 0x0000ffff)
+
+
+#if defined (CONFIG_UCQUICC)
+
+volatile extern void *_periph_base;
+/* sipex transceiver
+ *   mode bits for       are on pins
+ *
+ *    SCC2                d16..19
+ *    SCC3                d20..23
+ *    SCC4                d24..27
+ */
+#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
+
+static uint sipex_mode_bits = 0x00000000;
+
+#endif
+
+/* There is no `serial_state' defined back here in 2.0.
+ * Try to get by with serial_struct
+ */
+/* #define serial_state serial_struct */
+
+/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
+ * extras: */
+
+#if 0
+struct async_icount_24 {
+       __u32   cts, dsr, rng, dcd, tx, rx;
+       __u32   frame, parity, overrun, brk;
+       __u32   buf_overrun;
+} icount;
+#endif
+
+#if 0
+
+struct serial_state {
+        int     magic;
+        int     baud_base;
+        unsigned long   port;
+        int     irq;
+        int     flags;
+        int     hub6;
+        int     type;
+        int     line;
+        int     revision;       /* Chip revision (950) */
+        int     xmit_fifo_size;
+        int     custom_divisor;
+        int     count;
+        u8      *iomem_base;
+        u16     iomem_reg_shift;
+        unsigned short  close_delay;
+        unsigned short  closing_wait; /* time to wait before closing */
+        struct async_icount_24     icount; 
+        int     io_type;
+        struct async_struct *info;
+};
+#endif
+
+#define SSTATE_MAGIC 0x5302
+
+
+
+/* SMC2 is sometimes used for low performance TDM interfaces.  Define
+ * this as 1 if you want SMC2 as a serial port UART managed by this driver.
+ * Define this as 0 if you wish to use SMC2 for something else.
+ */
+#define USE_SMC2 1
+
+#if 0
+/* Define SCC to ttySx mapping. */
+#define SCC_NUM_BASE   (USE_SMC2 + 1)  /* SCC base tty "number" */
+
+/* Define which SCC is the first one to use for a serial port.  These
+ * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
+ * for Ethernet, and the first available SCC for serial UART is SCC2.
+ * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
+ * interrupt vectors in the table below to match.
+ */
+#define SCC_IDX_BASE   1       /* table index */
+#endif
+
+
+/* Processors other than the 860 only get SMCs configured by default.
+ * Either they don't have SCCs or they are allocated somewhere else.
+ * Of course, there are now 860s without some SCCs, so we will need to
+ * address that someday.
+ * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
+ * stereo codec parts, and we use SMC2 to help support that.
+ */
+static struct serial_state rs_table[] = {
+/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
+       {  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
+#if USE_SMC2
+       ,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
+#endif
+
+#if defined(CONFIG_SERIAL_68360_SCC)
+       ,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
+       ,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
+       ,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
+#endif
+};
+
+#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
+
+/* The number of buffer descriptors and their sizes.
+ */
+#define RX_NUM_FIFO    4
+#define RX_BUF_SIZE    32
+#define TX_NUM_FIFO    4
+#define TX_BUF_SIZE    32
+
+#define CONSOLE_NUM_FIFO 2
+#define CONSOLE_BUF_SIZE 4
+
+char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+       int                     magic;
+       int                     flags;
+
+       struct serial_state     *state;
+       /* struct serial_struct *state; */
+       /* struct async_struct  *state; */
+       
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     line;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     blocked_open; /* # of blocked opens */
+       struct work_struct      tqueue;
+       struct work_struct      tqueue_hangup;
+       wait_queue_head_t       open_wait; 
+       wait_queue_head_t       close_wait; 
+
+       
+/* CPM Buffer Descriptor pointers.
+       */
+       QUICC_BD                        *rx_bd_base;
+       QUICC_BD                        *rx_cur;
+       QUICC_BD                        *tx_bd_base;
+       QUICC_BD                        *tx_cur;
+} ser_info_t;
+
+
+/* since kmalloc_init() does not get called until much after this initialization: */
+static ser_info_t  quicc_ser_info[NR_PORTS];
+static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
+static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
+
+static void change_speed(ser_info_t *info);
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+                                       char *name, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%s) in %s\n";
+       static const char *badinfo =
+               "Warning: null async_struct for (%s) in %s\n";
+
+       if (!info) {
+               printk(badinfo, name, routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, name, routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value.  The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+/* This sucks. There is a better way: */
+#if defined(CONFIG_CONSOLE_9600)
+  #define CONSOLE_BAUDRATE 9600
+#elif defined(CONFIG_CONSOLE_19200)
+  #define CONSOLE_BAUDRATE 19200
+#elif defined(CONFIG_CONSOLE_115200)
+  #define CONSOLE_BAUDRATE 115200
+#else
+  #warning "console baud rate undefined"
+  #define CONSOLE_BAUDRATE 9600
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_360_stop(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_regs *smcp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_sccm &= ~UART_SCCM_TX;
+       } else {
+               /* smcp = &cpmp->cp_smc[idx]; */
+               smcp = &pquicc->smc_regs[idx];
+               smcp->smc_smcm &= ~SMCM_TX;
+       }
+       local_irq_restore(flags);
+}
+
+
+static void rs_360_start(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_regs *smcp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_stop"))
+               return;
+       
+       local_irq_save(flags);
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_sccm |= UART_SCCM_TX;
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+               smcp->smc_smcm |= SMCM_TX;
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+       struct tty_struct *tty = info->port.tty;
+       unsigned char ch, flag, *cp;
+       /*int   ignored = 0;*/
+       int     i;
+       ushort  status;
+        struct async_icount *icount; 
+       /* struct       async_icount_24 *icount; */
+       volatile QUICC_BD       *bdp;
+
+       icount = &info->state->icount;
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = info->rx_cur;
+       for (;;) {
+               if (bdp->status & BD_SC_EMPTY)  /* If this one is empty */
+                       break;                  /*   we are all done */
+
+               /* The read status mask tell us what we should do with
+                * incoming characters, especially if errors occur.
+                * One special case is the use of BD_SC_EMPTY.  If
+                * this is not set, we are supposed to be ignoring
+                * inputs.  In this case, just mark the buffer empty and
+                * continue.
+                */
+               if (!(info->read_status_mask & BD_SC_EMPTY)) {
+                       bdp->status |= BD_SC_EMPTY;
+                       bdp->status &=
+                               ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+                       if (bdp->status & BD_SC_WRAP)
+                               bdp = info->rx_bd_base;
+                       else
+                               bdp++;
+                       continue;
+               }
+
+               /* Get the number of characters and the buffer pointer.
+               */
+               i = bdp->length;
+               /* cp = (unsigned char *)__va(bdp->buf); */
+               cp = (char *)bdp->buf;
+               status = bdp->status;
+
+               while (i-- > 0) {
+                       ch = *cp++;
+                       icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+                       printk("DR%02x:%02x...", ch, status);
+#endif
+                       flag = TTY_NORMAL;
+
+                       if (status & (BD_SC_BR | BD_SC_FR |
+                                      BD_SC_PR | BD_SC_OV)) {
+                               /*
+                                * For statistics only
+                                */
+                               if (status & BD_SC_BR)
+                                       icount->brk++;
+                               else if (status & BD_SC_PR)
+                                       icount->parity++;
+                               else if (status & BD_SC_FR)
+                                       icount->frame++;
+                               if (status & BD_SC_OV)
+                                       icount->overrun++;
+
+                               /*
+                                * Now check to see if character should be
+                                * ignored, and mask off conditions which
+                                * should be ignored.
+                               if (status & info->ignore_status_mask) {
+                                       if (++ignored > 100)
+                                               break;
+                                       continue;
+                               }
+                                */
+                               status &= info->read_status_mask;
+               
+                               if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+                                       printk("handling break....");
+#endif
+                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
+                                       if (info->flags & ASYNC_SAK)
+                                               do_SAK(tty);
+                               } else if (status & BD_SC_PR)
+                                       flag = TTY_PARITY;
+                               else if (status & BD_SC_FR)
+                                       flag = TTY_FRAME;
+                       }
+                       tty_insert_flip_char(tty, ch, flag);
+                       if (status & BD_SC_OV)
+                               /*
+                                * Overrun is special, since it's
+                                * reported immediately, and doesn't
+                                * affect the current character
+                                */
+                               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+
+               /* This BD is ready to be used again.  Clear status.
+                * Get next BD.
+                */
+               bdp->status |= BD_SC_EMPTY;
+               bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = info->rx_bd_base;
+               else
+                       bdp++;
+       }
+
+       info->rx_cur = (QUICC_BD *)bdp;
+
+       tty_schedule_flip(tty);
+}
+
+static _INLINE_ void receive_break(ser_info_t *info)
+{
+       struct tty_struct *tty = info->port.tty;
+
+       info->state->icount.brk++;
+       /* Check to see if there is room in the tty buffer for
+        * the break.  If not, we exit now, losing the break.  FIXME
+        */
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       tty_schedule_flip(tty);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+
+       if ((info->flags & TX_WAKEUP) ||
+           (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+               schedule_work(&info->tqueue);
+       }
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+       /* I need to do this for the SCCs, so it is left as a reminder.
+       */
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+       int     status;
+       /* struct       async_icount *icount; */
+       struct  async_icount_24 *icount;
+       
+       status = serial_in(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->state->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                           (status & UART_MSR_DCD))
+                               hardpps();
+#endif
+               }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("scheduling hangup...");
+#endif
+                       queue_task(&info->tqueue_hangup,
+                                          &tq_scheduler);
+               }
+       }
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->port.tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->port.tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->port.tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                       }
+               }
+       }
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
+static void rs_360_interrupt(int vec, void *dev_id)
+{
+       u_char  events;
+       int     idx;
+       ser_info_t *info;
+       volatile struct smc_regs *smcp;
+       volatile struct scc_regs *sccp;
+       
+       info = dev_id;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               events = sccp->scc_scce;
+               if (events & SCCM_RX)
+                       receive_chars(info);
+               if (events & SCCM_TX)
+                       transmit_chars(info);
+               sccp->scc_scce = events;
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+               events = smcp->smc_smce;
+               if (events & SMCM_BRKE)
+                       receive_break(info);
+               if (events & SMCM_RX)
+                       receive_chars(info);
+               if (events & SMCM_TX)
+                       transmit_chars(info);
+               smcp->smc_smce = events;
+       }
+       
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d, %x)...",
+                                       info->state->smc_scc_num, events);
+#endif
+#ifdef modem_control
+       check_modem_status(info);
+#endif
+       info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+
+static void do_softint(void *private_)
+{
+       ser_info_t      *info = (ser_info_t *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
+               tty_wakeup(tty);
+}
+
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+       struct async_struct     *info = (struct async_struct *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+
+static int startup(ser_info_t *info)
+{
+       unsigned long flags;
+       int     retval=0;
+       int     idx;
+       /*struct serial_state *state = info->state;*/
+       volatile struct smc_regs *smcp;
+       volatile struct scc_regs *sccp;
+       volatile struct smc_uart_pram   *up;
+       volatile struct uart_pram           *scup;
+
+
+       local_irq_save(flags);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               goto errout;
+       }
+
+#ifdef maybe
+       if (!state->port || !state->type) {
+               if (info->port.tty)
+                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+               goto errout;
+       }
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+       info->MCR = 0;
+       if (info->port.tty->termios->c_cflag & CBAUD)
+               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+       
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info);
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               scup = &pquicc->pram[info->state->port].scc.pscc.u;
+
+               scup->mrblr = RX_BUF_SIZE;
+               scup->max_idl = RX_BUF_SIZE;
+
+               sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
+               sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+
+               /* Enable interrupts and I/O.
+               */
+               smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+               smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+               /* We can tune the buffer length and idle characters
+                * to take advantage of the entire incoming buffer size.
+                * If mrblr is something other than 1, maxidl has to be
+                * non-zero or we never get an interrupt.  The maxidl
+                * is the number of character times we wait after reception
+                * of the last character before we decide no more characters
+                * are coming.
+                */
+               /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
+               /* holy unionized structures, Batman: */
+               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+               up->mrblr = RX_BUF_SIZE;
+               up->max_idl = RX_BUF_SIZE;
+
+               up->brkcr = 1;  /* number of break chars */
+       }
+
+       info->flags |= ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+       return 0;
+       
+errout:
+       local_irq_restore(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t *info)
+{
+       unsigned long   flags;
+       struct serial_state *state;
+       int             idx;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              state->irq);
+#endif
+       
+       local_irq_save(flags);
+
+       idx = PORT_NUM(state->smc_scc_num);
+       if (state->smc_scc_num & NUM_IS_SCC) {
+               sccp = &pquicc->scc_regs[idx];
+               sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* We can't disable the transmitter if this is the
+                * system console.
+                */
+               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+               sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+       } else {
+               smcp = &pquicc->smc_regs[idx];
+
+               /* Disable interrupts and I/O.
+                */
+               smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* We can't disable the transmitter if this is the
+                * system console.
+                */
+               if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       }
+       
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+       int     baud_rate;
+       unsigned cflag, cval, scval, prev_mode;
+       int     i, bits, sbits, idx;
+       unsigned long   flags;
+       struct serial_state *state;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!info->port.tty || !info->port.tty->termios)
+               return;
+       cflag = info->port.tty->termios->c_cflag;
+
+       state = info->state;
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+       scval = 0;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: bits = 5; break;
+             case CS6: bits = 6; break;
+             case CS7: bits = 7; break;
+             case CS8: bits = 8; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  bits = 8; break;
+       }
+       sbits = bits - 5;
+
+       if (cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               scval |= SCU_PMSR_SL;
+               bits++;
+       }
+       if (cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               scval |= SCU_PMSR_PEN;
+               bits++;
+       }
+       if (!(cflag & PARODD)) {
+               cval |= SMCMR_PM_EVEN;
+               scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
+       }
+
+       /* Determine divisor based on baud rate */
+       i = cflag & CBAUD;
+       if (i >= (sizeof(baud_table)/sizeof(int)))
+               baud_rate = 9600;
+       else
+               baud_rate = baud_table[i];
+
+       info->timeout = (TX_BUF_SIZE*HZ*bits);
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+#ifdef modem_control
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       if (info->flags & ASYNC_HARDPPS_CD)
+               info->IER |= UART_IER_MSI;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+       } else
+               info->flags &= ~ASYNC_CTS_FLOW;
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       serial_out(info, UART_IER, info->IER);
+#endif
+
+       /*
+        * Set up parity check flag
+        */
+       info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (I_INPCK(info->port.tty))
+               info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+               info->read_status_mask |= BD_SC_BR;
+       
+       /*
+        * Characters to ignore
+        */
+       info->ignore_status_mask = 0;
+       if (I_IGNPAR(info->port.tty))
+               info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (I_IGNBRK(info->port.tty)) {
+               info->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore 
+                * overruns too.  (For real raw support).
+                */
+               if (I_IGNPAR(info->port.tty))
+                       info->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+        info->read_status_mask &= ~BD_SC_EMPTY;
+        local_irq_save(flags);
+
+        /* Start bit has not been added (so don't, because we would just
+         * subtract it later), and we need to add one for the number of
+         * stops bits (there is always at least one).
+         */
+        bits++;
+        idx = PORT_NUM(state->smc_scc_num);
+        if (state->smc_scc_num & NUM_IS_SCC) {
+         sccp = &pquicc->scc_regs[idx];
+         sccp->scc_psmr = (sbits << 12) | scval;
+     } else {
+         smcp = &pquicc->smc_regs[idx];
+
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = smcp->smc_smcmr;
+               smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
+               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+       }
+
+       m360_cpm_setbrg((state - rs_table), baud_rate);
+
+       local_irq_restore(flags);
+}
+
+static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile QUICC_BD       *bdp;
+
+       if (serial_paranoia_check(info, tty->name, "rs_put_char"))
+               return 0;
+
+       if (!tty)
+               return 0;
+
+       bdp = info->tx_cur;
+       while (bdp->status & BD_SC_READY);
+
+       /* *((char *)__va(bdp->buf)) = ch; */
+       *((char *)bdp->buf) = ch;
+       bdp->length = 1;
+       bdp->status |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->status & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (QUICC_BD *)bdp;
+       return 1;
+
+}
+
+static int rs_360_write(struct tty_struct * tty,
+                   const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile QUICC_BD *bdp;
+
+#ifdef CONFIG_KGDB
+       /* Try to let stub handle output. Returns true if it did. */ 
+       if (kgdb_output_string(buf, count))
+               return ret;
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_write"))
+               return 0;
+
+       if (!tty) 
+               return 0;
+
+       bdp = info->tx_cur;
+
+       while (1) {
+               c = min(count, TX_BUF_SIZE);
+
+               if (c <= 0)
+                       break;
+
+               if (bdp->status & BD_SC_READY) {
+                       info->flags |= TX_WAKEUP;
+                       break;
+               }
+
+               /* memcpy(__va(bdp->buf), buf, c); */
+               memcpy((void *)bdp->buf, buf, c);
+
+               bdp->length = c;
+               bdp->status |= BD_SC_READY;
+
+               buf += c;
+               count -= c;
+               ret += c;
+
+               /* Get next BD.
+               */
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = info->tx_bd_base;
+               else
+                       bdp++;
+               info->tx_cur = (QUICC_BD *)bdp;
+       }
+       return ret;
+}
+
+static int rs_360_write_room(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     ret;
+
+       if (serial_paranoia_check(info, tty->name, "rs_write_room"))
+               return 0;
+
+       if ((info->tx_cur->status & BD_SC_READY) == 0) {
+               info->flags &= ~TX_WAKEUP;
+               ret = TX_BUF_SIZE;
+       }
+       else {
+               info->flags |= TX_WAKEUP;
+               ret = 0;
+       }
+       return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_360_chars_in_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
+               return 0;
+       return 0;
+}
+
+static void rs_360_flush_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
+               return;
+
+       /* There is nothing to "flush", whatever we gave the CPM
+        * is on its way out.
+        */
+       tty_wakeup(tty);
+       info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_360_send_xchar(struct tty_struct *tty, char ch)
+{
+       volatile QUICC_BD       *bdp;
+
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->name, "rs_send_char"))
+               return;
+
+       bdp = info->tx_cur;
+       while (bdp->status & BD_SC_READY);
+
+       /* *((char *)__va(bdp->buf)) = ch; */
+       *((char *)bdp->buf) = ch;
+       bdp->length = 1;
+       bdp->status |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->status & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (QUICC_BD *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_360_throttle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               rs_360_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR &= ~UART_MCR_RTS;
+
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+}
+
+static void rs_360_unthrottle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_360_send_xchar(tty, START_CHAR(tty));
+       }
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR |= UART_MCR_RTS;
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+       unsigned char status;
+       unsigned int result;
+
+       local_irq_disable();
+       status = serial_in(info, UART_LSR);
+       local_irq_enable();
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+       return put_user(result,value);
+}
+#endif
+
+static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned int result = 0;
+#ifdef modem_control
+       unsigned char control, status;
+
+       if (serial_paranoia_check(info, tty->name, __func__))
+               return -ENODEV;
+
+       if (tty->flags & (1 << TTY_IO_ERROR))
+               return -EIO;
+
+       control = info->MCR;
+       local_irq_disable();
+       status = serial_in(info, UART_MSR);
+       local_irq_enable();
+       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+       return result;
+}
+
+static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
+                          unsigned int set, unsigned int clear)
+{
+#ifdef modem_control
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned int arg;
+
+       if (serial_paranoia_check(info, tty->name, __func__))
+               return -ENODEV;
+
+       if (tty->flags & (1 << TTY_IO_ERROR))
+               return -EIO;
+       /* FIXME: locking on info->mcr */
+       if (set & TIOCM_RTS)
+               info->mcr |= UART_MCR_RTS;
+       if (set & TIOCM_DTR)
+               info->mcr |= UART_MCR_DTR;
+       if (clear & TIOCM_RTS)
+               info->MCR &= ~UART_MCR_RTS;
+       if (clear & TIOCM_DTR)
+               info->MCR &= ~UART_MCR_DTR;
+
+#ifdef TIOCM_OUT1
+       if (set & TIOCM_OUT1)
+               info->MCR |= UART_MCR_OUT1;
+       if (set & TIOCM_OUT2)
+               info->MCR |= UART_MCR_OUT2;
+       if (clear & TIOCM_OUT1)
+               info->MCR &= ~UART_MCR_OUT1;
+       if (clear & TIOCM_OUT2)
+               info->MCR &= ~UART_MCR_OUT2;
+#endif
+
+       local_irq_disable();
+       serial_out(info, UART_MCR, info->MCR);
+       local_irq_enable();
+#endif
+       return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command.  We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static ushort  smc_chan_map[] = {
+       CPM_CR_CH_SMC1,
+       CPM_CR_CH_SMC2
+};
+
+static ushort  scc_chan_map[] = {
+       CPM_CR_CH_SCC1,
+       CPM_CR_CH_SCC2,
+       CPM_CR_CH_SCC3,
+       CPM_CR_CH_SCC4
+};
+
+static void begin_break(ser_info_t *info)
+{
+       volatile QUICC *cp;
+       ushort  chan;
+       int     idx;
+
+       cp = pquicc;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC)
+               chan = scc_chan_map[idx];
+       else
+               chan = smc_chan_map[idx];
+
+       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
+       while (cp->cp_cr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+       volatile QUICC *cp;
+       ushort  chan;
+       int idx;
+
+       cp = pquicc;
+
+       idx = PORT_NUM(info->state->smc_scc_num);
+       if (info->state->smc_scc_num & NUM_IS_SCC)
+               chan = scc_chan_map[idx];
+       else
+               chan = smc_chan_map[idx];
+
+       cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+       while (cp->cp_cr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, unsigned int duration)
+{
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+       begin_break(info);
+       msleep_interruptible(duration);
+       end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int rs_360_get_icount(struct tty_struct *tty,
+                               struct serial_icounter_struct *icount)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct async_icount cnow;
+
+       local_irq_disable();
+       cnow = info->state->icount;
+       local_irq_enable();
+
+       icount->cts = cnow.cts;
+       icount->dsr = cnow.dsr;
+       icount->rng = cnow.rng;
+       icount->dcd = cnow.dcd;
+
+       return 0;
+}
+
+static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int retval;
+       struct async_icount cnow; 
+       /* struct async_icount_24 cnow;*/       /* kernel counter temps */
+       struct serial_icounter_struct *p_cuser; /* user space */
+
+       if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+               return -ENODEV;
+
+       if (cmd != TIOCMIWAIT) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       if (!arg) {
+                               send_break(info, 250);  /* 1/4 second */
+                               if (signal_pending(current))
+                                       return -EINTR;
+                       }
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       send_break(info, arg ? arg*100 : 250);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return 0;
+               case TIOCSBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       begin_break(info);
+                       return 0;
+               case TIOCCBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       end_break(info);
+                       return 0;
+#ifdef maybe
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+#endif
+               /*
+                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                * - mask passed in arg for lines of interest
+                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                * Caller should use TIOCGICOUNT to see which one it was
+                */
+                case TIOCMIWAIT:
+#ifdef modem_control
+                       local_irq_disable();
+                       /* note the counters on entry */
+                       cprev = info->state->icount;
+                       local_irq_enable();
+                       while (1) {
+                               interruptible_sleep_on(&info->delta_msr_wait);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                               local_irq_disable();
+                               cnow = info->state->icount; /* atomic copy */
+                               local_irq_enable();
+                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+                                       return -EIO; /* no change => error */
+                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+                                       return 0;
+                               }
+                               cprev = cnow;
+                       }
+                       /* NOTREACHED */
+#else
+                       return 0;
+#endif
+
+
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       change_speed(info);
+
+#ifdef modem_control
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) &&
+           !(tty->termios->c_cflag & CBAUD)) {
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               local_irq_disable();
+               serial_out(info, UART_MCR, info->MCR);
+               local_irq_enable();
+       }
+       
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           (tty->termios->c_cflag & CBAUD)) {
+               info->MCR |= UART_MCR_DTR;
+               if (!tty->hw_stopped ||
+                   !(tty->termios->c_cflag & CRTSCTS)) {
+                       info->MCR |= UART_MCR_RTS;
+               }
+               local_irq_disable();
+               serial_out(info, UART_MCR, info->MCR);
+               local_irq_enable();
+       }
+       
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_360_start(tty);
+       }
+#endif
+
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_360_close(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       /* struct async_state *state; */
+       struct serial_state *state;
+       unsigned long   flags;
+       int             idx;
+       volatile struct smc_regs        *smcp;
+       volatile struct scc_regs        *sccp;
+
+       if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
+               return;
+
+       state = info->state;
+       
+       local_irq_save(flags);
+       
+       if (tty_hung_up_p(filp)) {
+               DBG_CNT("before DEC-hung");
+               local_irq_restore(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+       if ((tty->count == 1) && (state->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  state->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "state->count is %d\n", state->count);
+               state->count = 1;
+       }
+       if (--state->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, state->count);
+               state->count = 0;
+       }
+       if (state->count) {
+               DBG_CNT("before DEC-2");
+               local_irq_restore(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+       info->read_status_mask &= ~BD_SC_EMPTY;
+       if (info->flags & ASYNC_INITIALIZED) {
+
+               idx = PORT_NUM(info->state->smc_scc_num);
+               if (info->state->smc_scc_num & NUM_IS_SCC) {
+                       sccp = &pquicc->scc_regs[idx];
+                       sccp->scc_sccm &= ~UART_SCCM_RX;
+                       sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
+               } else {
+                       smcp = &pquicc->smc_regs[idx];
+                       smcp->smc_smcm &= ~SMCM_RX;
+                       smcp->smc_smcmr &= ~SMCMR_REN;
+               }
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               rs_360_wait_until_sent(tty, info->timeout);
+       }
+       shutdown(info);
+       rs_360_flush_buffer(tty);
+       tty_ldisc_flush(tty);           
+       tty->closing = 0;
+       info->event = 0;
+       info->port.tty = NULL;
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+       /*int lsr;*/
+       volatile QUICC_BD *bdp;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
+               return;
+
+#ifdef maybe
+       if (info->state->type == PORT_UNKNOWN)
+               return;
+#endif
+
+       orig_jiffies = jiffies;
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        * 
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = 1;
+       if (timeout)
+               char_time = min(char_time, (unsigned long)timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk("jiff=%lu...", jiffies);
+#endif
+
+       /* We go through the loop at least once because we can't tell
+        * exactly when the last character exits the shifter.  There can
+        * be at least two characters waiting to be sent after the buffers
+        * are empty.
+        */
+       do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+/*             current->counter = 0;    make us low-priority */
+               msleep_interruptible(jiffies_to_msecs(char_time));
+               if (signal_pending(current))
+                       break;
+               if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
+                       break;
+               /* The 'tx_cur' is really the next buffer to send.  We
+                * have to back up to the previous BD and wait for it
+                * to go.  This isn't perfect, because all this indicates
+                * is the buffer is available.  There are still characters
+                * in the CPM FIFO.
+                */
+               bdp = info->tx_cur;
+               if (bdp == info->tx_bd_base)
+                       bdp += (TX_NUM_FIFO-1);
+               else
+                       bdp--;
+       } while (bdp->status & BD_SC_READY);
+       current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_360_hangup(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct serial_state *state = info->state;
+       
+       if (serial_paranoia_check(info, tty->name, "rs_hangup"))
+               return;
+
+       state = info->state;
+       
+       rs_360_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       state->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->port.tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+       DECLARE_WAITQUEUE(wait, current);
+#endif
+       struct serial_state *state = info->state;
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        * If this is an SMC port, we don't have modem control to wait
+        * for, so just get out here.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR)) ||
+           !(info->state->smc_scc_num & NUM_IS_SCC)) {
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL)
+               do_clocal = 1;
+       
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, state->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+#ifdef DO_THIS_LATER
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              state->line, state->count);
+#endif
+       local_irq_disable();
+       if (!tty_hung_up_p(filp)) 
+               state->count--;
+       local_irq_enable();
+       info->blocked_open++;
+       while (1) {
+               local_irq_disable();
+               if (tty->termios->c_cflag & CBAUD)
+                       serial_out(info, UART_MCR,
+                                  serial_inp(info, UART_MCR) |
+                                  (UART_MCR_DTR | UART_MCR_RTS));
+               local_irq_enable();
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CLOSING) &&
+                   (do_clocal || (serial_in(info, UART_MSR) &
+                                  UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, state->count);
+#endif
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               state->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+       struct serial_state *sstate;
+
+       sstate = rs_table + line;
+       if (sstate->info) {
+               sstate->count++;
+               *ret_info = (ser_info_t *)sstate->info;
+               return 0;
+       }
+       else {
+               return -ENOMEM;
+       }
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_360_open(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t      *info;
+       int             retval, line;
+
+       line = tty->index;
+       if ((line < 0) || (line >= NR_PORTS))
+               return -ENODEV;
+       retval = get_async_struct(line, &info);
+       if (retval)
+               return retval;
+       if (serial_paranoia_check(info, tty->name, "rs_open"))
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s, count = %d\n", tty->name, info->state->count);
+#endif
+       tty->driver_data = info;
+       info->port.tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s successful...", tty->name);
+#endif
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+       struct async_struct *info = state->info, scr_info;
+       char    stat_buf[30], control, status;
+#endif
+       int     ret;
+
+       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+                     state->line,
+                     (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
+                     (unsigned int)(state->port), state->irq);
+
+       if (!state->port || (state->type == PORT_UNKNOWN)) {
+               ret += sprintf(buf+ret, "\n");
+               return ret;
+       }
+
+#ifdef notdef
+       /*
+        * Figure out the current RS-232 lines
+        */
+       if (!info) {
+               info = &scr_info;       /* This is just for serial_{in,out} */
+
+               info->magic = SERIAL_MAGIC;
+               info->port = state->port;
+               info->flags = state->flags;
+               info->quot = 0;
+               info->port.tty = NULL;
+       }
+       local_irq_disable();
+       status = serial_in(info, UART_MSR);
+       control = info ? info->MCR : serial_in(info, UART_MCR);
+       local_irq_enable();
+       
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (control & UART_MCR_RTS)
+               strcat(stat_buf, "|RTS");
+       if (status & UART_MSR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (control & UART_MCR_DTR)
+               strcat(stat_buf, "|DTR");
+       if (status & UART_MSR_DSR)
+               strcat(stat_buf, "|DSR");
+       if (status & UART_MSR_DCD)
+               strcat(stat_buf, "|CD");
+       if (status & UART_MSR_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->quot) {
+               ret += sprintf(buf+ret, " baud:%d",
+                              state->baud_base / info->quot);
+       }
+
+       ret += sprintf(buf+ret, " tx:%d rx:%d",
+                     state->icount.tx, state->icount.rx);
+
+       if (state->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+       
+       if (state->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+       
+       if (state->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+       if (state->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+       return ret;
+}
+
+int rs_360_read_proc(char *page, char **start, off_t off, int count,
+                int *eof, void *data)
+{
+       int i, len = 0;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               len += line_info(page + len, &rs_table[i]);
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (begin-off);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+/*
+ * The serial console driver used during boot.  Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time.  I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void my_console_write(int idx, const char *s,
+                               unsigned count)
+{
+       struct          serial_state    *ser;
+       ser_info_t              *info;
+       unsigned                i;
+       QUICC_BD                *bdp, *bdbase;
+       volatile struct smc_uart_pram   *up;
+       volatile        u_char          *cp;
+
+       ser = rs_table + idx;
+
+
+       /* If the port has been initialized for general use, we have
+        * to use the buffer descriptors allocated there.  Otherwise,
+        * we simply use the single buffer allocated.
+        */
+       if ((info = (ser_info_t *)ser->info) != NULL) {
+               bdp = info->tx_cur;
+               bdbase = info->tx_bd_base;
+       }
+       else {
+               /* Pointer to UART in parameter ram.
+               */
+               /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+               /* Get the address of the host memory buffer.
+                */
+               bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+       }
+
+       /*
+        * We need to gracefully shut down the transmitter, disable
+        * interrupts, then send our bytes out.
+        */
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, s++) {
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while (bdp->status & BD_SC_READY);
+
+               /* Send the character out.
+                */
+               cp = bdp->buf;
+               *cp = *s;
+               
+               bdp->length = 1;
+               bdp->status |= BD_SC_READY;
+
+               if (bdp->status & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*s == 10) {
+                       while (bdp->status & BD_SC_READY);
+                       /* cp = __va(bdp->buf); */
+                       cp = bdp->buf;
+                       *cp = 13;
+                       bdp->length = 1;
+                       bdp->status |= BD_SC_READY;
+
+                       if (bdp->status & BD_SC_WRAP) {
+                               bdp = bdbase;
+                       }
+                       else {
+                               bdp++;
+                       }
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while (bdp->status & BD_SC_READY);
+
+       if (info)
+               info->tx_cur = (QUICC_BD *)bdp;
+}
+
+static void serial_console_write(struct console *c, const char *s,
+                               unsigned count)
+{
+#ifdef CONFIG_KGDB
+       /* Try to let stub handle output. Returns true if it did. */ 
+       if (kgdb_output_string(s, count))
+               return;
+#endif
+       my_console_write(c->index, s, count);
+}
+
+
+
+/*void console_print_68360(const char *p)
+{
+       const char *cp = p;
+       int i;
+
+       for (i=0;cp[i]!=0;i++);
+
+       serial_console_write (p, i);
+
+       //Comment this if you want to have a strict interrupt-driven output
+       //rs_fair_output();
+
+       return;
+}*/
+
+
+
+
+
+
+#ifdef CONFIG_XMON
+int
+xmon_360_write(const char *s, unsigned count)
+{
+       my_console_write(0, s, count);
+       return(count);
+}
+#endif
+
+#ifdef CONFIG_KGDB
+void
+putDebugChar(char ch)
+{
+       my_console_write(0, &ch, 1);
+}
+#endif
+
+/*
+ * Receive character from the serial port.  This only works well
+ * before the port is initialized for real use.
+ */
+static int my_console_wait_key(int idx, int xmon, char *obuf)
+{
+       struct serial_state             *ser;
+       u_char                  c, *cp;
+       ser_info_t              *info;
+       QUICC_BD                *bdp;
+       volatile struct smc_uart_pram   *up;
+       int                             i;
+
+       ser = rs_table + idx;
+
+       /* Get the address of the host memory buffer.
+        * If the port has been initialized for general use, we must
+        * use information from the port structure.
+        */
+       if ((info = (ser_info_t *)ser->info))
+               bdp = info->rx_cur;
+       else
+               /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
+               bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+
+       /* Pointer to UART in parameter ram.
+        */
+       /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+       up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+       /*
+        * We need to gracefully shut down the receiver, disable
+        * interrupts, then read the input.
+        * XMON just wants a poll.  If no character, return -1, else
+        * return the character.
+        */
+       if (!xmon) {
+               while (bdp->status & BD_SC_EMPTY);
+       }
+       else {
+               if (bdp->status & BD_SC_EMPTY)
+                       return -1;
+       }
+
+       cp = (char *)bdp->buf;
+
+       if (obuf) {
+               i = c = bdp->length;
+               while (i-- > 0)
+                       *obuf++ = *cp++;
+       }
+       else {
+               c = *cp;
+       }
+       bdp->status |= BD_SC_EMPTY;
+
+       if (info) {
+               if (bdp->status & BD_SC_WRAP) {
+                       bdp = info->rx_bd_base;
+               }
+               else {
+                       bdp++;
+               }
+               info->rx_cur = (QUICC_BD *)bdp;
+       }
+
+       return((int)c);
+}
+
+static int serial_console_wait_key(struct console *co)
+{
+       return(my_console_wait_key(co->index, 0, NULL));
+}
+
+#ifdef CONFIG_XMON
+int
+xmon_360_read_poll(void)
+{
+       return(my_console_wait_key(0, 1, NULL));
+}
+
+int
+xmon_360_read_char(void)
+{
+       return(my_console_wait_key(0, 0, NULL));
+}
+#endif
+
+#ifdef CONFIG_KGDB
+static char kgdb_buf[RX_BUF_SIZE], *kgdp;
+static int kgdb_chars;
+
+unsigned char
+getDebugChar(void)
+{
+       if (kgdb_chars <= 0) {
+               kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
+               kgdp = kgdb_buf;
+       }
+       kgdb_chars--;
+
+       return(*kgdp++);
+}
+
+void kgdb_interruptible(int state)
+{
+}
+void kgdb_map_scc(void)
+{
+       struct          serial_state *ser;
+       uint            mem_addr;
+       volatile        QUICC_BD                *bdp;
+       volatile        smc_uart_t      *up;
+
+       cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+
+       /* To avoid data cache CPM DMA coherency problems, allocate a
+        * buffer in the CPM DPRAM.  This will work until the CPM and
+        * serial ports are initialized.  At that time a memory buffer
+        * will be allocated.
+        * The port is already initialized from the boot procedure, all
+        * we do here is give it a different buffer and make it a FIFO.
+        */
+
+       ser = rs_table;
+
+       /* Right now, assume we are using SMCs.
+       */
+       up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+       /* Allocate space for an input FIFO, plus a few bytes for output.
+        * Allocate bytes to maintain word alignment.
+        */
+       mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
+       bdp->buf = mem_addr;
+
+       bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
+       bdp->buf = mem_addr+RX_BUF_SIZE;
+
+       up->smc_mrblr = RX_BUF_SIZE;            /* receive buffer length */
+       up->smc_maxidl = RX_BUF_SIZE;
+}
+#endif
+
+static struct tty_struct *serial_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return serial_driver;
+}
+
+
+struct console sercons = {
+       .name           = "ttyS",
+       .write          = serial_console_write,
+       .device         = serial_console_device,
+       .wait_key       = serial_console_wait_key,
+       .setup          = serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = CONFIG_SERIAL_CONSOLE_PORT, 
+};
+
+
+
+/*
+ *     Register console.
+ */
+long console_360_init(long kmem_start, long kmem_end)
+{
+       register_console(&sercons);
+       /*register_console (console_print_68360); - 2.0.38 only required a write
+      function pointer. */
+       return kmem_start;
+}
+
+#endif
+
+/* Index in baud rate table of the default console baud rate.
+*/
+static int     baud_idx;
+
+static const struct tty_operations rs_360_ops = {
+       .owner = THIS_MODULE,
+       .open = rs_360_open,
+       .close = rs_360_close,
+       .write = rs_360_write,
+       .put_char = rs_360_put_char,
+       .write_room = rs_360_write_room,
+       .chars_in_buffer = rs_360_chars_in_buffer,
+       .flush_buffer = rs_360_flush_buffer,
+       .ioctl = rs_360_ioctl,
+       .throttle = rs_360_throttle,
+       .unthrottle = rs_360_unthrottle,
+       /* .send_xchar = rs_360_send_xchar, */
+       .set_termios = rs_360_set_termios,
+       .stop = rs_360_stop,
+       .start = rs_360_start,
+       .hangup = rs_360_hangup,
+       /* .wait_until_sent = rs_360_wait_until_sent, */
+       /* .read_proc = rs_360_read_proc, */
+       .tiocmget = rs_360_tiocmget,
+       .tiocmset = rs_360_tiocmset,
+       .get_icount = rs_360_get_icount,
+};
+
+static int __init rs_360_init(void)
+{
+       struct serial_state * state;
+       ser_info_t      *info;
+       void       *mem_addr;
+       uint            dp_addr, iobits;
+       int                 i, j, idx;
+       ushort          chan;
+       QUICC_BD        *bdp;
+       volatile        QUICC           *cp;
+       volatile        struct smc_regs *sp;
+       volatile        struct smc_uart_pram    *up;
+       volatile        struct scc_regs *scp;
+       volatile        struct uart_pram        *sup;
+       /* volatile     immap_t         *immap; */
+       
+       serial_driver = alloc_tty_driver(NR_PORTS);
+       if (!serial_driver)
+               return -1;
+
+       show_serial_version();
+
+       serial_driver->name = "ttyS";
+       serial_driver->major = TTY_MAJOR;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag =
+               baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(serial_driver, &rs_360_ops);
+       
+       if (tty_register_driver(serial_driver))
+               panic("Couldn't register serial driver\n");
+
+       cp = pquicc;    /* Get pointer to Communication Processor */
+       /* immap = (immap_t *)IMAP_ADDR; */     /* and to internal registers */
+
+
+       /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
+        */
+       /* The "standard" configuration through the 860.
+       */
+/*     immap->im_ioport.iop_papar |= 0x00fc; */
+/*     immap->im_ioport.iop_padir &= ~0x00fc; */
+/*     immap->im_ioport.iop_paodr &= ~0x00fc; */
+       cp->pio_papar |= 0x00fc;
+       cp->pio_padir &= ~0x00fc;
+       /* cp->pio_paodr &= ~0x00fc; */
+
+
+       /* Since we don't yet do modem control, connect the port C pins
+        * as general purpose I/O.  This will assert CTS and CD for the
+        * SCC ports.
+        */
+       /* FIXME: see 360um p.7-365 and 860um p.34-12 
+        * I can't make sense of these bits - mleslie*/
+/*     immap->im_ioport.iop_pcdir |= 0x03c6; */
+/*     immap->im_ioport.iop_pcpar &= ~0x03c6; */
+
+/*     cp->pio_pcdir |= 0x03c6; */
+/*     cp->pio_pcpar &= ~0x03c6; */
+
+
+
+       /* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
+        * BRG4 to SCC3.
+        */
+       cp->si_sicr &= ~0x00ffff00;
+       cp->si_sicr |=  0x001b1200;
+
+#ifdef CONFIG_PP04
+       /* Frequentis PP04 forced to RS-232 until we know better.
+        * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
+        */
+       immap->im_ioport.iop_pcdir |= 0x000c;
+       immap->im_ioport.iop_pcpar &= ~0x000c;
+       immap->im_ioport.iop_pcdat &= ~0x000c;
+
+       /* This enables the TX driver.
+       */
+       cp->cp_pbpar &= ~0x6000;
+       cp->cp_pbdat &= ~0x6000;
+#endif
+
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               state->magic = SSTATE_MAGIC;
+               state->line = i;
+               state->type = PORT_UNKNOWN;
+               state->custom_divisor = 0;
+               state->close_delay = 5*HZ/10;
+               state->closing_wait = 30*HZ;
+               state->icount.cts = state->icount.dsr = 
+                       state->icount.rng = state->icount.dcd = 0;
+               state->icount.rx = state->icount.tx = 0;
+               state->icount.frame = state->icount.parity = 0;
+               state->icount.overrun = state->icount.brk = 0;
+               printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
+                      i, (unsigned int)(state->irq),
+                      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
+
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* If we just printed the message on the console port, and
+                * we are about to initialize it for general use, we have
+                * to wait a couple of character times for the CR/NL to
+                * make it out of the transmit buffer.
+                */
+               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                       mdelay(8);
+
+
+/*             idx = PORT_NUM(info->state->smc_scc_num); */
+/*             if (info->state->smc_scc_num & NUM_IS_SCC) */
+/*                     chan = scc_chan_map[idx]; */
+/*             else */
+/*                     chan = smc_chan_map[idx]; */
+
+/*             cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
+/*             while (cp->cp_cr & CPM_CR_FLG); */
+
+#endif
+               /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
+               info = &quicc_ser_info[i];
+               if (info) {
+                       memset (info, 0, sizeof(ser_info_t));
+                       info->magic = SERIAL_MAGIC;
+                       info->line = i;
+                       info->flags = state->flags;
+                       INIT_WORK(&info->tqueue, do_softint, info);
+                       INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+                       init_waitqueue_head(&info->open_wait);
+                       init_waitqueue_head(&info->close_wait);
+                       info->state = state;
+                       state->info = (struct async_struct *)info;
+
+                       /* We need to allocate a transmit and receive buffer
+                        * descriptors from dual port ram, and a character
+                        * buffer area from host mem.
+                        */
+                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                        *  (for now this is from a static array of buffers :(
+                        */
+                       /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
+                       /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
+                       mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+                       info->rx_cur = info->rx_bd_base = bdp;
+
+                       /* initialize rx buffer descriptors */
+                       for (j=0; j<(RX_NUM_FIFO-1); j++) {
+                               bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+                               bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
+                               mem_addr += RX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+                       bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+
+                       idx = PORT_NUM(info->state->smc_scc_num);
+                       if (info->state->smc_scc_num & NUM_IS_SCC) {
+
+#if defined (CONFIG_UCQUICC) && 1
+                               /* set the transceiver mode to RS232 */
+                               sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
+                               sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
+                               *(uint *)_periph_base = sipex_mode_bits;
+                               /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
+#endif
+                       }
+
+                       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                       */
+                       /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
+                       /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
+                       mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+                       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+                       info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
+
+                       /* initialize tx buffer descriptors */
+                       for (j=0; j<(TX_NUM_FIFO-1); j++) {
+                               bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+                               bdp->status = BD_SC_INTRPT;
+                               mem_addr += TX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+                       bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
+
+                       if (info->state->smc_scc_num & NUM_IS_SCC) {
+                               scp = &pquicc->scc_regs[idx];
+                               sup = &pquicc->pram[info->state->port].scc.pscc.u;
+                               sup->rbase = dp_addr;
+                               sup->tbase = dp_addr;
+
+                               /* Set up the uart parameters in the
+                                * parameter ram.
+                                */
+                               sup->rfcr = SMC_EB;
+                               sup->tfcr = SMC_EB;
+
+                               /* Set this to 1 for now, so we get single
+                                * character interrupts.  Using idle character
+                                * time requires some additional tuning.
+                                */
+                               sup->mrblr = 1;
+                               sup->max_idl = 0;
+                               sup->brkcr = 1;
+                               sup->parec = 0;
+                               sup->frmer = 0;
+                               sup->nosec = 0;
+                               sup->brkec = 0;
+                               sup->uaddr1 = 0;
+                               sup->uaddr2 = 0;
+                               sup->toseq = 0;
+                               {
+                                       int i;
+                                       for (i=0;i<8;i++)
+                                               sup->cc[i] = 0x8000;
+                               }
+                               sup->rccm = 0xc0ff;
+
+                               /* Send the CPM an initialize command.
+                               */
+                               chan = scc_chan_map[idx];
+
+                               /* execute the INIT RX & TX PARAMS command for this channel. */
+                               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+                               while (cp->cp_cr & CPM_CR_FLG);
+
+                               /* Set UART mode, 8 bit, no parity, one stop.
+                                * Enable receive and transmit.
+                                */
+                               scp->scc_gsmr.w.high = 0;
+                               scp->scc_gsmr.w.low = 
+                                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+                               /* Disable all interrupts and clear all pending
+                                * events.
+                                */
+                               scp->scc_sccm = 0;
+                               scp->scc_scce = 0xffff;
+                               scp->scc_dsr = 0x7e7e;
+                               scp->scc_psmr = 0x3000;
+
+                               /* If the port is the console, enable Rx and Tx.
+                               */
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+                       }
+                       else {
+                               /* Configure SMCs Tx/Rx instead of port B
+                                * parallel I/O.
+                                */
+                               up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+                               up->rbase = dp_addr;
+
+                               iobits = 0xc0 << (idx * 4);
+                               cp->pip_pbpar |= iobits;
+                               cp->pip_pbdir &= ~iobits;
+                               cp->pip_pbodr &= ~iobits;
+
+
+                               /* Connect the baud rate generator to the
+                                * SMC based upon index in rs_table.  Also
+                                * make sure it is connected to NMSI.
+                                */
+                               cp->si_simode &= ~(0xffff << (idx * 16));
+                               cp->si_simode |= (i << ((idx * 16) + 12));
+
+                               up->tbase = dp_addr;
+
+                               /* Set up the uart parameters in the
+                                * parameter ram.
+                                */
+                               up->rfcr = SMC_EB;
+                               up->tfcr = SMC_EB;
+
+                               /* Set this to 1 for now, so we get single
+                                * character interrupts.  Using idle character
+                                * time requires some additional tuning.
+                                */
+                               up->mrblr = 1;
+                               up->max_idl = 0;
+                               up->brkcr = 1;
+
+                               /* Send the CPM an initialize command.
+                               */
+                               chan = smc_chan_map[idx];
+
+                               cp->cp_cr = mk_cr_cmd(chan,
+                                                                         CPM_CR_INIT_TRX) | CPM_CR_FLG;
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       printk("");
+#endif
+                               while (cp->cp_cr & CPM_CR_FLG);
+
+                               /* Set UART mode, 8 bit, no parity, one stop.
+                                * Enable receive and transmit.
+                                */
+                               sp = &cp->smc_regs[idx];
+                               sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+                               /* Disable all interrupts and clear all pending
+                                * events.
+                                */
+                               sp->smc_smcm = 0;
+                               sp->smc_smce = 0xff;
+
+                               /* If the port is the console, enable Rx and Tx.
+                               */
+#ifdef CONFIG_SERIAL_CONSOLE
+                               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                                       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+                       }
+
+                       /* Install interrupt handler.
+                       */
+                       /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
+                       /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
+                       request_irq(state->irq, rs_360_interrupt,
+                                               IRQ_FLG_LOCK, "ttyS", (void *)info);
+
+                       /* Set up the baud rate generator.
+                       */
+                       m360_cpm_setbrg(i, baud_table[baud_idx]);
+
+               }
+       }
+
+       return 0;
+}
+module_init(rs_360_init);
+
+/* This must always be called before the rs_360_init() function, otherwise
+ * it blows away the port control information.
+ */
+//static int __init serial_console_setup( struct console *co, char *options)
+int serial_console_setup( struct console *co, char *options)
+{
+       struct          serial_state    *ser;
+       uint            mem_addr, dp_addr, bidx, idx, iobits;
+       ushort          chan;
+       QUICC_BD        *bdp;
+       volatile        QUICC                   *cp;
+       volatile        struct smc_regs *sp;
+       volatile        struct scc_regs *scp;
+       volatile        struct smc_uart_pram    *up;
+       volatile        struct uart_pram                *sup;
+
+/* mleslie TODO:
+ * add something to the 68k bootloader to store a desired initial console baud rate */
+
+/*     bd_t                                            *bd; */ /* a board info struct used by EPPC-bug */
+/*     bd = (bd_t *)__res; */
+
+       for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
+        /* if (bd->bi_baudrate == baud_table[bidx]) */
+               if (CONSOLE_BAUDRATE == baud_table[bidx])
+                       break;
+
+       /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
+       baud_idx = bidx;
+
+       ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+
+       cp = pquicc;    /* Get pointer to Communication Processor */
+
+       idx = PORT_NUM(ser->smc_scc_num);
+       if (ser->smc_scc_num & NUM_IS_SCC) {
+
+               /* TODO: need to set up SCC pin assignment etc. here */
+               
+       }
+       else {
+               iobits = 0xc0 << (idx * 4);
+               cp->pip_pbpar |= iobits;
+               cp->pip_pbdir &= ~iobits;
+               cp->pip_pbodr &= ~iobits;
+
+               /* Connect the baud rate generator to the
+                * SMC based upon index in rs_table.  Also
+                * make sure it is connected to NMSI.
+                */
+               cp->si_simode &= ~(0xffff << (idx * 16));
+               cp->si_simode |= (idx << ((idx * 16) + 12));
+       }
+
+       /* When we get here, the CPM has been reset, so we need
+        * to configure the port.
+        * We need to allocate a transmit and receive buffer descriptor
+        * from dual port ram, and a character buffer area from host mem.
+        */
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+       */
+       dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
+
+       /* Allocate space for two 2 byte FIFOs in the host memory.
+        */
+       /* mem_addr = m360_cpm_hostalloc(8); */
+       mem_addr = (uint)console_fifos;
+
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+       bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+       bdp->buf = (char *)mem_addr;
+       (bdp+1)->buf = (char *)(mem_addr+4);
+
+       /* For the receive, set empty and wrap.
+        * For transmit, set wrap.
+        */
+       bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
+       (bdp+1)->status = BD_SC_WRAP;
+
+       /* Set up the uart parameters in the parameter ram.
+        */
+       if (ser->smc_scc_num & NUM_IS_SCC) {
+               scp = &cp->scc_regs[idx];
+               /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
+               sup = &pquicc->pram[ser->port].scc.pscc.u;
+
+               sup->rbase = dp_addr;
+               sup->tbase = dp_addr + sizeof(QUICC_BD);
+
+               /* Set up the uart parameters in the
+                * parameter ram.
+                */
+               sup->rfcr = SMC_EB;
+               sup->tfcr = SMC_EB;
+
+               /* Set this to 1 for now, so we get single
+                * character interrupts.  Using idle character
+                * time requires some additional tuning.
+                */
+               sup->mrblr = 1;
+               sup->max_idl = 0;
+               sup->brkcr = 1;
+               sup->parec = 0;
+               sup->frmer = 0;
+               sup->nosec = 0;
+               sup->brkec = 0;
+               sup->uaddr1 = 0;
+               sup->uaddr2 = 0;
+               sup->toseq = 0;
+               {
+                       int i;
+                       for (i=0;i<8;i++)
+                               sup->cc[i] = 0x8000;
+               }
+               sup->rccm = 0xc0ff;
+
+               /* Send the CPM an initialize command.
+               */
+               chan = scc_chan_map[idx];
+
+               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+               while (cp->cp_cr & CPM_CR_FLG);
+
+               /* Set UART mode, 8 bit, no parity, one stop.
+                * Enable receive and transmit.
+                */
+               scp->scc_gsmr.w.high = 0;
+               scp->scc_gsmr.w.low = 
+                       (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+               /* Disable all interrupts and clear all pending
+                * events.
+                */
+               scp->scc_sccm = 0;
+               scp->scc_scce = 0xffff;
+               scp->scc_dsr = 0x7e7e;
+               scp->scc_psmr = 0x3000;
+
+               scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       }
+       else {
+               /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
+               up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+               up->rbase = dp_addr;    /* Base of receive buffer desc. */
+               up->tbase = dp_addr+sizeof(QUICC_BD);   /* Base of xmt buffer desc. */
+               up->rfcr = SMC_EB;
+               up->tfcr = SMC_EB;
+
+               /* Set this to 1 for now, so we get single character interrupts.
+               */
+               up->mrblr = 1;          /* receive buffer length */
+               up->max_idl = 0;                /* wait forever for next char */
+
+               /* Send the CPM an initialize command.
+               */
+               chan = smc_chan_map[idx];
+               cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+               while (cp->cp_cr & CPM_CR_FLG);
+
+               /* Set UART mode, 8 bit, no parity, one stop.
+                * Enable receive and transmit.
+                */
+               sp = &cp->smc_regs[idx];
+               sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+               /* And finally, enable Rx and Tx.
+               */
+               sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+       }
+
+       /* Set up the baud rate generator.
+       */
+       /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
+       m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
+
+       return 0;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
new file mode 100644 (file)
index 0000000..3975df6
--- /dev/null
@@ -0,0 +1,3378 @@
+/*
+ *  linux/drivers/char/8250.c
+ *
+ *  Driver for 8250/16550-type serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.
+ *  membase is an 'ioremapped' cookie.
+ */
+
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/ratelimit.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/nmi.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "8250.h"
+
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
+/*
+ * Configuration:
+ *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
+ *                is unsafe when used on edge-triggered interrupts.
+ */
+static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+
+static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+       return (serial8250_reg.minor - 64) + port->line;
+}
+
+static unsigned int skip_txen_test; /* force skip of txen test at init time */
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)     printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)     do { } while (0)
+#endif
+
+#define PASS_LIMIT     256
+
+#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq) ((irq) != 0)
+
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ 1
+#endif
+#ifdef CONFIG_SERIAL_8250_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS 1
+#endif
+
+/*
+ * HUB6 is always on.  This will be removed once the header
+ * files have been cleaned.
+ */
+#define CONFIG_HUB6 1
+
+#include <asm/serial.h>
+/*
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism.   Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+#ifndef SERIAL_PORT_DFNS
+#define SERIAL_PORT_DFNS
+#endif
+
+static const struct old_serial_port old_serial_port[] = {
+       SERIAL_PORT_DFNS /* defined in asm/serial.h */
+};
+
+#define UART_NR        CONFIG_SERIAL_8250_NR_UARTS
+
+#ifdef CONFIG_SERIAL_8250_RSA
+
+#define PORT_RSA_MAX 4
+static unsigned long probe_rsa[PORT_RSA_MAX];
+static unsigned int probe_rsa_count;
+#endif /* CONFIG_SERIAL_8250_RSA  */
+
+struct uart_8250_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
+       unsigned int            tx_loadsz;      /* transmit fifo load size */
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           cur_iotype;     /* Running I/O type */
+
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+       unsigned char           lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+       unsigned char           msr_saved_flags;
+};
+
+struct irq_info {
+       struct                  hlist_node node;
+       int                     irq;
+       spinlock_t              lock;   /* Protects list not the hash */
+       struct list_head        *head;
+};
+
+#define NR_IRQ_HASH            32      /* Can be adjusted later */
+static struct hlist_head irq_lists[NR_IRQ_HASH];
+static DEFINE_MUTEX(hash_mutex);       /* Used to walk the hash */
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial8250_config uart_config[] = {
+       [PORT_UNKNOWN] = {
+               .name           = "unknown",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_8250] = {
+               .name           = "8250",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16450] = {
+               .name           = "16450",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16550] = {
+               .name           = "16550",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16550A] = {
+               .name           = "16550A",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_CIRRUS] = {
+               .name           = "Cirrus",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16650] = {
+               .name           = "ST16650",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16650V2] = {
+               .name           = "ST16650V2",
+               .fifo_size      = 32,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+                                 UART_FCR_T_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16750] = {
+               .name           = "TI16750",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+                                 UART_FCR7_64BYTE,
+               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
+       },
+       [PORT_STARTECH] = {
+               .name           = "Startech",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1,
+       },
+       [PORT_16C950] = {
+               .name           = "16C950/954",
+               .fifo_size      = 128,
+               .tx_loadsz      = 128,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               /* UART_CAP_EFR breaks billionon CF bluetooth card. */
+               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP,
+       },
+       [PORT_16654] = {
+               .name           = "ST16654",
+               .fifo_size      = 64,
+               .tx_loadsz      = 32,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+                                 UART_FCR_T_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_16850] = {
+               .name           = "XR16850",
+               .fifo_size      = 128,
+               .tx_loadsz      = 128,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+       },
+       [PORT_RSA] = {
+               .name           = "RSA",
+               .fifo_size      = 2048,
+               .tx_loadsz      = 2048,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_NS16550A] = {
+               .name           = "NS16550A",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_NATSEMI,
+       },
+       [PORT_XSCALE] = {
+               .name           = "XScale",
+               .fifo_size      = 32,
+               .tx_loadsz      = 32,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_UUE,
+       },
+       [PORT_RM9000] = {
+               .name           = "RM9000",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_OCTEON] = {
+               .name           = "OCTEON",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
+       [PORT_AR7] = {
+               .name           = "AR7",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
+       [PORT_U6_16550A] = {
+               .name           = "U6_16550A",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
+       },
+};
+
+#if defined(CONFIG_MIPS_ALCHEMY)
+
+/* Au1x00 UART hardware has a weird register layout */
+static const u8 au_io_in_map[] = {
+       [UART_RX]  = 0,
+       [UART_IER] = 2,
+       [UART_IIR] = 3,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+       [UART_LSR] = 7,
+       [UART_MSR] = 8,
+};
+
+static const u8 au_io_out_map[] = {
+       [UART_TX]  = 1,
+       [UART_IER] = 2,
+       [UART_FCR] = 4,
+       [UART_LCR] = 5,
+       [UART_MCR] = 6,
+};
+
+/* sane hardware needs no mapping */
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_AU)
+               return offset;
+       return au_io_in_map[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_AU)
+               return offset;
+       return au_io_out_map[offset];
+}
+
+#elif defined(CONFIG_SERIAL_8250_RM9K)
+
+static const u8
+       regmap_in[8] = {
+               [UART_RX]       = 0x00,
+               [UART_IER]      = 0x0c,
+               [UART_IIR]      = 0x14,
+               [UART_LCR]      = 0x1c,
+               [UART_MCR]      = 0x20,
+               [UART_LSR]      = 0x24,
+               [UART_MSR]      = 0x28,
+               [UART_SCR]      = 0x2c
+       },
+       regmap_out[8] = {
+               [UART_TX]       = 0x04,
+               [UART_IER]      = 0x0c,
+               [UART_FCR]      = 0x18,
+               [UART_LCR]      = 0x1c,
+               [UART_MCR]      = 0x20,
+               [UART_LSR]      = 0x24,
+               [UART_MSR]      = 0x28,
+               [UART_SCR]      = 0x2c
+       };
+
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_RM9000)
+               return offset;
+       return regmap_in[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
+{
+       if (p->iotype != UPIO_RM9000)
+               return offset;
+       return regmap_out[offset];
+}
+
+#else
+
+/* sane hardware needs no mapping */
+#define map_8250_in_reg(up, offset) (offset)
+#define map_8250_out_reg(up, offset) (offset)
+
+#endif
+
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       return inb(p->iobase + 1);
+}
+
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       outb(value, p->iobase + 1);
+}
+
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readb(p->membase + offset);
+}
+
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readl(p->membase + offset);
+}
+
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       __raw_writel(value, p->membase + offset);
+}
+
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int tmp;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       if (offset == UART_IIR) {
+               tmp = readl(p->membase + (UART_IIR & ~3));
+               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+       } else
+               return readb(p->membase + offset);
+}
+
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+               writeb(value, p->membase + offset);
+}
+
+/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
+static inline void dwapb_save_out_value(struct uart_port *p, int offset,
+                                       int value)
+{
+       struct uart_8250_port *up =
+               container_of(p, struct uart_8250_port, port);
+
+       if (offset == UART_LCR)
+               up->lcr = value;
+}
+
+/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
+static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
+{
+       if (offset == UART_TX || offset == UART_IER)
+               p->serial_in(p, UART_IER);
+}
+
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
+{
+       int save_offset = offset;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       dwapb_save_out_value(p, save_offset, value);
+       writeb(value, p->membase + offset);
+       dwapb_check_clear_ier(p, save_offset);
+}
+
+static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
+{
+       int save_offset = offset;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       dwapb_save_out_value(p, save_offset, value);
+       writel(value, p->membase + offset);
+       dwapb_check_clear_ier(p, save_offset);
+}
+
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+       struct uart_8250_port *up =
+               container_of(p, struct uart_8250_port, port);
+       switch (p->iotype) {
+       case UPIO_HUB6:
+               p->serial_in = hub6_serial_in;
+               p->serial_out = hub6_serial_out;
+               break;
+
+       case UPIO_MEM:
+               p->serial_in = mem_serial_in;
+               p->serial_out = mem_serial_out;
+               break;
+
+       case UPIO_RM9000:
+       case UPIO_MEM32:
+               p->serial_in = mem32_serial_in;
+               p->serial_out = mem32_serial_out;
+               break;
+
+       case UPIO_AU:
+               p->serial_in = au_serial_in;
+               p->serial_out = au_serial_out;
+               break;
+
+       case UPIO_TSI:
+               p->serial_in = tsi_serial_in;
+               p->serial_out = tsi_serial_out;
+               break;
+
+       case UPIO_DWAPB:
+               p->serial_in = mem_serial_in;
+               p->serial_out = dwapb_serial_out;
+               break;
+
+       case UPIO_DWAPB32:
+               p->serial_in = mem32_serial_in;
+               p->serial_out = dwapb32_serial_out;
+               break;
+
+       default:
+               p->serial_in = io_serial_in;
+               p->serial_out = io_serial_out;
+               break;
+       }
+       /* Remember loaded iotype */
+       up->cur_iotype = p->iotype;
+}
+
+static void
+serial_out_sync(struct uart_8250_port *up, int offset, int value)
+{
+       struct uart_port *p = &up->port;
+       switch (p->iotype) {
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               p->serial_out(p, offset, value);
+               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
+               break;
+       default:
+               p->serial_out(p, offset, value);
+       }
+}
+
+#define serial_in(up, offset)          \
+       (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value)  \
+       (up->port.serial_out(&(up)->port, (offset), (value)))
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(up, offset)         serial_in(up, offset)
+#define serial_outp(up, offset, value) serial_out(up, offset, value)
+
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+       serial_outp(up, UART_DLL, value & 0xff);
+       serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#if defined(CONFIG_MIPS_ALCHEMY)
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       if (up->port.iotype == UPIO_AU)
+               return __raw_readl(up->port.membase + 0x28);
+       else
+               return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_AU)
+               __raw_writel(value, up->port.membase + 0x28);
+       else
+               _serial_dl_write(up, value);
+}
+#elif defined(CONFIG_SERIAL_8250_RM9K)
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       return  (up->port.iotype == UPIO_RM9000) ?
+               (((__raw_readl(up->port.membase + 0x10) << 8) |
+               (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
+               _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_RM9000) {
+               __raw_writel(value, up->port.membase + 0x08);
+               __raw_writel(value >> 8, up->port.membase + 0x10);
+       } else {
+               _serial_dl_write(up, value);
+       }
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
+
+/*
+ * For the 16C950
+ */
+static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
+{
+       serial_out(up, UART_SCR, offset);
+       serial_out(up, UART_ICR, value);
+}
+
+static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
+{
+       unsigned int value;
+
+       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
+       serial_out(up, UART_SCR, offset);
+       value = serial_in(up, UART_ICR);
+       serial_icr_write(up, UART_ACR, up->acr);
+
+       return value;
+}
+
+/*
+ * FIFO support.
+ */
+static void serial8250_clear_fifos(struct uart_8250_port *p)
+{
+       if (p->capabilities & UART_CAP_FIFO) {
+               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
+                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+               serial_outp(p, UART_FCR, 0);
+       }
+}
+
+/*
+ * IER sleep support.  UARTs which have EFRs need the "extended
+ * capability" bit enabled.  Note that on XR16C850s, we need to
+ * reset LCR to write to IER.
+ */
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+{
+       if (p->capabilities & UART_CAP_SLEEP) {
+               if (p->capabilities & UART_CAP_EFR) {
+                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
+                       serial_outp(p, UART_EFR, UART_EFR_ECB);
+                       serial_outp(p, UART_LCR, 0);
+               }
+               serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
+               if (p->capabilities & UART_CAP_EFR) {
+                       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
+                       serial_outp(p, UART_EFR, 0);
+                       serial_outp(p, UART_LCR, 0);
+               }
+       }
+}
+
+#ifdef CONFIG_SERIAL_8250_RSA
+/*
+ * Attempts to turn on the RSA FIFO.  Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __enable_rsa(struct uart_8250_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       mode = serial_inp(up, UART_RSA_MSR);
+       result = mode & UART_RSA_MSR_FIFO;
+
+       if (!result) {
+               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = mode & UART_RSA_MSR_FIFO;
+       }
+
+       if (result)
+               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+       return result;
+}
+
+static void enable_rsa(struct uart_8250_port *up)
+{
+       if (up->port.type == PORT_RSA) {
+               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+                       spin_lock_irq(&up->port.lock);
+                       __enable_rsa(up);
+                       spin_unlock_irq(&up->port.lock);
+               }
+               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+                       serial_outp(up, UART_RSA_FRR, 0);
+       }
+}
+
+/*
+ * Attempts to turn off the RSA FIFO.  Returns zero on failure.
+ * It is unknown why interrupts were disabled in here.  However,
+ * the caller is expected to preserve this behaviour by grabbing
+ * the spinlock before calling this function.
+ */
+static void disable_rsa(struct uart_8250_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       if (up->port.type == PORT_RSA &&
+           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
+               spin_lock_irq(&up->port.lock);
+
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = !(mode & UART_RSA_MSR_FIFO);
+
+               if (!result) {
+                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+                       mode = serial_inp(up, UART_RSA_MSR);
+                       result = !(mode & UART_RSA_MSR_FIFO);
+               }
+
+               if (result)
+                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+               spin_unlock_irq(&up->port.lock);
+       }
+}
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct uart_8250_port *up)
+{
+       unsigned char old_fcr, old_mcr, old_lcr;
+       unsigned short old_dl;
+       int count;
+
+       old_lcr = serial_inp(up, UART_LCR);
+       serial_outp(up, UART_LCR, 0);
+       old_fcr = serial_inp(up, UART_FCR);
+       old_mcr = serial_inp(up, UART_MCR);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                   UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_outp(up, UART_MCR, UART_MCR_LOOP);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       old_dl = serial_dl_read(up);
+       serial_dl_write(up, 0x0001);
+       serial_outp(up, UART_LCR, 0x03);
+       for (count = 0; count < 256; count++)
+               serial_outp(up, UART_TX, count);
+       mdelay(20);/* FIXME - schedule_timeout */
+       for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
+            (count < 256); count++)
+               serial_inp(up, UART_RX);
+       serial_outp(up, UART_FCR, old_fcr);
+       serial_outp(up, UART_MCR, old_mcr);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_dl_write(up, old_dl);
+       serial_outp(up, UART_LCR, old_lcr);
+
+       return count;
+}
+
+/*
+ * Read UART ID using the divisor method - set DLL and DLM to zero
+ * and the revision will be in DLL and device type in DLM.  We
+ * preserve the device state across this.
+ */
+static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
+{
+       unsigned char old_dll, old_dlm, old_lcr;
+       unsigned int id;
+
+       old_lcr = serial_inp(p, UART_LCR);
+       serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       old_dll = serial_inp(p, UART_DLL);
+       old_dlm = serial_inp(p, UART_DLM);
+
+       serial_outp(p, UART_DLL, 0);
+       serial_outp(p, UART_DLM, 0);
+
+       id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8;
+
+       serial_outp(p, UART_DLL, old_dll);
+       serial_outp(p, UART_DLM, old_dlm);
+       serial_outp(p, UART_LCR, old_lcr);
+
+       return id;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones.  (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not?  Startech doesn't seem to even acknowledge its
+ * existence.)
+ *
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_has_efr(struct uart_8250_port *up)
+{
+       unsigned int id1, id2, id3, rev;
+
+       /*
+        * Everything with an EFR has SLEEP
+        */
+       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
+
+       /*
+        * First we check to see if it's an Oxford Semiconductor UART.
+        *
+        * If we have to do this here because some non-National
+        * Semiconductor clone chips lock up if you try writing to the
+        * LSR register (which serial_icr_read does)
+        */
+
+       /*
+        * Check for Oxford Semiconductor 16C950.
+        *
+        * EFR [4] must be set else this test fails.
+        *
+        * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)
+        * claims that it's needed for 952 dual UART's (which are not
+        * recommended for new designs).
+        */
+       up->acr = 0;
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_EFR, UART_EFR_ECB);
+       serial_out(up, UART_LCR, 0x00);
+       id1 = serial_icr_read(up, UART_ID1);
+       id2 = serial_icr_read(up, UART_ID2);
+       id3 = serial_icr_read(up, UART_ID3);
+       rev = serial_icr_read(up, UART_REV);
+
+       DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
+
+       if (id1 == 0x16 && id2 == 0xC9 &&
+           (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
+               up->port.type = PORT_16C950;
+
+               /*
+                * Enable work around for the Oxford Semiconductor 952 rev B
+                * chip which causes it to seriously miscalculate baud rates
+                * when DLL is 0.
+                */
+               if (id3 == 0x52 && rev == 0x01)
+                       up->bugs |= UART_BUG_QUOT;
+               return;
+       }
+
+       /*
+        * We check for a XR16C850 by setting DLL and DLM to 0, and then
+        * reading back DLL and DLM.  The chip type depends on the DLM
+        * value read back:
+        *  0x10 - XR16C850 and the DLL contains the chip revision.
+        *  0x12 - XR16C2850.
+        *  0x14 - XR16C854.
+        */
+       id1 = autoconfig_read_divisor_id(up);
+       DEBUG_AUTOCONF("850id=%04x ", id1);
+
+       id2 = id1 >> 8;
+       if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
+               up->port.type = PORT_16850;
+               return;
+       }
+
+       /*
+        * It wasn't an XR16C850.
+        *
+        * We distinguish between the '654 and the '650 by counting
+        * how many bytes are in the FIFO.  I'm using this for now,
+        * since that's the technique that was sent to me in the
+        * serial driver update, but I'm not convinced this works.
+        * I've had problems doing this in the past.  -TYT
+        */
+       if (size_fifo(up) == 64)
+               up->port.type = PORT_16654;
+       else
+               up->port.type = PORT_16650V2;
+}
+
+/*
+ * We detected a chip without a FIFO.  Only two fall into
+ * this category - the original 8250 and the 16450.  The
+ * 16450 has a scratch register (accessible with LCR=0)
+ */
+static void autoconfig_8250(struct uart_8250_port *up)
+{
+       unsigned char scratch, status1, status2;
+
+       up->port.type = PORT_8250;
+
+       scratch = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, 0xa5);
+       status1 = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, 0x5a);
+       status2 = serial_in(up, UART_SCR);
+       serial_outp(up, UART_SCR, scratch);
+
+       if (status1 == 0xa5 && status2 == 0x5a)
+               up->port.type = PORT_16450;
+}
+
+static int broken_efr(struct uart_8250_port *up)
+{
+       /*
+        * Exar ST16C2550 "A2" devices incorrectly detect as
+        * having an EFR, and report an ID of 0x0201.  See
+        * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 
+        */
+       if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * We know that the chip has FIFOs.  Does it have an EFR?  The
+ * EFR is located in the same register position as the IIR and
+ * we know the top two bits of the IIR are currently set.  The
+ * EFR should contain zero.  Try to read the EFR.
+ */
+static void autoconfig_16550a(struct uart_8250_port *up)
+{
+       unsigned char status1, status2;
+       unsigned int iersave;
+
+       up->port.type = PORT_16550A;
+       up->capabilities |= UART_CAP_FIFO;
+
+       /*
+        * Check for presence of the EFR when DLAB is set.
+        * Only ST16C650V1 UARTs pass this test.
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       if (serial_in(up, UART_EFR) == 0) {
+               serial_outp(up, UART_EFR, 0xA8);
+               if (serial_in(up, UART_EFR) != 0) {
+                       DEBUG_AUTOCONF("EFRv1 ");
+                       up->port.type = PORT_16650;
+                       up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
+               } else {
+                       DEBUG_AUTOCONF("Motorola 8xxx DUART ");
+               }
+               serial_outp(up, UART_EFR, 0);
+               return;
+       }
+
+       /*
+        * Maybe it requires 0xbf to be written to the LCR.
+        * (other ST16C650V2 UARTs, TI16C752A, etc)
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
+               DEBUG_AUTOCONF("EFRv2 ");
+               autoconfig_has_efr(up);
+               return;
+       }
+
+       /*
+        * Check for a National Semiconductor SuperIO chip.
+        * Attempt to switch to bank 2, read the value of the LOOP bit
+        * from EXCR1. Switch back to bank 0, change it in MCR. Then
+        * switch back to bank 2, read it from EXCR1 again and check
+        * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
+        */
+       serial_outp(up, UART_LCR, 0);
+       status1 = serial_in(up, UART_MCR);
+       serial_outp(up, UART_LCR, 0xE0);
+       status2 = serial_in(up, 0x02); /* EXCR1 */
+
+       if (!((status2 ^ status1) & UART_MCR_LOOP)) {
+               serial_outp(up, UART_LCR, 0);
+               serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
+               serial_outp(up, UART_LCR, 0xE0);
+               status2 = serial_in(up, 0x02); /* EXCR1 */
+               serial_outp(up, UART_LCR, 0);
+               serial_outp(up, UART_MCR, status1);
+
+               if ((status2 ^ status1) & UART_MCR_LOOP) {
+                       unsigned short quot;
+
+                       serial_outp(up, UART_LCR, 0xE0);
+
+                       quot = serial_dl_read(up);
+                       quot <<= 3;
+
+                       status1 = serial_in(up, 0x04); /* EXCR2 */
+                       status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+                       status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+                       serial_outp(up, 0x04, status1);
+
+                       serial_dl_write(up, quot);
+
+                       serial_outp(up, UART_LCR, 0);
+
+                       up->port.uartclk = 921600*16;
+                       up->port.type = PORT_NS16550A;
+                       up->capabilities |= UART_NATSEMI;
+                       return;
+               }
+       }
+
+       /*
+        * No EFR.  Try to detect a TI16750, which only sets bit 5 of
+        * the IIR when 64 byte FIFO mode is enabled when DLAB is set.
+        * Try setting it with and without DLAB set.  Cheap clones
+        * set bit 5 without DLAB set.
+        */
+       serial_outp(up, UART_LCR, 0);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+       status1 = serial_in(up, UART_IIR) >> 5;
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+       status2 = serial_in(up, UART_IIR) >> 5;
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_outp(up, UART_LCR, 0);
+
+       DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
+
+       if (status1 == 6 && status2 == 7) {
+               up->port.type = PORT_16750;
+               up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
+               return;
+       }
+
+       /*
+        * Try writing and reading the UART_IER_UUE bit (b6).
+        * If it works, this is probably one of the Xscale platform's
+        * internal UARTs.
+        * We're going to explicitly set the UUE bit to 0 before
+        * trying to write and read a 1 just to make sure it's not
+        * already a 1 and maybe locked there before we even start start.
+        */
+       iersave = serial_in(up, UART_IER);
+       serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
+       if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
+               /*
+                * OK it's in a known zero state, try writing and reading
+                * without disturbing the current state of the other bits.
+                */
+               serial_outp(up, UART_IER, iersave | UART_IER_UUE);
+               if (serial_in(up, UART_IER) & UART_IER_UUE) {
+                       /*
+                        * It's an Xscale.
+                        * We'll leave the UART_IER_UUE bit set to 1 (enabled).
+                        */
+                       DEBUG_AUTOCONF("Xscale ");
+                       up->port.type = PORT_XSCALE;
+                       up->capabilities |= UART_CAP_UUE;
+                       return;
+               }
+       } else {
+               /*
+                * If we got here we couldn't force the IER_UUE bit to 0.
+                * Log it and continue.
+                */
+               DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
+       }
+       serial_outp(up, UART_IER, iersave);
+
+       /*
+        * We distinguish between 16550A and U6 16550A by counting
+        * how many bytes are in the FIFO.
+        */
+       if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
+               up->port.type = PORT_U6_16550A;
+               up->capabilities |= UART_CAP_AFE;
+       }
+}
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+{
+       unsigned char status1, scratch, scratch2, scratch3;
+       unsigned char save_lcr, save_mcr;
+       unsigned long flags;
+
+       if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
+               return;
+
+       DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ",
+                      serial_index(&up->port), up->port.iobase, up->port.membase);
+
+       /*
+        * We really do need global IRQs disabled here - we're going to
+        * be frobbing the chips IRQ enable register to see if it exists.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->capabilities = 0;
+       up->bugs = 0;
+
+       if (!(up->port.flags & UPF_BUGGY_UART)) {
+               /*
+                * Do a simple existence test first; if we fail this,
+                * there's no point trying anything else.
+                *
+                * 0x80 is used as a nonsense port to prevent against
+                * false positives due to ISA bus float.  The
+                * assumption is that 0x80 is a non-existent port;
+                * which should be safe since include/asm/io.h also
+                * makes this assumption.
+                *
+                * Note: this is safe as long as MCR bit 4 is clear
+                * and the device is in "PC" mode.
+                */
+               scratch = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0);
+#ifdef __i386__
+               outb(0xff, 0x080);
+#endif
+               /*
+                * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
+                * 16C754B) allow only to modify them if an EFR bit is set.
+                */
+               scratch2 = serial_inp(up, UART_IER) & 0x0f;
+               serial_outp(up, UART_IER, 0x0F);
+#ifdef __i386__
+               outb(0, 0x080);
+#endif
+               scratch3 = serial_inp(up, UART_IER) & 0x0f;
+               serial_outp(up, UART_IER, scratch);
+               if (scratch2 != 0 || scratch3 != 0x0F) {
+                       /*
+                        * We failed; there's nothing here
+                        */
+                       DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
+                                      scratch2, scratch3);
+                       goto out;
+               }
+       }
+
+       save_mcr = serial_in(up, UART_MCR);
+       save_lcr = serial_in(up, UART_LCR);
+
+       /*
+        * Check to see if a UART is really there.  Certain broken
+        * internal modems based on the Rockwell chipset fail this
+        * test, because they apparently don't implement the loopback
+        * test mode.  So this test is skipped on the COM 1 through
+        * COM 4 ports.  This *should* be safe, since no board
+        * manufacturer would be stupid enough to design a board
+        * that conflicts with COM 1-4 --- we hope!
+        */
+       if (!(up->port.flags & UPF_SKIP_TEST)) {
+               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+               status1 = serial_inp(up, UART_MSR) & 0xF0;
+               serial_outp(up, UART_MCR, save_mcr);
+               if (status1 != 0x90) {
+                       DEBUG_AUTOCONF("LOOP test failed (%02x) ",
+                                      status1);
+                       goto out;
+               }
+       }
+
+       /*
+        * We're pretty sure there's a port here.  Lets find out what
+        * type of port it is.  The IIR top two bits allows us to find
+        * out if it's 8250 or 16450, 16550, 16550A or later.  This
+        * determines what we test for next.
+        *
+        * We also initialise the EFR (if any) to zero for later.  The
+        * EFR occupies the same register location as the FCR and IIR.
+        */
+       serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_outp(up, UART_EFR, 0);
+       serial_outp(up, UART_LCR, 0);
+
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(up, UART_IIR) >> 6;
+
+       DEBUG_AUTOCONF("iir=%d ", scratch);
+
+       switch (scratch) {
+       case 0:
+               autoconfig_8250(up);
+               break;
+       case 1:
+               up->port.type = PORT_UNKNOWN;
+               break;
+       case 2:
+               up->port.type = PORT_16550;
+               break;
+       case 3:
+               autoconfig_16550a(up);
+               break;
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Only probe for RSA ports if we got the region.
+        */
+       if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
+               int i;
+
+               for (i = 0 ; i < probe_rsa_count; ++i) {
+                       if (probe_rsa[i] == up->port.iobase &&
+                           __enable_rsa(up)) {
+                               up->port.type = PORT_RSA;
+                               break;
+                       }
+               }
+       }
+#endif
+
+       serial_outp(up, UART_LCR, save_lcr);
+
+       if (up->capabilities != uart_config[up->port.type].flags) {
+               printk(KERN_WARNING
+                      "ttyS%d: detected caps %08x should be %08x\n",
+                      serial_index(&up->port), up->capabilities,
+                      uart_config[up->port.type].flags);
+       }
+
+       up->port.fifosize = uart_config[up->port.type].fifo_size;
+       up->capabilities = uart_config[up->port.type].flags;
+       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+
+       if (up->port.type == PORT_UNKNOWN)
+               goto out;
+
+       /*
+        * Reset the UART.
+        */
+#ifdef CONFIG_SERIAL_8250_RSA
+       if (up->port.type == PORT_RSA)
+               serial_outp(up, UART_RSA_FRR, 0);
+#endif
+       serial_outp(up, UART_MCR, save_mcr);
+       serial8250_clear_fifos(up);
+       serial_in(up, UART_RX);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_outp(up, UART_IER, UART_IER_UUE);
+       else
+               serial_outp(up, UART_IER, 0);
+
+ out:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+}
+
+static void autoconfig_irq(struct uart_8250_port *up)
+{
+       unsigned char save_mcr, save_ier;
+       unsigned char save_ICP = 0;
+       unsigned int ICP = 0;
+       unsigned long irqs;
+       int irq;
+
+       if (up->port.flags & UPF_FOURPORT) {
+               ICP = (up->port.iobase & 0xfe0) | 0x1f;
+               save_ICP = inb_p(ICP);
+               outb_p(0x80, ICP);
+               (void) inb_p(ICP);
+       }
+
+       /* forget possible initially masked and pending IRQ */
+       probe_irq_off(probe_irq_on());
+       save_mcr = serial_inp(up, UART_MCR);
+       save_ier = serial_inp(up, UART_IER);
+       serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
+       irqs = probe_irq_on();
+       serial_outp(up, UART_MCR, 0);
+       udelay(10);
+       if (up->port.flags & UPF_FOURPORT) {
+               serial_outp(up, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS);
+       } else {
+               serial_outp(up, UART_MCR,
+                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+       }
+       serial_outp(up, UART_IER, 0x0f);        /* enable all intrs */
+       (void)serial_inp(up, UART_LSR);
+       (void)serial_inp(up, UART_RX);
+       (void)serial_inp(up, UART_IIR);
+       (void)serial_inp(up, UART_MSR);
+       serial_outp(up, UART_TX, 0xFF);
+       udelay(20);
+       irq = probe_irq_off(irqs);
+
+       serial_outp(up, UART_MCR, save_mcr);
+       serial_outp(up, UART_IER, save_ier);
+
+       if (up->port.flags & UPF_FOURPORT)
+               outb_p(save_ICP, ICP);
+
+       up->port.irq = (irq > 0) ? irq : 0;
+}
+
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void serial8250_stop_tx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       __stop_tx(up);
+
+       /*
+        * We really want to stop the transmitter from sending.
+        */
+       if (up->port.type == PORT_16C950) {
+               up->acr |= UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void transmit_chars(struct uart_8250_port *up);
+
+static void serial8250_start_tx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+
+               if (up->bugs & UART_BUG_TXEN) {
+                       unsigned char lsr;
+                       lsr = serial_in(up, UART_LSR);
+                       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+                       if ((up->port.type == PORT_RM9000) ?
+                               (lsr & UART_LSR_THRE) :
+                               (lsr & UART_LSR_TEMT))
+                               transmit_chars(up);
+               }
+       }
+
+       /*
+        * Re-enable the transmitter if we disabled it.
+        */
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
+               up->acr &= ~UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void serial8250_stop_rx(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial8250_enable_ms(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       /* no MSR capabilities */
+       if (up->bugs & UART_BUG_NOMSR)
+               return;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void
+receive_chars(struct uart_8250_port *up, unsigned int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch, lsr = *status;
+       int max_count = 256;
+       char flag;
+
+       do {
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_inp(up, UART_RX);
+               else
+                       /*
+                        * Intel 82571 has a Serial Over Lan device that will
+                        * set UART_LSR_BI without setting UART_LSR_DR when
+                        * it receives a break. To avoid reading from the
+                        * receive buffer without UART_LSR_DR bit set, we
+                        * just force the read character to be 0
+                        */
+                       ch = 0;
+
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               lsr |= up->lsr_saved_flags;
+               up->lsr_saved_flags = 0;
+
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (lsr & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (lsr & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (lsr & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       lsr &= up->port.read_status_mask;
+
+                       if (lsr & UART_LSR_BI) {
+                               DEBUG_INTR("handling break....");
+                               flag = TTY_BREAK;
+                       } else if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+
+ignore_char:
+               lsr = serial_inp(up, UART_LSR);
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+       *status = lsr;
+}
+
+static void transmit_chars(struct uart_8250_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_outp(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_tx_stopped(&up->port)) {
+               serial8250_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
+               return;
+       }
+
+       count = up->tx_loadsz;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       DEBUG_INTR("THRE...");
+
+       if (uart_circ_empty(xmit))
+               __stop_tx(up);
+}
+
+static unsigned int check_modem_status(struct uart_8250_port *up)
+{
+       unsigned int status = serial_in(up, UART_MSR);
+
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.state != NULL) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       return status;
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static void serial8250_handle_port(struct uart_8250_port *up)
+{
+       unsigned int status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       status = serial_inp(up, UART_LSR);
+
+       DEBUG_INTR("status = %x...", status);
+
+       if (status & (UART_LSR_DR | UART_LSR_BI))
+               receive_chars(up, &status);
+       check_modem_status(up);
+       if (status & UART_LSR_THRE)
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
+{
+       struct irq_info *i = dev_id;
+       struct list_head *l, *end = NULL;
+       int pass_counter = 0, handled = 0;
+
+       DEBUG_INTR("serial8250_interrupt(%d)...", irq);
+
+       spin_lock(&i->lock);
+
+       l = i->head;
+       do {
+               struct uart_8250_port *up;
+               unsigned int iir;
+
+               up = list_entry(l, struct uart_8250_port, list);
+
+               iir = serial_in(up, UART_IIR);
+               if (!(iir & UART_IIR_NO_INT)) {
+                       serial8250_handle_port(up);
+
+                       handled = 1;
+
+                       end = NULL;
+               } else if ((up->port.iotype == UPIO_DWAPB ||
+                           up->port.iotype == UPIO_DWAPB32) &&
+                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+                       /* The DesignWare APB UART has an Busy Detect (0x07)
+                        * interrupt meaning an LCR write attempt occured while the
+                        * UART was busy. The interrupt must be cleared by reading
+                        * the UART status register (USR) and the LCR re-written. */
+                       unsigned int status;
+                       status = *(volatile u32 *)up->port.private_data;
+                       serial_out(up, UART_LCR, up->lcr);
+
+                       handled = 1;
+
+                       end = NULL;
+               } else if (end == NULL)
+                       end = l;
+
+               l = l->next;
+
+               if (l == i->head && pass_counter++ > PASS_LIMIT) {
+                       /* If we hit this, we're dead. */
+                       printk_ratelimited(KERN_ERR
+                               "serial8250: too much work for irq%d\n", irq);
+                       break;
+               }
+       } while (l != end);
+
+       spin_unlock(&i->lock);
+
+       DEBUG_INTR("end.\n");
+
+       return IRQ_RETVAL(handled);
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
+{
+       spin_lock_irq(&i->lock);
+
+       if (!list_empty(i->head)) {
+               if (i->head == &up->list)
+                       i->head = i->head->next;
+               list_del(&up->list);
+       } else {
+               BUG_ON(i->head != &up->list);
+               i->head = NULL;
+       }
+       spin_unlock_irq(&i->lock);
+       /* List empty so throw away the hash node */
+       if (i->head == NULL) {
+               hlist_del(&i->node);
+               kfree(i);
+       }
+}
+
+static int serial_link_irq_chain(struct uart_8250_port *up)
+{
+       struct hlist_head *h;
+       struct hlist_node *n;
+       struct irq_info *i;
+       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
+
+       mutex_lock(&hash_mutex);
+
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       if (n == NULL) {
+               i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
+               if (i == NULL) {
+                       mutex_unlock(&hash_mutex);
+                       return -ENOMEM;
+               }
+               spin_lock_init(&i->lock);
+               i->irq = up->port.irq;
+               hlist_add_head(&i->node, h);
+       }
+       mutex_unlock(&hash_mutex);
+
+       spin_lock_irq(&i->lock);
+
+       if (i->head) {
+               list_add(&up->list, i->head);
+               spin_unlock_irq(&i->lock);
+
+               ret = 0;
+       } else {
+               INIT_LIST_HEAD(&up->list);
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+               irq_flags |= up->port.irqflags;
+               ret = request_irq(up->port.irq, serial8250_interrupt,
+                                 irq_flags, "serial", i);
+               if (ret < 0)
+                       serial_do_unlink(i, up);
+       }
+
+       return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_8250_port *up)
+{
+       struct irq_info *i;
+       struct hlist_node *n;
+       struct hlist_head *h;
+
+       mutex_lock(&hash_mutex);
+
+       h = &irq_lists[up->port.irq % NR_IRQ_HASH];
+
+       hlist_for_each(n, h) {
+               i = hlist_entry(n, struct irq_info, node);
+               if (i->irq == up->port.irq)
+                       break;
+       }
+
+       BUG_ON(n == NULL);
+       BUG_ON(i->head == NULL);
+
+       if (list_empty(i->head))
+               free_irq(up->port.irq, i);
+
+       serial_do_unlink(i, up);
+       mutex_unlock(&hash_mutex);
+}
+
+/*
+ * This function is used to handle ports that do not have an
+ * interrupt.  This doesn't work very well for 16450's, but gives
+ * barely passable results for a 16550A.  (Although at the expense
+ * of much CPU overhead).
+ */
+static void serial8250_timeout(unsigned long data)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)data;
+       unsigned int iir;
+
+       iir = serial_in(up, UART_IIR);
+       if (!(iir & UART_IIR_NO_INT))
+               serial8250_handle_port(up);
+       mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
+}
+
+static void serial8250_backup_timeout(unsigned long data)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)data;
+       unsigned int iir, ier = 0, lsr;
+       unsigned long flags;
+
+       /*
+        * Must disable interrupts or else we risk racing with the interrupt
+        * based handler.
+        */
+       if (is_real_interrupt(up->port.irq)) {
+               ier = serial_in(up, UART_IER);
+               serial_out(up, UART_IER, 0);
+       }
+
+       iir = serial_in(up, UART_IIR);
+
+       /*
+        * This should be a safe test for anyone who doesn't trust the
+        * IIR bits on their UART, but it's specifically designed for
+        * the "Diva" UART used on the management processor on many HP
+        * ia64 and parisc boxes.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
+           (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
+           (lsr & UART_LSR_THRE)) {
+               iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
+               iir |= UART_IIR_THRI;
+       }
+
+       if (!(iir & UART_IIR_NO_INT))
+               serial8250_handle_port(up);
+
+       if (is_real_interrupt(up->port.irq))
+               serial_out(up, UART_IER, ier);
+
+       /* Standard timer interval plus 0.2s to keep the port running */
+       mod_timer(&up->timer,
+               jiffies + uart_poll_timeout(&up->port) + HZ / 5);
+}
+
+static unsigned int serial8250_tx_empty(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+       unsigned int lsr;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned int status;
+       unsigned int ret;
+
+       status = check_modem_status(up);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial8250_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       for (;;) {
+               status = serial_in(up, UART_LSR);
+
+               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
+
+               if ((status & bits) == bits)
+                       break;
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       }
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               unsigned int tmout;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
+                       udelay(1);
+                       touch_nmi_watchdog();
+               }
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial8250_get_poll_char(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char lsr = serial_inp(up, UART_LSR);
+
+       if (!(lsr & UART_LSR_DR))
+               return NO_POLL_CHAR;
+
+       return serial_inp(up, UART_RX);
+}
+
+
+static void serial8250_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       unsigned int ier;
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_out(up, UART_IER, UART_IER_UUE);
+       else
+               serial_out(up, UART_IER, 0);
+
+       wait_for_xmitr(up, BOTH_EMPTY);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       serial_out(up, UART_TX, c);
+       if (c == 10) {
+               wait_for_xmitr(up, BOTH_EMPTY);
+               serial_out(up, UART_TX, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int serial8250_startup(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+       unsigned char lsr, iir;
+       int retval;
+
+       up->port.fifosize = uart_config[up->port.type].fifo_size;
+       up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
+       up->capabilities = uart_config[up->port.type].flags;
+       up->mcr = 0;
+
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
+       if (up->port.type == PORT_16C950) {
+               /* Wake up and initialize UART */
+               up->acr = 0;
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_IER, 0);
+               serial_outp(up, UART_LCR, 0);
+               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_LCR, 0);
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * If this is an RSA port, see if we can kick it up to the
+        * higher speed clock.
+        */
+       enable_rsa(up);
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial8250_clear_fifos(up);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       /*
+        * At this point, there's no way the LSR could still be 0xff;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (!(up->port.flags & UPF_BUGGY_UART) &&
+           (serial_inp(up, UART_LSR) == 0xff)) {
+               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                      serial_index(&up->port));
+               return -ENODEV;
+       }
+
+       /*
+        * For a XR16C850, we need to set the trigger levels
+        */
+       if (up->port.type == PORT_16850) {
+               unsigned char fctr;
+
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+               fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
+               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
+               serial_outp(up, UART_TRG, UART_TRG_96);
+               serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
+               serial_outp(up, UART_TRG, UART_TRG_96);
+
+               serial_outp(up, UART_LCR, 0);
+       }
+
+       if (is_real_interrupt(up->port.irq)) {
+               unsigned char iir1;
+               /*
+                * Test for UARTs that do not reassert THRE when the
+                * transmitter is idle and the interrupt has already
+                * been cleared.  Real 16550s should always reassert
+                * this interrupt whenever the transmitter is idle and
+                * the interrupt is enabled.  Delays are necessary to
+                * allow register changes to become visible.
+                */
+               spin_lock_irqsave(&up->port.lock, flags);
+               if (up->port.irqflags & IRQF_SHARED)
+                       disable_irq_nosync(up->port.irq);
+
+               wait_for_xmitr(up, UART_LSR_THRE);
+               serial_out_sync(up, UART_IER, UART_IER_THRI);
+               udelay(1); /* allow THRE to set */
+               iir1 = serial_in(up, UART_IIR);
+               serial_out(up, UART_IER, 0);
+               serial_out_sync(up, UART_IER, UART_IER_THRI);
+               udelay(1); /* allow a working UART time to re-assert THRE */
+               iir = serial_in(up, UART_IIR);
+               serial_out(up, UART_IER, 0);
+
+               if (up->port.irqflags & IRQF_SHARED)
+                       enable_irq(up->port.irq);
+               spin_unlock_irqrestore(&up->port.lock, flags);
+
+               /*
+                * If the interrupt is not reasserted, setup a timer to
+                * kick the UART on a regular basis.
+                */
+               if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
+                       up->bugs |= UART_BUG_THRE;
+                       pr_debug("ttyS%d - using backup timer\n",
+                                serial_index(port));
+               }
+       }
+
+       /*
+        * The above check will only give an accurate result the first time
+        * the port is opened so this value needs to be preserved.
+        */
+       if (up->bugs & UART_BUG_THRE) {
+               up->timer.function = serial8250_backup_timeout;
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies +
+                       uart_poll_timeout(port) + HZ / 5);
+       }
+
+       /*
+        * If the "interrupt" for this port doesn't correspond with any
+        * hardware interrupt, we use a timer-based system.  The original
+        * driver used to do this with IRQ0.
+        */
+       if (!is_real_interrupt(up->port.irq)) {
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
+       } else {
+               retval = serial_link_irq_chain(up);
+               if (retval)
+                       return retval;
+       }
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               if (!is_real_interrupt(up->port.irq))
+                       up->port.mctrl |= TIOCM_OUT1;
+       } else
+               /*
+                * Most PC uarts need OUT2 raised to enable interrupts.
+                */
+               if (is_real_interrupt(up->port.irq))
+                       up->port.mctrl |= TIOCM_OUT2;
+
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+
+       /* Serial over Lan (SoL) hack:
+          Intel 8257x Gigabit ethernet chips have a
+          16550 emulation, to be used for Serial Over Lan.
+          Those chips take a longer time than a normal
+          serial device to signalize that a transmission
+          data was queued. Due to that, the above test generally
+          fails. One solution would be to delay the reading of
+          iir. However, this is not reliable, since the timeout
+          is variable. So, let's just don't test if we receive
+          TX irq. This way, we'll never enable UART_BUG_TXEN.
+        */
+       if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST)
+               goto dont_test_tx_en;
+
+       /*
+        * Do a quick test to see if we receive an
+        * interrupt when we enable the TX irq.
+        */
+       serial_outp(up, UART_IER, UART_IER_THRI);
+       lsr = serial_in(up, UART_LSR);
+       iir = serial_in(up, UART_IIR);
+       serial_outp(up, UART_IER, 0);
+
+       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+               if (!(up->bugs & UART_BUG_TXEN)) {
+                       up->bugs |= UART_BUG_TXEN;
+                       pr_debug("ttyS%d - enabling bad tx status workarounds\n",
+                                serial_index(port));
+               }
+       } else {
+               up->bugs &= ~UART_BUG_TXEN;
+       }
+
+dont_test_tx_en:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Clear the interrupt registers again for luck, and clear the
+        * saved flags to avoid getting false values from polling
+        * routines or the previous session.
+        */
+       serial_inp(up, UART_LSR);
+       serial_inp(up, UART_RX);
+       serial_inp(up, UART_IIR);
+       serial_inp(up, UART_MSR);
+       up->lsr_saved_flags = 0;
+       up->msr_saved_flags = 0;
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(up, UART_IER, up->ier);
+
+       if (up->port.flags & UPF_FOURPORT) {
+               unsigned int icp;
+               /*
+                * Enable interrupts on the AST Fourport board
+                */
+               icp = (up->port.iobase & 0xfe0) | 0x01f;
+               outb_p(0x80, icp);
+               (void) inb_p(icp);
+       }
+
+       return 0;
+}
+
+static void serial8250_shutdown(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_outp(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               inb((up->port.iobase & 0xfe0) | 0x1f);
+               up->port.mctrl |= TIOCM_OUT1;
+       } else
+               up->port.mctrl &= ~TIOCM_OUT2;
+
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+       serial8250_clear_fifos(up);
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Reset the RSA board back to 115kbps compat mode.
+        */
+       disable_rsa(up);
+#endif
+
+       /*
+        * Read data port to reset things, and then unlink from
+        * the IRQ chain.
+        */
+       (void) serial_in(up, UART_RX);
+
+       del_timer_sync(&up->timer);
+       up->timer.function = serial8250_timeout;
+       if (is_real_interrupt(up->port.irq))
+               serial_unlink_irq_chain(up);
+}
+
+static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int quot;
+
+       /*
+        * Handle magic divisors for baud rates above baud_base on
+        * SMSC SuperIO chips.
+        */
+       if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+           baud == (port->uartclk/4))
+               quot = 0x8001;
+       else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+                baud == (port->uartclk/8))
+               quot = 0x8002;
+       else
+               quot = uart_get_divisor(port, baud);
+
+       return quot;
+}
+
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+                         struct ktermios *old)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (termios->c_cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 port->uartclk / 16);
+       quot = serial8250_get_divisor(port, baud);
+
+       /*
+        * Oxford Semi 952 rev B workaround
+        */
+       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
+               quot++;
+
+       if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
+               if (baud < 2400)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+               else
+                       fcr = uart_config[up->port.type].fcr;
+       }
+
+       /*
+        * MCR-based auto flow control.  When AFE is enabled, RTS will be
+        * deasserted when the receive FIFO contains more characters than
+        * the trigger, or the MCR RTS bit is cleared.  In the case where
+        * the remote UART is not using CTS auto flow control, we must
+        * have sufficient FIFO entries for the latency of the remote
+        * UART to respond.  IOW, at least 32 bytes of FIFO.
+        */
+       if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
+               up->mcr &= ~UART_MCR_AFE;
+               if (termios->c_cflag & CRTSCTS)
+                       up->mcr |= UART_MCR_AFE;
+       }
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (!(up->bugs & UART_BUG_NOMSR) &&
+                       UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+       if (up->capabilities & UART_CAP_UUE)
+               up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (up->capabilities & UART_CAP_EFR) {
+               unsigned char efr = 0;
+               /*
+                * TI16C752/Startech hardware flow control.  FIXME:
+                * - TI16C752 requires control thresholds to be set.
+                * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
+                */
+               if (termios->c_cflag & CRTSCTS)
+                       efr |= UART_EFR_CTS;
+
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               serial_outp(up, UART_EFR, efr);
+       }
+
+#ifdef CONFIG_ARCH_OMAP
+       /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+       if (cpu_is_omap1510() && is_omap_port(up)) {
+               if (baud == 115200) {
+                       quot = 1;
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+               } else
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+       }
+#endif
+
+       if (up->capabilities & UART_NATSEMI) {
+               /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
+               serial_outp(up, UART_LCR, 0xe0);
+       } else {
+               serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       }
+
+       serial_dl_write(up, quot);
+
+       /*
+        * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
+        * is written without DLAB set, this mode will be disabled.
+        */
+       if (up->port.type == PORT_16750)
+               serial_outp(up, UART_FCR, fcr);
+
+       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       if (up->port.type != PORT_16750) {
+               if (fcr & UART_FCR_ENABLE_FIFO) {
+                       /* emulated UARTs (Lucent Venus 167x) need two steps */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               }
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       }
+       serial8250_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+}
+EXPORT_SYMBOL(serial8250_do_set_termios);
+
+static void
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       if (port->set_termios)
+               port->set_termios(port, termios, old);
+       else
+               serial8250_do_set_termios(port, termios, old);
+}
+
+static void
+serial8250_set_ldisc(struct uart_port *port, int new)
+{
+       if (new == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               serial8250_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
+
+void serial8250_do_pm(struct uart_port *port, unsigned int state,
+                     unsigned int oldstate)
+{
+       struct uart_8250_port *p =
+               container_of(port, struct uart_8250_port, port);
+
+       serial8250_set_sleep(p, state != 0);
+}
+EXPORT_SYMBOL(serial8250_do_pm);
+
+static void
+serial8250_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       if (port->pm)
+               port->pm(port, state, oldstate);
+       else
+               serial8250_do_pm(port, state, oldstate);
+}
+
+static unsigned int serial8250_port_size(struct uart_8250_port *pt)
+{
+       if (pt->port.iotype == UPIO_AU)
+               return 0x1000;
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port(pt))
+               return 0x16 << pt->port.regshift;
+#endif
+       return 8 << pt->port.regshift;
+}
+
+/*
+ * Resource handling.
+ */
+static int serial8250_request_std_resource(struct uart_8250_port *up)
+{
+       unsigned int size = serial8250_port_size(up);
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_MEM32:
+       case UPIO_MEM:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               if (!up->port.mapbase)
+                       break;
+
+               if (!request_mem_region(up->port.mapbase, size, "serial")) {
+                       ret = -EBUSY;
+                       break;
+               }
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       up->port.membase = ioremap_nocache(up->port.mapbase,
+                                                                       size);
+                       if (!up->port.membase) {
+                               release_mem_region(up->port.mapbase, size);
+                               ret = -ENOMEM;
+                       }
+               }
+               break;
+
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               if (!request_region(up->port.iobase, size, "serial"))
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void serial8250_release_std_resource(struct uart_8250_port *up)
+{
+       unsigned int size = serial8250_port_size(up);
+
+       switch (up->port.iotype) {
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_MEM32:
+       case UPIO_MEM:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               if (!up->port.mapbase)
+                       break;
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+               }
+
+               release_mem_region(up->port.mapbase, size);
+               break;
+
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               release_region(up->port.iobase, size);
+               break;
+       }
+}
+
+static int serial8250_request_rsa_resource(struct uart_8250_port *up)
+{
+       unsigned long start = UART_RSA_BASE << up->port.regshift;
+       unsigned int size = 8 << up->port.regshift;
+       int ret = -EINVAL;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               start += up->port.iobase;
+               if (request_region(start, size, "serial-rsa"))
+                       ret = 0;
+               else
+                       ret = -EBUSY;
+               break;
+       }
+
+       return ret;
+}
+
+static void serial8250_release_rsa_resource(struct uart_8250_port *up)
+{
+       unsigned long offset = UART_RSA_BASE << up->port.regshift;
+       unsigned int size = 8 << up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+       case UPIO_PORT:
+               release_region(up->port.iobase + offset, size);
+               break;
+       }
+}
+
+static void serial8250_release_port(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       serial8250_release_std_resource(up);
+       if (up->port.type == PORT_RSA)
+               serial8250_release_rsa_resource(up);
+}
+
+static int serial8250_request_port(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       int ret = 0;
+
+       ret = serial8250_request_std_resource(up);
+       if (ret == 0 && up->port.type == PORT_RSA) {
+               ret = serial8250_request_rsa_resource(up);
+               if (ret < 0)
+                       serial8250_release_std_resource(up);
+       }
+
+       return ret;
+}
+
+static void serial8250_config_port(struct uart_port *port, int flags)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       int probeflags = PROBE_ANY;
+       int ret;
+
+       /*
+        * Find the region that we can probe for.  This in turn
+        * tells us whether we can probe for the type of port.
+        */
+       ret = serial8250_request_std_resource(up);
+       if (ret < 0)
+               return;
+
+       ret = serial8250_request_rsa_resource(up);
+       if (ret < 0)
+               probeflags &= ~PROBE_RSA;
+
+       if (up->port.iotype != up->cur_iotype)
+               set_io_from_upio(port);
+
+       if (flags & UART_CONFIG_TYPE)
+               autoconfig(up, probeflags);
+
+       /* if access method is AU, it is a 16550 with a quirk */
+       if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
+               up->bugs |= UART_BUG_NOMSR;
+
+       if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
+               autoconfig_irq(up);
+
+       if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
+               serial8250_release_rsa_resource(up);
+       if (up->port.type == PORT_UNKNOWN)
+               serial8250_release_std_resource(up);
+}
+
+static int
+serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->irq >= nr_irqs || ser->irq < 0 ||
+           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+           ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
+           ser->type == PORT_STARTECH)
+               return -EINVAL;
+       return 0;
+}
+
+static const char *
+serial8250_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops serial8250_pops = {
+       .tx_empty       = serial8250_tx_empty,
+       .set_mctrl      = serial8250_set_mctrl,
+       .get_mctrl      = serial8250_get_mctrl,
+       .stop_tx        = serial8250_stop_tx,
+       .start_tx       = serial8250_start_tx,
+       .stop_rx        = serial8250_stop_rx,
+       .enable_ms      = serial8250_enable_ms,
+       .break_ctl      = serial8250_break_ctl,
+       .startup        = serial8250_startup,
+       .shutdown       = serial8250_shutdown,
+       .set_termios    = serial8250_set_termios,
+       .set_ldisc      = serial8250_set_ldisc,
+       .pm             = serial8250_pm,
+       .type           = serial8250_type,
+       .release_port   = serial8250_release_port,
+       .request_port   = serial8250_request_port,
+       .config_port    = serial8250_config_port,
+       .verify_port    = serial8250_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = serial8250_get_poll_char,
+       .poll_put_char = serial8250_put_poll_char,
+#endif
+};
+
+static struct uart_8250_port serial8250_ports[UART_NR];
+
+static void (*serial8250_isa_config)(int port, struct uart_port *up,
+       unsigned short *capabilities);
+
+void serial8250_set_isa_configurator(
+       void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
+{
+       serial8250_isa_config = v;
+}
+EXPORT_SYMBOL(serial8250_set_isa_configurator);
+
+static void __init serial8250_isa_init_ports(void)
+{
+       struct uart_8250_port *up;
+       static int first = 1;
+       int i, irqflag = 0;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               up->port.line = i;
+               spin_lock_init(&up->port.lock);
+
+               init_timer(&up->timer);
+               up->timer.function = serial8250_timeout;
+
+               /*
+                * ALPHA_KLUDGE_MCR needs to be killed.
+                */
+               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+               up->mcr_force = ALPHA_KLUDGE_MCR;
+
+               up->port.ops = &serial8250_pops;
+       }
+
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
+       for (i = 0, up = serial8250_ports;
+            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
+            i++, up++) {
+               up->port.iobase   = old_serial_port[i].port;
+               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+               up->port.irqflags = old_serial_port[i].irqflags;
+               up->port.uartclk  = old_serial_port[i].baud_base * 16;
+               up->port.flags    = old_serial_port[i].flags;
+               up->port.hub6     = old_serial_port[i].hub6;
+               up->port.membase  = old_serial_port[i].iomem_base;
+               up->port.iotype   = old_serial_port[i].io_type;
+               up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               set_io_from_upio(&up->port);
+               up->port.irqflags |= irqflag;
+               if (serial8250_isa_config != NULL)
+                       serial8250_isa_config(i, &up->port, &up->capabilities);
+
+       }
+}
+
+static void
+serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
+{
+       up->port.type = type;
+       up->port.fifosize = uart_config[type].fifo_size;
+       up->capabilities = uart_config[type].flags;
+       up->tx_loadsz = uart_config[type].tx_loadsz;
+}
+
+static void __init
+serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+{
+       int i;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+               up->cur_iotype = 0xFF;
+       }
+
+       serial8250_isa_init_ports();
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               up->port.dev = dev;
+
+               if (up->port.flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(up, up->port.type);
+
+               uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+
+static void serial8250_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       wait_for_xmitr(up, UART_LSR_THRE);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void
+serial8250_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_8250_port *up = &serial8250_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       touch_nmi_watchdog();
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               /* serial8250_handle_port() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+
+       if (up->capabilities & UART_CAP_UUE)
+               serial_out(up, UART_IER, UART_IER_UUE);
+       else
+               serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial8250_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier);
+
+       /*
+        *      The receive handling will happen properly because the
+        *      receive ready bit will still be set; it is not cleared
+        *      on read.  However, modem control will not, we must
+        *      call it if we have saved something in the saved flags
+        *      while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init serial8250_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= nr_uarts)
+               co->index = 0;
+       port = &serial8250_ports[co->index].port;
+       if (!port->iobase && !port->membase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static int serial8250_console_early_setup(void)
+{
+       return serial8250_find_port_for_earlycon();
+}
+
+static struct console serial8250_console = {
+       .name           = "ttyS",
+       .write          = serial8250_console_write,
+       .device         = uart_console_device,
+       .setup          = serial8250_console_setup,
+       .early_setup    = serial8250_console_early_setup,
+       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
+       .index          = -1,
+       .data           = &serial8250_reg,
+};
+
+static int __init serial8250_console_init(void)
+{
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
+       serial8250_isa_init_ports();
+       register_console(&serial8250_console);
+       return 0;
+}
+console_initcall(serial8250_console_init);
+
+int serial8250_find_port(struct uart_port *p)
+{
+       int line;
+       struct uart_port *port;
+
+       for (line = 0; line < nr_uarts; line++) {
+               port = &serial8250_ports[line].port;
+               if (uart_match_port(p, port))
+                       return line;
+       }
+       return -ENODEV;
+}
+
+#define SERIAL8250_CONSOLE     &serial8250_console
+#else
+#define SERIAL8250_CONSOLE     NULL
+#endif
+
+static struct uart_driver serial8250_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .cons                   = SERIAL8250_CONSOLE,
+};
+
+/*
+ * early_serial_setup - early registration for 8250 ports
+ *
+ * Setup an 8250 port structure prior to console initialisation.  Use
+ * after console initialisation will cause undefined behaviour.
+ */
+int __init early_serial_setup(struct uart_port *port)
+{
+       struct uart_port *p;
+
+       if (port->line >= ARRAY_SIZE(serial8250_ports))
+               return -ENODEV;
+
+       serial8250_isa_init_ports();
+       p = &serial8250_ports[port->line].port;
+       p->iobase       = port->iobase;
+       p->membase      = port->membase;
+       p->irq          = port->irq;
+       p->irqflags     = port->irqflags;
+       p->uartclk      = port->uartclk;
+       p->fifosize     = port->fifosize;
+       p->regshift     = port->regshift;
+       p->iotype       = port->iotype;
+       p->flags        = port->flags;
+       p->mapbase      = port->mapbase;
+       p->private_data = port->private_data;
+       p->type         = port->type;
+       p->line         = port->line;
+
+       set_io_from_upio(p);
+       if (port->serial_in)
+               p->serial_in = port->serial_in;
+       if (port->serial_out)
+               p->serial_out = port->serial_out;
+
+       return 0;
+}
+
+/**
+ *     serial8250_suspend_port - suspend one serial port
+ *     @line:  serial line number
+ *
+ *     Suspend one serial port.
+ */
+void serial8250_suspend_port(int line)
+{
+       uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
+}
+
+/**
+ *     serial8250_resume_port - resume one serial port
+ *     @line:  serial line number
+ *
+ *     Resume one serial port.
+ */
+void serial8250_resume_port(int line)
+{
+       struct uart_8250_port *up = &serial8250_ports[line];
+
+       if (up->capabilities & UART_NATSEMI) {
+               unsigned char tmp;
+
+               /* Ensure it's still in high speed mode */
+               serial_outp(up, UART_LCR, 0xE0);
+
+               tmp = serial_in(up, 0x04); /* EXCR2 */
+               tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+               tmp |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+               serial_outp(up, 0x04, tmp);
+
+               serial_outp(up, UART_LCR, 0);
+       }
+       uart_resume_port(&serial8250_reg, &up->port);
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.  The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set.
+ */
+static int __devinit serial8250_probe(struct platform_device *dev)
+{
+       struct plat_serial8250_port *p = dev->dev.platform_data;
+       struct uart_port port;
+       int ret, i, irqflag = 0;
+
+       memset(&port, 0, sizeof(struct uart_port));
+
+       if (share_irqs)
+               irqflag = IRQF_SHARED;
+
+       for (i = 0; p && p->flags != 0; p++, i++) {
+               port.iobase             = p->iobase;
+               port.membase            = p->membase;
+               port.irq                = p->irq;
+               port.irqflags           = p->irqflags;
+               port.uartclk            = p->uartclk;
+               port.regshift           = p->regshift;
+               port.iotype             = p->iotype;
+               port.flags              = p->flags;
+               port.mapbase            = p->mapbase;
+               port.hub6               = p->hub6;
+               port.private_data       = p->private_data;
+               port.type               = p->type;
+               port.serial_in          = p->serial_in;
+               port.serial_out         = p->serial_out;
+               port.set_termios        = p->set_termios;
+               port.pm                 = p->pm;
+               port.dev                = &dev->dev;
+               port.irqflags           |= irqflag;
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial8250_remove(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.dev == &dev->dev)
+                       serial8250_unregister_port(i);
+       }
+       return 0;
+}
+
+static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_suspend_port(&serial8250_reg, &up->port);
+       }
+
+       return 0;
+}
+
+static int serial8250_resume(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       serial8250_resume_port(i);
+       }
+
+       return 0;
+}
+
+static struct platform_driver serial8250_isa_driver = {
+       .probe          = serial8250_probe,
+       .remove         = __devexit_p(serial8250_remove),
+       .suspend        = serial8250_suspend,
+       .resume         = serial8250_resume,
+       .driver         = {
+               .name   = "serial8250",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*
+ * This "device" covers _all_ ISA 8250-compatible serial devices listed
+ * in the table in include/asm/serial.h
+ */
+static struct platform_device *serial8250_isa_devs;
+
+/*
+ * serial8250_register_port and serial8250_unregister_port allows for
+ * 16x50 serial ports to be configured at run-time, to support PCMCIA
+ * modems and PCI multiport cards.
+ */
+static DEFINE_MUTEX(serial_mutex);
+
+static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+{
+       int i;
+
+       /*
+        * First, find a port entry which matches.
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (uart_match_port(&serial8250_ports[i].port, port))
+                       return &serial8250_ports[i];
+
+       /*
+        * We didn't find a matching entry, so look for the first
+        * free entry.  We look for one which hasn't been previously
+        * used (indicated by zero iobase).
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
+                   serial8250_ports[i].port.iobase == 0)
+                       return &serial8250_ports[i];
+
+       /*
+        * That also failed.  Last resort is to find any entry which
+        * doesn't have a real port associated with it.
+        */
+       for (i = 0; i < nr_uarts; i++)
+               if (serial8250_ports[i].port.type == PORT_UNKNOWN)
+                       return &serial8250_ports[i];
+
+       return NULL;
+}
+
+/**
+ *     serial8250_register_port - register a serial port
+ *     @port: serial port template
+ *
+ *     Configure the serial port specified by the request. If the
+ *     port exists and is in use, it is hung up and unregistered
+ *     first.
+ *
+ *     The port is then probed and if necessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_port(struct uart_port *port)
+{
+       struct uart_8250_port *uart;
+       int ret = -ENOSPC;
+
+       if (port->uartclk == 0)
+               return -EINVAL;
+
+       mutex_lock(&serial_mutex);
+
+       uart = serial8250_find_match_or_unused(port);
+       if (uart) {
+               uart_remove_one_port(&serial8250_reg, &uart->port);
+
+               uart->port.iobase       = port->iobase;
+               uart->port.membase      = port->membase;
+               uart->port.irq          = port->irq;
+               uart->port.irqflags     = port->irqflags;
+               uart->port.uartclk      = port->uartclk;
+               uart->port.fifosize     = port->fifosize;
+               uart->port.regshift     = port->regshift;
+               uart->port.iotype       = port->iotype;
+               uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
+               uart->port.mapbase      = port->mapbase;
+               uart->port.private_data = port->private_data;
+               if (port->dev)
+                       uart->port.dev = port->dev;
+
+               if (port->flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(uart, port->type);
+
+               set_io_from_upio(&uart->port);
+               /* Possibly override default I/O functions.  */
+               if (port->serial_in)
+                       uart->port.serial_in = port->serial_in;
+               if (port->serial_out)
+                       uart->port.serial_out = port->serial_out;
+               /*  Possibly override set_termios call */
+               if (port->set_termios)
+                       uart->port.set_termios = port->set_termios;
+               if (port->pm)
+                       uart->port.pm = port->pm;
+
+               if (serial8250_isa_config != NULL)
+                       serial8250_isa_config(0, &uart->port,
+                                       &uart->capabilities);
+
+               ret = uart_add_one_port(&serial8250_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
+       }
+       mutex_unlock(&serial_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(serial8250_register_port);
+
+/**
+ *     serial8250_unregister_port - remove a 16x50 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may not be called from interrupt
+ *     context.  We hand the port back to the our control.
+ */
+void serial8250_unregister_port(int line)
+{
+       struct uart_8250_port *uart = &serial8250_ports[line];
+
+       mutex_lock(&serial_mutex);
+       uart_remove_one_port(&serial8250_reg, &uart->port);
+       if (serial8250_isa_devs) {
+               uart->port.flags &= ~UPF_BOOT_AUTOCONF;
+               uart->port.type = PORT_UNKNOWN;
+               uart->port.dev = &serial8250_isa_devs->dev;
+               uart_add_one_port(&serial8250_reg, &uart->port);
+       } else {
+               uart->port.dev = NULL;
+       }
+       mutex_unlock(&serial_mutex);
+}
+EXPORT_SYMBOL(serial8250_unregister_port);
+
+static int __init serial8250_init(void)
+{
+       int ret;
+
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
+       printk(KERN_INFO "Serial: 8250/16550 driver, "
+               "%d ports, IRQ sharing %sabled\n", nr_uarts,
+               share_irqs ? "en" : "dis");
+
+#ifdef CONFIG_SPARC
+       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+       serial8250_reg.nr = UART_NR;
+       ret = uart_register_driver(&serial8250_reg);
+#endif
+       if (ret)
+               goto out;
+
+       serial8250_isa_devs = platform_device_alloc("serial8250",
+                                                   PLAT8250_DEV_LEGACY);
+       if (!serial8250_isa_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
+       }
+
+       ret = platform_device_add(serial8250_isa_devs);
+       if (ret)
+               goto put_dev;
+
+       serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
+
+       ret = platform_driver_register(&serial8250_isa_driver);
+       if (ret == 0)
+               goto out;
+
+       platform_device_del(serial8250_isa_devs);
+put_dev:
+       platform_device_put(serial8250_isa_devs);
+unreg_uart_drv:
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+       uart_unregister_driver(&serial8250_reg);
+#endif
+out:
+       return ret;
+}
+
+static void __exit serial8250_exit(void)
+{
+       struct platform_device *isa_dev = serial8250_isa_devs;
+
+       /*
+        * This tells serial8250_unregister_port() not to re-register
+        * the ports (thereby making serial8250_isa_driver permanently
+        * in use.)
+        */
+       serial8250_isa_devs = NULL;
+
+       platform_driver_unregister(&serial8250_isa_driver);
+       platform_device_unregister(isa_dev);
+
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+       uart_unregister_driver(&serial8250_reg);
+#endif
+}
+
+module_init(serial8250_init);
+module_exit(serial8250_exit);
+
+EXPORT_SYMBOL(serial8250_suspend_port);
+EXPORT_SYMBOL(serial8250_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
+
+module_param(share_irqs, uint, 0644);
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
+       " (unsafe)");
+
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
+module_param(skip_txen_test, uint, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
+#ifdef CONFIG_SERIAL_8250_RSA
+module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+#endif
+MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250.h
new file mode 100644 (file)
index 0000000..6e19ea3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  linux/drivers/char/8250.h
+ *
+ *  Driver for 8250/16550-type serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/serial_8250.h>
+
+struct old_serial_port {
+       unsigned int uart;
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       unsigned int flags;
+       unsigned char hub6;
+       unsigned char io_type;
+       unsigned char *iomem_base;
+       unsigned short iomem_reg_shift;
+       unsigned long irqflags;
+};
+
+/*
+ * This replaces serial_uart_config in include/linux/serial.h
+ */
+struct serial8250_config {
+       const char      *name;
+       unsigned short  fifo_size;
+       unsigned short  tx_loadsz;
+       unsigned char   fcr;
+       unsigned int    flags;
+};
+
+#define UART_CAP_FIFO  (1 << 8)        /* UART has FIFO */
+#define UART_CAP_EFR   (1 << 9)        /* UART has EFR */
+#define UART_CAP_SLEEP (1 << 10)       /* UART has IER sleep */
+#define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
+#define UART_CAP_UUE   (1 << 12)       /* UART needs IER bit 6 set (Xscale) */
+
+#define UART_BUG_QUOT  (1 << 0)        /* UART has buggy quot LSB */
+#define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
+#define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
+#define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
+
+#define PROBE_RSA      (1 << 0)
+#define PROBE_ANY      (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
+#define SERIAL8250_SHARE_IRQS 1
+#else
+#define SERIAL8250_SHARE_IRQS 0
+#endif
+
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+/*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on at least some ALPHA's.  The failure mode is that if either
+ * is cleared, the machine locks up with endless interrupts.
+ */
+#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#elif defined(CONFIG_SBC8560)
+/*
+ * WindRiver did something similarly broken on their SBC8560 board. The
+ * UART tristates its IRQ output while OUT2 is clear, but they pulled
+ * the interrupt line _up_ instead of down, so if we register the IRQ
+ * while the UART is in that state, we die in an IRQ storm. */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
+#else
+#define ALPHA_KLUDGE_MCR 0
+#endif
diff --git a/drivers/tty/serial/8250_accent.c b/drivers/tty/serial/8250_accent.c
new file mode 100644 (file)
index 0000000..9c10262
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  linux/drivers/serial/8250_accent.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port accent_data[] = {
+       PORT(0x330, 4),
+       PORT(0x338, 4),
+       { },
+};
+
+static struct platform_device accent_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_ACCENT,
+       .dev                    = {
+               .platform_data  = accent_data,
+       },
+};
+
+static int __init accent_init(void)
+{
+       return platform_device_register(&accent_device);
+}
+
+module_init(accent_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_acorn.c b/drivers/tty/serial/8250_acorn.c
new file mode 100644 (file)
index 0000000..b0ce8c5
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  linux/drivers/serial/acorn.c
+ *
+ *  Copyright (C) 1996-2003 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/ecard.h>
+#include <asm/string.h>
+
+#include "8250.h"
+
+#define MAX_PORTS      3
+
+struct serial_card_type {
+       unsigned int    num_ports;
+       unsigned int    uartclk;
+       unsigned int    type;
+       unsigned int    offset[MAX_PORTS];
+};
+
+struct serial_card_info {
+       unsigned int    num_ports;
+       int             ports[MAX_PORTS];
+       void __iomem *vaddr;
+};
+
+static int __devinit
+serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+       struct serial_card_info *info;
+       struct serial_card_type *type = id->data;
+       struct uart_port port;
+       unsigned long bus_addr;
+       unsigned int i;
+
+       info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->num_ports = type->num_ports;
+
+       bus_addr = ecard_resource_start(ec, type->type);
+       info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
+       if (!info->vaddr) {
+               kfree(info);
+               return -ENOMEM;
+       }
+
+       ecard_set_drvdata(ec, info);
+
+       memset(&port, 0, sizeof(struct uart_port));
+       port.irq        = ec->irq;
+       port.flags      = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       port.uartclk    = type->uartclk;
+       port.iotype     = UPIO_MEM;
+       port.regshift   = 2;
+       port.dev        = &ec->dev;
+
+       for (i = 0; i < info->num_ports; i ++) {
+               port.membase = info->vaddr + type->offset[i];
+               port.mapbase = bus_addr + type->offset[i];
+
+               info->ports[i] = serial8250_register_port(&port);
+       }
+
+       return 0;
+}
+
+static void __devexit serial_card_remove(struct expansion_card *ec)
+{
+       struct serial_card_info *info = ecard_get_drvdata(ec);
+       int i;
+
+       ecard_set_drvdata(ec, NULL);
+
+       for (i = 0; i < info->num_ports; i++)
+               if (info->ports[i] > 0)
+                       serial8250_unregister_port(info->ports[i]);
+
+       kfree(info);
+}
+
+static struct serial_card_type atomwide_type = {
+       .num_ports      = 3,
+       .uartclk        = 7372800,
+       .type           = ECARD_RES_IOCSLOW,
+       .offset         = { 0x2800, 0x2400, 0x2000 },
+};
+
+static struct serial_card_type serport_type = {
+       .num_ports      = 2,
+       .uartclk        = 3686400,
+       .type           = ECARD_RES_IOCSLOW,
+       .offset         = { 0x2000, 0x2020 },
+};
+
+static const struct ecard_id serial_cids[] = {
+       { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
+       { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
+       { 0xffff, 0xffff }
+};
+
+static struct ecard_driver serial_card_driver = {
+       .probe          = serial_card_probe,
+       .remove         = __devexit_p(serial_card_remove),
+       .id_table       = serial_cids,
+       .drv = {
+               .name   = "8250_acorn",
+       },
+};
+
+static int __init serial_card_init(void)
+{
+       return ecard_register_driver(&serial_card_driver);
+}
+
+static void __exit serial_card_exit(void)
+{
+       ecard_remove_driver(&serial_card_driver);
+}
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
+MODULE_LICENSE("GPL");
+
+module_init(serial_card_init);
+module_exit(serial_card_exit);
diff --git a/drivers/tty/serial/8250_boca.c b/drivers/tty/serial/8250_boca.c
new file mode 100644 (file)
index 0000000..3bfe0f7
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  linux/drivers/serial/8250_boca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port boca_data[] = {
+       PORT(0x100, 12),
+       PORT(0x108, 12),
+       PORT(0x110, 12),
+       PORT(0x118, 12),
+       PORT(0x120, 12),
+       PORT(0x128, 12),
+       PORT(0x130, 12),
+       PORT(0x138, 12),
+       PORT(0x140, 12),
+       PORT(0x148, 12),
+       PORT(0x150, 12),
+       PORT(0x158, 12),
+       PORT(0x160, 12),
+       PORT(0x168, 12),
+       PORT(0x170, 12),
+       PORT(0x178, 12),
+       { },
+};
+
+static struct platform_device boca_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_BOCA,
+       .dev                    = {
+               .platform_data  = boca_data,
+       },
+};
+
+static int __init boca_init(void)
+{
+       return platform_device_register(&boca_device);
+}
+
+module_init(boca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_early.c b/drivers/tty/serial/8250_early.c
new file mode 100644 (file)
index 0000000..eaafb98
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Early serial console for 8250/16550 devices
+ *
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
+ * and on early_printk.c by Andi Kleen.
+ *
+ * This is for use before the serial driver has initialized, in
+ * particular, before the UARTs have been discovered and named.
+ * Instead of specifying the console device as, e.g., "ttyS0",
+ * we locate the device directly by its MMIO or I/O port address.
+ *
+ * The user can specify the device directly, e.g.,
+ *     earlycon=uart8250,io,0x3f8,9600n8
+ *     earlycon=uart8250,mmio,0xff5e0000,115200n8
+ *     earlycon=uart8250,mmio32,0xff5e0000,115200n8
+ * or
+ *     console=uart8250,io,0x3f8,9600n8
+ *     console=uart8250,mmio,0xff5e0000,115200n8
+ *     console=uart8250,mmio32,0xff5e0000,115200n8
+ */
+
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+#ifdef CONFIG_FIX_EARLYCON_MEM
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#endif
+
+struct early_serial8250_device {
+       struct uart_port port;
+       char options[16];               /* e.g., 115200n8 */
+       unsigned int baud;
+};
+
+static struct early_serial8250_device early_device;
+
+static unsigned int __init serial_in(struct uart_port *port, int offset)
+{
+       switch (port->iotype) {
+       case UPIO_MEM:
+               return readb(port->membase + offset);
+       case UPIO_MEM32:
+               return readl(port->membase + (offset << 2));
+       case UPIO_PORT:
+               return inb(port->iobase + offset);
+       default:
+               return 0;
+       }
+}
+
+static void __init serial_out(struct uart_port *port, int offset, int value)
+{
+       switch (port->iotype) {
+       case UPIO_MEM:
+               writeb(value, port->membase + offset);
+               break;
+       case UPIO_MEM32:
+               writel(value, port->membase + (offset << 2));
+               break;
+       case UPIO_PORT:
+               outb(value, port->iobase + offset);
+               break;
+       }
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void __init wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int status;
+
+       for (;;) {
+               status = serial_in(port, UART_LSR);
+               if ((status & BOTH_EMPTY) == BOTH_EMPTY)
+                       return;
+               cpu_relax();
+       }
+}
+
+static void __init serial_putc(struct uart_port *port, int c)
+{
+       wait_for_xmitr(port);
+       serial_out(port, UART_TX, c);
+}
+
+static void __init early_serial8250_write(struct console *console,
+                                       const char *s, unsigned int count)
+{
+       struct uart_port *port = &early_device.port;
+       unsigned int ier;
+
+       /* Save the IER and disable interrupts */
+       ier = serial_in(port, UART_IER);
+       serial_out(port, UART_IER, 0);
+
+       uart_console_write(port, s, count, serial_putc);
+
+       /* Wait for transmitter to become empty and restore the IER */
+       wait_for_xmitr(port);
+       serial_out(port, UART_IER, ier);
+}
+
+static unsigned int __init probe_baud(struct uart_port *port)
+{
+       unsigned char lcr, dll, dlm;
+       unsigned int quot;
+
+       lcr = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+       dll = serial_in(port, UART_DLL);
+       dlm = serial_in(port, UART_DLM);
+       serial_out(port, UART_LCR, lcr);
+
+       quot = (dlm << 8) | dll;
+       return (port->uartclk / 16) / quot;
+}
+
+static void __init init_port(struct early_serial8250_device *device)
+{
+       struct uart_port *port = &device->port;
+       unsigned int divisor;
+       unsigned char c;
+
+       serial_out(port, UART_LCR, 0x3);        /* 8n1 */
+       serial_out(port, UART_IER, 0);          /* no interrupt */
+       serial_out(port, UART_FCR, 0);          /* no fifo */
+       serial_out(port, UART_MCR, 0x3);        /* DTR + RTS */
+
+       divisor = port->uartclk / (16 * device->baud);
+       c = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, c | UART_LCR_DLAB);
+       serial_out(port, UART_DLL, divisor & 0xff);
+       serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
+       serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+}
+
+static int __init parse_options(struct early_serial8250_device *device,
+                                                               char *options)
+{
+       struct uart_port *port = &device->port;
+       int mmio, mmio32, length;
+
+       if (!options)
+               return -ENODEV;
+
+       port->uartclk = BASE_BAUD * 16;
+
+       mmio = !strncmp(options, "mmio,", 5);
+       mmio32 = !strncmp(options, "mmio32,", 7);
+       if (mmio || mmio32) {
+               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
+               port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
+                                              &options, 0);
+               if (mmio32)
+                       port->regshift = 2;
+#ifdef CONFIG_FIX_EARLYCON_MEM
+               set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
+                                       port->mapbase & PAGE_MASK);
+               port->membase =
+                       (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+               port->membase += port->mapbase & ~PAGE_MASK;
+#else
+               port->membase = ioremap_nocache(port->mapbase, 64);
+               if (!port->membase) {
+                       printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
+                               __func__,
+                              (unsigned long long) port->mapbase);
+                       return -ENOMEM;
+               }
+#endif
+       } else if (!strncmp(options, "io,", 3)) {
+               port->iotype = UPIO_PORT;
+               port->iobase = simple_strtoul(options + 3, &options, 0);
+               mmio = 0;
+       } else
+               return -EINVAL;
+
+       options = strchr(options, ',');
+       if (options) {
+               options++;
+               device->baud = simple_strtoul(options, NULL, 0);
+               length = min(strcspn(options, " "), sizeof(device->options));
+               strncpy(device->options, options, length);
+       } else {
+               device->baud = probe_baud(port);
+               snprintf(device->options, sizeof(device->options), "%u",
+                       device->baud);
+       }
+
+       if (mmio || mmio32)
+               printk(KERN_INFO
+                      "Early serial console at MMIO%s 0x%llx (options '%s')\n",
+                       mmio32 ? "32" : "",
+                       (unsigned long long)port->mapbase,
+                       device->options);
+       else
+               printk(KERN_INFO
+                     "Early serial console at I/O port 0x%lx (options '%s')\n",
+                       port->iobase,
+                       device->options);
+
+       return 0;
+}
+
+static struct console early_serial8250_console __initdata = {
+       .name   = "uart",
+       .write  = early_serial8250_write,
+       .flags  = CON_PRINTBUFFER | CON_BOOT,
+       .index  = -1,
+};
+
+static int __init early_serial8250_setup(char *options)
+{
+       struct early_serial8250_device *device = &early_device;
+       int err;
+
+       if (device->port.membase || device->port.iobase)
+               return 0;
+
+       err = parse_options(device, options);
+       if (err < 0)
+               return err;
+
+       init_port(device);
+       return 0;
+}
+
+int __init setup_early_serial8250_console(char *cmdline)
+{
+       char *options;
+       int err;
+
+       options = strstr(cmdline, "uart8250,");
+       if (!options) {
+               options = strstr(cmdline, "uart,");
+               if (!options)
+                       return 0;
+       }
+
+       options = strchr(cmdline, ',') + 1;
+       err = early_serial8250_setup(options);
+       if (err < 0)
+               return err;
+
+       register_console(&early_serial8250_console);
+
+       return 0;
+}
+
+int serial8250_find_port_for_earlycon(void)
+{
+       struct early_serial8250_device *device = &early_device;
+       struct uart_port *port = &device->port;
+       int line;
+       int ret;
+
+       if (!device->port.membase && !device->port.iobase)
+               return -ENODEV;
+
+       line = serial8250_find_port(port);
+       if (line < 0)
+               return -ENODEV;
+
+       ret = update_console_cmdline("uart", 8250,
+                            "ttyS", line, device->options);
+       if (ret < 0)
+               ret = update_console_cmdline("uart", 0,
+                                    "ttyS", line, device->options);
+
+       return ret;
+}
+
+early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/tty/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250_exar_st16c554.c
new file mode 100644 (file)
index 0000000..567143a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/drivers/serial/8250_exar.c
+ *
+ *  Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com >
+ *  Based on 8250_boca.
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port exar_data[] = {
+       PORT(0x100, 5),
+       PORT(0x108, 5),
+       PORT(0x110, 5),
+       PORT(0x118, 5),
+       { },
+};
+
+static struct platform_device exar_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_EXAR_ST16C554,
+       .dev                    = {
+               .platform_data  = exar_data,
+       },
+};
+
+static int __init exar_init(void)
+{
+       return platform_device_register(&exar_device);
+}
+
+module_init(exar_init);
+
+MODULE_AUTHOR("Paul B Schroeder");
+MODULE_DESCRIPTION("8250 serial probe module for Exar cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_fourport.c b/drivers/tty/serial/8250_fourport.c
new file mode 100644 (file)
index 0000000..6375d68
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  linux/drivers/serial/8250_fourport.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq)                                               \
+       {                                                               \
+               .iobase         = _base,                                \
+               .irq            = _irq,                                 \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_PORT,                            \
+               .flags          = UPF_BOOT_AUTOCONF | UPF_FOURPORT,     \
+       }
+
+static struct plat_serial8250_port fourport_data[] = {
+       PORT(0x1a0, 9),
+       PORT(0x1a8, 9),
+       PORT(0x1b0, 9),
+       PORT(0x1b8, 9),
+       PORT(0x2a0, 5),
+       PORT(0x2a8, 5),
+       PORT(0x2b0, 5),
+       PORT(0x2b8, 5),
+       { },
+};
+
+static struct platform_device fourport_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_FOURPORT,
+       .dev                    = {
+               .platform_data  = fourport_data,
+       },
+};
+
+static int __init fourport_init(void)
+{
+       return platform_device_register(&fourport_device);
+}
+
+module_init(fourport_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_gsc.c b/drivers/tty/serial/8250_gsc.c
new file mode 100644 (file)
index 0000000..d8c0ffb
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *     Serial Device Initialisation for Lasi/Asp/Wax/Dino
+ *
+ *     (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/serial_core.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include <asm/hardware.h>
+#include <asm/parisc-device.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+static int __init serial_init_chip(struct parisc_device *dev)
+{
+       struct uart_port port;
+       unsigned long address;
+       int err;
+
+       if (!dev->irq) {
+               /* We find some unattached serial ports by walking native
+                * busses.  These should be silently ignored.  Otherwise,
+                * what we have here is a missing parent device, so tell
+                * the user what they're missing.
+                */
+               if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
+                       printk(KERN_INFO
+                               "Serial: device 0x%llx not configured.\n"
+                               "Enable support for Wax, Lasi, Asp or Dino.\n",
+                               (unsigned long long)dev->hpa.start);
+               return -ENODEV;
+       }
+
+       address = dev->hpa.start;
+       if (dev->id.sversion != 0x8d)
+               address += 0x800;
+
+       memset(&port, 0, sizeof(port));
+       port.iotype     = UPIO_MEM;
+       /* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
+       port.uartclk    = 7272727;
+       port.mapbase    = address;
+       port.membase    = ioremap_nocache(address, 16);
+       port.irq        = dev->irq;
+       port.flags      = UPF_BOOT_AUTOCONF;
+       port.dev        = &dev->dev;
+
+       err = serial8250_register_port(&port);
+       if (err < 0) {
+               printk(KERN_WARNING
+                       "serial8250_register_port returned error %d\n", err);
+               iounmap(port.membase);
+               return err;
+       }
+
+       return 0;
+}
+
+static struct parisc_device_id serial_tbl[] = {
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
+       { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
+       { 0 }
+};
+
+/* Hack.  Some machines have SERIAL_0 attached to Lasi and SERIAL_1
+ * attached to Dino.  Unfortunately, Dino appears before Lasi in the device
+ * tree.  To ensure that ttyS0 == SERIAL_0, we register two drivers; one
+ * which only knows about Lasi and then a second which will find all the
+ * other serial ports.  HPUX ignores this problem.
+ */
+static struct parisc_device_id lasi_tbl[] = {
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
+       { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
+       { 0 }
+};
+
+
+MODULE_DEVICE_TABLE(parisc, serial_tbl);
+
+static struct parisc_driver lasi_driver = {
+       .name           = "serial_1",
+       .id_table       = lasi_tbl,
+       .probe          = serial_init_chip,
+};
+
+static struct parisc_driver serial_driver = {
+       .name           = "serial",
+       .id_table       = serial_tbl,
+       .probe          = serial_init_chip,
+};
+
+static int __init probe_serial_gsc(void)
+{
+       register_parisc_driver(&lasi_driver);
+       register_parisc_driver(&serial_driver);
+       return 0;
+}
+
+module_init(probe_serial_gsc);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_hp300.c b/drivers/tty/serial/8250_hp300.c
new file mode 100644 (file)
index 0000000..c13438c
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Driver for the 98626/98644/internal serial interface on hp300/hp400
+ * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
+ *
+ * Ported from 2.2 and modified to use the normal 8250 driver
+ * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/delay.h>
+#include <linux/dio.h>
+#include <linux/console.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
+#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
+#endif
+
+#ifdef CONFIG_HPAPCI
+struct hp300_port
+{
+       struct hp300_port *next;        /* next port */
+       int line;                       /* line (tty) number */
+};
+
+static struct hp300_port *hp300_ports;
+#endif
+
+#ifdef CONFIG_HPDCA
+
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                       const struct dio_device_id *ent);
+static void __devexit hpdca_remove_one(struct dio_dev *d);
+
+static struct dio_device_id hpdca_dio_tbl[] = {
+       { DIO_ID_DCA0 },
+       { DIO_ID_DCA0REM },
+       { DIO_ID_DCA1 },
+       { DIO_ID_DCA1REM },
+       { 0 }
+};
+
+static struct dio_driver hpdca_driver = {
+       .name      = "hpdca",
+       .id_table  = hpdca_dio_tbl,
+       .probe     = hpdca_init_one,
+       .remove    = __devexit_p(hpdca_remove_one),
+};
+
+#endif
+
+static unsigned int num_ports;
+
+extern int hp300_uart_scode;
+
+/* Offset to UART registers from base of DCA */
+#define UART_OFFSET    17
+
+#define DCA_ID         0x01    /* ID (read), reset (write) */
+#define DCA_IC         0x03    /* Interrupt control        */
+
+/* Interrupt control */
+#define DCA_IC_IE      0x80    /* Master interrupt enable  */
+
+#define HPDCA_BAUD_BASE 153600
+
+/* Base address of the Frodo part */
+#define FRODO_BASE     (0x41c000)
+
+/*
+ * Where we find the 8250-like APCI ports, and how far apart they are.
+ */
+#define FRODO_APCIBASE         0x0
+#define FRODO_APCISPACE                0x20
+#define FRODO_APCI_OFFSET(x)   (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
+
+#define HPAPCI_BAUD_BASE 500400
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+/*
+ * Parse the bootinfo to find descriptions for headless console and
+ * debug serial ports and register them with the 8250 driver.
+ * This function should be called before serial_console_init() is called
+ * to make sure the serial console will be available for use. IA-64 kernel
+ * calls this function from setup_arch() after the EFI and ACPI tables have
+ * been parsed.
+ */
+int __init hp300_setup_serial_console(void)
+{
+       int scode;
+       struct uart_port port;
+
+       memset(&port, 0, sizeof(port));
+
+       if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
+               return 0;
+
+       if (DIO_SCINHOLE(hp300_uart_scode))
+               return 0;
+
+       scode = hp300_uart_scode;
+
+       /* Memory mapped I/O */
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       port.type = PORT_UNKNOWN;
+
+       /* Check for APCI console */
+       if (scode == 256) {
+#ifdef CONFIG_HPAPCI
+               printk(KERN_INFO "Serial console is HP APCI 1\n");
+
+               port.uartclk = HPAPCI_BAUD_BASE * 16;
+               port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 2;
+               add_preferred_console("ttyS", port.line, "9600n8");
+#else
+               printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+               return 0;
+#endif
+       } else {
+#ifdef CONFIG_HPDCA
+               unsigned long pa = dio_scodetophysaddr(scode);
+               if (!pa)
+                       return 0;
+
+               printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+
+               port.uartclk = HPDCA_BAUD_BASE * 16;
+               port.mapbase = (pa + UART_OFFSET);
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 1;
+               port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
+
+               /* Enable board-interrupts */
+               out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+
+               if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
+                       add_preferred_console("ttyS", port.line, "9600n8");
+#else
+               printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+               return 0;
+#endif
+       }
+
+       if (early_serial_setup(&port) < 0)
+               printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+       return 0;
+}
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+#ifdef CONFIG_HPDCA
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                               const struct dio_device_id *ent)
+{
+       struct uart_port port;
+       int line;
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       if (hp300_uart_scode == d->scode) {
+               /* Already got it. */
+               return 0;
+       }
+#endif
+       memset(&port, 0, sizeof(struct uart_port));
+
+       /* Memory mapped I/O */
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       port.irq = d->ipl;
+       port.uartclk = HPDCA_BAUD_BASE * 16;
+       port.mapbase = (d->resource.start + UART_OFFSET);
+       port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+       port.regshift = 1;
+       port.dev = &d->dev;
+       line = serial8250_register_port(&port);
+
+       if (line < 0) {
+               printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
+                      " irq %d failed\n", d->scode, port.irq);
+               return -ENOMEM;
+       }
+
+       /* Enable board-interrupts */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+       dio_set_drvdata(d, (void *)line);
+
+       /* Reset the DCA */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
+       udelay(100);
+
+       num_ports++;
+
+       return 0;
+}
+#endif
+
+static int __init hp300_8250_init(void)
+{
+       static int called;
+#ifdef CONFIG_HPAPCI
+       int line;
+       unsigned long base;
+       struct uart_port uport;
+       struct hp300_port *port;
+       int i;
+#endif
+       if (called)
+               return -ENODEV;
+       called = 1;
+
+       if (!MACH_IS_HP300)
+               return -ENODEV;
+
+#ifdef CONFIG_HPDCA
+       dio_register_driver(&hpdca_driver);
+#endif
+#ifdef CONFIG_HPAPCI
+       if (hp300_model < HP_400) {
+               if (!num_ports)
+                       return -ENODEV;
+               return 0;
+       }
+       /* These models have the Frodo chip.
+        * Port 0 is reserved for the Apollo Domain keyboard.
+        * Port 1 is either the console or the DCA.
+        */
+       for (i = 1; i < 4; i++) {
+               /* Port 1 is the console on a 425e, on other machines it's
+                * mapped to DCA.
+                */
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+               if (i == 1)
+                       continue;
+#endif
+
+               /* Create new serial device */
+               port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
+               if (!port)
+                       return -ENOMEM;
+
+               memset(&uport, 0, sizeof(struct uart_port));
+
+               base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
+
+               /* Memory mapped I/O */
+               uport.iotype = UPIO_MEM;
+               uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
+                             | UPF_BOOT_AUTOCONF;
+               /* XXX - no interrupt support yet */
+               uport.irq = 0;
+               uport.uartclk = HPAPCI_BAUD_BASE * 16;
+               uport.mapbase = base;
+               uport.membase = (char *)(base + DIO_VIRADDRBASE);
+               uport.regshift = 2;
+
+               line = serial8250_register_port(&uport);
+
+               if (line < 0) {
+                       printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
+                              " %d irq %d failed\n", i, uport.irq);
+                       kfree(port);
+                       continue;
+               }
+
+               port->line = line;
+               port->next = hp300_ports;
+               hp300_ports = port;
+
+               num_ports++;
+       }
+#endif
+
+       /* Any boards found? */
+       if (!num_ports)
+               return -ENODEV;
+
+       return 0;
+}
+
+#ifdef CONFIG_HPDCA
+static void __devexit hpdca_remove_one(struct dio_dev *d)
+{
+       int line;
+
+       line = (int) dio_get_drvdata(d);
+       if (d->resource.start) {
+               /* Disable board-interrupts */
+               out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
+       }
+       serial8250_unregister_port(line);
+}
+#endif
+
+static void __exit hp300_8250_exit(void)
+{
+#ifdef CONFIG_HPAPCI
+       struct hp300_port *port, *to_free;
+
+       for (port = hp300_ports; port; ) {
+               serial8250_unregister_port(port->line);
+               to_free = port;
+               port = port->next;
+               kfree(to_free);
+       }
+
+       hp300_ports = NULL;
+#endif
+#ifdef CONFIG_HPDCA
+       dio_unregister_driver(&hpdca_driver);
+#endif
+}
+
+module_init(hp300_8250_init);
+module_exit(hp300_8250_exit);
+MODULE_DESCRIPTION("HP DCA/APCI serial driver");
+MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_hub6.c b/drivers/tty/serial/8250_hub6.c
new file mode 100644 (file)
index 0000000..7609150
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  linux/drivers/serial/8250_hub6.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define HUB6(card,port)                                                        \
+       {                                                               \
+               .iobase         = 0x302,                                \
+               .irq            = 3,                                    \
+               .uartclk        = 1843200,                              \
+               .iotype         = UPIO_HUB6,                            \
+               .flags          = UPF_BOOT_AUTOCONF,                    \
+               .hub6           = (card) << 6 | (port) << 3 | 1,        \
+       }
+
+static struct plat_serial8250_port hub6_data[] = {
+       HUB6(0, 0),
+       HUB6(0, 1),
+       HUB6(0, 2),
+       HUB6(0, 3),
+       HUB6(0, 4),
+       HUB6(0, 5),
+       HUB6(1, 0),
+       HUB6(1, 1),
+       HUB6(1, 2),
+       HUB6(1, 3),
+       HUB6(1, 4),
+       HUB6(1, 5),
+       { },
+};
+
+static struct platform_device hub6_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_HUB6,
+       .dev                    = {
+               .platform_data  = hub6_data,
+       },
+};
+
+static int __init hub6_init(void)
+{
+       return platform_device_register(&hub6_device);
+}
+
+module_init(hub6_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_mca.c b/drivers/tty/serial/8250_mca.c
new file mode 100644 (file)
index 0000000..d10be94
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/drivers/serial/8250_mca.c
+ *
+ *  Copyright (C) 2005 Russell King.
+ *  Data taken from include/asm-i386/serial.h
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/serial_8250.h>
+
+/*
+ * FIXME: Should we be doing AUTO_IRQ here?
+ */
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
+#else
+#define MCA_FLAGS      UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+#endif
+
+#define PORT(_base,_irq)                       \
+       {                                       \
+               .iobase         = _base,        \
+               .irq            = _irq,         \
+               .uartclk        = 1843200,      \
+               .iotype         = UPIO_PORT,    \
+               .flags          = MCA_FLAGS,    \
+       }
+
+static struct plat_serial8250_port mca_data[] = {
+       PORT(0x3220, 3),
+       PORT(0x3228, 3),
+       PORT(0x4220, 3),
+       PORT(0x4228, 3),
+       PORT(0x5220, 3),
+       PORT(0x5228, 3),
+       { },
+};
+
+static struct platform_device mca_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_MCA,
+       .dev                    = {
+               .platform_data  = mca_data,
+       },
+};
+
+static int __init mca_init(void)
+{
+       if (!MCA_bus)
+               return -ENODEV;
+       return platform_device_register(&mca_device);
+}
+
+module_init(mca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
new file mode 100644 (file)
index 0000000..8b8930f
--- /dev/null
@@ -0,0 +1,3850 @@
+/*
+ *  linux/drivers/char/8250_pci.c
+ *
+ *  Probe module for 8250/16550-type PCI serial ports.
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/8250_pci.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include "8250.h"
+
+#undef SERIAL_DEBUG_PCI
+
+/*
+ * init function returns:
+ *  > 0 - number of ports
+ *  = 0 - use board->num_ports
+ *  < 0 - error
+ */
+struct pci_serial_quirk {
+       u32     vendor;
+       u32     device;
+       u32     subvendor;
+       u32     subdevice;
+       int     (*init)(struct pci_dev *dev);
+       int     (*setup)(struct serial_private *,
+                        const struct pciserial_board *,
+                        struct uart_port *, int);
+       void    (*exit)(struct pci_dev *dev);
+};
+
+#define PCI_NUM_BAR_RESOURCES  6
+
+struct serial_private {
+       struct pci_dev          *dev;
+       unsigned int            nr;
+       void __iomem            *remapped_bar[PCI_NUM_BAR_RESOURCES];
+       struct pci_serial_quirk *quirk;
+       int                     line[0];
+};
+
+static void moan_device(const char *str, struct pci_dev *dev)
+{
+       printk(KERN_WARNING
+              "%s: %s\n"
+              "Please send the output of lspci -vv, this\n"
+              "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
+              "manufacturer and name of serial board or\n"
+              "modem board to rmk+serial@arm.linux.org.uk.\n",
+              pci_name(dev), str, dev->vendor, dev->device,
+              dev->subsystem_vendor, dev->subsystem_device);
+}
+
+static int
+setup_port(struct serial_private *priv, struct uart_port *port,
+          int bar, int offset, int regshift)
+{
+       struct pci_dev *dev = priv->dev;
+       unsigned long base, len;
+
+       if (bar >= PCI_NUM_BAR_RESOURCES)
+               return -EINVAL;
+
+       base = pci_resource_start(dev, bar);
+
+       if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
+               len =  pci_resource_len(dev, bar);
+
+               if (!priv->remapped_bar[bar])
+                       priv->remapped_bar[bar] = ioremap_nocache(base, len);
+               if (!priv->remapped_bar[bar])
+                       return -ENOMEM;
+
+               port->iotype = UPIO_MEM;
+               port->iobase = 0;
+               port->mapbase = base + offset;
+               port->membase = priv->remapped_bar[bar] + offset;
+               port->regshift = regshift;
+       } else {
+               port->iotype = UPIO_PORT;
+               port->iobase = base + offset;
+               port->mapbase = 0;
+               port->membase = NULL;
+               port->regshift = 0;
+       }
+       return 0;
+}
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+                               const struct pciserial_board *board,
+                               struct uart_port *port, int idx)
+{
+       unsigned int bar = 0, offset = board->first_offset;
+       bar = FL_GET_BASE(board->flags);
+
+       if (idx < 2) {
+               offset += idx * board->uart_offset;
+       } else if ((idx >= 2) && (idx < 4)) {
+               bar += 1;
+               offset += ((idx - 2) * board->uart_offset);
+       } else if ((idx >= 4) && (idx < 6)) {
+               bar += 2;
+               offset += ((idx - 4) * board->uart_offset);
+       } else if (idx >= 6) {
+               bar += 3;
+               offset += ((idx - 6) * board->uart_offset);
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * AFAVLAB uses a different mixture of BARs and offsets
+ * Not that ugly ;) -- HW
+ */
+static int
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
+             struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       bar = FL_GET_BASE(board->flags);
+       if (idx < 4)
+               bar += idx;
+       else {
+               bar = 4;
+               offset += (idx - 4) * board->uart_offset;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * HP's Remote Management Console.  The Diva chip came in several
+ * different versions.  N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused).  Superdome
+ * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int pci_hp_diva_init(struct pci_dev *dev)
+{
+       int rc = 0;
+
+       switch (dev->subsystem_device) {
+       case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+       case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+       case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+               rc = 3;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+               rc = 2;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+               rc = 4;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+       case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+               rc = 1;
+               break;
+       }
+
+       return rc;
+}
+
+/*
+ * HP's Diva chip puts the 4th/5th serial port further out, and
+ * some serial ports are supposed to be hidden on certain models.
+ */
+static int
+pci_hp_diva_setup(struct serial_private *priv,
+               const struct pciserial_board *board,
+               struct uart_port *port, int idx)
+{
+       unsigned int offset = board->first_offset;
+       unsigned int bar = FL_GET_BASE(board->flags);
+
+       switch (priv->dev->subsystem_device) {
+       case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+               if (idx == 3)
+                       idx++;
+               break;
+       case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+               if (idx > 0)
+                       idx++;
+               if (idx > 2)
+                       idx++;
+               break;
+       }
+       if (idx > 2)
+               offset = 0x18;
+
+       offset += idx * board->uart_offset;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Added for EKF Intel i960 serial boards
+ */
+static int pci_inteli960ni_init(struct pci_dev *dev)
+{
+       unsigned long oldval;
+
+       if (!(dev->subsystem_device & 0x1000))
+               return -ENODEV;
+
+       /* is firmware started? */
+       pci_read_config_dword(dev, 0x44, (void *)&oldval);
+       if (oldval == 0x00001000L) { /* RESET value */
+               printk(KERN_DEBUG "Local i960 firmware missing");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled.  This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int pci_plx9050_init(struct pci_dev *dev)
+{
+       u8 irq_config;
+       void __iomem *p;
+
+       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar 0", dev);
+               return 0;
+       }
+
+       irq_config = 0x41;
+       if (dev->vendor == PCI_VENDOR_ID_PANACOM ||
+           dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS)
+               irq_config = 0x43;
+
+       if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+           (dev->device == PCI_DEVICE_ID_PLX_ROMULUS))
+               /*
+                * As the megawolf cards have the int pins active
+                * high, and have 2 UART chips, both ints must be
+                * enabled on the 9050. Also, the UARTS are set in
+                * 16450 mode by default, so we have to enable the
+                * 16C950 'enhanced' mode so that we can use the
+                * deep FIFOs
+                */
+               irq_config = 0x5b;
+       /*
+        * enable/disable interrupts
+        */
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p == NULL)
+               return -ENOMEM;
+       writel(irq_config, p + 0x4c);
+
+       /*
+        * Read the register back to ensure that it took effect.
+        */
+       readl(p + 0x4c);
+       iounmap(p);
+
+       return 0;
+}
+
+static void __devexit pci_plx9050_exit(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0)
+               return;
+
+       /*
+        * disable interrupts
+        */
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p != NULL) {
+               writel(0, p + 0x4c);
+
+               /*
+                * Read the register back to ensure that it took effect.
+                */
+               readl(p + 0x4c);
+               iounmap(p);
+       }
+}
+
+#define NI8420_INT_ENABLE_REG  0x38
+#define NI8420_INT_ENABLE_BIT  0x2000
+
+static void __devexit pci_ni8420_exit(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return;
+
+       /* Disable the CPU Interrupt */
+       writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
+              p + NI8420_INT_ENABLE_REG);
+       iounmap(p);
+}
+
+
+/* MITE registers */
+#define MITE_IOWBSR1   0xc4
+#define MITE_IOWCR1    0xf4
+#define MITE_LCIMR1    0x08
+#define MITE_LCIMR2    0x10
+
+#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
+
+static void __devexit pci_ni8430_exit(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return;
+
+       /* Disable the CPU Interrupt */
+       writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2);
+       iounmap(p);
+}
+
+/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
+static int
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
+               struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       bar = 0;
+
+       if (idx < 4) {
+               /* first four channels map to 0, 0x100, 0x200, 0x300 */
+               offset += idx * board->uart_offset;
+       } else if (idx < 8) {
+               /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
+               offset += idx * board->uart_offset + 0xC00;
+       } else /* we have only 8 ports on PMC-OCTALPRO */
+               return 1;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+* This does initialization for PMC OCTALPRO cards:
+* maps the device memory, resets the UARTs (needed, bc
+* if the module is removed and inserted again, the card
+* is in the sleep mode) and enables global interrupt.
+*/
+
+/* global control register offset for SBS PMC-OctalPro */
+#define OCT_REG_CR_OFF         0x500
+
+static int sbs_init(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       p = pci_ioremap_bar(dev, 0);
+
+       if (p == NULL)
+               return -ENOMEM;
+       /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
+       writeb(0x10, p + OCT_REG_CR_OFF);
+       udelay(50);
+       writeb(0x0, p + OCT_REG_CR_OFF);
+
+       /* Set bit-2 (INTENABLE) of Control Register */
+       writeb(0x4, p + OCT_REG_CR_OFF);
+       iounmap(p);
+
+       return 0;
+}
+
+/*
+ * Disables the global interrupt of PMC-OctalPro
+ */
+
+static void __devexit sbs_exit(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+
+       p = pci_ioremap_bar(dev, 0);
+       /* FIXME: What if resource_len < OCT_REG_CR_OFF */
+       if (p != NULL)
+               writeb(0, p + OCT_REG_CR_OFF);
+       iounmap(p);
+}
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ *  SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
+ *
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ *     - 10x cards have control registers in IO and/or memory space;
+ *     - 20x cards have control registers in standard PCI configuration space.
+ *
+ * Note: all 10x cards have PCI device ids 0x10..
+ *       all 20x cards have PCI device ids 0x20..
+ *
+ * There are also Quartet Serial cards which use Oxford Semiconductor
+ * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
+ *
+ * Note: some SIIG cards are probed by the parport_serial object.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int pci_siig10x_init(struct pci_dev *dev)
+{
+       u16 data;
+       void __iomem *p;
+
+       switch (dev->device & 0xfff8) {
+       case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
+               data = 0xffdf;
+               break;
+       case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
+               data = 0xf7ff;
+               break;
+       default:                        /* 1S1P, 4S */
+               data = 0xfffb;
+               break;
+       }
+
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
+       if (p == NULL)
+               return -ENOMEM;
+
+       writew(readw(p + 0x28) & data, p + 0x28);
+       readw(p + 0x28);
+       iounmap(p);
+       return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int pci_siig20x_init(struct pci_dev *dev)
+{
+       u8 data;
+
+       /* Change clock frequency for the first UART. */
+       pci_read_config_byte(dev, 0x6f, &data);
+       pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+       /* If this card has 2 UART, we have to do the same with second UART. */
+       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+               pci_read_config_byte(dev, 0x73, &data);
+               pci_write_config_byte(dev, 0x73, data & 0xef);
+       }
+       return 0;
+}
+
+static int pci_siig_init(struct pci_dev *dev)
+{
+       unsigned int type = dev->device & 0xff00;
+
+       if (type == 0x1000)
+               return pci_siig10x_init(dev);
+       else if (type == 0x2000)
+               return pci_siig20x_init(dev);
+
+       moan_device("Unknown SIIG card", dev);
+       return -ENODEV;
+}
+
+static int pci_siig_setup(struct serial_private *priv,
+                         const struct pciserial_board *board,
+                         struct uart_port *port, int idx)
+{
+       unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
+
+       if (idx > 3) {
+               bar = 4;
+               offset = (idx - 4) * 8;
+       }
+
+       return setup_port(priv, port, bar, offset, 0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static const unsigned short timedia_single_port[] = {
+       0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
+};
+
+static const unsigned short timedia_dual_port[] = {
+       0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+       0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
+       0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
+       0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+       0xD079, 0
+};
+
+static const unsigned short timedia_quad_port[] = {
+       0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
+       0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
+       0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+       0xB157, 0
+};
+
+static const unsigned short timedia_eight_port[] = {
+       0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
+       0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
+};
+
+static const struct timedia_struct {
+       int num;
+       const unsigned short *ids;
+} timedia_data[] = {
+       { 1, timedia_single_port },
+       { 2, timedia_dual_port },
+       { 4, timedia_quad_port },
+       { 8, timedia_eight_port }
+};
+
+static int pci_timedia_init(struct pci_dev *dev)
+{
+       const unsigned short *ids;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
+               ids = timedia_data[i].ids;
+               for (j = 0; ids[j]; j++)
+                       if (dev->subsystem_device == ids[j])
+                               return timedia_data[i].num;
+       }
+       return 0;
+}
+
+/*
+ * Timedia/SUNIX uses a mixture of BARs and offsets
+ * Ugh, this is ugly as all hell --- TYT
+ */
+static int
+pci_timedia_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       unsigned int bar = 0, offset = board->first_offset;
+
+       switch (idx) {
+       case 0:
+               bar = 0;
+               break;
+       case 1:
+               offset = board->uart_offset;
+               bar = 0;
+               break;
+       case 2:
+               bar = 1;
+               break;
+       case 3:
+               offset = board->uart_offset;
+               /* FALLTHROUGH */
+       case 4: /* BAR 2 */
+       case 5: /* BAR 3 */
+       case 6: /* BAR 4 */
+       case 7: /* BAR 5 */
+               bar = idx - 2;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Some Titan cards are also a little weird
+ */
+static int
+titan_400l_800l_setup(struct serial_private *priv,
+                     const struct pciserial_board *board,
+                     struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset;
+
+       switch (idx) {
+       case 0:
+               bar = 1;
+               break;
+       case 1:
+               bar = 2;
+               break;
+       default:
+               bar = 4;
+               offset = (idx - 2) * board->uart_offset;
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_xircom_init(struct pci_dev *dev)
+{
+       msleep(100);
+       return 0;
+}
+
+static int pci_ni8420_init(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return 0;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return -ENOMEM;
+
+       /* Enable CPU Interrupt */
+       writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT,
+              p + NI8420_INT_ENABLE_REG);
+
+       iounmap(p);
+       return 0;
+}
+
+#define MITE_IOWBSR1_WSIZE     0xa
+#define MITE_IOWBSR1_WIN_OFFSET        0x800
+#define MITE_IOWBSR1_WENAB     (1 << 7)
+#define MITE_LCIMR1_IO_IE_0    (1 << 24)
+#define MITE_LCIMR2_SET_CPU_IE (1 << 31)
+#define MITE_IOWCR1_RAMSEL_MASK        0xfffffffe
+
+static int pci_ni8430_init(struct pci_dev *dev)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       u32 device_window;
+       unsigned int bar = 0;
+
+       if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+               moan_device("no memory in bar", dev);
+               return 0;
+       }
+
+       base = pci_resource_start(dev, bar);
+       len =  pci_resource_len(dev, bar);
+       p = ioremap_nocache(base, len);
+       if (p == NULL)
+               return -ENOMEM;
+
+       /* Set device window address and size in BAR0 */
+       device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
+                       | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+       writel(device_window, p + MITE_IOWBSR1);
+
+       /* Set window access to go to RAMSEL IO address space */
+       writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK),
+              p + MITE_IOWCR1);
+
+       /* Enable IO Bus Interrupt 0 */
+       writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1);
+
+       /* Enable CPU Interrupt */
+       writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2);
+
+       iounmap(p);
+       return 0;
+}
+
+/* UART Port Control Register */
+#define NI8430_PORTCON 0x0f
+#define NI8430_PORTCON_TXVR_ENABLE     (1 << 3)
+
+static int
+pci_ni8430_setup(struct serial_private *priv,
+                const struct pciserial_board *board,
+                struct uart_port *port, int idx)
+{
+       void __iomem *p;
+       unsigned long base, len;
+       unsigned int bar, offset = board->first_offset;
+
+       if (idx >= board->num_ports)
+               return 1;
+
+       bar = FL_GET_BASE(board->flags);
+       offset += idx * board->uart_offset;
+
+       base = pci_resource_start(priv->dev, bar);
+       len =  pci_resource_len(priv->dev, bar);
+       p = ioremap_nocache(base, len);
+
+       /* enable the transciever */
+       writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
+              p + offset + NI8430_PORTCON);
+
+       iounmap(p);
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+
+static int pci_netmos_init(struct pci_dev *dev)
+{
+       /* subdevice 0x00PS means <P> parallel, <S> serial */
+       unsigned int num_serial = dev->subsystem_device & 0xf;
+
+       if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
+               (dev->device == PCI_DEVICE_ID_NETMOS_9865))
+               return 0;
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+                       dev->subsystem_device == 0x0299)
+               return 0;
+
+       if (num_serial == 0)
+               return -ENODEV;
+       return num_serial;
+}
+
+/*
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR         0x9c
+#define ITE_887x_INTCBAR       0x78
+#define ITE_887x_UARTBAR       0x7c
+#define ITE_887x_PS0BAR                0x10
+#define ITE_887x_POSIO0                0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE                32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8                (3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32       (5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED           (3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE          (1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+       /* inta_addr are the configuration addresses of the ITE */
+       static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+                                                       0x200, 0x280, 0 };
+       int ret, i, type;
+       struct resource *iobase = NULL;
+       u32 miscr, uartbar, ioport;
+
+       /* search for the base-ioport */
+       i = 0;
+       while (inta_addr[i] && iobase == NULL) {
+               iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
+                                                               "ite887x");
+               if (iobase != NULL) {
+                       /* write POSIO0R - speed | size | ioport */
+                       pci_write_config_dword(dev, ITE_887x_POSIO0,
+                               ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+                               ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+                       /* write INTCBAR - ioport */
+                       pci_write_config_dword(dev, ITE_887x_INTCBAR,
+                                                               inta_addr[i]);
+                       ret = inb(inta_addr[i]);
+                       if (ret != 0xff) {
+                               /* ioport connected */
+                               break;
+                       }
+                       release_region(iobase->start, ITE_887x_IOSIZE);
+                       iobase = NULL;
+               }
+               i++;
+       }
+
+       if (!inta_addr[i]) {
+               printk(KERN_ERR "ite887x: could not find iobase\n");
+               return -ENODEV;
+       }
+
+       /* start of undocumented type checking (see parport_pc.c) */
+       type = inb(iobase->start + 0x18) & 0x0f;
+
+       switch (type) {
+       case 0x2:       /* ITE8871 (1P) */
+       case 0xa:       /* ITE8875 (1P) */
+               ret = 0;
+               break;
+       case 0xe:       /* ITE8872 (2S1P) */
+               ret = 2;
+               break;
+       case 0x6:       /* ITE8873 (1S) */
+               ret = 1;
+               break;
+       case 0x8:       /* ITE8874 (2S) */
+               ret = 2;
+               break;
+       default:
+               moan_device("Unknown ITE887x", dev);
+               ret = -ENODEV;
+       }
+
+       /* configure all serial ports */
+       for (i = 0; i < ret; i++) {
+               /* read the I/O port from the device */
+               pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+                                                               &ioport);
+               ioport &= 0x0000FF00;   /* the actual base address */
+               pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+                       ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+                       ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+               /* write the ioport to the UARTBAR */
+               pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+               uartbar &= ~(0xffff << (16 * i));       /* clear half the reg */
+               uartbar |= (ioport << (16 * i));        /* set the ioport */
+               pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+               /* get current config */
+               pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+               /* disable interrupts (UARTx_Routing[3:0]) */
+               miscr &= ~(0xf << (12 - 4 * i));
+               /* activate the UART (UARTx_En) */
+               miscr |= 1 << (23 - i);
+               /* write new config with activated UART */
+               pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+       }
+
+       if (ret <= 0) {
+               /* the device has no UARTs if we get here */
+               release_region(iobase->start, ITE_887x_IOSIZE);
+       }
+
+       return ret;
+}
+
+static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+{
+       u32 ioport;
+       /* the ioport is bit 0-15 in POSIO0R */
+       pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+       ioport &= 0xffff;
+       release_region(ioport, ITE_887x_IOSIZE);
+}
+
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+       u8 __iomem *p;
+       unsigned long deviceID;
+       unsigned int  number_uarts = 0;
+
+       /* OxSemi Tornado devices are all 0xCxxx */
+       if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+           (dev->device & 0xF000) != 0xC000)
+               return 0;
+
+       p = pci_iomap(dev, 0, 5);
+       if (p == NULL)
+               return -ENOMEM;
+
+       deviceID = ioread32(p);
+       /* Tornado device */
+       if (deviceID == 0x07000200) {
+               number_uarts = ioread8(p + 4);
+               printk(KERN_DEBUG
+                       "%d ports detected on Oxford PCI Express device\n",
+                                                               number_uarts);
+       }
+       pci_iounmap(dev, p);
+       return number_uarts;
+}
+
+static int
+pci_default_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       unsigned int bar, offset = board->first_offset, maxnr;
+
+       bar = FL_GET_BASE(board->flags);
+       if (board->flags & FL_BASE_BARS)
+               bar += idx;
+       else
+               offset += idx * board->uart_offset;
+
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
+
+       if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+               return 1;
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int
+ce4100_serial_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       int ret;
+
+       ret = setup_port(priv, port, 0, 0, board->reg_shift);
+       port->iotype = UPIO_MEM32;
+       port->type = PORT_XSCALE;
+       port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+       port->regshift = 2;
+
+       return ret;
+}
+
+static int skip_tx_en_setup(struct serial_private *priv,
+                       const struct pciserial_board *board,
+                       struct uart_port *port, int idx)
+{
+       port->flags |= UPF_NO_TXEN_TEST;
+       printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
+                         "[%04x:%04x] subsystem [%04x:%04x]\n",
+                         priv->dev->vendor,
+                         priv->dev->device,
+                         priv->dev->subsystem_vendor,
+                         priv->dev->subsystem_device);
+
+       return pci_default_setup(priv, board, port, idx);
+}
+
+/* This should be in linux/pci_ids.h */
+#define PCI_VENDOR_ID_SBSMODULARIO     0x124B
+#define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
+#define PCI_DEVICE_ID_OCTPRO           0x0001
+#define PCI_SUBDEVICE_ID_OCTPRO232     0x0108
+#define PCI_SUBDEVICE_ID_OCTPRO422     0x0208
+#define PCI_SUBDEVICE_ID_POCTAL232     0x0308
+#define PCI_SUBDEVICE_ID_POCTAL422     0x0408
+#define PCI_VENDOR_ID_ADVANTECH                0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
+#define PCI_DEVICE_ID_ADVANTECH_PCI3620        0x3620
+#define PCI_DEVICE_ID_TITAN_200I       0x8028
+#define PCI_DEVICE_ID_TITAN_400I       0x8048
+#define PCI_DEVICE_ID_TITAN_800I       0x8088
+#define PCI_DEVICE_ID_TITAN_800EH      0xA007
+#define PCI_DEVICE_ID_TITAN_800EHB     0xA008
+#define PCI_DEVICE_ID_TITAN_400EH      0xA009
+#define PCI_DEVICE_ID_TITAN_100E       0xA010
+#define PCI_DEVICE_ID_TITAN_200E       0xA012
+#define PCI_DEVICE_ID_TITAN_400E       0xA013
+#define PCI_DEVICE_ID_TITAN_800E       0xA014
+#define PCI_DEVICE_ID_TITAN_200EI      0xA016
+#define PCI_DEVICE_ID_TITAN_200EISI    0xA017
+#define PCI_DEVICE_ID_OXSEMI_16PCI958  0x9538
+
+/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
+
+/*
+ * Master list of serial port init/setup/exit quirks.
+ * This does not describe the general nature of the port.
+ * (ie, baud base, number and location of ports, etc)
+ *
+ * This list is ordered alphabetically by vendor then device.
+ * Specific entries must come before more generic entries.
+ */
+static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {
+               .vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
+               .device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = addidata_apci7800_setup,
+       },
+       /*
+        * AFAVLAB cards - these may be called via parport_serial
+        *  It is not clear whether this applies to all products.
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_AFAVLAB,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = afavlab_setup,
+       },
+       /*
+        * HP Diva
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_HP,
+               .device         = PCI_DEVICE_ID_HP_DIVA,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_hp_diva_init,
+               .setup          = pci_hp_diva_setup,
+       },
+       /*
+        * Intel
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_80960_RP,
+               .subvendor      = 0xe4bf,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_inteli960ni_init,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_8257X_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573L_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573E_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_CE4100_UART,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = ce4100_serial_setup,
+       },
+       /*
+        * ITE
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_ITE,
+               .device         = PCI_DEVICE_ID_ITE_8872,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ite887x_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ite887x_exit),
+       },
+       /*
+        * National Instruments
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI23216,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2328,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2324I,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PCI2322I,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_23216,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2328,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8420_2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8422_2324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_DEVICE_ID_NI_PXI8422_2322,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8420_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_ni8420_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_NI,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_ni8430_init,
+               .setup          = pci_ni8430_setup,
+               .exit           = __devexit_p(pci_ni8430_exit),
+       },
+       /*
+        * Panacom
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_PANACOM,
+               .device         = PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PANACOM,
+               .device         = PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       /*
+        * PLX
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9030,
+               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_SUBVENDOR_ID_EXSYS,
+               .subdevice      = PCI_SUBDEVICE_ID_EXSYS_4055,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_SUBVENDOR_ID_KEYSPAN,
+               .subdevice      = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_9050,
+               .subvendor      = PCI_VENDOR_ID_PLX,
+               .subdevice      = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = PCI_DEVICE_ID_PLX_ROMULUS,
+               .subvendor      = PCI_VENDOR_ID_PLX,
+               .subdevice      = PCI_DEVICE_ID_PLX_ROMULUS,
+               .init           = pci_plx9050_init,
+               .setup          = pci_default_setup,
+               .exit           = __devexit_p(pci_plx9050_exit),
+       },
+       /*
+        * SBS Technologies, Inc., PMC-OCTALPRO 232
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO232,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., PMC-OCTALPRO 422
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_OCTPRO422,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., P-Octal 232
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_POCTAL232,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SBS Technologies, Inc., P-Octal 422
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SBSMODULARIO,
+               .device         = PCI_DEVICE_ID_OCTPRO,
+               .subvendor      = PCI_SUBVENDOR_ID_SBSMODULARIO,
+               .subdevice      = PCI_SUBDEVICE_ID_POCTAL422,
+               .init           = sbs_init,
+               .setup          = sbs_setup,
+               .exit           = __devexit_p(sbs_exit),
+       },
+       /*
+        * SIIG cards - these may be called via parport_serial
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_SIIG,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_siig_init,
+               .setup          = pci_siig_setup,
+       },
+       /*
+        * Titan cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_TITAN,
+               .device         = PCI_DEVICE_ID_TITAN_400L,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = titan_400l_800l_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_TITAN,
+               .device         = PCI_DEVICE_ID_TITAN_800L,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = titan_400l_800l_setup,
+       },
+       /*
+        * Timedia cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_TIMEDIA,
+               .device         = PCI_DEVICE_ID_TIMEDIA_1889,
+               .subvendor      = PCI_VENDOR_ID_TIMEDIA,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_timedia_init,
+               .setup          = pci_timedia_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_TIMEDIA,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_timedia_setup,
+       },
+       /*
+        * Xircom cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_XIRCOM,
+               .device         = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_xircom_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * Netmos cards - these may be called via parport_serial
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_NETMOS,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_netmos_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * For Oxford Semiconductor and Mainpine
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_OXSEMI,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_MAINPINE,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_oxsemi_tornado_init,
+               .setup          = pci_default_setup,
+       },
+       /*
+        * Default "match everything" terminator entry
+        */
+       {
+               .vendor         = PCI_ANY_ID,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_default_setup,
+       }
+};
+
+static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
+{
+       return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
+}
+
+static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
+{
+       struct pci_serial_quirk *quirk;
+
+       for (quirk = pci_serial_quirks; ; quirk++)
+               if (quirk_id_matches(quirk->vendor, dev->vendor) &&
+                   quirk_id_matches(quirk->device, dev->device) &&
+                   quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
+                   quirk_id_matches(quirk->subdevice, dev->subsystem_device))
+                       break;
+       return quirk;
+}
+
+static inline int get_pci_irq(struct pci_dev *dev,
+                               const struct pciserial_board *board)
+{
+       if (board->flags & FL_NOIRQ)
+               return 0;
+       else
+               return dev->irq;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ *
+ * The makeup of these names are:
+ *  pbn_bn{_bt}_n_baud{_offsetinhex}
+ *
+ *  bn         = PCI BAR number
+ *  bt         = Index using PCI BARs
+ *  n          = number of serial ports
+ *  baud       = baud rate
+ *  offsetinhex        = offset for each sequential port (in hex)
+ *
+ * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
+ *
+ * Please note: in theory if n = 1, _bt infix should make no difference.
+ * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
+ */
+enum pci_board_num_t {
+       pbn_default = 0,
+
+       pbn_b0_1_115200,
+       pbn_b0_2_115200,
+       pbn_b0_4_115200,
+       pbn_b0_5_115200,
+       pbn_b0_8_115200,
+
+       pbn_b0_1_921600,
+       pbn_b0_2_921600,
+       pbn_b0_4_921600,
+
+       pbn_b0_2_1130000,
+
+       pbn_b0_4_1152000,
+
+       pbn_b0_2_1843200,
+       pbn_b0_4_1843200,
+
+       pbn_b0_2_1843200_200,
+       pbn_b0_4_1843200_200,
+       pbn_b0_8_1843200_200,
+
+       pbn_b0_1_4000000,
+
+       pbn_b0_bt_1_115200,
+       pbn_b0_bt_2_115200,
+       pbn_b0_bt_4_115200,
+       pbn_b0_bt_8_115200,
+
+       pbn_b0_bt_1_460800,
+       pbn_b0_bt_2_460800,
+       pbn_b0_bt_4_460800,
+
+       pbn_b0_bt_1_921600,
+       pbn_b0_bt_2_921600,
+       pbn_b0_bt_4_921600,
+       pbn_b0_bt_8_921600,
+
+       pbn_b1_1_115200,
+       pbn_b1_2_115200,
+       pbn_b1_4_115200,
+       pbn_b1_8_115200,
+       pbn_b1_16_115200,
+
+       pbn_b1_1_921600,
+       pbn_b1_2_921600,
+       pbn_b1_4_921600,
+       pbn_b1_8_921600,
+
+       pbn_b1_2_1250000,
+
+       pbn_b1_bt_1_115200,
+       pbn_b1_bt_2_115200,
+       pbn_b1_bt_4_115200,
+
+       pbn_b1_bt_2_921600,
+
+       pbn_b1_1_1382400,
+       pbn_b1_2_1382400,
+       pbn_b1_4_1382400,
+       pbn_b1_8_1382400,
+
+       pbn_b2_1_115200,
+       pbn_b2_2_115200,
+       pbn_b2_4_115200,
+       pbn_b2_8_115200,
+
+       pbn_b2_1_460800,
+       pbn_b2_4_460800,
+       pbn_b2_8_460800,
+       pbn_b2_16_460800,
+
+       pbn_b2_1_921600,
+       pbn_b2_4_921600,
+       pbn_b2_8_921600,
+
+       pbn_b2_8_1152000,
+
+       pbn_b2_bt_1_115200,
+       pbn_b2_bt_2_115200,
+       pbn_b2_bt_4_115200,
+
+       pbn_b2_bt_2_921600,
+       pbn_b2_bt_4_921600,
+
+       pbn_b3_2_115200,
+       pbn_b3_4_115200,
+       pbn_b3_8_115200,
+
+       pbn_b4_bt_2_921600,
+       pbn_b4_bt_4_921600,
+       pbn_b4_bt_8_921600,
+
+       /*
+        * Board-specific versions.
+        */
+       pbn_panacom,
+       pbn_panacom2,
+       pbn_panacom4,
+       pbn_exsys_4055,
+       pbn_plx_romulus,
+       pbn_oxsemi,
+       pbn_oxsemi_1_4000000,
+       pbn_oxsemi_2_4000000,
+       pbn_oxsemi_4_4000000,
+       pbn_oxsemi_8_4000000,
+       pbn_intel_i960,
+       pbn_sgi_ioc3,
+       pbn_computone_4,
+       pbn_computone_6,
+       pbn_computone_8,
+       pbn_sbsxrsio,
+       pbn_exar_XR17C152,
+       pbn_exar_XR17C154,
+       pbn_exar_XR17C158,
+       pbn_exar_ibm_saturn,
+       pbn_pasemi_1682M,
+       pbn_ni8430_2,
+       pbn_ni8430_4,
+       pbn_ni8430_8,
+       pbn_ni8430_16,
+       pbn_ADDIDATA_PCIe_1_3906250,
+       pbn_ADDIDATA_PCIe_2_3906250,
+       pbn_ADDIDATA_PCIe_4_3906250,
+       pbn_ADDIDATA_PCIe_8_3906250,
+       pbn_ce4100_1_115200,
+};
+
+/*
+ * uart_offset - the space between channels
+ * reg_shift   - describes how the UART registers are mapped
+ *               to PCI memory by the card.
+ * For example IER register on SBS, Inc. PMC-OctPro is located at
+ * offset 0x10 from the UART base, while UART_IER is defined as 1
+ * in include/linux/serial_reg.h,
+ * see first lines of serial_in() and serial_out() in 8250.c
+*/
+
+static struct pciserial_board pci_boards[] __devinitdata = {
+       [pbn_default] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_1_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_2_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_5_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 5,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_8_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_1_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_2_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_921600] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1130000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1130000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_4_1152000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1152000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1843200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1843200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_4_1843200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1843200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_2_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_4_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_8_1843200_200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 1843200,
+               .uart_offset    = 0x200,
+       },
+       [pbn_b0_1_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 4000000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_8_115200] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_460800] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b0_bt_1_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_2_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_4_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b0_bt_8_921600] = {
+               .flags          = FL_BASE0|FL_BASE_BARS,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_16_115200] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 16,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_921600] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_1250000] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 1250000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_bt_1_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_bt_2_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_bt_4_115200] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_bt_2_921600] = {
+               .flags          = FL_BASE1|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b1_1_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 1,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_2_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 2,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_4_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 4,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+       [pbn_b1_8_1382400] = {
+               .flags          = FL_BASE1,
+               .num_ports      = 8,
+               .base_baud      = 1382400,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_1_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_2_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_115200] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_1_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_16_460800] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 16,
+               .base_baud      = 460800,
+               .uart_offset    = 8,
+        },
+
+       [pbn_b2_1_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_4_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_8_921600] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_8_1152000] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 8,
+               .base_baud      = 1152000,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_bt_1_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 1,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_2_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_4_115200] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b2_bt_2_921600] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b2_bt_4_921600] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b3_2_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b3_4_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_b3_8_115200] = {
+               .flags          = FL_BASE3,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       [pbn_b4_bt_2_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b4_bt_4_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+       [pbn_b4_bt_8_921600] = {
+               .flags          = FL_BASE4,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 8,
+       },
+
+       /*
+        * Entries following this are board-specific.
+        */
+
+       /*
+        * Panacom - IOMEM
+        */
+       [pbn_panacom] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+       [pbn_panacom2] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+       [pbn_panacom4] = {
+               .flags          = FL_BASE2|FL_BASE_BARS,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x400,
+               .reg_shift      = 7,
+       },
+
+       [pbn_exsys_4055] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+
+       /* I think this entry is broken - the first_offset looks wrong --rmk */
+       [pbn_plx_romulus] = {
+               .flags          = FL_BASE2,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 8 << 2,
+               .reg_shift      = 2,
+               .first_offset   = 0x03,
+       },
+
+       /*
+        * This board uses the size of PCI Base region 0 to
+        * signal now many ports are available
+        */
+       [pbn_oxsemi] = {
+               .flags          = FL_BASE0|FL_REGION_SZ_CAP,
+               .num_ports      = 32,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
+       [pbn_oxsemi_1_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_2_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_4_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_oxsemi_8_4000000] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 4000000,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+
+
+       /*
+        * EKF addition for i960 Boards form EKF with serial port.
+        * Max 256 ports.
+        */
+       [pbn_intel_i960] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 32,
+               .base_baud      = 921600,
+               .uart_offset    = 8 << 2,
+               .reg_shift      = 2,
+               .first_offset   = 0x10000,
+       },
+       [pbn_sgi_ioc3] = {
+               .flags          = FL_BASE0|FL_NOIRQ,
+               .num_ports      = 1,
+               .base_baud      = 458333,
+               .uart_offset    = 8,
+               .reg_shift      = 0,
+               .first_offset   = 0x20178,
+       },
+
+       /*
+        * Computone - uses IOMEM.
+        */
+       [pbn_computone_4] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_computone_6] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 6,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_computone_8] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 0x40,
+               .reg_shift      = 2,
+               .first_offset   = 0x200,
+       },
+       [pbn_sbsxrsio] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 460800,
+               .uart_offset    = 256,
+               .reg_shift      = 4,
+       },
+       /*
+        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
+        *  Only basic 16550A support.
+        *  XR17C15[24] are not tested, but they should work.
+        */
+       [pbn_exar_XR17C152] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_XR17C154] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_XR17C158] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+       [pbn_exar_ibm_saturn] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .uart_offset    = 0x200,
+       },
+
+       /*
+        * PA Semi PWRficient PA6T-1682M on-chip UART
+        */
+       [pbn_pasemi_1682M] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 8333333,
+       },
+       /*
+        * National Instruments 843x
+        */
+       [pbn_ni8430_16] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 16,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_8] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_4] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       [pbn_ni8430_2] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 3686400,
+               .uart_offset    = 0x10,
+               .first_offset   = 0x800,
+       },
+       /*
+        * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
+        */
+       [pbn_ADDIDATA_PCIe_1_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_2_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_4_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ADDIDATA_PCIe_8_3906250] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 3906250,
+               .uart_offset    = 0x200,
+               .first_offset   = 0x1000,
+       },
+       [pbn_ce4100_1_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .base_baud      = 921600,
+               .reg_shift      = 2,
+       },
+};
+
+static const struct pci_device_id softmodem_blacklist[] = {
+       { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+       { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+       { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit
+serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
+{
+       const struct pci_device_id *blacklist;
+       int num_iomem, num_port, first_port = -1, i;
+
+       /*
+        * If it is not a communications device or the programming
+        * interface is greater than 6, give up.
+        *
+        * (Should we try to make guesses for multiport serial devices
+        * later?)
+        */
+       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+            ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+           (dev->class & 0xff) > 6)
+               return -ENODEV;
+
+       /*
+        * Do not access blacklisted devices that are known not to
+        * feature serial ports.
+        */
+       for (blacklist = softmodem_blacklist;
+            blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
+            blacklist++) {
+               if (dev->vendor == blacklist->vendor &&
+                   dev->device == blacklist->device)
+                       return -ENODEV;
+       }
+
+       num_iomem = num_port = 0;
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+               if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+                       num_iomem++;
+       }
+
+       /*
+        * If there is 1 or 0 iomem regions, and exactly one port,
+        * use it.  We guess the number of ports based on the IO
+        * region size.
+        */
+       if (num_iomem <= 1 && num_port == 1) {
+               board->flags = first_port;
+               board->num_ports = pci_resource_len(dev, first_port) / 8;
+               return 0;
+       }
+
+       /*
+        * Now guess if we've got a board which indexes by BARs.
+        * Each IO BAR should be 8 bytes, and they should follow
+        * consecutively.
+        */
+       first_port = -1;
+       num_port = 0;
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
+                   pci_resource_len(dev, i) == 8 &&
+                   (first_port == -1 || (first_port + num_port) == i)) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+       }
+
+       if (num_port > 1) {
+               board->flags = first_port | FL_BASE_BARS;
+               board->num_ports = num_port;
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static inline int
+serial_pci_matches(const struct pciserial_board *board,
+                  const struct pciserial_board *guessed)
+{
+       return
+           board->num_ports == guessed->num_ports &&
+           board->base_baud == guessed->base_baud &&
+           board->uart_offset == guessed->uart_offset &&
+           board->reg_shift == guessed->reg_shift &&
+           board->first_offset == guessed->first_offset;
+}
+
+struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
+{
+       struct uart_port serial_port;
+       struct serial_private *priv;
+       struct pci_serial_quirk *quirk;
+       int rc, nr_ports, i;
+
+       nr_ports = board->num_ports;
+
+       /*
+        * Find an init and setup quirks.
+        */
+       quirk = find_quirk(dev);
+
+       /*
+        * Run the new-style initialization function.
+        * The initialization function returns:
+        *  <0  - error
+        *   0  - use board->num_ports
+        *  >0  - number of ports
+        */
+       if (quirk->init) {
+               rc = quirk->init(dev);
+               if (rc < 0) {
+                       priv = ERR_PTR(rc);
+                       goto err_out;
+               }
+               if (rc)
+                       nr_ports = rc;
+       }
+
+       priv = kzalloc(sizeof(struct serial_private) +
+                      sizeof(unsigned int) * nr_ports,
+                      GFP_KERNEL);
+       if (!priv) {
+               priv = ERR_PTR(-ENOMEM);
+               goto err_deinit;
+       }
+
+       priv->dev = dev;
+       priv->quirk = quirk;
+
+       memset(&serial_port, 0, sizeof(struct uart_port));
+       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       serial_port.uartclk = board->base_baud * 16;
+       serial_port.irq = get_pci_irq(dev, board);
+       serial_port.dev = &dev->dev;
+
+       for (i = 0; i < nr_ports; i++) {
+               if (quirk->setup(priv, board, &serial_port, i))
+                       break;
+
+#ifdef SERIAL_DEBUG_PCI
+               printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
+                      serial_port.iobase, serial_port.irq, serial_port.iotype);
+#endif
+
+               priv->line[i] = serial8250_register_port(&serial_port);
+               if (priv->line[i] < 0) {
+                       printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
+                       break;
+               }
+       }
+       priv->nr = i;
+       return priv;
+
+err_deinit:
+       if (quirk->exit)
+               quirk->exit(dev);
+err_out:
+       return priv;
+}
+EXPORT_SYMBOL_GPL(pciserial_init_ports);
+
+void pciserial_remove_ports(struct serial_private *priv)
+{
+       struct pci_serial_quirk *quirk;
+       int i;
+
+       for (i = 0; i < priv->nr; i++)
+               serial8250_unregister_port(priv->line[i]);
+
+       for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+               if (priv->remapped_bar[i])
+                       iounmap(priv->remapped_bar[i]);
+               priv->remapped_bar[i] = NULL;
+       }
+
+       /*
+        * Find the exit quirks.
+        */
+       quirk = find_quirk(priv->dev);
+       if (quirk->exit)
+               quirk->exit(priv->dev);
+
+       kfree(priv);
+}
+EXPORT_SYMBOL_GPL(pciserial_remove_ports);
+
+void pciserial_suspend_ports(struct serial_private *priv)
+{
+       int i;
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_suspend_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
+
+void pciserial_resume_ports(struct serial_private *priv)
+{
+       int i;
+
+       /*
+        * Ensure that the board is correctly configured.
+        */
+       if (priv->quirk->init)
+               priv->quirk->init(priv->dev);
+
+       for (i = 0; i < priv->nr; i++)
+               if (priv->line[i] >= 0)
+                       serial8250_resume_port(priv->line[i]);
+}
+EXPORT_SYMBOL_GPL(pciserial_resume_ports);
+
+/*
+ * Probe one serial board.  Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int __devinit
+pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct serial_private *priv;
+       const struct pciserial_board *board;
+       struct pciserial_board tmp;
+       int rc;
+
+       if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+               printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
+                       ent->driver_data);
+               return -EINVAL;
+       }
+
+       board = &pci_boards[ent->driver_data];
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       if (ent->driver_data == pbn_default) {
+               /*
+                * Use a copy of the pci_board entry for this;
+                * avoid changing entries in the table.
+                */
+               memcpy(&tmp, board, sizeof(struct pciserial_board));
+               board = &tmp;
+
+               /*
+                * We matched one of our class entries.  Try to
+                * determine the parameters of this board.
+                */
+               rc = serial_pci_guess_board(dev, &tmp);
+               if (rc)
+                       goto disable;
+       } else {
+               /*
+                * We matched an explicit entry.  If we are able to
+                * detect this boards settings with our heuristic,
+                * then we no longer need this entry.
+                */
+               memcpy(&tmp, &pci_boards[pbn_default],
+                      sizeof(struct pciserial_board));
+               rc = serial_pci_guess_board(dev, &tmp);
+               if (rc == 0 && serial_pci_matches(board, &tmp))
+                       moan_device("Redundant entry in serial pci_table.",
+                                   dev);
+       }
+
+       priv = pciserial_init_ports(dev, board);
+       if (!IS_ERR(priv)) {
+               pci_set_drvdata(dev, priv);
+               return 0;
+       }
+
+       rc = PTR_ERR(priv);
+
+ disable:
+       pci_disable_device(dev);
+       return rc;
+}
+
+static void __devexit pciserial_remove_one(struct pci_dev *dev)
+{
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+
+       pciserial_remove_ports(priv);
+
+       pci_disable_device(dev);
+}
+
+#ifdef CONFIG_PM
+static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
+{
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       if (priv)
+               pciserial_suspend_ports(priv);
+
+       pci_save_state(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       return 0;
+}
+
+static int pciserial_resume_one(struct pci_dev *dev)
+{
+       int err;
+       struct serial_private *priv = pci_get_drvdata(dev);
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       if (priv) {
+               /*
+                * The device may have been disabled.  Re-enable it.
+                */
+               err = pci_enable_device(dev);
+               /* FIXME: We cannot simply error out here */
+               if (err)
+                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
+               pciserial_resume_ports(priv);
+       }
+       return 0;
+}
+#endif
+
+static struct pci_device_id serial_pci_tbl[] = {
+       /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
+       {       PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
+               PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
+               pbn_b2_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+               pbn_b1_2_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+               pbn_b1_8_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+               pbn_b1_4_921600 },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
+               pbn_b1_2_1250000 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
+               pbn_b0_2_1843200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
+               pbn_b0_4_1843200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_AFAVLAB,
+               PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
+               pbn_b0_4_1152000 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
+               pbn_b0_2_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0,
+               pbn_b0_4_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0,
+               pbn_b0_8_1843200_200 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT,
+               0, 0, pbn_exar_ibm_saturn },
+
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_1_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_115200 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_115200 },
+
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       /*
+        * VScom SPCOM800, from sl@s.pl
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_8_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_4_921600 },
+       /* Unknown card - subdevice 0x1584 */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_VENDOR_ID_PLX,
+               PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
+               pbn_b0_4_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_KEYSPAN,
+               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+               pbn_panacom },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom4 },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom2 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_VENDOR_ID_ESDGMBH,
+               PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
+               pbn_b2_4_115200 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+               pbn_b2_16_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+               pbn_b2_4_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+               pbn_b2_8_460800 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_EXSYS,
+               PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
+               pbn_exsys_4055 },
+       /*
+        * Megawolf Romulus PCI Serial Card, from Mike Hudson
+        * (Exoray@isys.ca)
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+               0x10b5, 0x106a, 0, 0,
+               pbn_plx_romulus },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_4_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_2_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+               0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
+               0, 0,
+               pbn_b0_4_1152000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0x9505,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+
+               /*
+                * The below card is a little controversial since it is the
+                * subject of a PCI vendor/device ID clash.  (See
+                * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
+                * For now just used the hex ID 0x950a.
+                */
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
+               pbn_b0_2_115200 },
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_2_1130000 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+               PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_115200 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
+               PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+               pbn_b2_8_1152000 },
+
+       /*
+        * Oxford Semiconductor Inc. Tornado PCI express device range.
+        */
+       {       PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       /*
+        * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
+        */
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       /*
+        * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
+        * from skokodyn@yahoo.com
+        */
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
+               pbn_sbsxrsio },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
+               pbn_sbsxrsio },
+
+       /*
+        * Digitan DS560-558, from jimd@esoft.com
+        */
+       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_115200 },
+
+       /*
+        * Titan Electronic cards
+        *  The 400L and 800L have a custom setup quirk.
+        */
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b4_bt_8_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_1_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_4_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_8_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi_2_4000000 },
+
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_460800 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_921600 },
+
+       /*
+        * Computone devices submitted by Doug McNash dmcnash@computone.com
+        */
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+               0, 0, pbn_computone_4 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+               0, 0, pbn_computone_8 },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+               0, 0, pbn_computone_6 },
+
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_oxsemi },
+       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_921600 },
+
+       /*
+        * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
+        */
+       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_115200 },
+       {       PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_8_115200 },
+
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_4_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_460800 },
+
+       /*
+        * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
+        * Cards are identified by their subsystem vendor IDs, which
+        * (in hex) match the model number.
+        *
+        * Note that JC140x are RS422/485 cards which require ox950
+        * ACR = 0x10, and as such are not currently fully supported.
+        */
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1204, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1402, 0x0002, 0, 0,
+               pbn_b0_2_921600 }, */
+/*     {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1404, 0x0004, 0, 0,
+               pbn_b0_4_921600 }, */
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+               0x1204, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+               0x1208, 0x0004, 0, 0,
+               pbn_b0_4_921600 },
+       /*
+        * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
+        */
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_1382400 },
+
+       /*
+        * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
+        */
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_1_1382400 },
+
+       /*
+        * RAStel 2 port modem, gerg@moreton.com.au
+        */
+       {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+
+       /*
+        * EKF addition for i960 Boards form EKF with serial port
+        */
+       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+               0xE4BF, PCI_ANY_ID, 0, 0,
+               pbn_intel_i960 },
+
+       /*
+        * Xircom Cardbus/Ethernet combos
+        */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+       /*
+        * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
+        */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+
+       /*
+        * Untested PCI modems, sent in from various folks...
+        */
+
+       /*
+        * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
+        */
+       {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
+               0x1048, 0x1500, 0, 0,
+               pbn_b1_1_115200 },
+
+       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+               0xFF00, 0, 0, 0,
+               pbn_sgi_ioc3 },
+
+       /*
+        * HP Diva card
+        */
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+               PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
+               pbn_b1_1_115200 },
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_5_115200 },
+       {       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_1_115200 },
+
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_2_115200 },
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_4_115200 },
+       {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b3_8_115200 },
+
+       /*
+        * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
+        */
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C152 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C154 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17C158 },
+
+       /*
+        * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
+        */
+       {       PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_1_115200 },
+       /*
+        * ITE
+        */
+       {       PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b1_bt_1_115200 },
+
+       /*
+        * IntaShield IS-200
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,   /* 135a.0811 */
+               pbn_b2_2_115200 },
+       /*
+        * IntaShield IS-400
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
+               pbn_b2_4_115200 },
+       /*
+        * Perle PCI-RAS cards
+        */
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
+               0, 0, pbn_b2_4_921600 },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
+               0, 0, pbn_b2_8_921600 },
+
+       /*
+        * Mainpine series cards: Fairly standard layout but fools
+        * parts of the autodetect in some cases and uses otherwise
+        * unmatched communications subclasses in the PCI Express case
+        */
+
+       {       /* RockForceDUO */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUATRO */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0300,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceDUO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0400,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUATRO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForce+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0600,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForce+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0700,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceOCTO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0800,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceDUO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0C00,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceQUARTRO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x0D00,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceOCTO+ */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x1D00,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceD1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2000,
+               0, 0, pbn_b0_1_115200 },
+       {       /* RockForceF1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2100,
+               0, 0, pbn_b0_1_115200 },
+       {       /* RockForceD2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceF2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2300,
+               0, 0, pbn_b0_2_115200 },
+       {       /* RockForceD4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2400,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceF4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* RockForceD8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2600,
+               0, 0, pbn_b0_8_115200 },
+       {       /* RockForceF8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x2700,
+               0, 0, pbn_b0_8_115200 },
+       {       /* IQ Express D1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3000,
+               0, 0, pbn_b0_1_115200 },
+       {       /* IQ Express F1 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3100,
+               0, 0, pbn_b0_1_115200 },
+       {       /* IQ Express D2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3200,
+               0, 0, pbn_b0_2_115200 },
+       {       /* IQ Express F2 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3300,
+               0, 0, pbn_b0_2_115200 },
+       {       /* IQ Express D4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3400,
+               0, 0, pbn_b0_4_115200 },
+       {       /* IQ Express F4 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3500,
+               0, 0, pbn_b0_4_115200 },
+       {       /* IQ Express D8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3C00,
+               0, 0, pbn_b0_8_115200 },
+       {       /* IQ Express F8 */
+               PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+               PCI_VENDOR_ID_MAINPINE, 0x3D00,
+               0, 0, pbn_b0_8_115200 },
+
+
+       /*
+        * PA Semi PA6T-1682M on-chip UART
+        */
+       {       PCI_VENDOR_ID_PASEMI, 0xa004,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pasemi_1682M },
+
+       /*
+        * National Instruments
+        */
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_16_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_16_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_8_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_4_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b1_bt_2_115200 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_8 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_8 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_16 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_16 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_2 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+       {       PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_ni8430_4 },
+
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA_OLD,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b1_8_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_8_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7500,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_4_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7420,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_2_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7300,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_1_3906250 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCIe7800,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_ADDIDATA_PCIe_8_3906250 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+               PCI_VENDOR_ID_IBM, 0x0299,
+               0, 0, pbn_b0_bt_2_115200 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
+       /*
+        * Best Connectivity PCI Multi I/O cards
+        */
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+               0xA000, 0x3004,
+               0, 0, pbn_b0_bt_4_115200 },
+       /* Intel CE4100 */
+       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+               PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
+               pbn_ce4100_1_115200 },
+
+
+       /*
+        * These entries match devices with class COMMUNICATION_SERIAL,
+        * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
+        */
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_SERIAL << 8,
+               0xffff00, pbn_default },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MODEM << 8,
+               0xffff00, pbn_default },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+               0xffff00, pbn_default },
+       { 0, }
+};
+
+static struct pci_driver serial_pci_driver = {
+       .name           = "serial",
+       .probe          = pciserial_init_one,
+       .remove         = __devexit_p(pciserial_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = pciserial_suspend_one,
+       .resume         = pciserial_resume_one,
+#endif
+       .id_table       = serial_pci_tbl,
+};
+
+static int __init serial8250_pci_init(void)
+{
+       return pci_register_driver(&serial_pci_driver);
+}
+
+static void __exit serial8250_pci_exit(void)
+{
+       pci_unregister_driver(&serial_pci_driver);
+}
+
+module_init(serial8250_pci_init);
+module_exit(serial8250_pci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
new file mode 100644 (file)
index 0000000..4822cb5
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/char/8250_pnp.c
+ *
+ *  Probe module for 8250/16550-type ISAPNP serial ports.
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ *  Ported to the Linux PnP Layer - (C) Adam Belay.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+
+#include "8250.h"
+
+#define UNKNOWN_DEV 0x3000
+
+
+static const struct pnp_device_id pnp_dev_table[] = {
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "AAC000F",              0       },
+       /* Anchor Datacomm BV */
+       /* SXPro 144 External Data Fax Modem Plug & Play */
+       {       "ADC0001",              0       },
+       /* SXPro 288 External Data Fax Modem Plug & Play */
+       {       "ADC0002",              0       },
+       /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
+       {       "AEI0250",              0       },
+       /* Actiontec ISA PNP 56K X2 Fax Modem */
+       {       "AEI1240",              0       },
+       /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+       {       "AKY1021",              0 /*SPCI_FL_NO_SHIRQ*/  },
+       /* AZT3005 PnP SOUND DEVICE */
+       {       "AZT4001",              0       },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       "BDP3336",              0       },
+       /*  Boca Research */
+       /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+       {       "BRI0A49",              0       },
+       /* Boca Research 33,600 ACF Modem */
+       {       "BRI1400",              0       },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       "BRI3400",              0       },
+       /* Boca 33.6 Kbps Internal FD34FSVD */
+       {       "BRI0A49",              0       },
+       /* Best Data Products Inc. Smart One 336F PnP Modem */
+       {       "BDP3336",              0       },
+       /* Computer Peripherals Inc */
+       /* EuroViVa CommCenter-33.6 SP PnP */
+       {       "CPI4050",              0       },
+       /* Creative Labs */
+       /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+       {       "CTL3001",              0       },
+       /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+       {       "CTL3011",              0       },
+       /* Davicom ISA 33.6K Modem */
+       {       "DAV0336",              0       },
+       /* Creative */
+       /* Creative Modem Blaster Flash56 DI5601-1 */
+       {       "DMB1032",              0       },
+       /* Creative Modem Blaster V.90 DI5660 */
+       {       "DMB2001",              0       },
+       /* E-Tech */
+       /* E-Tech CyberBULLET PC56RVP */
+       {       "ETT0002",              0       },
+       /* FUJITSU */
+       /* Fujitsu 33600 PnP-I2 R Plug & Play */
+       {       "FUJ0202",              0       },
+       /* Fujitsu FMV-FX431 Plug & Play */
+       {       "FUJ0205",              0       },
+       /* Fujitsu 33600 PnP-I4 R Plug & Play */
+       {       "FUJ0206",              0       },
+       /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+       {       "FUJ0209",              0       },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "GVC000F",              0       },
+       /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
+       {       "GVC0303",              0       },
+       /* Hayes */
+       /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+       {       "HAY0001",              0       },
+       /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+       {       "HAY000C",              0       },
+       /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+       {       "HAY000D",              0       },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       "HAY5670",              0       },
+       /* Hayes Accura 56K Ext Fax Modem PnP */
+       {       "HAY5674",              0       },
+       /* Hayes Accura 56K Fax Modem PnP */
+       {       "HAY5675",              0       },
+       /* Hayes 288, V.34 + FAX */
+       {       "HAYF000",              0       },
+       /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+       {       "HAYF001",              0       },
+       /* IBM */
+       /* IBM Thinkpad 701 Internal Modem Voice */
+       {       "IBM0033",              0       },
+       /* Intertex */
+       /* Intertex 28k8 33k6 Voice EXT PnP */
+       {       "IXDC801",              0       },
+       /* Intertex 33k6 56k Voice EXT PnP */
+       {       "IXDC901",              0       },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       "IXDD801",              0       },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       "IXDD901",              0       },
+       /* Intertex 28k8 33k6 Voice SP INT PnP */
+       {       "IXDF401",              0       },
+       /* Intertex 28k8 33k6 Voice SP EXT PnP */
+       {       "IXDF801",              0       },
+       /* Intertex 33k6 56k Voice SP EXT PnP */
+       {       "IXDF901",              0       },
+       /* Kortex International */
+       /* KORTEX 28800 Externe PnP */
+       {       "KOR4522",              0       },
+       /* KXPro 33.6 Vocal ASVD PnP */
+       {       "KORF661",              0       },
+       /* Lasat */
+       /* LASAT Internet 33600 PnP */
+       {       "LAS4040",              0       },
+       /* Lasat Safire 560 PnP */
+       {       "LAS4540",              0       },
+       /* Lasat Safire 336  PnP */
+       {       "LAS5440",              0       },
+       /* Microcom, Inc. */
+       /* Microcom TravelPorte FAST V.34 Plug & Play */
+       {       "MNP0281",              0       },
+       /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+       {       "MNP0336",              0       },
+       /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+       {       "MNP0339",              0       },
+       /* Microcom DeskPorte 28.8P Plug & Play */
+       {       "MNP0342",              0       },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       "MNP0500",              0       },
+       /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+       {       "MNP0501",              0       },
+       /* Microcom DeskPorte 28.8S Internal Plug & Play */
+       {       "MNP0502",              0       },
+       /* Motorola */
+       /* Motorola BitSURFR Plug & Play */
+       {       "MOT1105",              0       },
+       /* Motorola TA210 Plug & Play */
+       {       "MOT1111",              0       },
+       /* Motorola HMTA 200 (ISDN) Plug & Play */
+       {       "MOT1114",              0       },
+       /* Motorola BitSURFR Plug & Play */
+       {       "MOT1115",              0       },
+       /* Motorola Lifestyle 28.8 Internal */
+       {       "MOT1190",              0       },
+       /* Motorola V.3400 Plug & Play */
+       {       "MOT1501",              0       },
+       /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+       {       "MOT1502",              0       },
+       /* Motorola Power 28.8 V.34 Plug & Play */
+       {       "MOT1505",              0       },
+       /* Motorola ModemSURFR External 28.8 Plug & Play */
+       {       "MOT1509",              0       },
+       /* Motorola Premier 33.6 Desktop Plug & Play */
+       {       "MOT150A",              0       },
+       /* Motorola VoiceSURFR 56K External PnP */
+       {       "MOT150F",              0       },
+       /* Motorola ModemSURFR 56K External PnP */
+       {       "MOT1510",              0       },
+       /* Motorola ModemSURFR 56K Internal PnP */
+       {       "MOT1550",              0       },
+       /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+       {       "MOT1560",              0       },
+       /* Motorola Premier 33.6 Internal Plug & Play */
+       {       "MOT1580",              0       },
+       /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+       {       "MOT15B0",              0       },
+       /* Motorola VoiceSURFR 56K Internal PnP */
+       {       "MOT15F0",              0       },
+       /* Com 1 */
+       /*  Deskline K56 Phone System PnP */
+       {       "MVX00A1",              0       },
+       /* PC Rider K56 Phone System PnP */
+       {       "MVX00F2",              0       },
+       /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
+       {       "nEC8241",              0       },
+       /* Pace 56 Voice Internal Plug & Play Modem */
+       {       "PMC2430",              0       },
+       /* Generic */
+       /* Generic standard PC COM port  */
+       {       "PNP0500",              0       },
+       /* Generic 16550A-compatible COM port */
+       {       "PNP0501",              0       },
+       /* Compaq 14400 Modem */
+       {       "PNPC000",              0       },
+       /* Compaq 2400/9600 Modem */
+       {       "PNPC001",              0       },
+       /* Dial-Up Networking Serial Cable between 2 PCs */
+       {       "PNPC031",              0       },
+       /* Dial-Up Networking Parallel Cable between 2 PCs */
+       {       "PNPC032",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC100",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC101",              0       },
+       /*  Standard 28800 bps Modem*/
+       {       "PNPC102",              0       },
+       /*  Standard Modem*/
+       {       "PNPC103",              0       },
+       /*  Standard 9600 bps Modem*/
+       {       "PNPC104",              0       },
+       /*  Standard 14400 bps Modem*/
+       {       "PNPC105",              0       },
+       /*  Standard 28800 bps Modem*/
+       {       "PNPC106",              0       },
+       /*  Standard Modem */
+       {       "PNPC107",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC108",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC109",              0       },
+       /* Standard 28800 bps Modem */
+       {       "PNPC10A",              0       },
+       /* Standard Modem */
+       {       "PNPC10B",              0       },
+       /* Standard 9600 bps Modem */
+       {       "PNPC10C",              0       },
+       /* Standard 14400 bps Modem */
+       {       "PNPC10D",              0       },
+       /* Standard 28800 bps Modem */
+       {       "PNPC10E",              0       },
+       /* Standard Modem */
+       {       "PNPC10F",              0       },
+       /* Standard PCMCIA Card Modem */
+       {       "PNP2000",              0       },
+       /* Rockwell */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF Internal PnP */
+       /* Modular Technology 33.6 Internal PnP */
+       {       "ROK0030",              0       },
+       /* Kortex International */
+       /* KORTEX 14400 Externe PnP */
+       {       "ROK0100",              0       },
+       /* Rockwell 28.8 */
+       {       "ROK4120",              0       },
+       /* Viking Components, Inc */
+       /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+       {       "ROK4920",              0       },
+       /* Rockwell */
+       /* British Telecom */
+       /* Modular Technology */
+       /* Rockwell 33.6 DPF External PnP */
+       /* BT Prologue 33.6 External PnP */
+       /* Modular Technology 33.6 External PnP */
+       {       "RSS00A0",              0       },
+       /* Viking 56K FAX INT */
+       {       "RSS0262",              0       },
+       /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
+       {       "RSS0250",              0       },
+       /* SupraExpress 28.8 Data/Fax PnP modem */
+       {       "SUP1310",              0       },
+       /* SupraExpress 336i PnP Voice Modem */
+       {       "SUP1381",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1421",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1590",              0       },
+       /* SupraExpress 336i Sp ASVD */
+       {       "SUP1620",              0       },
+       /* SupraExpress 33.6 Data/Fax PnP modem */
+       {       "SUP1760",              0       },
+       /* SupraExpress 56i Sp Intl */
+       {       "SUP2171",              0       },
+       /* Phoebe Micro */
+       /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+       {       "TEX0011",              0       },
+       /* Archtek America Corp. */
+       /* Archtek SmartLink Modem 3334BT Plug & Play */
+       {       "UAC000F",              0       },
+       /* 3Com Corp. */
+       /* Gateway Telepath IIvi 33.6 */
+       {       "USR0000",              0       },
+       /* U.S. Robotics Sporster 33.6K Fax INT PnP */
+       {       "USR0002",              0       },
+       /*  Sportster Vi 14.4 PnP FAX Voicemail */
+       {       "USR0004",              0       },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       "USR0006",              0       },
+       /* U.S. Robotics 33.6K Voice EXT PnP */
+       {       "USR0007",              0       },
+       /* U.S. Robotics Courier V.Everything INT PnP */
+       {       "USR0009",              0       },
+       /* U.S. Robotics 33.6K Voice INT PnP */
+       {       "USR2002",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR2070",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       "USR2080",              0       },
+       /* U.S. Robotics 56K FAX INT */
+       {       "USR3031",              0       },
+       /* U.S. Robotics 56K FAX INT */
+       {       "USR3050",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR3070",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP */
+       {       "USR3080",              0       },
+       /* U.S. Robotics 56K Voice INT PnP */
+       {       "USR3090",              0       },
+       /* U.S. Robotics 56K Message  */
+       {       "USR9100",              0       },
+       /* U.S. Robotics 56K FAX EXT PnP*/
+       {       "USR9160",              0       },
+       /* U.S. Robotics 56K FAX INT PnP*/
+       {       "USR9170",              0       },
+       /* U.S. Robotics 56K Voice EXT PnP*/
+       {       "USR9180",              0       },
+       /* U.S. Robotics 56K Voice INT PnP*/
+       {       "USR9190",              0       },
+       /* Wacom tablets */
+       {       "WACFXXX",              0       },
+       /* Compaq touchscreen */
+       {       "FPI2002",              0 },
+       /* Fujitsu Stylistic touchscreens */
+       {       "FUJ02B2",              0 },
+       {       "FUJ02B3",              0 },
+       /* Fujitsu Stylistic LT touchscreens */
+       {       "FUJ02B4",              0 },
+       /* Passive Fujitsu Stylistic touchscreens */
+       {       "FUJ02B6",              0 },
+       {       "FUJ02B7",              0 },
+       {       "FUJ02B8",              0 },
+       {       "FUJ02B9",              0 },
+       {       "FUJ02BC",              0 },
+       /* Fujitsu Wacom Tablet PC device */
+       {       "FUJ02E5",              0       },
+       /* Fujitsu P-series tablet PC device */
+       {       "FUJ02E6",              0       },
+       /* Fujitsu Wacom 2FGT Tablet PC device */
+       {       "FUJ02E7",              0       },
+       /* Fujitsu Wacom 1FGT Tablet PC device */
+       {       "FUJ02E9",              0       },
+       /*
+        * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
+        * disguise)
+        */
+       {       "LTS0001",              0       },
+       /* Rockwell's (PORALiNK) 33600 INT PNP */
+       {       "WCI0003",              0       },
+       /* Unknown PnP modems */
+       {       "PNPCXXX",              UNKNOWN_DEV     },
+       /* More unknown PnP modems */
+       {       "PNPDXXX",              UNKNOWN_DEV     },
+       {       "",                     0       }
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static char *modem_names[] __devinitdata = {
+       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+       "56K", "56k", "K56", "33.6", "28.8", "14.4",
+       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+       "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
+};
+
+static int __devinit check_name(char *name)
+{
+       char **tmp;
+
+       for (tmp = modem_names; *tmp; tmp++)
+               if (strstr(name, *tmp))
+                       return 1;
+
+       return 0;
+}
+
+static int __devinit check_resources(struct pnp_dev *dev)
+{
+       resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(base); i++) {
+               if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Given a complete unknown PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ *     - dev->name or dev->bus->name must contain "modem" substring;
+ *     - device must have only one IO region (8 byte long) with base address
+ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
+{
+       if (!(check_name(pnp_dev_name(dev)) ||
+               (dev->card && check_name(dev->card->name))))
+                       return -ENODEV;
+
+       if (check_resources(dev))
+               return 0;
+
+       return -ENODEV;
+}
+
+static int __devinit
+serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+       struct uart_port port;
+       int ret, line, flags = dev_id->driver_data;
+
+       if (flags & UNKNOWN_DEV) {
+               ret = serial_pnp_guess_board(dev, &flags);
+               if (ret < 0)
+                       return ret;
+       }
+
+       memset(&port, 0, sizeof(struct uart_port));
+       if (pnp_irq_valid(dev, 0))
+               port.irq = pnp_irq(dev, 0);
+       if (pnp_port_valid(dev, 0)) {
+               port.iobase = pnp_port_start(dev, 0);
+               port.iotype = UPIO_PORT;
+       } else if (pnp_mem_valid(dev, 0)) {
+               port.mapbase = pnp_mem_start(dev, 0);
+               port.iotype = UPIO_MEM;
+               port.flags = UPF_IOREMAP;
+       } else
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk(KERN_DEBUG
+               "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
+                      port.iobase, port.mapbase, port.irq, port.iotype);
+#endif
+
+       port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
+               port.flags |= UPF_SHARE_IRQ;
+       port.uartclk = 1843200;
+       port.dev = &dev->dev;
+
+       line = serial8250_register_port(&port);
+       if (line < 0)
+               return -ENODEV;
+
+       pnp_set_drvdata(dev, (void *)((long)line + 1));
+       return 0;
+}
+
+static void __devexit serial_pnp_remove(struct pnp_dev *dev)
+{
+       long line = (long)pnp_get_drvdata(dev);
+       if (line)
+               serial8250_unregister_port(line - 1);
+}
+
+#ifdef CONFIG_PM
+static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+       long line = (long)pnp_get_drvdata(dev);
+
+       if (!line)
+               return -ENODEV;
+       serial8250_suspend_port(line - 1);
+       return 0;
+}
+
+static int serial_pnp_resume(struct pnp_dev *dev)
+{
+       long line = (long)pnp_get_drvdata(dev);
+
+       if (!line)
+               return -ENODEV;
+       serial8250_resume_port(line - 1);
+       return 0;
+}
+#else
+#define serial_pnp_suspend NULL
+#define serial_pnp_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pnp_driver serial_pnp_driver = {
+       .name           = "serial",
+       .probe          = serial_pnp_probe,
+       .remove         = __devexit_p(serial_pnp_remove),
+       .suspend        = serial_pnp_suspend,
+       .resume         = serial_pnp_resume,
+       .id_table       = pnp_dev_table,
+};
+
+static int __init serial8250_pnp_init(void)
+{
+       return pnp_register_driver(&serial_pnp_driver);
+}
+
+static void __exit serial8250_pnp_exit(void)
+{
+       pnp_unregister_driver(&serial_pnp_driver);
+}
+
+module_init(serial8250_pnp_init);
+module_exit(serial8250_pnp_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
new file mode 100644 (file)
index 0000000..2b83346
--- /dev/null
@@ -0,0 +1,1599 @@
+#
+# Serial device configuration
+#
+
+menu "Serial drivers"
+       depends on HAS_IOMEM
+
+#
+# The new 8250/16550 serial drivers
+config SERIAL_8250
+       tristate "8250/16550 and compatible serial support"
+       select SERIAL_CORE
+       ---help---
+         This selects whether you want to include the driver for the standard
+         serial ports.  The standard answer is Y.  People who might say N
+         here are those that are setting up dedicated Ethernet WWW/FTP
+         servers, or users that have one of the various bus mice instead of a
+         serial mouse and don't intend to use their machine's standard serial
+         port for anything.  (Note that the Cyclades and Stallion multi
+         serial port drivers do not need this driver built in for them to
+         work.)
+
+         To compile this driver as a module, choose M here: the
+         module will be called 8250.
+         [WARNING: Do not compile this driver as a module if you are using
+         non-standard serial ports, since the configuration information will
+         be lost when the driver is unloaded.  This limitation may be lifted
+         in the future.]
+
+         BTW1: If you have a mouseman serial mouse which is not recognized by
+         the X window system, try running gpm first.
+
+         BTW2: If you intend to use a software modem (also called Winmodem)
+         under Linux, forget it.  These modems are crippled and require
+         proprietary drivers which are only available under Windows.
+
+         Most people will say Y or M here, so that they can use serial mice,
+         modems and similar devices connecting to the standard serial ports.
+
+config SERIAL_8250_CONSOLE
+       bool "Console on 8250/16550 and compatible serial port"
+       depends on SERIAL_8250=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode). This could be useful if some terminal or printer is connected
+         to that serial port.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyS1". (Try "man bootparam" or see the documentation of
+         your boot loader (grub or lilo or loadlin) about how to pass options
+         to the kernel at boot time.)
+
+         If you don't have a VGA card installed and you say Y here, the
+         kernel will automatically use the first serial line, /dev/ttyS0, as
+         system console.
+
+         You can set that using a kernel command line option such as
+         "console=uart8250,io,0x3f8,9600n8"
+         "console=uart8250,mmio,0xff5e0000,115200n8".
+         and it will switch to normal serial console when the corresponding 
+         port is ready.
+         "earlycon=uart8250,io,0x3f8,9600n8"
+         "earlycon=uart8250,mmio,0xff5e0000,115200n8".
+         it will not only setup early console.
+
+         If unsure, say N.
+
+config FIX_EARLYCON_MEM
+       bool
+       depends on X86
+       default y
+
+config SERIAL_8250_GSC
+       tristate
+       depends on SERIAL_8250 && GSC
+       default SERIAL_8250
+
+config SERIAL_8250_PCI
+       tristate "8250/16550 PCI device support" if EXPERT
+       depends on SERIAL_8250 && PCI
+       default SERIAL_8250
+       help
+         This builds standard PCI serial support. You may be able to
+         disable this feature if you only need legacy serial support.
+         Saves about 9K.
+
+config SERIAL_8250_PNP
+       tristate "8250/16550 PNP device support" if EXPERT
+       depends on SERIAL_8250 && PNP
+       default SERIAL_8250
+       help
+         This builds standard PNP serial support. You may be able to
+         disable this feature if you only need legacy serial support.
+
+config SERIAL_8250_HP300
+       tristate
+       depends on SERIAL_8250 && HP300
+       default SERIAL_8250
+
+config SERIAL_8250_CS
+       tristate "8250/16550 PCMCIA device support"
+       depends on PCMCIA && SERIAL_8250
+       ---help---
+         Say Y here to enable support for 16-bit PCMCIA serial devices,
+         including serial port cards, modems, and the modem functions of
+         multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
+         credit-card size devices often used with laptops.)
+
+         To compile this driver as a module, choose M here: the
+         module will be called serial_cs.
+
+         If unsure, say N.
+
+config SERIAL_8250_NR_UARTS
+       int "Maximum number of 8250/16550 serial ports"
+       depends on SERIAL_8250
+       default "4"
+       help
+         Set this to the number of serial ports you want the driver
+         to support.  This includes any ports discovered via ACPI or
+         PCI enumeration and any ports that may be added at run-time
+         via hot-plug, or any ISA multi-port serial cards.
+
+config SERIAL_8250_RUNTIME_UARTS
+       int "Number of 8250/16550 serial ports to register at runtime"
+       depends on SERIAL_8250
+       range 0 SERIAL_8250_NR_UARTS
+       default "4"
+       help
+         Set this to the maximum number of serial ports you want
+         the kernel to register at boot time.  This can be overridden
+         with the module parameter "nr_uarts", or boot-time parameter
+         8250.nr_uarts
+
+config SERIAL_8250_EXTENDED
+       bool "Extended 8250/16550 serial driver options"
+       depends on SERIAL_8250
+       help
+         If you wish to use any non-standard features of the standard "dumb"
+         driver, say Y here. This includes HUB6 support, shared serial
+         interrupts, special multiport support, support for more than the
+         four COM 1/2/3/4 boards, etc.
+
+         Note that the answer to this question won't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about serial driver options. If unsure, say N.
+
+config SERIAL_8250_MANY_PORTS
+       bool "Support more than 4 legacy serial ports"
+       depends on SERIAL_8250_EXTENDED && !IA64
+       help
+         Say Y here if you have dumb serial boards other than the four
+         standard COM 1/2/3/4 ports. This may happen if you have an AST
+         FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
+         from <http://www.tldp.org/docs.html#howto>), or other custom
+         serial port hardware which acts similar to standard serial port
+         hardware. If you only use the standard COM 1/2/3/4 ports, you can
+         say N here to save some memory. You can also say Y if you have an
+         "intelligent" multiport card such as Cyclades, Digiboards, etc.
+
+#
+# Multi-port serial cards
+#
+
+config SERIAL_8250_FOURPORT
+       tristate "Support Fourport cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an AST FourPort serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_fourport.
+
+config SERIAL_8250_ACCENT
+       tristate "Support Accent cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have an Accent Async serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_accent.
+
+config SERIAL_8250_BOCA
+       tristate "Support Boca cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a Boca serial board.  Please read the Boca
+         mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_boca.
+
+config SERIAL_8250_EXAR_ST16C554
+       tristate "Support Exar ST16C554/554D Quad UART"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         The Uplogix Envoy TU301 uses this Exar Quad UART.  If you are
+         tinkering with your Envoy TU301, or have a machine with this UART,
+         say Y here.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_exar_st16c554.
+
+config SERIAL_8250_HUB6
+       tristate "Support Hub6 cards"
+       depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+       help
+         Say Y here if you have a HUB6 serial board.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_hub6.
+
+config SERIAL_8250_SHARE_IRQ
+       bool "Support for sharing serial interrupts"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Some serial boards have hardware support which allows multiple dumb
+         serial ports on the same board to share a single IRQ. To enable
+         support for this in the serial driver, say Y here.
+
+config SERIAL_8250_DETECT_IRQ
+       bool "Autodetect IRQ on standard ports (unsafe)"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Say Y here if you want the kernel to try to guess which IRQ
+         to use for your serial port.
+
+         This is considered unsafe; it is far better to configure the IRQ in
+         a boot script using the setserial command.
+
+         If unsure, say N.
+
+config SERIAL_8250_RSA
+       bool "Support RSA serial ports"
+       depends on SERIAL_8250_EXTENDED
+       help
+         ::: To be written :::
+
+config SERIAL_8250_MCA
+       tristate "Support 8250-type ports on MCA buses"
+       depends on SERIAL_8250 != n && MCA
+       help
+         Say Y here if you have a MCA serial ports.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 8250_mca.
+
+config SERIAL_8250_ACORN
+       tristate "Acorn expansion card serial port support"
+       depends on ARCH_ACORN && SERIAL_8250
+       help
+         If you have an Atomwide Serial card or Serial Port card for an Acorn
+         system, say Y to this option.  The driver can handle 1, 2, or 3 port
+         cards.  If unsure, say N.
+
+config SERIAL_8250_RM9K
+       bool "Support for MIPS RM9xxx integrated serial port"
+       depends on SERIAL_8250 != n && SERIAL_RM9000
+       select SERIAL_8250_SHARE_IRQ
+       help
+         Selecting this option will add support for the integrated serial
+         port hardware found on MIPS RM9122 and similar processors.
+         If unsure, say N.
+
+comment "Non-8250 serial port support"
+
+config SERIAL_AMBA_PL010
+       tristate "ARM AMBA PL010 serial port support"
+       depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
+       select SERIAL_CORE
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell PL010 UART.  If you have
+         an Integrator/AP or Integrator/PP2 platform, or if you have a
+         Cirrus Logic EP93xx CPU, say Y or M here.
+
+         If unsure, say N.
+
+config SERIAL_AMBA_PL010_CONSOLE
+       bool "Support for console on AMBA serial port"
+       depends on SERIAL_AMBA_PL010=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         Say Y here if you wish to use an AMBA PrimeCell UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyAM0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_AMBA_PL011
+       tristate "ARM AMBA PL011 serial port support"
+       depends on ARM_AMBA
+       select SERIAL_CORE
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
+         an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
+         here.
+
+         If unsure, say N.
+
+config SERIAL_AMBA_PL011_CONSOLE
+       bool "Support for console on AMBA serial port"
+       depends on SERIAL_AMBA_PL011=y
+       select SERIAL_CORE_CONSOLE
+       ---help---
+         Say Y here if you wish to use an AMBA PrimeCell UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyAMA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SB1250_DUART
+       tristate "BCM1xxx on-chip DUART serial support"
+       depends on SIBYTE_SB1xxx_SOC=y
+       select SERIAL_CORE
+       default y
+       ---help---
+         Support for the asynchronous serial interface (DUART) included in
+         the BCM1250 and derived System-On-a-Chip (SOC) devices.  Note that
+         the letter D in DUART stands for "dual", which is how the device
+         is implemented.  Depending on the SOC configuration there may be
+         one or more DUARTs available of which all are handled.
+
+         If unsure, say Y.  To compile this driver as a module, choose M here:
+         the module will be called sb1250-duart.
+
+config SERIAL_SB1250_DUART_CONSOLE
+       bool "Support for console on a BCM1xxx DUART serial port"
+       depends on SERIAL_SB1250_DUART=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         If unsure, say Y.
+
+config SERIAL_ATMEL
+       bool "AT91 / AT32 on-chip serial port support"
+       depends on (ARM && ARCH_AT91) || AVR32
+       select SERIAL_CORE
+       help
+         This enables the driver for the on-chip UARTs of the Atmel
+         AT91 and AT32 processors.
+
+config SERIAL_ATMEL_CONSOLE
+       bool "Support for console on AT91 / AT32 serial port"
+       depends on SERIAL_ATMEL=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use an on-chip UART on a Atmel
+         AT91 or AT32 processor as the system console (the system
+         console is the device which receives all kernel messages and
+         warnings and which allows logins in single user mode).
+
+config SERIAL_ATMEL_PDC
+       bool "Support DMA transfers on AT91 / AT32 serial port"
+       depends on SERIAL_ATMEL
+       default y
+       help
+         Say Y here if you wish to use the PDC to do DMA transfers to
+         and from the Atmel AT91 / AT32 serial port. In order to
+         actually use DMA transfers, make sure that the use_dma_tx
+         and use_dma_rx members in the atmel_uart_data struct is set
+         appropriately for each port.
+
+         Note that break and error handling currently doesn't work
+         properly when DMA is enabled. Make sure that ports where
+         this matters don't use DMA.
+
+config SERIAL_ATMEL_TTYAT
+       bool "Install as device ttyATn instead of ttySn"
+       depends on SERIAL_ATMEL=y
+       help
+         Say Y here if you wish to have the internal AT91 / AT32 UARTs
+         appear as /dev/ttyATn (major 204, minor starting at 154)
+         instead of the normal /dev/ttySn (major 4, minor starting at
+         64). This is necessary if you also want other UARTs, such as
+         external 8250/16C550 compatible UARTs.
+         The ttySn nodes are legally reserved for the 8250 serial driver
+         but are often misused by other serial drivers.
+
+         To use this, you should create suitable ttyATn device nodes in
+         /dev/, and pass "console=ttyATn" to the kernel.
+
+         Say Y if you have an external 8250/16C550 UART.  If unsure, say N.
+
+config SERIAL_KS8695
+       bool "Micrel KS8695 (Centaur) serial port support"
+       depends on ARCH_KS8695
+       select SERIAL_CORE
+       help
+         This selects the Micrel Centaur KS8695 UART.  Say Y here.
+
+config SERIAL_KS8695_CONSOLE
+       bool "Support for console on KS8695 (Centaur) serial port"
+       depends on SERIAL_KS8695=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a KS8695 (Centaur) UART as the
+         system console (the system console is the device which
+         receives all kernel messages and warnings and which allows
+         logins in single user mode).
+
+config SERIAL_CLPS711X
+       tristate "CLPS711X serial port support"
+       depends on ARM && ARCH_CLPS711X
+       select SERIAL_CORE
+       help
+         ::: To be written :::
+
+config SERIAL_CLPS711X_CONSOLE
+       bool "Support for console on CLPS711X serial port"
+       depends on SERIAL_CLPS711X=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyCL1". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SAMSUNG
+       tristate "Samsung SoC serial support"
+       depends on ARM && PLAT_SAMSUNG
+       select SERIAL_CORE
+       help
+         Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
+         providing /dev/ttySAC0, 1 and 2 (note, some machines may not
+         provide all of these ports, depending on how the serial port
+         pins are configured.
+
+config SERIAL_SAMSUNG_UARTS_4
+       bool
+       depends on ARM && PLAT_SAMSUNG
+       default y if CPU_S3C2443
+       help
+         Internal node for the common case of 4 Samsung compatible UARTs
+
+config SERIAL_SAMSUNG_UARTS
+       int
+       depends on ARM && PLAT_SAMSUNG
+       default 2 if ARCH_S3C2400
+       default 6 if ARCH_S5P6450
+       default 4 if SERIAL_SAMSUNG_UARTS_4
+       default 3
+       help
+         Select the number of available UART ports for the Samsung S3C
+         serial driver
+       
+config SERIAL_SAMSUNG_DEBUG
+       bool "Samsung SoC serial debug"
+       depends on SERIAL_SAMSUNG && DEBUG_LL
+       help
+         Add support for debugging the serial driver. Since this is
+         generally being used as a console, we use our own output
+         routines that go via the low-level debug printascii()
+         function.
+
+config SERIAL_SAMSUNG_CONSOLE
+       bool "Support for console on Samsung SoC serial port"
+       depends on SERIAL_SAMSUNG=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Allow selection of the S3C24XX on-board serial ports for use as
+         an virtual console.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySACx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
+
+config SERIAL_S3C2400
+       tristate "Samsung S3C2410 Serial port support"
+       depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400
+       default y if CPU_S3C2400
+       help
+         Serial port support for the Samsung S3C2400 SoC
+
+config SERIAL_S3C2410
+       tristate "Samsung S3C2410 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C2410
+       default y if CPU_S3C2410
+       help
+         Serial port support for the Samsung S3C2410 SoC
+
+config SERIAL_S3C2412
+       tristate "Samsung S3C2412/S3C2413 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C2412
+       default y if CPU_S3C2412
+       help
+         Serial port support for the Samsung S3C2412 and S3C2413 SoC
+
+config SERIAL_S3C2440
+       tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
+       default y if CPU_S3C2440
+       default y if CPU_S3C2442
+       select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
+       help
+         Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
+
+config SERIAL_S3C24A0
+       tristate "Samsung S3C24A0 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C24A0
+       default y if CPU_S3C24A0
+       help
+         Serial port support for the Samsung S3C24A0 SoC
+
+config SERIAL_S3C6400
+       tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
+       select SERIAL_SAMSUNG_UARTS_4
+       default y
+       help
+         Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
+         and S5PC100 SoCs
+
+config SERIAL_S5PV210
+       tristate "Samsung S5PV210 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310)
+       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310)
+       default y
+       help
+         Serial port support for Samsung's S5P Family of SoC's
+
+
+config SERIAL_MAX3100
+       tristate "MAX3100 support"
+       depends on SPI
+       select SERIAL_CORE
+       help
+         MAX3100 chip support
+
+config SERIAL_MAX3107
+       tristate "MAX3107 support"
+       depends on SPI
+       select SERIAL_CORE
+       help
+         MAX3107 chip support
+
+config SERIAL_MAX3107_AAVA
+       tristate "MAX3107 AAVA platform support"
+       depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB
+       select SERIAL_CORE
+       help
+         Support for the MAX3107 chip configuration found on the AAVA
+         platform. Includes the extra initialisation and GPIO support
+         neded for this device.
+
+config SERIAL_DZ
+       bool "DECstation DZ serial driver"
+       depends on MACH_DECSTATION && 32BIT
+       select SERIAL_CORE
+       default y
+       ---help---
+         DZ11-family serial controllers for DECstations and VAXstations,
+         including the DC7085, M7814, and M7819.
+
+config SERIAL_DZ_CONSOLE
+       bool "Support console on DECstation DZ serial driver"
+       depends on SERIAL_DZ=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         Note that the firmware uses ttyS3 as the serial console on
+         DECstations that use this driver.
+
+         If unsure, say Y.
+
+config SERIAL_ZS
+       tristate "DECstation Z85C30 serial support"
+       depends on MACH_DECSTATION
+       select SERIAL_CORE
+       default y
+       ---help---
+         Support for the Zilog 85C350 serial communications controller used
+         for serial ports in newer DECstation systems.  These include the
+         DECsystem 5900 and all models of the DECstation and DECsystem 5000
+         systems except from model 200.
+
+         If unsure, say Y.  To compile this driver as a module, choose M here:
+         the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+       bool "Support for console on a DECstation Z85C30 serial port"
+       depends on SERIAL_ZS=y
+       select SERIAL_CORE_CONSOLE
+       default y
+       ---help---
+         If you say Y here, it will be possible to use a serial port as the
+         system console (the system console is the device which receives all
+         kernel messages and warnings and which allows logins in single user
+         mode).
+
+         Note that the firmware uses ttyS1 as the serial console on the
+         Maxine and ttyS3 on the others using this driver.
+
+         If unsure, say Y.
+
+config SERIAL_21285
+       tristate "DC21285 serial port support"
+       depends on ARM && FOOTBRIDGE
+       select SERIAL_CORE
+       help
+         If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
+         PCI bridge you can enable its onboard serial port by enabling this
+         option.
+
+config SERIAL_21285_CONSOLE
+       bool "Console on DC21285 serial port"
+       depends on SERIAL_21285=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the 21285 footbridge you can
+         make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyFB". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_MPSC
+       bool "Marvell MPSC serial port support"
+       depends on PPC32 && MV64X60
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the Marvell MPSC serial controller.
+
+config SERIAL_MPSC_CONSOLE
+       bool "Support for console on Marvell MPSC serial port"
+       depends on SERIAL_MPSC
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you want to support a serial console on a Marvell MPSC.
+
+config SERIAL_PXA
+       bool "PXA serial port support"
+       depends on ARCH_PXA || ARCH_MMP
+       select SERIAL_CORE
+       help
+         If you have a machine based on an Intel XScale PXA2xx CPU you
+         can enable its onboard serial ports by enabling this option.
+
+config SERIAL_PXA_CONSOLE
+       bool "Console on PXA serial port"
+       depends on SERIAL_PXA
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Intel XScale PXA
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SA1100
+       bool "SA1100 serial port support"
+       depends on ARM && ARCH_SA1100
+       select SERIAL_CORE
+       help
+         If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
+         can enable its onboard serial port by enabling this option.
+         Please read <file:Documentation/arm/SA1100/serial_UART> for further
+         info.
+
+config SERIAL_SA1100_CONSOLE
+       bool "Console on SA1100 serial port"
+       depends on SERIAL_SA1100
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the SA1100/SA1110 StrongARM
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_MRST_MAX3110
+       tristate "SPI UART driver for Max3110"
+       depends on SPI_DW_PCI
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       help
+         This is the UART protocol driver for the MAX3110 device on
+         the Intel Moorestown platform. On other systems use the max3100
+         driver.
+
+config SERIAL_MFD_HSU
+       tristate "Medfield High Speed UART support"
+       depends on PCI
+       select SERIAL_CORE
+
+config SERIAL_MFD_HSU_CONSOLE
+       boolean "Medfile HSU serial console support"
+       depends on SERIAL_MFD_HSU=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_BFIN
+       tristate "Blackfin serial port support"
+       depends on BLACKFIN
+       select SERIAL_CORE
+       select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
+       help
+         Add support for the built-in UARTs on the Blackfin.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_5xx.
+
+config SERIAL_BFIN_CONSOLE
+       bool "Console on Blackfin serial port"
+       depends on SERIAL_BFIN=y
+       select SERIAL_CORE_CONSOLE
+
+choice
+       prompt "UART Mode"
+       depends on SERIAL_BFIN
+       default SERIAL_BFIN_DMA
+       help
+         This driver supports the built-in serial ports of the Blackfin family
+         of CPUs
+
+config SERIAL_BFIN_DMA
+       bool "DMA mode"
+       depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n
+       help
+         This driver works under DMA mode. If this option is selected, the
+         blackfin simple dma driver is also enabled.
+
+config SERIAL_BFIN_PIO
+       bool "PIO mode"
+       help
+         This driver works under PIO mode.
+
+endchoice
+
+config SERIAL_BFIN_UART0
+       bool "Enable UART0"
+       depends on SERIAL_BFIN
+       help
+         Enable UART0
+
+config BFIN_UART0_CTSRTS
+       bool "Enable UART0 hardware flow control"
+       depends on SERIAL_BFIN_UART0
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART1
+       bool "Enable UART1"
+       depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
+       help
+         Enable UART1
+
+config BFIN_UART1_CTSRTS
+       bool "Enable UART1 hardware flow control"
+       depends on SERIAL_BFIN_UART1
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART2
+       bool "Enable UART2"
+       depends on SERIAL_BFIN && (BF54x || BF538 || BF539)
+       help
+         Enable UART2
+
+config BFIN_UART2_CTSRTS
+       bool "Enable UART2 hardware flow control"
+       depends on SERIAL_BFIN_UART2
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_UART3
+       bool "Enable UART3"
+       depends on SERIAL_BFIN && (BF54x)
+       help
+         Enable UART3
+
+config BFIN_UART3_CTSRTS
+       bool "Enable UART3 hardware flow control"
+       depends on SERIAL_BFIN_UART3
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_IMX
+       bool "IMX serial port support"
+       depends on ARM && (ARCH_IMX || ARCH_MXC)
+       select SERIAL_CORE
+       select RATIONAL
+       help
+         If you have a machine based on a Motorola IMX CPU you
+         can enable its onboard serial port by enabling this option.
+
+config SERIAL_IMX_CONSOLE
+       bool "Console on IMX serial port"
+       depends on SERIAL_IMX
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Motorola IMX
+         CPU you can make it the console by answering Y to this option.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttySA0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_UARTLITE
+       tristate "Xilinx uartlite serial port support"
+       depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the Xilinx uartlite serial controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called uartlite.
+
+config SERIAL_UARTLITE_CONSOLE
+       bool "Support for console on Xilinx uartlite serial port"
+       depends on SERIAL_UARTLITE=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a Xilinx uartlite as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+config SERIAL_SUNCORE
+       bool
+       depends on SPARC
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       default y
+
+config SERIAL_SUNZILOG
+       tristate "Sun Zilog8530 serial support"
+       depends on SPARC
+       help
+         This driver supports the Zilog8530 serial ports found on many Sparc
+         systems.  Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_SUNZILOG_CONSOLE
+       bool "Console on Sun Zilog8530 serial port"
+       depends on SERIAL_SUNZILOG=y
+       help
+         If you would like to be able to use the Zilog8530 serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_SUNSU
+       tristate "Sun SU serial support"
+       depends on SPARC && PCI
+       help
+         This driver supports the 8250 serial ports that run the keyboard and
+         mouse on (PCI) UltraSPARC systems.  Say Y or M if you want to be able
+         to these serial ports.
+
+config SERIAL_SUNSU_CONSOLE
+       bool "Console on Sun SU serial port"
+       depends on SERIAL_SUNSU=y
+       help
+         If you would like to be able to use the SU serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_MUX
+       tristate "Serial MUX support"
+       depends on GSC
+       select SERIAL_CORE
+       default y
+       ---help---
+         Saying Y here will enable the hardware MUX serial driver for
+         the Nova, K class systems and D class with a 'remote control card'.
+         The hardware MUX is not 8250/16550 compatible therefore the
+         /dev/ttyB0 device is shared between the Serial MUX and the PDC
+         software console. The following steps need to be completed to use
+         the Serial MUX:
+
+           1. create the device entry (mknod /dev/ttyB0 c 11 0)
+           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+           3. Add device ttyB0 to /etc/securetty (if you want to log on as
+                root on this console.)
+           4. Change the kernel command console parameter to: console=ttyB0
+
+config SERIAL_MUX_CONSOLE
+       bool "Support for console on serial MUX"
+       depends on SERIAL_MUX=y
+       select SERIAL_CORE_CONSOLE
+       default y
+
+config PDC_CONSOLE
+       bool "PDC software console support"
+       depends on PARISC && !SERIAL_MUX && VT
+       default n
+       help
+         Saying Y here will enable the software based PDC console to be 
+         used as the system console.  This is useful for machines in 
+         which the hardware based console has not been written yet.  The
+         following steps must be competed to use the PDC console:
+
+           1. create the device entry (mknod /dev/ttyB0 c 11 0)
+           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+           3. Add device ttyB0 to /etc/securetty (if you want to log on as
+                root on this console.)
+           4. Change the kernel command console parameter to: console=ttyB0
+
+config SERIAL_SUNSAB
+       tristate "Sun Siemens SAB82532 serial support"
+       depends on SPARC && PCI
+       help
+         This driver supports the Siemens SAB82532 DUSCC serial ports on newer
+         (PCI) UltraSPARC systems.  Say Y or M if you want to be able to these
+         serial ports.
+
+config SERIAL_SUNSAB_CONSOLE
+       bool "Console on Sun Siemens SAB82532 serial port"
+       depends on SERIAL_SUNSAB=y
+       help
+         If you would like to be able to use the SAB82532 serial port
+         on your Sparc system as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_SUNHV
+       bool "Sun4v Hypervisor Console support"
+       depends on SPARC64
+       help
+         This driver supports the console device found on SUN4V Sparc
+         systems.  Say Y if you want to be able to use this device.
+
+config SERIAL_IP22_ZILOG
+       tristate "SGI Zilog8530 serial support"
+       depends on SGI_HAS_ZILOG
+       select SERIAL_CORE
+       help
+         This driver supports the Zilog8530 serial ports found on SGI
+         systems.  Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_IP22_ZILOG_CONSOLE
+       bool "Console on SGI Zilog8530 serial port"
+       depends on SERIAL_IP22_ZILOG=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_SH_SCI
+       tristate "SuperH SCI(F) serial port support"
+       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
+       select SERIAL_CORE
+
+config SERIAL_SH_SCI_NR_UARTS
+       int "Maximum number of SCI(F) serial ports"
+       depends on SERIAL_SH_SCI
+       default "2"
+
+config SERIAL_SH_SCI_CONSOLE
+       bool "Support for console on SuperH SCI(F)"
+       depends on SERIAL_SH_SCI=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_SH_SCI_DMA
+       bool "DMA support"
+       depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
+
+config SERIAL_PNX8XXX
+       bool "Enable PNX8XXX SoCs' UART Support"
+       depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
+       select SERIAL_CORE
+       help
+         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+         and you want to use serial ports, say Y.  Otherwise, say N.
+
+config SERIAL_PNX8XXX_CONSOLE
+       bool "Enable PNX8XX0 serial console"
+       depends on SERIAL_PNX8XXX
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+         and you want to use serial console, say Y. Otherwise, say N.
+
+config SERIAL_CORE
+       tristate
+
+config SERIAL_CORE_CONSOLE
+       bool
+
+config CONSOLE_POLL
+       bool
+
+config SERIAL_68328
+       bool "68328 serial support"
+       depends on M68328 || M68EZ328 || M68VZ328
+       help
+         This driver supports the built-in serial port of the Motorola 68328
+         (standard, EZ and VZ varieties).
+
+config SERIAL_68328_RTS_CTS
+       bool "Support RTS/CTS on 68328 serial port"
+       depends on SERIAL_68328
+
+config SERIAL_MCF
+       bool "Coldfire serial support"
+       depends on COLDFIRE
+       select SERIAL_CORE
+       help
+         This serial driver supports the Freescale Coldfire serial ports.
+
+config SERIAL_MCF_BAUDRATE
+       int "Default baudrate for Coldfire serial ports"
+       depends on SERIAL_MCF
+       default 19200
+       help
+         This setting lets you define what the default baudrate is for the
+         ColdFire serial ports. The usual default varies from board to board,
+         and this setting is a way of catering for that.
+
+config SERIAL_MCF_CONSOLE
+       bool "Coldfire serial console support"
+       depends on SERIAL_MCF
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a ColdFire internal serial port to be the system console.
+
+config SERIAL_68360_SMC
+       bool "68360 SMC uart support"
+       depends on M68360
+       help
+         This driver supports the SMC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360_SCC
+       bool "68360 SCC uart support"
+       depends on M68360
+       help
+         This driver supports the SCC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360
+       bool
+       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
+       default y
+
+config SERIAL_PMACZILOG
+       tristate "Mac or PowerMac z85c30 ESCC support"
+       depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
+       select SERIAL_CORE
+       help
+         This driver supports the Zilog z85C30 serial ports found on
+         (Power)Mac machines.
+         Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_PMACZILOG_TTYS
+       bool "Use ttySn device nodes for Zilog z85c30"
+       depends on SERIAL_PMACZILOG
+       help
+         The pmac_zilog driver for the z85C30 chip on many powermacs
+         historically used the device numbers for /dev/ttySn.  The
+         8250 serial port driver also uses these numbers, which means
+         the two drivers being unable to coexist; you could not use
+         both z85C30 and 8250 type ports at the same time.
+
+         If this option is not selected, the pmac_zilog driver will
+         use the device numbers allocated for /dev/ttyPZn.  This allows
+         the pmac_zilog and 8250 drivers to co-exist, but may cause
+         existing userspace setups to break.  Programs that need to
+         access the built-in serial ports on powermacs will need to
+         be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
+
+         If you enable this option, any z85c30 ports in the system will
+         be registered as ttyS0 onwards as in the past, and you will be
+         unable to use the 8250 module for PCMCIA or other 16C550-style
+         UARTs.
+
+         Say N unless you need the z85c30 ports on your (Power)Mac
+         to appear as /dev/ttySn.
+
+config SERIAL_PMACZILOG_CONSOLE
+       bool "Console on Mac or PowerMac z85c30 serial port"
+       depends on SERIAL_PMACZILOG=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you would like to be able to use the z85c30 serial port
+         on your (Power)Mac as the console, you can do so by answering
+         Y to this option.
+
+config SERIAL_LH7A40X
+       tristate "Sharp LH7A40X embedded UART support"
+       depends on ARM && ARCH_LH7A40X
+       select SERIAL_CORE
+       help
+         This enables support for the three on-board UARTs of the
+         Sharp LH7A40X series CPUs.  Choose Y or M.
+
+config SERIAL_LH7A40X_CONSOLE
+       bool "Support for console on Sharp LH7A40X serial port"
+       depends on SERIAL_LH7A40X=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use one of the serial ports as the
+         system console--the system console is the device which
+         receives all kernel messages and warnings and which allows
+         logins in single user mode.
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the default system console, but
+         you can alter that using a kernel command line, for example
+         "console=ttyAM1".
+
+config SERIAL_CPM
+       tristate "CPM SCC/SMC serial port support"
+       depends on CPM2 || 8xx
+       select SERIAL_CORE
+       help
+         This driver supports the SCC and SMC serial ports on Motorola 
+         embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
+
+config SERIAL_CPM_CONSOLE
+       bool "Support for console on CPM SCC/SMC serial port"
+       depends on SERIAL_CPM=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use a SCC or SMC CPM UART as the system
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
+
+         Even if you say Y here, the currently visible framebuffer console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyCPM0". (Try "man bootparam" or see the documentation of
+         your boot loader (lilo or loadlin) about how to pass options to the
+         kernel at boot time.)
+
+config SERIAL_SGI_L1_CONSOLE
+       bool "SGI Altix L1 serial console support"
+       depends on IA64_GENERIC || IA64_SGI_SN2
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       help
+               If you have an SGI Altix and you would like to use the system
+               controller serial port as your console (you want this!),
+               say Y.  Otherwise, say N.
+
+config SERIAL_MPC52xx
+       tristate "Freescale MPC52xx/MPC512x family PSC serial support"
+       depends on PPC_MPC52xx || PPC_MPC512x
+       select SERIAL_CORE
+       help
+         This driver supports MPC52xx and MPC512x PSC serial ports. If you would
+         like to use them, you must answer Y or M to this option. Note that
+         for use as console, it must be included in kernel and not as a
+         module.
+
+config SERIAL_MPC52xx_CONSOLE
+       bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
+       depends on SERIAL_MPC52xx=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this options if you'd like to use one of the PSC serial port
+         of the Freescale MPC52xx family as a console.
+
+config SERIAL_MPC52xx_CONSOLE_BAUD
+       int "Freescale MPC52xx/MPC512x family PSC serial port baud"
+       depends on SERIAL_MPC52xx_CONSOLE=y
+       default "9600"
+       help
+         Select the MPC52xx console baud rate.
+         This value is only used if the bootloader doesn't pass in the
+         console baudrate
+
+config SERIAL_ICOM
+       tristate "IBM Multiport Serial Adapter"
+       depends on PCI && (PPC_ISERIES || PPC_PSERIES)
+       select SERIAL_CORE
+       select FW_LOADER
+       help
+         This driver is for a family of multiport serial adapters
+         including 2 port RVX, 2 port internal modem, 4 port internal
+         modem and a split 1 port RVX and 1 port internal modem.
+
+         This driver can also be built as a module.  If so, the module
+         will be called icom.
+
+config SERIAL_M32R_SIO
+       bool "M32R SIO I/F"
+       depends on M32R
+       default y
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the M32R serial controller.
+
+config SERIAL_M32R_SIO_CONSOLE
+       bool "use SIO console"
+       depends on SERIAL_M32R_SIO=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you want to support a serial console.
+
+         If you use an M3T-M32700UT or an OPSPUT platform,
+         please say also y for SERIAL_M32R_PLDSIO.
+
+config SERIAL_M32R_PLDSIO
+       bool "M32R SIO I/F on a PLD"
+       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT)
+       default n
+       help
+         Say Y here if you want to use the M32R serial controller
+         on a PLD (Programmable Logic Device).
+
+         If you use an M3T-M32700UT or an OPSPUT platform,
+         please say Y.
+
+config SERIAL_TXX9
+       bool "TMPTX39XX/49XX SIO support"
+       depends on HAS_TXX9_SERIAL
+       select SERIAL_CORE
+       default y
+
+config HAS_TXX9_SERIAL
+       bool
+
+config SERIAL_TXX9_NR_UARTS
+       int "Maximum number of TMPTX39XX/49XX SIO ports"
+       depends on SERIAL_TXX9
+       default "6"
+
+config SERIAL_TXX9_CONSOLE
+       bool "TMPTX39XX/49XX SIO Console support"
+       depends on SERIAL_TXX9=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_TXX9_STDSERIAL
+       bool "TX39XX/49XX SIO act as standard serial"
+       depends on !SERIAL_8250 && SERIAL_TXX9
+
+config SERIAL_VR41XX
+       tristate "NEC VR4100 series Serial Interface Unit support"
+       depends on CPU_VR41XX
+       select SERIAL_CORE
+       help
+         If you have a NEC VR4100 series processor and you want to use
+         Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
+         (not include VR4111/VR4121 DSIU), say Y.  Otherwise, say N.
+
+config SERIAL_VR41XX_CONSOLE
+       bool "Enable NEC VR4100 series Serial Interface Unit console"
+       depends on SERIAL_VR41XX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have a NEC VR4100 series processor and you want to use
+         a console on a serial port, say Y.  Otherwise, say N.
+
+config SERIAL_JSM
+       tristate "Digi International NEO PCI Support"
+       depends on PCI
+       select SERIAL_CORE
+       help
+         This is a driver for Digi International's Neo series
+         of cards which provide multiple serial ports. You would need
+         something like this to connect more than two modems to your Linux
+         box, for instance in order to become a dial-in server. This driver
+         supports PCI boards only.
+
+         If you have a card like this, say Y here, otherwise say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called jsm.
+
+config SERIAL_SGI_IOC4
+       tristate "SGI IOC4 controller serial support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
+       select SERIAL_CORE
+       help
+               If you have an SGI Altix with an IOC4 based Base IO card
+               and wish to use the serial ports on this card, say Y.
+               Otherwise, say N.
+
+config SERIAL_SGI_IOC3
+       tristate "SGI Altix IOC3 serial support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
+       select SERIAL_CORE
+       help
+         If you have an SGI Altix with an IOC3 serial card,
+         say Y or M.  Otherwise, say N.
+
+config SERIAL_MSM
+       bool "MSM on-chip serial port support"
+       depends on ARM && ARCH_MSM
+       select SERIAL_CORE
+
+config SERIAL_MSM_CONSOLE
+       bool "MSM serial console support"
+       depends on SERIAL_MSM=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_VT8500
+       bool "VIA VT8500 on-chip serial port support"
+       depends on ARM && ARCH_VT8500
+       select SERIAL_CORE
+
+config SERIAL_VT8500_CONSOLE
+       bool "VIA VT8500 serial console support"
+       depends on SERIAL_VT8500=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_NETX
+       tristate "NetX serial port support"
+       depends on ARM && ARCH_NETX
+       select SERIAL_CORE
+       help
+         If you have a machine based on a Hilscher NetX SoC you
+         can enable its onboard serial port by enabling this option.
+
+          To compile this driver as a module, choose M here: the
+          module will be called netx-serial.
+
+config SERIAL_NETX_CONSOLE
+       bool "Console on NetX serial port"
+       depends on SERIAL_NETX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the Hilscher NetX SoC
+         you can make it the console by answering Y to this option.
+
+config SERIAL_OF_PLATFORM
+       tristate "Serial port on Open Firmware platform bus"
+       depends on OF
+       depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
+       help
+         If you have a PowerPC based system that has serial ports
+         on a platform specific bus, you should enable this option.
+         Currently, only 8250 compatible ports are supported, but
+         others can easily be added.
+
+config SERIAL_OMAP
+       tristate "OMAP serial port support"
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+       select SERIAL_CORE
+       help
+         If you have a machine based on an Texas Instruments OMAP CPU you
+         can enable its onboard serial ports by enabling this option.
+
+         By enabling this option you take advantage of dma feature available
+         with the omap-serial driver. DMA support can be enabled from platform
+         data.
+
+config SERIAL_OMAP_CONSOLE
+       bool "Console on OMAP serial port"
+       depends on SERIAL_OMAP
+       select SERIAL_CORE_CONSOLE
+       help
+         Select this option if you would like to use omap serial port as
+         console.
+
+         Even if you say Y here, the currently visible virtual console
+         (/dev/tty0) will still be used as the system console by default, but
+         you can alter that using a kernel command line option such as
+         "console=ttyOx". (Try "man bootparam" or see the documentation of
+         your boot loader about how to pass options to the kernel at
+         boot time.)
+
+config SERIAL_OF_PLATFORM_NWPSERIAL
+       tristate "NWP serial port driver"
+       depends on PPC_OF && PPC_DCR
+       select SERIAL_OF_PLATFORM
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_CORE
+       help
+         This driver supports the cell network processor nwp serial
+         device.
+
+config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+       bool "Console on NWP serial port"
+       depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on the NWP serial ports.
+
+config SERIAL_QE
+       tristate "Freescale QUICC Engine serial port support"
+       depends on QUICC_ENGINE
+       select SERIAL_CORE
+       select FW_LOADER
+       default n
+       help
+         This driver supports the QE serial ports on Freescale embedded
+         PowerPC that contain a QUICC Engine.
+
+config SERIAL_SC26XX
+       tristate "SC2681/SC2692 serial port support"
+       depends on SNI_RM
+       select SERIAL_CORE
+       help
+         This is a driver for the onboard serial ports of
+         older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+       bool "Console on SC2681/SC2692 serial port"
+       depends on SERIAL_SC26XX
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on SC2681/SC2692 serial ports.
+
+config SERIAL_BFIN_SPORT
+       tristate "Blackfin SPORT emulate UART"
+       depends on BLACKFIN
+       select SERIAL_CORE
+       help
+         Enable SPORT emulate UART on Blackfin series.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_sport_uart.
+
+config SERIAL_BFIN_SPORT_CONSOLE
+       bool "Console on Blackfin sport emulated uart"
+       depends on SERIAL_BFIN_SPORT=y
+       select SERIAL_CORE_CONSOLE
+
+config SERIAL_BFIN_SPORT0_UART
+       bool "Enable UART over SPORT0"
+       depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
+       help
+         Enable UART over SPORT0
+
+config SERIAL_BFIN_SPORT0_UART_CTSRTS
+       bool "Enable UART over SPORT0 hardware flow control"
+       depends on SERIAL_BFIN_SPORT0_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT1_UART
+       bool "Enable UART over SPORT1"
+       depends on SERIAL_BFIN_SPORT
+       help
+         Enable UART over SPORT1
+
+config SERIAL_BFIN_SPORT1_UART_CTSRTS
+       bool "Enable UART over SPORT1 hardware flow control"
+       depends on SERIAL_BFIN_SPORT1_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT2_UART
+       bool "Enable UART over SPORT2"
+       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+       help
+         Enable UART over SPORT2
+
+config SERIAL_BFIN_SPORT2_UART_CTSRTS
+       bool "Enable UART over SPORT2 hardware flow control"
+       depends on SERIAL_BFIN_SPORT2_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_BFIN_SPORT3_UART
+       bool "Enable UART over SPORT3"
+       depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+       help
+         Enable UART over SPORT3
+
+config SERIAL_BFIN_SPORT3_UART_CTSRTS
+       bool "Enable UART over SPORT3 hardware flow control"
+       depends on SERIAL_BFIN_SPORT3_UART
+       help
+         Enable hardware flow control in the driver.
+
+config SERIAL_TIMBERDALE
+       tristate "Support for timberdale UART"
+       select SERIAL_CORE
+       ---help---
+       Add support for UART controller on timberdale.
+
+config SERIAL_BCM63XX
+       tristate "bcm63xx serial port support"
+       select SERIAL_CORE
+       depends on BCM63XX
+       help
+         If you have a bcm63xx CPU, you can enable its onboard
+         serial port by enabling this options.
+
+          To compile this driver as a module, choose M here: the
+          module will be called bcm963xx_uart.
+
+config SERIAL_BCM63XX_CONSOLE
+       bool "Console on bcm63xx serial port"
+       depends on SERIAL_BCM63XX=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the serial port on the bcm63xx CPU
+         you can make it the console by answering Y to this option.
+
+config SERIAL_GRLIB_GAISLER_APBUART
+       tristate "GRLIB APBUART serial support"
+       depends on OF
+       select SERIAL_CORE
+       ---help---
+       Add support for the GRLIB APBUART serial port.
+
+config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+       bool "Console on GRLIB APBUART serial port"
+       depends on SERIAL_GRLIB_GAISLER_APBUART=y
+       select SERIAL_CORE_CONSOLE
+       help
+       Support for running a console on the GRLIB APBUART
+
+config SERIAL_ALTERA_JTAGUART
+       tristate "Altera JTAG UART support"
+       select SERIAL_CORE
+       help
+         This driver supports the Altera JTAG UART port.
+
+config SERIAL_ALTERA_JTAGUART_CONSOLE
+       bool "Altera JTAG UART console support"
+       depends on SERIAL_ALTERA_JTAGUART=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a Altera JTAG UART port to be the system console.
+
+config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
+       bool "Bypass output when no connection"
+       depends on SERIAL_ALTERA_JTAGUART_CONSOLE
+       select SERIAL_CORE_CONSOLE
+       help
+         Bypass console output and keep going even if there is no
+         JTAG terminal connection with the host.
+
+config SERIAL_ALTERA_UART
+       tristate "Altera UART support"
+       select SERIAL_CORE
+       help
+         This driver supports the Altera softcore UART port.
+
+config SERIAL_ALTERA_UART_MAXPORTS
+       int "Maximum number of Altera UART ports"
+       depends on SERIAL_ALTERA_UART
+       default 4
+       help
+         This setting lets you define the maximum number of the Altera
+         UART ports. The usual default varies from board to board, and
+         this setting is a way of catering for that.
+
+config SERIAL_ALTERA_UART_BAUDRATE
+       int "Default baudrate for Altera UART ports"
+       depends on SERIAL_ALTERA_UART
+       default 115200
+       help
+         This setting lets you define what the default baudrate is for the
+         Altera UART ports. The usual default varies from board to board,
+         and this setting is a way of catering for that.
+
+config SERIAL_ALTERA_UART_CONSOLE
+       bool "Altera UART console support"
+       depends on SERIAL_ALTERA_UART=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a Altera UART port to be the system console.
+
+config SERIAL_IFX6X60
+        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
+       depends on GPIOLIB && SPI && EXPERIMENTAL
+       help
+         Support for the IFX6x60 modem devices on Intel MID platforms.
+
+config SERIAL_PCH_UART
+       tristate "Intel EG20T PCH UART"
+       depends on PCI && DMADEVICES
+       select SERIAL_CORE
+       select PCH_DMA
+       help
+         This driver is for PCH(Platform controller Hub) UART of Intel EG20T
+         which is an IOH(Input/Output Hub) for x86 embedded processor.
+         Enabling PCH_DMA, this PCH UART works as DMA mode.
+endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
new file mode 100644 (file)
index 0000000..8ea92e9
--- /dev/null
@@ -0,0 +1,94 @@
+#
+# Makefile for the kernel serial device drivers.
+#
+
+obj-$(CONFIG_SERIAL_CORE) += serial_core.o
+obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
+obj-$(CONFIG_SERIAL_8250) += 8250.o
+obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
+obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
+obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
+obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
+obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
+obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
+obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
+obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
+obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
+obj-$(CONFIG_SERIAL_PXA) += pxa.o
+obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
+obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
+obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
+obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
+obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
+obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
+obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
+obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
+obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
+obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
+obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
+obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
+obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
+obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
+obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
+obj-$(CONFIG_SERIAL_MUX) += mux.o
+obj-$(CONFIG_SERIAL_68328) += 68328serial.o
+obj-$(CONFIG_SERIAL_68360) += 68360serial.o
+obj-$(CONFIG_SERIAL_MCF) += mcf.o
+obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
+obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
+obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
+obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
+obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
+obj-$(CONFIG_SERIAL_IMX) += imx.o
+obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
+obj-$(CONFIG_SERIAL_ICOM) += icom.o
+obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
+obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
+obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
+obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
+obj-$(CONFIG_SERIAL_JSM) += jsm/
+obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
+obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
+obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
+obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
+obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
+obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
+obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
+obj-$(CONFIG_SERIAL_TIMBERDALE)        += timbuart.o
+obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
+obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
+obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
+obj-$(CONFIG_SERIAL_MRST_MAX3110)      += mrst_max3110.o
+obj-$(CONFIG_SERIAL_MFD_HSU)   += mfd.o
+obj-$(CONFIG_SERIAL_IFX6X60)   += ifx6x60.o
+obj-$(CONFIG_SERIAL_PCH_UART)  += pch_uart.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
new file mode 100644 (file)
index 0000000..f9b49b5
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * altera_jtaguart.c -- Altera JTAG UART driver
+ *
+ * Based on mcf.c -- Freescale ColdFire UART driver
+ *
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
+ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/altera_jtaguart.h>
+
+#define DRV_NAME "altera_jtaguart"
+
+/*
+ * Altera JTAG UART register definitions according to the Altera JTAG UART
+ * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
+ */
+
+#define ALTERA_JTAGUART_SIZE                   8
+
+#define ALTERA_JTAGUART_DATA_REG               0
+
+#define ALTERA_JTAGUART_DATA_DATA_MSK          0x000000FF
+#define ALTERA_JTAGUART_DATA_RVALID_MSK                0x00008000
+#define ALTERA_JTAGUART_DATA_RAVAIL_MSK                0xFFFF0000
+#define ALTERA_JTAGUART_DATA_RAVAIL_OFF                16
+
+#define ALTERA_JTAGUART_CONTROL_REG            4
+
+#define ALTERA_JTAGUART_CONTROL_RE_MSK         0x00000001
+#define ALTERA_JTAGUART_CONTROL_WE_MSK         0x00000002
+#define ALTERA_JTAGUART_CONTROL_RI_MSK         0x00000100
+#define ALTERA_JTAGUART_CONTROL_RI_OFF         8
+#define ALTERA_JTAGUART_CONTROL_WI_MSK         0x00000200
+#define ALTERA_JTAGUART_CONTROL_AC_MSK         0x00000400
+#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK     0xFFFF0000
+#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF     16
+
+/*
+ * Local per-uart structure.
+ */
+struct altera_jtaguart {
+       struct uart_port port;
+       unsigned int sigs;      /* Local copy of line sigs */
+       unsigned long imr;      /* Local IMR mirror */
+};
+
+static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
+{
+       return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+}
+
+static void altera_jtaguart_start_tx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_stop_tx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_stop_rx(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+
+       pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void altera_jtaguart_enable_ms(struct uart_port *port)
+{
+}
+
+static void altera_jtaguart_set_termios(struct uart_port *port,
+                                       struct ktermios *termios,
+                                       struct ktermios *old)
+{
+       /* Just copy the old termios settings back */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+}
+
+static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char ch, flag;
+       unsigned long status;
+
+       while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
+              ALTERA_JTAGUART_DATA_RVALID_MSK) {
+               ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, 0, 0, ch, flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int pending, count;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       pending = uart_circ_chars_pending(xmit);
+       if (pending > 0) {
+               count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+                               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
+                       ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
+               if (count > pending)
+                       count = pending;
+               if (count > 0) {
+                       pending -= count;
+                       while (count--) {
+                               writel(xmit->buf[xmit->tail],
+                                      port->membase + ALTERA_JTAGUART_DATA_REG);
+                               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                               port->icount.tx++;
+                       }
+                       if (pending < WAKEUP_CHARS)
+                               uart_write_wakeup(port);
+               }
+       }
+
+       if (pending == 0) {
+               pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
+               writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+       }
+}
+
+static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned int isr;
+
+       isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
+              ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
+
+       spin_lock(&port->lock);
+
+       if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
+               altera_jtaguart_rx_chars(pp);
+       if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
+               altera_jtaguart_tx_chars(pp);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_RETVAL(isr);
+}
+
+static void altera_jtaguart_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ALTERA_JTAGUART;
+
+       /* Clear mask, so no surprise interrupts. */
+       writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+static int altera_jtaguart_startup(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned long flags;
+       int ret;
+
+       ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
+                       DRV_NAME, port);
+       if (ret) {
+               pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
+                      "interrupt vector=%d\n", port->line, port->irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Enable RX interrupts now */
+       pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+static void altera_jtaguart_shutdown(struct uart_port *port)
+{
+       struct altera_jtaguart *pp =
+           container_of(port, struct altera_jtaguart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       free_irq(port->irq, port);
+}
+
+static const char *altera_jtaguart_type(struct uart_port *port)
+{
+       return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
+}
+
+static int altera_jtaguart_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+static void altera_jtaguart_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+static int altera_jtaguart_verify_port(struct uart_port *port,
+                                      struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
+               return -EINVAL;
+       return 0;
+}
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static struct uart_ops altera_jtaguart_ops = {
+       .tx_empty       = altera_jtaguart_tx_empty,
+       .get_mctrl      = altera_jtaguart_get_mctrl,
+       .set_mctrl      = altera_jtaguart_set_mctrl,
+       .start_tx       = altera_jtaguart_start_tx,
+       .stop_tx        = altera_jtaguart_stop_tx,
+       .stop_rx        = altera_jtaguart_stop_rx,
+       .enable_ms      = altera_jtaguart_enable_ms,
+       .break_ctl      = altera_jtaguart_break_ctl,
+       .startup        = altera_jtaguart_startup,
+       .shutdown       = altera_jtaguart_shutdown,
+       .set_termios    = altera_jtaguart_set_termios,
+       .type           = altera_jtaguart_type,
+       .request_port   = altera_jtaguart_request_port,
+       .release_port   = altera_jtaguart_release_port,
+       .config_port    = altera_jtaguart_config_port,
+       .verify_port    = altera_jtaguart_verify_port,
+};
+
+#define ALTERA_JTAGUART_MAXPORTS 1
+static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
+
+int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
+                                      *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_jtaguart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_JTAGUART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+               port->ops = &altera_jtaguart_ops;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
+static void altera_jtaguart_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+       unsigned long status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
+               if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       return; /* no connection activity */
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               cpu_relax();
+               spin_lock_irqsave(&port->lock, flags);
+       }
+       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+#else
+static void altera_jtaguart_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               cpu_relax();
+               spin_lock_irqsave(&port->lock, flags);
+       }
+       writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+#endif
+
+static void altera_jtaguart_console_write(struct console *co, const char *s,
+                                         unsigned int count)
+{
+       for (; count; count--, s++) {
+               altera_jtaguart_console_putc(co, *s);
+               if (*s == '\n')
+                       altera_jtaguart_console_putc(co, '\r');
+       }
+}
+
+static int __init altera_jtaguart_console_setup(struct console *co,
+                                               char *options)
+{
+       struct uart_port *port;
+
+       if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
+               return -EINVAL;
+       port = &altera_jtaguart_ports[co->index].port;
+       if (port->membase == 0)
+               return -ENODEV;
+       return 0;
+}
+
+static struct uart_driver altera_jtaguart_driver;
+
+static struct console altera_jtaguart_console = {
+       .name   = "ttyJ",
+       .write  = altera_jtaguart_console_write,
+       .device = uart_console_device,
+       .setup  = altera_jtaguart_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &altera_jtaguart_driver,
+};
+
+static int __init altera_jtaguart_console_init(void)
+{
+       register_console(&altera_jtaguart_console);
+       return 0;
+}
+
+console_initcall(altera_jtaguart_console_init);
+
+#define        ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
+
+#else
+
+#define        ALTERA_JTAGUART_CONSOLE NULL
+
+#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
+
+static struct uart_driver altera_jtaguart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "altera_jtaguart",
+       .dev_name       = "ttyJ",
+       .major          = ALTERA_JTAGUART_MAJOR,
+       .minor          = ALTERA_JTAGUART_MINOR,
+       .nr             = ALTERA_JTAGUART_MAXPORTS,
+       .cons           = ALTERA_JTAGUART_CONSOLE,
+};
+
+static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
+{
+       struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_jtaguart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_JTAGUART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->ops = &altera_jtaguart_ops;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+
+               uart_add_one_port(&altera_jtaguart_driver, port);
+       }
+
+       return 0;
+}
+
+static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
+               port = &altera_jtaguart_ports[i].port;
+               if (port)
+                       uart_remove_one_port(&altera_jtaguart_driver, port);
+       }
+
+       return 0;
+}
+
+static struct platform_driver altera_jtaguart_platform_driver = {
+       .probe  = altera_jtaguart_probe,
+       .remove = __devexit_p(altera_jtaguart_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init altera_jtaguart_init(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&altera_jtaguart_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&altera_jtaguart_platform_driver);
+       if (rc) {
+               uart_unregister_driver(&altera_jtaguart_driver);
+               return rc;
+       }
+       return 0;
+}
+
+static void __exit altera_jtaguart_exit(void)
+{
+       platform_driver_unregister(&altera_jtaguart_platform_driver);
+       uart_unregister_driver(&altera_jtaguart_driver);
+}
+
+module_init(altera_jtaguart_init);
+module_exit(altera_jtaguart_exit);
+
+MODULE_DESCRIPTION("Altera JTAG UART driver");
+MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
new file mode 100644 (file)
index 0000000..7212162
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * altera_uart.c -- Altera UART driver
+ *
+ * Based on mcf.c -- Freescale ColdFire UART driver
+ *
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
+ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/altera_uart.h>
+
+#define DRV_NAME "altera_uart"
+#define SERIAL_ALTERA_MAJOR 204
+#define SERIAL_ALTERA_MINOR 213
+
+/*
+ * Altera UART register definitions according to the Nios UART datasheet:
+ * http://www.altera.com/literature/ds/ds_nios_uart.pdf
+ */
+
+#define ALTERA_UART_SIZE               32
+
+#define ALTERA_UART_RXDATA_REG         0
+#define ALTERA_UART_TXDATA_REG         4
+#define ALTERA_UART_STATUS_REG         8
+#define ALTERA_UART_CONTROL_REG                12
+#define ALTERA_UART_DIVISOR_REG                16
+#define ALTERA_UART_EOP_REG            20
+
+#define ALTERA_UART_STATUS_PE_MSK      0x0001  /* parity error */
+#define ALTERA_UART_STATUS_FE_MSK      0x0002  /* framing error */
+#define ALTERA_UART_STATUS_BRK_MSK     0x0004  /* break */
+#define ALTERA_UART_STATUS_ROE_MSK     0x0008  /* RX overrun error */
+#define ALTERA_UART_STATUS_TOE_MSK     0x0010  /* TX overrun error */
+#define ALTERA_UART_STATUS_TMT_MSK     0x0020  /* TX shift register state */
+#define ALTERA_UART_STATUS_TRDY_MSK    0x0040  /* TX ready */
+#define ALTERA_UART_STATUS_RRDY_MSK    0x0080  /* RX ready */
+#define ALTERA_UART_STATUS_E_MSK       0x0100  /* exception condition */
+#define ALTERA_UART_STATUS_DCTS_MSK    0x0400  /* CTS logic-level change */
+#define ALTERA_UART_STATUS_CTS_MSK     0x0800  /* CTS logic state */
+#define ALTERA_UART_STATUS_EOP_MSK     0x1000  /* EOP written/read */
+
+                                               /* Enable interrupt on... */
+#define ALTERA_UART_CONTROL_PE_MSK     0x0001  /* ...parity error */
+#define ALTERA_UART_CONTROL_FE_MSK     0x0002  /* ...framing error */
+#define ALTERA_UART_CONTROL_BRK_MSK    0x0004  /* ...break */
+#define ALTERA_UART_CONTROL_ROE_MSK    0x0008  /* ...RX overrun */
+#define ALTERA_UART_CONTROL_TOE_MSK    0x0010  /* ...TX overrun */
+#define ALTERA_UART_CONTROL_TMT_MSK    0x0020  /* ...TX shift register empty */
+#define ALTERA_UART_CONTROL_TRDY_MSK   0x0040  /* ...TX ready */
+#define ALTERA_UART_CONTROL_RRDY_MSK   0x0080  /* ...RX ready */
+#define ALTERA_UART_CONTROL_E_MSK      0x0100  /* ...exception*/
+
+#define ALTERA_UART_CONTROL_TRBK_MSK   0x0200  /* TX break */
+#define ALTERA_UART_CONTROL_DCTS_MSK   0x0400  /* Interrupt on CTS change */
+#define ALTERA_UART_CONTROL_RTS_MSK    0x0800  /* RTS signal */
+#define ALTERA_UART_CONTROL_EOP_MSK    0x1000  /* Interrupt on EOP */
+
+/*
+ * Local per-uart structure.
+ */
+struct altera_uart {
+       struct uart_port port;
+       struct timer_list tmr;
+       unsigned int sigs;      /* Local copy of line sigs */
+       unsigned short imr;     /* Local IMR mirror */
+};
+
+static u32 altera_uart_readl(struct uart_port *port, int reg)
+{
+       struct altera_uart_platform_uart *platp = port->private_data;
+
+       return readl(port->membase + (reg << platp->bus_shift));
+}
+
+static void altera_uart_writel(struct uart_port *port, u32 dat, int reg)
+{
+       struct altera_uart_platform_uart *platp = port->private_data;
+
+       writel(dat, port->membase + (reg << platp->bus_shift));
+}
+
+static unsigned int altera_uart_tx_empty(struct uart_port *port)
+{
+       return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+               ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int altera_uart_get_mctrl(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned int sigs;
+
+       sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+            ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
+       sigs |= (pp->sigs & TIOCM_RTS);
+
+       return sigs;
+}
+
+static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->sigs = sigs;
+       if (sigs & TIOCM_RTS)
+               pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
+       else
+               pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_start_tx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_stop_tx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_stop_rx(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+}
+
+static void altera_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
+       else
+               pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
+       altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void altera_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void altera_uart_set_termios(struct uart_port *port,
+                                   struct ktermios *termios,
+                                   struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, baudclk;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       baudclk = port->uartclk / baud;
+
+       if (old)
+               tty_termios_copy_hw(termios, old);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void altera_uart_rx_chars(struct altera_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char ch, flag;
+       unsigned short status;
+
+       while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) &
+              ALTERA_UART_STATUS_RRDY_MSK) {
+               ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (status & ALTERA_UART_STATUS_E_MSK) {
+                       altera_uart_writel(port, status,
+                                          ALTERA_UART_STATUS_REG);
+
+                       if (status & ALTERA_UART_STATUS_BRK_MSK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & ALTERA_UART_STATUS_PE_MSK) {
+                               port->icount.parity++;
+                       } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
+                               port->icount.overrun++;
+                       } else if (status & ALTERA_UART_STATUS_FE_MSK) {
+                               port->icount.frame++;
+                       }
+
+                       status &= port->read_status_mask;
+
+                       if (status & ALTERA_UART_STATUS_BRK_MSK)
+                               flag = TTY_BREAK;
+                       else if (status & ALTERA_UART_STATUS_PE_MSK)
+                               flag = TTY_PARITY;
+                       else if (status & ALTERA_UART_STATUS_FE_MSK)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
+                                flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+static void altera_uart_tx_chars(struct altera_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+              ALTERA_UART_STATUS_TRDY_MSK) {
+               if (xmit->head == xmit->tail)
+                       break;
+               altera_uart_writel(port, xmit->buf[xmit->tail],
+                      ALTERA_UART_TXDATA_REG);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (xmit->head == xmit->tail) {
+               pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
+               altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+       }
+}
+
+static irqreturn_t altera_uart_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned int isr;
+
+       isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
+
+       spin_lock(&port->lock);
+       if (isr & ALTERA_UART_STATUS_RRDY_MSK)
+               altera_uart_rx_chars(pp);
+       if (isr & ALTERA_UART_STATUS_TRDY_MSK)
+               altera_uart_tx_chars(pp);
+       spin_unlock(&port->lock);
+
+       return IRQ_RETVAL(isr);
+}
+
+static void altera_uart_timer(unsigned long data)
+{
+       struct uart_port *port = (void *)data;
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+
+       altera_uart_interrupt(0, port);
+       mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
+}
+
+static void altera_uart_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ALTERA_UART;
+
+       /* Clear mask, so no surprise interrupts. */
+       altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG);
+       /* Clear status register */
+       altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG);
+}
+
+static int altera_uart_startup(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+       int ret;
+
+       if (!port->irq) {
+               setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port);
+               mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
+               return 0;
+       }
+
+       ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
+                       DRV_NAME, port);
+       if (ret) {
+               pr_err(DRV_NAME ": unable to attach Altera UART %d "
+                      "interrupt vector=%d\n", port->line, port->irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Enable RX interrupts now */
+       pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
+       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+static void altera_uart_shutdown(struct uart_port *port)
+{
+       struct altera_uart *pp = container_of(port, struct altera_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (port->irq)
+               free_irq(port->irq, port);
+       else
+               del_timer_sync(&pp->tmr);
+}
+
+static const char *altera_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
+}
+
+static int altera_uart_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+static void altera_uart_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+static int altera_uart_verify_port(struct uart_port *port,
+                                  struct serial_struct *ser)
+{
+       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
+               return -EINVAL;
+       return 0;
+}
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static struct uart_ops altera_uart_ops = {
+       .tx_empty       = altera_uart_tx_empty,
+       .get_mctrl      = altera_uart_get_mctrl,
+       .set_mctrl      = altera_uart_set_mctrl,
+       .start_tx       = altera_uart_start_tx,
+       .stop_tx        = altera_uart_stop_tx,
+       .stop_rx        = altera_uart_stop_rx,
+       .enable_ms      = altera_uart_enable_ms,
+       .break_ctl      = altera_uart_break_ctl,
+       .startup        = altera_uart_startup,
+       .shutdown       = altera_uart_shutdown,
+       .set_termios    = altera_uart_set_termios,
+       .type           = altera_uart_type,
+       .request_port   = altera_uart_request_port,
+       .release_port   = altera_uart_release_port,
+       .config_port    = altera_uart_config_port,
+       .verify_port    = altera_uart_verify_port,
+};
+
+static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
+
+#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
+
+int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
+               port = &altera_uart_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_ALTERA_UART;
+               port->mapbase = platp[i].mapbase;
+               port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = platp[i].uartclk;
+               port->flags = UPF_BOOT_AUTOCONF;
+               port->ops = &altera_uart_ops;
+               port->private_data = platp;
+       }
+
+       return 0;
+}
+
+static void altera_uart_console_putc(struct uart_port *port, const char c)
+{
+       while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+                ALTERA_UART_STATUS_TRDY_MSK))
+               cpu_relax();
+
+       writel(c, port->membase + ALTERA_UART_TXDATA_REG);
+}
+
+static void altera_uart_console_write(struct console *co, const char *s,
+                                     unsigned int count)
+{
+       struct uart_port *port = &(altera_uart_ports + co->index)->port;
+
+       for (; count; count--, s++) {
+               altera_uart_console_putc(port, *s);
+               if (*s == '\n')
+                       altera_uart_console_putc(port, '\r');
+       }
+}
+
+static int __init altera_uart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
+               return -EINVAL;
+       port = &altera_uart_ports[co->index].port;
+       if (!port->membase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver altera_uart_driver;
+
+static struct console altera_uart_console = {
+       .name   = "ttyAL",
+       .write  = altera_uart_console_write,
+       .device = uart_console_device,
+       .setup  = altera_uart_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &altera_uart_driver,
+};
+
+static int __init altera_uart_console_init(void)
+{
+       register_console(&altera_uart_console);
+       return 0;
+}
+
+console_initcall(altera_uart_console_init);
+
+#define        ALTERA_UART_CONSOLE     (&altera_uart_console)
+
+#else
+
+#define        ALTERA_UART_CONSOLE     NULL
+
+#endif /* CONFIG_ALTERA_UART_CONSOLE */
+
+/*
+ *     Define the altera_uart UART driver structure.
+ */
+static struct uart_driver altera_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRV_NAME,
+       .dev_name       = "ttyAL",
+       .major          = SERIAL_ALTERA_MAJOR,
+       .minor          = SERIAL_ALTERA_MINOR,
+       .nr             = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
+       .cons           = ALTERA_UART_CONSOLE,
+};
+
+static int __devinit altera_uart_probe(struct platform_device *pdev)
+{
+       struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       struct resource *res_mem;
+       struct resource *res_irq;
+       int i = pdev->id;
+
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+               i = 0;
+
+       if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
+               return -EINVAL;
+
+       port = &altera_uart_ports[i].port;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem)
+               port->mapbase = res_mem->start;
+       else if (platp->mapbase)
+               port->mapbase = platp->mapbase;
+       else
+               return -EINVAL;
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res_irq)
+               port->irq = res_irq->start;
+       else if (platp->irq)
+               port->irq = platp->irq;
+
+       port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
+       if (!port->membase)
+               return -ENOMEM;
+
+       port->line = i;
+       port->type = PORT_ALTERA_UART;
+       port->iotype = SERIAL_IO_MEM;
+       port->uartclk = platp->uartclk;
+       port->ops = &altera_uart_ops;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->private_data = platp;
+
+       uart_add_one_port(&altera_uart_driver, port);
+
+       return 0;
+}
+
+static int __devexit altera_uart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = &altera_uart_ports[pdev->id].port;
+
+       uart_remove_one_port(&altera_uart_driver, port);
+       return 0;
+}
+
+static struct platform_driver altera_uart_platform_driver = {
+       .probe  = altera_uart_probe,
+       .remove = __devexit_p(altera_uart_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = NULL,
+       },
+};
+
+static int __init altera_uart_init(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&altera_uart_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&altera_uart_platform_driver);
+       if (rc) {
+               uart_unregister_driver(&altera_uart_driver);
+               return rc;
+       }
+       return 0;
+}
+
+static void __exit altera_uart_exit(void)
+{
+       platform_driver_unregister(&altera_uart_platform_driver);
+       uart_unregister_driver(&altera_uart_driver);
+}
+
+module_init(altera_uart_init);
+module_exit(altera_uart_exit);
+
+MODULE_DESCRIPTION("Altera UART driver");
+MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
new file mode 100644 (file)
index 0000000..2904aa0
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ *  linux/drivers/char/amba.c
+ *
+ *  Driver for AMBA serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This is a generic driver for ARM AMBA-type serial ports.  They
+ * have a lot of 16550-like features, but are not register compatible.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs.  If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ */
+
+#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+#define UART_NR                8
+
+#define SERIAL_AMBA_MAJOR      204
+#define SERIAL_AMBA_MINOR      16
+#define SERIAL_AMBA_NR         UART_NR
+
+#define AMBA_ISR_PASS_LIMIT    256
+
+#define UART_RX_DATA(s)                (((s) & UART01x_FR_RXFE) == 0)
+#define UART_TX_READY(s)       (((s) & UART01x_FR_TXFF) == 0)
+
+#define UART_DUMMY_RSR_RX      256
+#define UART_PORT_SIZE         64
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+       struct uart_port        port;
+       struct clk              *clk;
+       struct amba_device      *dev;
+       struct amba_pl010_data  *data;
+       unsigned int            old_status;
+};
+
+static void pl010_stop_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr &= ~UART010_CR_TIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_start_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr |= UART010_CR_TIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_stop_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_enable_ms(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr |= UART010_CR_MSIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
+static void pl010_rx_chars(struct uart_amba_port *uap)
+{
+       struct tty_struct *tty = uap->port.state->port.tty;
+       unsigned int status, ch, flag, rsr, max_count = 256;
+
+       status = readb(uap->port.membase + UART01x_FR);
+       while (UART_RX_DATA(status) && max_count--) {
+               ch = readb(uap->port.membase + UART01x_DR);
+               flag = TTY_NORMAL;
+
+               uap->port.icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
+               if (unlikely(rsr & UART01x_RSR_ANY)) {
+                       writel(0, uap->port.membase + UART01x_ECR);
+
+                       if (rsr & UART01x_RSR_BE) {
+                               rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto ignore_char;
+                       } else if (rsr & UART01x_RSR_PE)
+                               uap->port.icount.parity++;
+                       else if (rsr & UART01x_RSR_FE)
+                               uap->port.icount.frame++;
+                       if (rsr & UART01x_RSR_OE)
+                               uap->port.icount.overrun++;
+
+                       rsr &= uap->port.read_status_mask;
+
+                       if (rsr & UART01x_RSR_BE)
+                               flag = TTY_BREAK;
+                       else if (rsr & UART01x_RSR_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & UART01x_RSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&uap->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
+
+       ignore_char:
+               status = readb(uap->port.membase + UART01x_FR);
+       }
+       spin_unlock(&uap->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&uap->port.lock);
+}
+
+static void pl010_tx_chars(struct uart_amba_port *uap)
+{
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       int count;
+
+       if (uap->port.x_char) {
+               writel(uap->port.x_char, uap->port.membase + UART01x_DR);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+               pl010_stop_tx(&uap->port);
+               return;
+       }
+
+       count = uap->port.fifosize >> 1;
+       do {
+               writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uap->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       if (uart_circ_empty(xmit))
+               pl010_stop_tx(&uap->port);
+}
+
+static void pl010_modem_status(struct uart_amba_port *uap)
+{
+       unsigned int status, delta;
+
+       writel(0, uap->port.membase + UART010_ICR);
+
+       status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       delta = status ^ uap->old_status;
+       uap->old_status = status;
+
+       if (!delta)
+               return;
+
+       if (delta & UART01x_FR_DCD)
+               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+
+       if (delta & UART01x_FR_DSR)
+               uap->port.icount.dsr++;
+
+       if (delta & UART01x_FR_CTS)
+               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+
+       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t pl010_int(int irq, void *dev_id)
+{
+       struct uart_amba_port *uap = dev_id;
+       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+       int handled = 0;
+
+       spin_lock(&uap->port.lock);
+
+       status = readb(uap->port.membase + UART010_IIR);
+       if (status) {
+               do {
+                       if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
+                               pl010_rx_chars(uap);
+                       if (status & UART010_IIR_MIS)
+                               pl010_modem_status(uap);
+                       if (status & UART010_IIR_TIS)
+                               pl010_tx_chars(uap);
+
+                       if (pass_counter-- == 0)
+                               break;
+
+                       status = readb(uap->port.membase + UART010_IIR);
+               } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
+                                  UART010_IIR_TIS));
+               handled = 1;
+       }
+
+       spin_unlock(&uap->port.lock);
+
+       return IRQ_RETVAL(handled);
+}
+
+static unsigned int pl010_tx_empty(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status = readb(uap->port.membase + UART01x_FR);
+       return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pl010_get_mctrl(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int result = 0;
+       unsigned int status;
+
+       status = readb(uap->port.membase + UART01x_FR);
+       if (status & UART01x_FR_DCD)
+               result |= TIOCM_CAR;
+       if (status & UART01x_FR_DSR)
+               result |= TIOCM_DSR;
+       if (status & UART01x_FR_CTS)
+               result |= TIOCM_CTS;
+
+       return result;
+}
+
+static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (uap->data)
+               uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
+}
+
+static void pl010_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned long flags;
+       unsigned int lcr_h;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       lcr_h = readb(uap->port.membase + UART010_LCRH);
+       if (break_state == -1)
+               lcr_h |= UART01x_LCRH_BRK;
+       else
+               lcr_h &= ~UART01x_LCRH_BRK;
+       writel(lcr_h, uap->port.membase + UART010_LCRH);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static int pl010_startup(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       int retval;
+
+       /*
+        * Try to enable the clock producer.
+        */
+       retval = clk_enable(uap->clk);
+       if (retval)
+               goto out;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
+       if (retval)
+               goto clk_dis;
+
+       /*
+        * initialise the old status of the modem signals
+        */
+       uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       /*
+        * Finally, enable interrupts
+        */
+       writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
+              uap->port.membase + UART010_CR);
+
+       return 0;
+
+ clk_dis:
+       clk_disable(uap->clk);
+ out:
+       return retval;
+}
+
+static void pl010_shutdown(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(uap->port.irq, uap);
+
+       /*
+        * disable all interrupts, disable the port
+        */
+       writel(0, uap->port.membase + UART010_CR);
+
+       /* disable break condition and fifos */
+       writel(readb(uap->port.membase + UART010_LCRH) &
+               ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
+              uap->port.membase + UART010_LCRH);
+
+       /*
+        * Shut down the clock producer
+        */
+       clk_disable(uap->clk);
+}
+
+static void
+pl010_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int lcr_h, old_cr;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr_h = UART01x_LCRH_WLEN_5;
+               break;
+       case CS6:
+               lcr_h = UART01x_LCRH_WLEN_6;
+               break;
+       case CS7:
+               lcr_h = UART01x_LCRH_WLEN_7;
+               break;
+       default: // CS8
+               lcr_h = UART01x_LCRH_WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               lcr_h |= UART01x_LCRH_STP2;
+       if (termios->c_cflag & PARENB) {
+               lcr_h |= UART01x_LCRH_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_h |= UART01x_LCRH_EPS;
+       }
+       if (uap->port.fifosize > 1)
+               lcr_h |= UART01x_LCRH_FEN;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       uap->port.read_status_mask = UART01x_RSR_OE;
+       if (termios->c_iflag & INPCK)
+               uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uap->port.read_status_mask |= UART01x_RSR_BE;
+
+       /*
+        * Characters to ignore
+        */
+       uap->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               uap->port.ignore_status_mask |= UART01x_RSR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       uap->port.ignore_status_mask |= UART01x_RSR_OE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+       /* first, disable everything */
+       old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
+
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               old_cr |= UART010_CR_MSIE;
+
+       writel(0, uap->port.membase + UART010_CR);
+
+       /* Set baud rate */
+       quot -= 1;
+       writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
+       writel(quot & 0xff, uap->port.membase + UART010_LCRL);
+
+       /*
+        * ----------v----------v----------v----------v-----
+        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+        * ----------^----------^----------^----------^-----
+        */
+       writel(lcr_h, uap->port.membase + UART010_LCRH);
+       writel(old_cr, uap->port.membase + UART010_CR);
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl010_set_ldisc(struct uart_port *port, int new)
+{
+       if (new == N_PPS) {
+               port->flags |= UPF_HARDPPS_CD;
+               pl010_enable_ms(port);
+       } else
+               port->flags &= ~UPF_HARDPPS_CD;
+}
+
+static const char *pl010_type(struct uart_port *port)
+{
+       return port->type == PORT_AMBA ? "AMBA" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void pl010_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int pl010_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")
+                       != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pl010_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_AMBA;
+               pl010_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops amba_pl010_pops = {
+       .tx_empty       = pl010_tx_empty,
+       .set_mctrl      = pl010_set_mctrl,
+       .get_mctrl      = pl010_get_mctrl,
+       .stop_tx        = pl010_stop_tx,
+       .start_tx       = pl010_start_tx,
+       .stop_rx        = pl010_stop_rx,
+       .enable_ms      = pl010_enable_ms,
+       .break_ctl      = pl010_break_ctl,
+       .startup        = pl010_startup,
+       .shutdown       = pl010_shutdown,
+       .set_termios    = pl010_set_termios,
+       .set_ldisc      = pl010_set_ldisc,
+       .type           = pl010_type,
+       .release_port   = pl010_release_port,
+       .request_port   = pl010_request_port,
+       .config_port    = pl010_config_port,
+       .verify_port    = pl010_verify_port,
+};
+
+static struct uart_amba_port *amba_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
+
+static void pl010_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status;
+
+       do {
+               status = readb(uap->port.membase + UART01x_FR);
+               barrier();
+       } while (!UART_TX_READY(status));
+       writel(ch, uap->port.membase + UART01x_DR);
+}
+
+static void
+pl010_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_amba_port *uap = amba_ports[co->index];
+       unsigned int status, old_cr;
+
+       clk_enable(uap->clk);
+
+       /*
+        *      First save the CR then disable the interrupts
+        */
+       old_cr = readb(uap->port.membase + UART010_CR);
+       writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
+
+       uart_console_write(&uap->port, s, count, pl010_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = readb(uap->port.membase + UART01x_FR);
+               barrier();
+       } while (status & UART01x_FR_BUSY);
+       writel(old_cr, uap->port.membase + UART010_CR);
+
+       clk_disable(uap->clk);
+}
+
+static void __init
+pl010_console_get_options(struct uart_amba_port *uap, int *baud,
+                            int *parity, int *bits)
+{
+       if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
+               unsigned int lcr_h, quot;
+               lcr_h = readb(uap->port.membase + UART010_LCRH);
+
+               *parity = 'n';
+               if (lcr_h & UART01x_LCRH_PEN) {
+                       if (lcr_h & UART01x_LCRH_EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               quot = readb(uap->port.membase + UART010_LCRL) |
+                      readb(uap->port.membase + UART010_LCRM) << 8;
+               *baud = uap->port.uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init pl010_console_setup(struct console *co, char *options)
+{
+       struct uart_amba_port *uap;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       uap = amba_ports[co->index];
+       if (!uap)
+               return -ENODEV;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               pl010_console_get_options(uap, &baud, &parity, &bits);
+
+       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver amba_reg;
+static struct console amba_console = {
+       .name           = "ttyAM",
+       .write          = pl010_console_write,
+       .device         = uart_console_device,
+       .setup          = pl010_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &amba_reg,
+};
+
+#define AMBA_CONSOLE   &amba_console
+#else
+#define AMBA_CONSOLE   NULL
+#endif
+
+static struct uart_driver amba_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAM",
+       .dev_name               = "ttyAM",
+       .major                  = SERIAL_AMBA_MAJOR,
+       .minor                  = SERIAL_AMBA_MINOR,
+       .nr                     = UART_NR,
+       .cons                   = AMBA_CONSOLE,
+};
+
+static int pl010_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct uart_amba_port *uap;
+       void __iomem *base;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == NULL)
+                       break;
+
+       if (i == ARRAY_SIZE(amba_ports)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       if (!uap) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       base = ioremap(dev->res.start, resource_size(&dev->res));
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       uap->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(uap->clk)) {
+               ret = PTR_ERR(uap->clk);
+               goto unmap;
+       }
+
+       uap->port.dev = &dev->dev;
+       uap->port.mapbase = dev->res.start;
+       uap->port.membase = base;
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = dev->irq[0];
+       uap->port.fifosize = 16;
+       uap->port.ops = &amba_pl010_pops;
+       uap->port.flags = UPF_BOOT_AUTOCONF;
+       uap->port.line = i;
+       uap->dev = dev;
+       uap->data = dev->dev.platform_data;
+
+       amba_ports[i] = uap;
+
+       amba_set_drvdata(dev, uap);
+       ret = uart_add_one_port(&amba_reg, &uap->port);
+       if (ret) {
+               amba_set_drvdata(dev, NULL);
+               amba_ports[i] = NULL;
+               clk_put(uap->clk);
+ unmap:
+               iounmap(base);
+ free:
+               kfree(uap);
+       }
+ out:
+       return ret;
+}
+
+static int pl010_remove(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       int i;
+
+       amba_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&amba_reg, &uap->port);
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == uap)
+                       amba_ports[i] = NULL;
+
+       iounmap(uap->port.membase);
+       clk_put(uap->clk);
+       kfree(uap);
+       return 0;
+}
+
+static int pl010_suspend(struct amba_device *dev, pm_message_t state)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (uap)
+               uart_suspend_port(&amba_reg, &uap->port);
+
+       return 0;
+}
+
+static int pl010_resume(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (uap)
+               uart_resume_port(&amba_reg, &uap->port);
+
+       return 0;
+}
+
+static struct amba_id pl010_ids[] = {
+       {
+               .id     = 0x00041010,
+               .mask   = 0x000fffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl010_driver = {
+       .drv = {
+               .name   = "uart-pl010",
+       },
+       .id_table       = pl010_ids,
+       .probe          = pl010_probe,
+       .remove         = pl010_remove,
+       .suspend        = pl010_suspend,
+       .resume         = pl010_resume,
+};
+
+static int __init pl010_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: AMBA driver\n");
+
+       ret = uart_register_driver(&amba_reg);
+       if (ret == 0) {
+               ret = amba_driver_register(&pl010_driver);
+               if (ret)
+                       uart_unregister_driver(&amba_reg);
+       }
+       return ret;
+}
+
+static void __exit pl010_exit(void)
+{
+       amba_driver_unregister(&pl010_driver);
+       uart_unregister_driver(&amba_reg);
+}
+
+module_init(pl010_init);
+module_exit(pl010_exit);
+
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("ARM AMBA serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
new file mode 100644 (file)
index 0000000..e76d7d0
--- /dev/null
@@ -0,0 +1,1519 @@
+/*
+ *  linux/drivers/char/amba.c
+ *
+ *  Driver for AMBA serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This is a generic driver for ARM AMBA-type serial ports.  They
+ * have a lot of 16550-like features, but are not register compatible.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs.  If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ */
+
+#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#define UART_NR                        14
+
+#define SERIAL_AMBA_MAJOR      204
+#define SERIAL_AMBA_MINOR      64
+#define SERIAL_AMBA_NR         UART_NR
+
+#define AMBA_ISR_PASS_LIMIT    256
+
+#define UART_DR_ERROR          (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
+#define UART_DUMMY_DR_RX       (1 << 16)
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+       unsigned int            ifls;
+       unsigned int            fifosize;
+       unsigned int            lcrh_tx;
+       unsigned int            lcrh_rx;
+       bool                    oversampling;
+       bool                    dma_threshold;
+};
+
+static struct vendor_data vendor_arm = {
+       .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+       .fifosize               = 16,
+       .lcrh_tx                = UART011_LCRH,
+       .lcrh_rx                = UART011_LCRH,
+       .oversampling           = false,
+       .dma_threshold          = false,
+};
+
+static struct vendor_data vendor_st = {
+       .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+       .fifosize               = 64,
+       .lcrh_tx                = ST_UART011_LCRH_TX,
+       .lcrh_rx                = ST_UART011_LCRH_RX,
+       .oversampling           = true,
+       .dma_threshold          = true,
+};
+
+/* Deals with DMA transactions */
+struct pl011_dmatx_data {
+       struct dma_chan         *chan;
+       struct scatterlist      sg;
+       char                    *buf;
+       bool                    queued;
+};
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+       struct uart_port        port;
+       struct clk              *clk;
+       const struct vendor_data *vendor;
+       unsigned int            dmacr;          /* dma control reg */
+       unsigned int            im;             /* interrupt mask */
+       unsigned int            old_status;
+       unsigned int            fifosize;       /* vendor-specific */
+       unsigned int            lcrh_tx;        /* vendor-specific */
+       unsigned int            lcrh_rx;        /* vendor-specific */
+       bool                    autorts;
+       char                    type[12];
+#ifdef CONFIG_DMA_ENGINE
+       /* DMA stuff */
+       bool                    using_dma;
+       struct pl011_dmatx_data dmatx;
+#endif
+};
+
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+
+#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+
+static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
+{
+       /* DMA is the sole user of the platform data right now */
+       struct amba_pl011_data *plat = uap->port.dev->platform_data;
+       struct dma_slave_config tx_conf = {
+               .dst_addr = uap->port.mapbase + UART01x_DR,
+               .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+               .direction = DMA_TO_DEVICE,
+               .dst_maxburst = uap->fifosize >> 1,
+       };
+       struct dma_chan *chan;
+       dma_cap_mask_t mask;
+
+       /* We need platform data */
+       if (!plat || !plat->dma_filter) {
+               dev_info(uap->port.dev, "no DMA platform data\n");
+               return;
+       }
+
+       /* Try to acquire a generic DMA engine slave channel */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
+       if (!chan) {
+               dev_err(uap->port.dev, "no TX DMA channel!\n");
+               return;
+       }
+
+       dmaengine_slave_config(chan, &tx_conf);
+       uap->dmatx.chan = chan;
+
+       dev_info(uap->port.dev, "DMA channel TX %s\n",
+                dma_chan_name(uap->dmatx.chan));
+}
+
+#ifndef MODULE
+/*
+ * Stack up the UARTs and let the above initcall be done at device
+ * initcall time, because the serial driver is called as an arch
+ * initcall, and at this time the DMA subsystem is not yet registered.
+ * At this point the driver will switch over to using DMA where desired.
+ */
+struct dma_uap {
+       struct list_head node;
+       struct uart_amba_port *uap;
+};
+
+static LIST_HEAD(pl011_dma_uarts);
+
+static int __init pl011_dma_initcall(void)
+{
+       struct list_head *node, *tmp;
+
+       list_for_each_safe(node, tmp, &pl011_dma_uarts) {
+               struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
+               pl011_dma_probe_initcall(dmau->uap);
+               list_del(node);
+               kfree(dmau);
+       }
+       return 0;
+}
+
+device_initcall(pl011_dma_initcall);
+
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+       struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
+       if (dmau) {
+               dmau->uap = uap;
+               list_add_tail(&dmau->node, &pl011_dma_uarts);
+       }
+}
+#else
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+       pl011_dma_probe_initcall(uap);
+}
+#endif
+
+static void pl011_dma_remove(struct uart_amba_port *uap)
+{
+       /* TODO: remove the initcall if it has not yet executed */
+       if (uap->dmatx.chan)
+               dma_release_channel(uap->dmatx.chan);
+}
+
+
+/* Forward declare this for the refill routine */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap);
+
+/*
+ * The current DMA TX buffer has been sent.
+ * Try to queue up another DMA buffer.
+ */
+static void pl011_dma_tx_callback(void *data)
+{
+       struct uart_amba_port *uap = data;
+       struct pl011_dmatx_data *dmatx = &uap->dmatx;
+       unsigned long flags;
+       u16 dmacr;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       if (uap->dmatx.queued)
+               dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
+                            DMA_TO_DEVICE);
+
+       dmacr = uap->dmacr;
+       uap->dmacr = dmacr & ~UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       /*
+        * If TX DMA was disabled, it means that we've stopped the DMA for
+        * some reason (eg, XOFF received, or we want to send an X-char.)
+        *
+        * Note: we need to be careful here of a potential race between DMA
+        * and the rest of the driver - if the driver disables TX DMA while
+        * a TX buffer completing, we must update the tx queued status to
+        * get further refills (hence we check dmacr).
+        */
+       if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
+           uart_circ_empty(&uap->port.state->xmit)) {
+               uap->dmatx.queued = false;
+               spin_unlock_irqrestore(&uap->port.lock, flags);
+               return;
+       }
+
+       if (pl011_dma_tx_refill(uap) <= 0) {
+               /*
+                * We didn't queue a DMA buffer for some reason, but we
+                * have data pending to be sent.  Re-enable the TX IRQ.
+                */
+               uap->im |= UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+       }
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Try to refill the TX DMA buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   1 if we queued up a TX DMA buffer.
+ *   0 if we didn't want to handle this by DMA
+ *  <0 on error
+ */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap)
+{
+       struct pl011_dmatx_data *dmatx = &uap->dmatx;
+       struct dma_chan *chan = dmatx->chan;
+       struct dma_device *dma_dev = chan->device;
+       struct dma_async_tx_descriptor *desc;
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       unsigned int count;
+
+       /*
+        * Try to avoid the overhead involved in using DMA if the
+        * transaction fits in the first half of the FIFO, by using
+        * the standard interrupt handling.  This ensures that we
+        * issue a uart_write_wakeup() at the appropriate time.
+        */
+       count = uart_circ_chars_pending(xmit);
+       if (count < (uap->fifosize >> 1)) {
+               uap->dmatx.queued = false;
+               return 0;
+       }
+
+       /*
+        * Bodge: don't send the last character by DMA, as this
+        * will prevent XON from notifying us to restart DMA.
+        */
+       count -= 1;
+
+       /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
+       if (count > PL011_DMA_BUFFER_SIZE)
+               count = PL011_DMA_BUFFER_SIZE;
+
+       if (xmit->tail < xmit->head)
+               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
+       else {
+               size_t first = UART_XMIT_SIZE - xmit->tail;
+               size_t second = xmit->head;
+
+               memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
+               if (second)
+                       memcpy(&dmatx->buf[first], &xmit->buf[0], second);
+       }
+
+       dmatx->sg.length = count;
+
+       if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
+               uap->dmatx.queued = false;
+               dev_dbg(uap->port.dev, "unable to map TX DMA\n");
+               return -EBUSY;
+       }
+
+       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
+                                            DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+               /*
+                * If DMA cannot be used right now, we complete this
+                * transaction via IRQ and let the TTY layer retry.
+                */
+               dev_dbg(uap->port.dev, "TX DMA busy\n");
+               return -EBUSY;
+       }
+
+       /* Some data to go along to the callback */
+       desc->callback = pl011_dma_tx_callback;
+       desc->callback_param = uap;
+
+       /* All errors should happen at prepare time */
+       dmaengine_submit(desc);
+
+       /* Fire the DMA transaction */
+       dma_dev->device_issue_pending(chan);
+
+       uap->dmacr |= UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       uap->dmatx.queued = true;
+
+       /*
+        * Now we know that DMA will fire, so advance the ring buffer
+        * with the stuff we just dispatched.
+        */
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       uap->port.icount.tx += count;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       return 1;
+}
+
+/*
+ * We received a transmit interrupt without a pending X-char but with
+ * pending characters.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want to use PIO to transmit
+ *   true if we queued a DMA buffer
+ */
+static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+       if (!uap->using_dma)
+               return false;
+
+       /*
+        * If we already have a TX buffer queued, but received a
+        * TX interrupt, it will be because we've just sent an X-char.
+        * Ensure the TX DMA is enabled and the TX IRQ is disabled.
+        */
+       if (uap->dmatx.queued) {
+               uap->dmacr |= UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+               uap->im &= ~UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+               return true;
+       }
+
+       /*
+        * We don't have a TX buffer queued, so try to queue one.
+        * If we succesfully queued a buffer, mask the TX IRQ.
+        */
+       if (pl011_dma_tx_refill(uap) > 0) {
+               uap->im &= ~UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+               return true;
+       }
+       return false;
+}
+
+/*
+ * Stop the DMA transmit (eg, due to received XOFF).
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+       if (uap->dmatx.queued) {
+               uap->dmacr &= ~UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       }
+}
+
+/*
+ * Try to start a DMA transmit, or in the case of an XON/OFF
+ * character queued for send, try to get that character out ASAP.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ *   false if we want the TX IRQ to be enabled
+ *   true if we have a buffer queued
+ */
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+       u16 dmacr;
+
+       if (!uap->using_dma)
+               return false;
+
+       if (!uap->port.x_char) {
+               /* no X-char, try to push chars out in DMA mode */
+               bool ret = true;
+
+               if (!uap->dmatx.queued) {
+                       if (pl011_dma_tx_refill(uap) > 0) {
+                               uap->im &= ~UART011_TXIM;
+                               ret = true;
+                       } else {
+                               uap->im |= UART011_TXIM;
+                               ret = false;
+                       }
+                       writew(uap->im, uap->port.membase + UART011_IMSC);
+               } else if (!(uap->dmacr & UART011_TXDMAE)) {
+                       uap->dmacr |= UART011_TXDMAE;
+                       writew(uap->dmacr,
+                                      uap->port.membase + UART011_DMACR);
+               }
+               return ret;
+       }
+
+       /*
+        * We have an X-char to send.  Disable DMA to prevent it loading
+        * the TX fifo, and then see if we can stuff it into the FIFO.
+        */
+       dmacr = uap->dmacr;
+       uap->dmacr &= ~UART011_TXDMAE;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+               /*
+                * No space in the FIFO, so enable the transmit interrupt
+                * so we know when there is space.  Note that once we've
+                * loaded the character, we should just re-enable DMA.
+                */
+               return false;
+       }
+
+       writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+       uap->port.icount.tx++;
+       uap->port.x_char = 0;
+
+       /* Success - restore the DMA state */
+       uap->dmacr = dmacr;
+       writew(dmacr, uap->port.membase + UART011_DMACR);
+
+       return true;
+}
+
+/*
+ * Flush the transmit buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static void pl011_dma_flush_buffer(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (!uap->using_dma)
+               return;
+
+       /* Avoid deadlock with the DMA engine callback */
+       spin_unlock(&uap->port.lock);
+       dmaengine_terminate_all(uap->dmatx.chan);
+       spin_lock(&uap->port.lock);
+       if (uap->dmatx.queued) {
+               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+                            DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+               uap->dmacr &= ~UART011_TXDMAE;
+               writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       }
+}
+
+
+static void pl011_dma_startup(struct uart_amba_port *uap)
+{
+       if (!uap->dmatx.chan)
+               return;
+
+       uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+       if (!uap->dmatx.buf) {
+               dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
+               uap->port.fifosize = uap->fifosize;
+               return;
+       }
+
+       sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
+
+       /* The DMA buffer is now the FIFO the TTY subsystem can use */
+       uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
+       uap->using_dma = true;
+
+       /* Turn on DMA error (RX/TX will be enabled on demand) */
+       uap->dmacr |= UART011_DMAONERR;
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+       /*
+        * ST Micro variants has some specific dma burst threshold
+        * compensation. Set this to 16 bytes, so burst will only
+        * be issued above/below 16 bytes.
+        */
+       if (uap->vendor->dma_threshold)
+               writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
+                              uap->port.membase + ST_UART011_DMAWM);
+}
+
+static void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+       if (!uap->using_dma)
+               return;
+
+       /* Disable RX and TX DMA */
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+               barrier();
+
+       spin_lock_irq(&uap->port.lock);
+       uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
+       writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+       spin_unlock_irq(&uap->port.lock);
+
+       /* In theory, this should already be done by pl011_dma_flush_buffer */
+       dmaengine_terminate_all(uap->dmatx.chan);
+       if (uap->dmatx.queued) {
+               dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+                            DMA_TO_DEVICE);
+               uap->dmatx.queued = false;
+       }
+
+       kfree(uap->dmatx.buf);
+
+       uap->using_dma = false;
+}
+
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_remove(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_startup(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+       return false;
+}
+
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+       return false;
+}
+
+#define pl011_dma_flush_buffer NULL
+#endif
+
+
+static void pl011_stop_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im &= ~UART011_TXIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       pl011_dma_tx_stop(uap);
+}
+
+static void pl011_start_tx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       if (!pl011_dma_tx_start(uap)) {
+               uap->im |= UART011_TXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
+       }
+}
+
+static void pl011_stop_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
+                    UART011_PEIM|UART011_BEIM|UART011_OEIM);
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+}
+
+static void pl011_enable_ms(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+}
+
+static void pl011_rx_chars(struct uart_amba_port *uap)
+{
+       struct tty_struct *tty = uap->port.state->port.tty;
+       unsigned int status, ch, flag, max_count = 256;
+
+       status = readw(uap->port.membase + UART01x_FR);
+       while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
+               ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
+               flag = TTY_NORMAL;
+               uap->port.icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(ch & UART_DR_ERROR)) {
+                       if (ch & UART011_DR_BE) {
+                               ch &= ~(UART011_DR_FE | UART011_DR_PE);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto ignore_char;
+                       } else if (ch & UART011_DR_PE)
+                               uap->port.icount.parity++;
+                       else if (ch & UART011_DR_FE)
+                               uap->port.icount.frame++;
+                       if (ch & UART011_DR_OE)
+                               uap->port.icount.overrun++;
+
+                       ch &= uap->port.read_status_mask;
+
+                       if (ch & UART011_DR_BE)
+                               flag = TTY_BREAK;
+                       else if (ch & UART011_DR_PE)
+                               flag = TTY_PARITY;
+                       else if (ch & UART011_DR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&uap->port, ch & 255))
+                       goto ignore_char;
+
+               uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+
+       ignore_char:
+               status = readw(uap->port.membase + UART01x_FR);
+       }
+       spin_unlock(&uap->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&uap->port.lock);
+}
+
+static void pl011_tx_chars(struct uart_amba_port *uap)
+{
+       struct circ_buf *xmit = &uap->port.state->xmit;
+       int count;
+
+       if (uap->port.x_char) {
+               writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+               pl011_stop_tx(&uap->port);
+               return;
+       }
+
+       /* If we are using DMA mode, try to send some characters. */
+       if (pl011_dma_tx_irq(uap))
+               return;
+
+       count = uap->fifosize >> 1;
+       do {
+               writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uap->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       if (uart_circ_empty(xmit))
+               pl011_stop_tx(&uap->port);
+}
+
+static void pl011_modem_status(struct uart_amba_port *uap)
+{
+       unsigned int status, delta;
+
+       status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       delta = status ^ uap->old_status;
+       uap->old_status = status;
+
+       if (!delta)
+               return;
+
+       if (delta & UART01x_FR_DCD)
+               uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+
+       if (delta & UART01x_FR_DSR)
+               uap->port.icount.dsr++;
+
+       if (delta & UART01x_FR_CTS)
+               uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+
+       wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t pl011_int(int irq, void *dev_id)
+{
+       struct uart_amba_port *uap = dev_id;
+       unsigned long flags;
+       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+       int handled = 0;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       status = readw(uap->port.membase + UART011_MIS);
+       if (status) {
+               do {
+                       writew(status & ~(UART011_TXIS|UART011_RTIS|
+                                         UART011_RXIS),
+                              uap->port.membase + UART011_ICR);
+
+                       if (status & (UART011_RTIS|UART011_RXIS))
+                               pl011_rx_chars(uap);
+                       if (status & (UART011_DSRMIS|UART011_DCDMIS|
+                                     UART011_CTSMIS|UART011_RIMIS))
+                               pl011_modem_status(uap);
+                       if (status & UART011_TXIS)
+                               pl011_tx_chars(uap);
+
+                       if (pass_counter-- == 0)
+                               break;
+
+                       status = readw(uap->port.membase + UART011_MIS);
+               } while (status != 0);
+               handled = 1;
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+static unsigned int pl01x_tx_empty(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status = readw(uap->port.membase + UART01x_FR);
+       return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pl01x_get_mctrl(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int result = 0;
+       unsigned int status = readw(uap->port.membase + UART01x_FR);
+
+#define TIOCMBIT(uartbit, tiocmbit)    \
+       if (status & uartbit)           \
+               result |= tiocmbit
+
+       TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
+       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
+       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
+       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+#undef TIOCMBIT
+       return result;
+}
+
+static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readw(uap->port.membase + UART011_CR);
+
+#define        TIOCMBIT(tiocmbit, uartbit)             \
+       if (mctrl & tiocmbit)           \
+               cr |= uartbit;          \
+       else                            \
+               cr &= ~uartbit
+
+       TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
+       TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
+       TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
+       TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
+       TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+
+       if (uap->autorts) {
+               /* We need to disable auto-RTS if we want to turn RTS off */
+               TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+       }
+#undef TIOCMBIT
+
+       writew(cr, uap->port.membase + UART011_CR);
+}
+
+static void pl011_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned long flags;
+       unsigned int lcr_h;
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+       if (break_state == -1)
+               lcr_h |= UART01x_LCRH_BRK;
+       else
+               lcr_h &= ~UART01x_LCRH_BRK;
+       writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int pl010_get_poll_char(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status;
+
+       status = readw(uap->port.membase + UART01x_FR);
+       if (status & UART01x_FR_RXFE)
+               return NO_POLL_CHAR;
+
+       return readw(uap->port.membase + UART01x_DR);
+}
+
+static void pl010_put_poll_char(struct uart_port *port,
+                        unsigned char ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
+
+       writew(ch, uap->port.membase + UART01x_DR);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int pl011_startup(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+       int retval;
+
+       /*
+        * Try to enable the clock producer.
+        */
+       retval = clk_enable(uap->clk);
+       if (retval)
+               goto out;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+       if (retval)
+               goto clk_dis;
+
+       writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
+
+       /*
+        * Provoke TX FIFO interrupt into asserting.
+        */
+       cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
+       writew(cr, uap->port.membase + UART011_CR);
+       writew(0, uap->port.membase + UART011_FBRD);
+       writew(1, uap->port.membase + UART011_IBRD);
+       writew(0, uap->port.membase + uap->lcrh_rx);
+       if (uap->lcrh_tx != uap->lcrh_rx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(0, uap->port.membase + uap->lcrh_tx);
+       }
+       writew(0, uap->port.membase + UART01x_DR);
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+               barrier();
+
+       cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
+       writew(cr, uap->port.membase + UART011_CR);
+
+       /* Clear pending error interrupts */
+       writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
+              uap->port.membase + UART011_ICR);
+
+       /*
+        * initialise the old status of the modem signals
+        */
+       uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+
+       /* Startup DMA */
+       pl011_dma_startup(uap);
+
+       /*
+        * Finally, enable interrupts
+        */
+       spin_lock_irq(&uap->port.lock);
+       uap->im = UART011_RXIM | UART011_RTIM;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       spin_unlock_irq(&uap->port.lock);
+
+       return 0;
+
+ clk_dis:
+       clk_disable(uap->clk);
+ out:
+       return retval;
+}
+
+static void pl011_shutdown_channel(struct uart_amba_port *uap,
+                                       unsigned int lcrh)
+{
+      unsigned long val;
+
+      val = readw(uap->port.membase + lcrh);
+      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
+      writew(val, uap->port.membase + lcrh);
+}
+
+static void pl011_shutdown(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       /*
+        * disable all interrupts
+        */
+       spin_lock_irq(&uap->port.lock);
+       uap->im = 0;
+       writew(uap->im, uap->port.membase + UART011_IMSC);
+       writew(0xffff, uap->port.membase + UART011_ICR);
+       spin_unlock_irq(&uap->port.lock);
+
+       pl011_dma_shutdown(uap);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(uap->port.irq, uap);
+
+       /*
+        * disable the port
+        */
+       uap->autorts = false;
+       writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
+
+       /*
+        * disable break condition and fifos
+        */
+       pl011_shutdown_channel(uap, uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx)
+               pl011_shutdown_channel(uap, uap->lcrh_tx);
+
+       /*
+        * Shut down the clock producer
+        */
+       clk_disable(uap->clk);
+}
+
+static void
+pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int lcr_h, old_cr;
+       unsigned long flags;
+       unsigned int baud, quot, clkdiv;
+
+       if (uap->vendor->oversampling)
+               clkdiv = 8;
+       else
+               clkdiv = 16;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0,
+                                 port->uartclk / clkdiv);
+
+       if (baud > port->uartclk/16)
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
+       else
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr_h = UART01x_LCRH_WLEN_5;
+               break;
+       case CS6:
+               lcr_h = UART01x_LCRH_WLEN_6;
+               break;
+       case CS7:
+               lcr_h = UART01x_LCRH_WLEN_7;
+               break;
+       default: // CS8
+               lcr_h = UART01x_LCRH_WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               lcr_h |= UART01x_LCRH_STP2;
+       if (termios->c_cflag & PARENB) {
+               lcr_h |= UART01x_LCRH_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_h |= UART01x_LCRH_EPS;
+       }
+       if (uap->fifosize > 1)
+               lcr_h |= UART01x_LCRH_FEN;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UART011_DR_OE | 255;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART011_DR_BE;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= UART011_DR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UART011_DR_OE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_DR_RX;
+
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               pl011_enable_ms(port);
+
+       /* first, disable everything */
+       old_cr = readw(port->membase + UART011_CR);
+       writew(0, port->membase + UART011_CR);
+
+       if (termios->c_cflag & CRTSCTS) {
+               if (old_cr & UART011_CR_RTS)
+                       old_cr |= UART011_CR_RTSEN;
+
+               old_cr |= UART011_CR_CTSEN;
+               uap->autorts = true;
+       } else {
+               old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
+               uap->autorts = false;
+       }
+
+       if (uap->vendor->oversampling) {
+               if (baud > port->uartclk / 16)
+                       old_cr |= ST_UART011_CR_OVSFACT;
+               else
+                       old_cr &= ~ST_UART011_CR_OVSFACT;
+       }
+
+       /* Set baud rate */
+       writew(quot & 0x3f, port->membase + UART011_FBRD);
+       writew(quot >> 6, port->membase + UART011_IBRD);
+
+       /*
+        * ----------v----------v----------v----------v-----
+        * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+        * ----------^----------^----------^----------^-----
+        */
+       writew(lcr_h, port->membase + uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(lcr_h, port->membase + uap->lcrh_tx);
+       }
+       writew(old_cr, port->membase + UART011_CR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pl011_type(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       return uap->port.type == PORT_AMBA ? uap->type : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void pl010_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, SZ_4K);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int pl010_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
+                       != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pl010_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_AMBA;
+               pl010_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops amba_pl011_pops = {
+       .tx_empty       = pl01x_tx_empty,
+       .set_mctrl      = pl011_set_mctrl,
+       .get_mctrl      = pl01x_get_mctrl,
+       .stop_tx        = pl011_stop_tx,
+       .start_tx       = pl011_start_tx,
+       .stop_rx        = pl011_stop_rx,
+       .enable_ms      = pl011_enable_ms,
+       .break_ctl      = pl011_break_ctl,
+       .startup        = pl011_startup,
+       .shutdown       = pl011_shutdown,
+       .flush_buffer   = pl011_dma_flush_buffer,
+       .set_termios    = pl011_set_termios,
+       .type           = pl011_type,
+       .release_port   = pl010_release_port,
+       .request_port   = pl010_request_port,
+       .config_port    = pl010_config_port,
+       .verify_port    = pl010_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = pl010_get_poll_char,
+       .poll_put_char = pl010_put_poll_char,
+#endif
+};
+
+static struct uart_amba_port *amba_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
+
+static void pl011_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
+       writew(ch, uap->port.membase + UART01x_DR);
+}
+
+static void
+pl011_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_amba_port *uap = amba_ports[co->index];
+       unsigned int status, old_cr, new_cr;
+
+       clk_enable(uap->clk);
+
+       /*
+        *      First save the CR then disable the interrupts
+        */
+       old_cr = readw(uap->port.membase + UART011_CR);
+       new_cr = old_cr & ~UART011_CR_CTSEN;
+       new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+       writew(new_cr, uap->port.membase + UART011_CR);
+
+       uart_console_write(&uap->port, s, count, pl011_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = readw(uap->port.membase + UART01x_FR);
+       } while (status & UART01x_FR_BUSY);
+       writew(old_cr, uap->port.membase + UART011_CR);
+
+       clk_disable(uap->clk);
+}
+
+static void __init
+pl011_console_get_options(struct uart_amba_port *uap, int *baud,
+                            int *parity, int *bits)
+{
+       if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
+               unsigned int lcr_h, ibrd, fbrd;
+
+               lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+
+               *parity = 'n';
+               if (lcr_h & UART01x_LCRH_PEN) {
+                       if (lcr_h & UART01x_LCRH_EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               ibrd = readw(uap->port.membase + UART011_IBRD);
+               fbrd = readw(uap->port.membase + UART011_FBRD);
+
+               *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+
+               if (uap->vendor->oversampling) {
+                       if (readw(uap->port.membase + UART011_CR)
+                                 & ST_UART011_CR_OVSFACT)
+                               *baud *= 2;
+               }
+       }
+}
+
+static int __init pl011_console_setup(struct console *co, char *options)
+{
+       struct uart_amba_port *uap;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       uap = amba_ports[co->index];
+       if (!uap)
+               return -ENODEV;
+
+       uap->port.uartclk = clk_get_rate(uap->clk);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               pl011_console_get_options(uap, &baud, &parity, &bits);
+
+       return uart_set_options(&uap->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver amba_reg;
+static struct console amba_console = {
+       .name           = "ttyAMA",
+       .write          = pl011_console_write,
+       .device         = uart_console_device,
+       .setup          = pl011_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &amba_reg,
+};
+
+#define AMBA_CONSOLE   (&amba_console)
+#else
+#define AMBA_CONSOLE   NULL
+#endif
+
+static struct uart_driver amba_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAMA",
+       .dev_name               = "ttyAMA",
+       .major                  = SERIAL_AMBA_MAJOR,
+       .minor                  = SERIAL_AMBA_MINOR,
+       .nr                     = UART_NR,
+       .cons                   = AMBA_CONSOLE,
+};
+
+static int pl011_probe(struct amba_device *dev, struct amba_id *id)
+{
+       struct uart_amba_port *uap;
+       struct vendor_data *vendor = id->data;
+       void __iomem *base;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == NULL)
+                       break;
+
+       if (i == ARRAY_SIZE(amba_ports)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       if (uap == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       base = ioremap(dev->res.start, resource_size(&dev->res));
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       uap->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(uap->clk)) {
+               ret = PTR_ERR(uap->clk);
+               goto unmap;
+       }
+
+       uap->vendor = vendor;
+       uap->lcrh_rx = vendor->lcrh_rx;
+       uap->lcrh_tx = vendor->lcrh_tx;
+       uap->fifosize = vendor->fifosize;
+       uap->port.dev = &dev->dev;
+       uap->port.mapbase = dev->res.start;
+       uap->port.membase = base;
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = dev->irq[0];
+       uap->port.fifosize = uap->fifosize;
+       uap->port.ops = &amba_pl011_pops;
+       uap->port.flags = UPF_BOOT_AUTOCONF;
+       uap->port.line = i;
+       pl011_dma_probe(uap);
+
+       snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+
+       amba_ports[i] = uap;
+
+       amba_set_drvdata(dev, uap);
+       ret = uart_add_one_port(&amba_reg, &uap->port);
+       if (ret) {
+               amba_set_drvdata(dev, NULL);
+               amba_ports[i] = NULL;
+               pl011_dma_remove(uap);
+               clk_put(uap->clk);
+ unmap:
+               iounmap(base);
+ free:
+               kfree(uap);
+       }
+ out:
+       return ret;
+}
+
+static int pl011_remove(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       int i;
+
+       amba_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&amba_reg, &uap->port);
+
+       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+               if (amba_ports[i] == uap)
+                       amba_ports[i] = NULL;
+
+       pl011_dma_remove(uap);
+       iounmap(uap->port.membase);
+       clk_put(uap->clk);
+       kfree(uap);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pl011_suspend(struct amba_device *dev, pm_message_t state)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (!uap)
+               return -EINVAL;
+
+       return uart_suspend_port(&amba_reg, &uap->port);
+}
+
+static int pl011_resume(struct amba_device *dev)
+{
+       struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+       if (!uap)
+               return -EINVAL;
+
+       return uart_resume_port(&amba_reg, &uap->port);
+}
+#endif
+
+static struct amba_id pl011_ids[] = {
+       {
+               .id     = 0x00041011,
+               .mask   = 0x000fffff,
+               .data   = &vendor_arm,
+       },
+       {
+               .id     = 0x00380802,
+               .mask   = 0x00ffffff,
+               .data   = &vendor_st,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl011_driver = {
+       .drv = {
+               .name   = "uart-pl011",
+       },
+       .id_table       = pl011_ids,
+       .probe          = pl011_probe,
+       .remove         = pl011_remove,
+#ifdef CONFIG_PM
+       .suspend        = pl011_suspend,
+       .resume         = pl011_resume,
+#endif
+};
+
+static int __init pl011_init(void)
+{
+       int ret;
+       printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
+
+       ret = uart_register_driver(&amba_reg);
+       if (ret == 0) {
+               ret = amba_driver_register(&pl011_driver);
+               if (ret)
+                       uart_unregister_driver(&amba_reg);
+       }
+       return ret;
+}
+
+static void __exit pl011_exit(void)
+{
+       amba_driver_unregister(&pl011_driver);
+       uart_unregister_driver(&amba_reg);
+}
+
+/*
+ * While this can be a module, if builtin it's most likely the console
+ * So let's leave module_exit but move module_init to an earlier place
+ */
+arch_initcall(pl011_init);
+module_exit(pl011_exit);
+
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("ARM AMBA serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
new file mode 100644 (file)
index 0000000..095a5d5
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ *  Driver for GRLIB serial ports (APBUART)
+ *
+ *  Based on linux/drivers/serial/amba.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
+ *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
+ *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
+ *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
+ */
+
+#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <asm/irq.h>
+
+#include "apbuart.h"
+
+#define SERIAL_APBUART_MAJOR   TTY_MAJOR
+#define SERIAL_APBUART_MINOR   64
+#define UART_DUMMY_RSR_RX      0x8000  /* for ignore all read */
+
+static void apbuart_tx_chars(struct uart_port *port);
+
+static void apbuart_stop_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_start_tx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr |= UART_CTRL_TI;
+       UART_PUT_CTRL(port, cr);
+
+       if (UART_GET_STATUS(port) & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+}
+
+static void apbuart_stop_rx(struct uart_port *port)
+{
+       unsigned int cr;
+
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_RI);
+       UART_PUT_CTRL(port, cr);
+}
+
+static void apbuart_enable_ms(struct uart_port *port)
+{
+       /* No modem status change interrupts for APBUART */
+}
+
+static void apbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, rsr, flag;
+       unsigned int max_chars = port->fifosize;
+
+       status = UART_GET_STATUS(port);
+
+       while (UART_RX_DATA(status) && (max_chars--)) {
+
+               ch = UART_GET_CHAR(port);
+               flag = TTY_NORMAL;
+
+               port->icount.rx++;
+
+               rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
+               UART_PUT_STATUS(port, 0);
+               if (rsr & UART_STATUS_ERR) {
+
+                       if (rsr & UART_STATUS_BR) {
+                               rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       } else if (rsr & UART_STATUS_PE) {
+                               port->icount.parity++;
+                       } else if (rsr & UART_STATUS_FE) {
+                               port->icount.frame++;
+                       }
+                       if (rsr & UART_STATUS_OE)
+                               port->icount.overrun++;
+
+                       rsr &= port->read_status_mask;
+
+                       if (rsr & UART_STATUS_PE)
+                               flag = TTY_PARITY;
+                       else if (rsr & UART_STATUS_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
+
+
+             ignore_char:
+               status = UART_GET_STATUS(port);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
+static void apbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       int count;
+
+       if (port->x_char) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               apbuart_stop_tx(port);
+               return;
+       }
+
+       /* amba: fill FIFO */
+       count = port->fifosize >> 1;
+       do {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               apbuart_stop_tx(port);
+}
+
+static irqreturn_t apbuart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status;
+
+       spin_lock(&port->lock);
+
+       status = UART_GET_STATUS(port);
+       if (status & UART_STATUS_DR)
+               apbuart_rx_chars(port);
+       if (status & UART_STATUS_THE)
+               apbuart_tx_chars(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int apbuart_tx_empty(struct uart_port *port)
+{
+       unsigned int status = UART_GET_STATUS(port);
+       return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int apbuart_get_mctrl(struct uart_port *port)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* The GRLIB APBUART handles flow control in hardware */
+}
+
+static void apbuart_break_ctl(struct uart_port *port, int break_state)
+{
+       /* We don't support sending break */
+}
+
+static int apbuart_startup(struct uart_port *port)
+{
+       int retval;
+       unsigned int cr;
+
+       /* Allocate the IRQ */
+       retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
+       if (retval)
+               return retval;
+
+       /* Finally, enable interrupts */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr | UART_CTRL_RE | UART_CTRL_TE |
+                     UART_CTRL_RI | UART_CTRL_TI);
+
+       return 0;
+}
+
+static void apbuart_shutdown(struct uart_port *port)
+{
+       unsigned int cr;
+
+       /* disable all interrupts, disable the port */
+       cr = UART_GET_CTRL(port);
+       UART_PUT_CTRL(port,
+                     cr & ~(UART_CTRL_RE | UART_CTRL_TE |
+                            UART_CTRL_RI | UART_CTRL_TI));
+
+       /* Free the interrupt */
+       free_irq(port->irq, port);
+}
+
+static void apbuart_set_termios(struct uart_port *port,
+                               struct ktermios *termios, struct ktermios *old)
+{
+       unsigned int cr;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /* Ask the core to calculate the divisor for us. */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       if (baud == 0)
+               panic("invalid baudrate %i\n", port->uartclk / 16);
+
+       /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
+       quot = (uart_get_divisor(port, baud)) * 2;
+       cr = UART_GET_CTRL(port);
+       cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
+
+       if (termios->c_cflag & PARENB) {
+               cr |= UART_CTRL_PE;
+               if ((termios->c_cflag & PARODD))
+                       cr |= UART_CTRL_PS;
+       }
+
+       /* Enable flow control. */
+       if (termios->c_cflag & CRTSCTS)
+               cr |= UART_CTRL_FL;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UART_STATUS_OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Characters to ignore */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
+
+       /* Ignore all characters if CREAD is not set. */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+       /* Set baud rate */
+       quot -= 1;
+       UART_PUT_SCAL(port, quot);
+       UART_PUT_CTRL(port, cr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *apbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
+}
+
+static void apbuart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, 0x100);
+}
+
+static int apbuart_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
+           != NULL ? 0 : -EBUSY;
+       return 0;
+}
+
+/* Configure/autoconfigure the port */
+static void apbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_APBUART;
+               apbuart_request_port(port);
+       }
+}
+
+/* Verify the new serial_struct (for TIOCSSERIAL) */
+static int apbuart_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops grlib_apbuart_ops = {
+       .tx_empty = apbuart_tx_empty,
+       .set_mctrl = apbuart_set_mctrl,
+       .get_mctrl = apbuart_get_mctrl,
+       .stop_tx = apbuart_stop_tx,
+       .start_tx = apbuart_start_tx,
+       .stop_rx = apbuart_stop_rx,
+       .enable_ms = apbuart_enable_ms,
+       .break_ctl = apbuart_break_ctl,
+       .startup = apbuart_startup,
+       .shutdown = apbuart_shutdown,
+       .set_termios = apbuart_set_termios,
+       .type = apbuart_type,
+       .release_port = apbuart_release_port,
+       .request_port = apbuart_request_port,
+       .config_port = apbuart_config_port,
+       .verify_port = apbuart_verify_port,
+};
+
+static struct uart_port grlib_apbuart_ports[UART_NR];
+static struct device_node *grlib_apbuart_nodes[UART_NR];
+
+static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
+{
+       int ctrl, loop = 0;
+       int status;
+       int fifosize;
+       unsigned long flags;
+
+       ctrl = UART_GET_CTRL(port);
+
+       /*
+        * Enable the transceiver and wait for it to be ready to send data.
+        * Clear interrupts so that this process will not be externally
+        * interrupted in the middle (which can cause the transceiver to
+        * drain prematurely).
+        */
+
+       local_irq_save(flags);
+
+       UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
+
+       while (!UART_TX_READY(UART_GET_STATUS(port)))
+               loop++;
+
+       /*
+        * Disable the transceiver so data isn't actually sent during the
+        * actual test.
+        */
+
+       UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
+
+       fifosize = 1;
+       UART_PUT_CHAR(port, 0);
+
+       /*
+        * So long as transmitting a character increments the tranceivier FIFO
+        * length the FIFO must be at least that big. These bytes will
+        * automatically drain off of the FIFO.
+        */
+
+       status = UART_GET_STATUS(port);
+       while (((status >> 20) & 0x3F) == fifosize) {
+               fifosize++;
+               UART_PUT_CHAR(port, 0);
+               status = UART_GET_STATUS(port);
+       }
+
+       fifosize--;
+
+       UART_PUT_CTRL(port, ctrl);
+       local_irq_restore(flags);
+
+       if (fifosize == 0)
+               fifosize = 1;
+
+       return fifosize;
+}
+
+static void apbuart_flush_fifo(struct uart_port *port)
+{
+       int i;
+
+       for (i = 0; i < port->fifosize; i++)
+               UART_GET_CHAR(port);
+}
+
+
+/* ======================================================================== */
+/* Console driver, if enabled                                               */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
+
+static void apbuart_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int status;
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CHAR(port, ch);
+}
+
+static void
+apbuart_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &grlib_apbuart_ports[co->index];
+       unsigned int status, old_cr, new_cr;
+
+       /* First save the CR then disable the interrupts */
+       old_cr = UART_GET_CTRL(port);
+       new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
+       UART_PUT_CTRL(port, new_cr);
+
+       uart_console_write(port, s, count, apbuart_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the TCR
+        */
+       do {
+               status = UART_GET_STATUS(port);
+       } while (!UART_TX_READY(status));
+       UART_PUT_CTRL(port, old_cr);
+}
+
+static void __init
+apbuart_console_get_options(struct uart_port *port, int *baud,
+                           int *parity, int *bits)
+{
+       if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
+
+               unsigned int quot, status;
+               status = UART_GET_STATUS(port);
+
+               *parity = 'n';
+               if (status & UART_CTRL_PE) {
+                       if ((status & UART_CTRL_PS) == 0)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               *bits = 8;
+               quot = UART_GET_SCAL(port) / 8;
+               *baud = port->uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init apbuart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
+                co, co->index, options);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= grlib_apbuart_port_nr)
+               co->index = 0;
+
+       port = &grlib_apbuart_ports[co->index];
+
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               apbuart_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver grlib_apbuart_driver;
+
+static struct console grlib_apbuart_console = {
+       .name = "ttyS",
+       .write = apbuart_console_write,
+       .device = uart_console_device,
+       .setup = apbuart_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &grlib_apbuart_driver,
+};
+
+
+static int grlib_apbuart_configure(void);
+
+static int __init apbuart_console_init(void)
+{
+       if (grlib_apbuart_configure())
+               return -ENODEV;
+       register_console(&grlib_apbuart_console);
+       return 0;
+}
+
+console_initcall(apbuart_console_init);
+
+#define APBUART_CONSOLE        (&grlib_apbuart_console)
+#else
+#define APBUART_CONSOLE        NULL
+#endif
+
+static struct uart_driver grlib_apbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "serial",
+       .dev_name = "ttyS",
+       .major = SERIAL_APBUART_MAJOR,
+       .minor = SERIAL_APBUART_MINOR,
+       .nr = UART_NR,
+       .cons = APBUART_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static int __devinit apbuart_probe(struct platform_device *op,
+                                  const struct of_device_id *match)
+{
+       int i = -1;
+       struct uart_port *port = NULL;
+
+       i = 0;
+       for (i = 0; i < grlib_apbuart_port_nr; i++) {
+               if (op->dev.of_node == grlib_apbuart_nodes[i])
+                       break;
+       }
+
+       port = &grlib_apbuart_ports[i];
+       port->dev = &op->dev;
+
+       uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
+
+       apbuart_flush_fifo((struct uart_port *) port);
+
+       printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
+              (unsigned long long) port->mapbase, port->irq);
+       return 0;
+}
+
+static struct of_device_id __initdata apbuart_match[] = {
+       {
+        .name = "GAISLER_APBUART",
+        },
+       {
+        .name = "01_00c",
+        },
+       {},
+};
+
+static struct of_platform_driver grlib_apbuart_of_driver = {
+       .probe = apbuart_probe,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "grlib-apbuart",
+               .of_match_table = apbuart_match,
+       },
+};
+
+
+static int grlib_apbuart_configure(void)
+{
+       struct device_node *np, *rp;
+       const u32 *prop;
+       int freq_khz, line = 0;
+
+       /* Get bus frequency */
+       rp = of_find_node_by_path("/");
+       if (!rp)
+               return -ENODEV;
+       rp = of_get_next_child(rp, NULL);
+       if (!rp)
+               return -ENODEV;
+       prop = of_get_property(rp, "clock-frequency", NULL);
+       if (!prop)
+               return -ENODEV;
+       freq_khz = *prop;
+
+       for_each_matching_node(np, apbuart_match) {
+               const int *irqs, *ampopts;
+               const struct amba_prom_registers *regs;
+               struct uart_port *port;
+               unsigned long addr;
+
+               ampopts = of_get_property(np, "ampopts", NULL);
+               if (ampopts && (*ampopts == 0))
+                       continue; /* Ignore if used by another OS instance */
+
+               irqs = of_get_property(np, "interrupts", NULL);
+               regs = of_get_property(np, "reg", NULL);
+
+               if (!irqs || !regs)
+                       continue;
+
+               grlib_apbuart_nodes[line] = np;
+
+               addr = regs->phys_addr;
+
+               port = &grlib_apbuart_ports[line];
+
+               port->mapbase = addr;
+               port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
+               port->irq = *irqs;
+               port->iotype = UPIO_MEM;
+               port->ops = &grlib_apbuart_ops;
+               port->flags = UPF_BOOT_AUTOCONF;
+               port->line = line;
+               port->uartclk = freq_khz * 1000;
+               port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
+               line++;
+
+               /* We support maximum UART_NR uarts ... */
+               if (line == UART_NR)
+                       break;
+       }
+
+       grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+       return line ? 0 : -ENODEV;
+}
+
+static int __init grlib_apbuart_init(void)
+{
+       int ret;
+
+       /* Find all APBUARTS in device the tree and initialize their ports */
+       ret = grlib_apbuart_configure();
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
+
+       ret = uart_register_driver(&grlib_apbuart_driver);
+
+       if (ret) {
+               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+                      __FILE__, ret);
+               return ret;
+       }
+
+       ret = of_register_platform_driver(&grlib_apbuart_of_driver);
+       if (ret) {
+               printk(KERN_ERR
+                      "%s: of_register_platform_driver failed (%i)\n",
+                      __FILE__, ret);
+               uart_unregister_driver(&grlib_apbuart_driver);
+               return ret;
+       }
+
+       return ret;
+}
+
+static void __exit grlib_apbuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < grlib_apbuart_port_nr; i++)
+               uart_remove_one_port(&grlib_apbuart_driver,
+                                    &grlib_apbuart_ports[i]);
+
+       uart_unregister_driver(&grlib_apbuart_driver);
+       of_unregister_platform_driver(&grlib_apbuart_of_driver);
+}
+
+module_init(grlib_apbuart_init);
+module_exit(grlib_apbuart_exit);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB");
+MODULE_DESCRIPTION("GRLIB APBUART serial driver");
+MODULE_VERSION("2.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/apbuart.h b/drivers/tty/serial/apbuart.h
new file mode 100644 (file)
index 0000000..5faf87c
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __GRLIB_APBUART_H__
+#define __GRLIB_APBUART_H__
+
+#include <asm/io.h>
+
+#define UART_NR                8
+static int grlib_apbuart_port_nr;
+
+struct grlib_apbuart_regs_map {
+       u32 data;
+       u32 status;
+       u32 ctrl;
+       u32 scaler;
+};
+
+struct amba_prom_registers {
+       unsigned int phys_addr;
+       unsigned int reg_size;
+};
+
+/*
+ *  The following defines the bits in the APBUART Status Registers.
+ */
+#define UART_STATUS_DR   0x00000001    /* Data Ready */
+#define UART_STATUS_TSE  0x00000002    /* TX Send Register Empty */
+#define UART_STATUS_THE  0x00000004    /* TX Hold Register Empty */
+#define UART_STATUS_BR   0x00000008    /* Break Error */
+#define UART_STATUS_OE   0x00000010    /* RX Overrun Error */
+#define UART_STATUS_PE   0x00000020    /* RX Parity Error */
+#define UART_STATUS_FE   0x00000040    /* RX Framing Error */
+#define UART_STATUS_ERR  0x00000078    /* Error Mask */
+
+/*
+ *  The following defines the bits in the APBUART Ctrl Registers.
+ */
+#define UART_CTRL_RE     0x00000001    /* Receiver enable */
+#define UART_CTRL_TE     0x00000002    /* Transmitter enable */
+#define UART_CTRL_RI     0x00000004    /* Receiver interrupt enable */
+#define UART_CTRL_TI     0x00000008    /* Transmitter irq */
+#define UART_CTRL_PS     0x00000010    /* Parity select */
+#define UART_CTRL_PE     0x00000020    /* Parity enable */
+#define UART_CTRL_FL     0x00000040    /* Flow control enable */
+#define UART_CTRL_LB     0x00000080    /* Loopback enable */
+
+#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
+
+#define APBBASE_DATA_P(port)   (&(APBBASE(port)->data))
+#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
+#define APBBASE_CTRL_P(port)   (&(APBBASE(port)->ctrl))
+#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
+
+#define UART_GET_CHAR(port)    (__raw_readl(APBBASE_DATA_P(port)))
+#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
+#define UART_GET_STATUS(port)  (__raw_readl(APBBASE_STATUS_P(port)))
+#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
+#define UART_GET_CTRL(port)    (__raw_readl(APBBASE_CTRL_P(port)))
+#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
+#define UART_GET_SCAL(port)    (__raw_readl(APBBASE_SCALAR_P(port)))
+#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
+
+#define UART_RX_DATA(s)                (((s) & UART_STATUS_DR) != 0)
+#define UART_TX_READY(s)       (((s) & UART_STATUS_THE) != 0)
+
+#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
new file mode 100644 (file)
index 0000000..2a1d52f
--- /dev/null
@@ -0,0 +1,1813 @@
+/*
+ *  linux/drivers/char/atmel_serial.c
+ *
+ *  Driver for Atmel AT91 / AT32 Serial ports
+ *  Copyright (C) 2003 Rick Bronson
+ *
+ *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  DMA support added by Chip Coldwell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
+#include <linux/atmel_serial.h>
+#include <linux/uaccess.h>
+
+#include <asm/io.h>
+#include <asm/ioctls.h>
+
+#include <asm/mach/serial_at91.h>
+#include <mach/board.h>
+
+#ifdef CONFIG_ARM
+#include <mach/cpu.h>
+#include <mach/gpio.h>
+#endif
+
+#define PDC_BUFFER_SIZE                512
+/* Revisit: We should calculate this based on the actual port settings */
+#define PDC_RX_TIMEOUT         (3 * 10)                /* 3 bytes */
+
+#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+static void atmel_start_rx(struct uart_port *port);
+static void atmel_stop_rx(struct uart_port *port);
+
+#ifdef CONFIG_SERIAL_ATMEL_TTYAT
+
+/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
+ * should coexist with the 8250 driver, such as if we have an external 16C550
+ * UART. */
+#define SERIAL_ATMEL_MAJOR     204
+#define MINOR_START            154
+#define ATMEL_DEVICENAME       "ttyAT"
+
+#else
+
+/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
+ * name, but it is legally reserved for the 8250 driver. */
+#define SERIAL_ATMEL_MAJOR     TTY_MAJOR
+#define MINOR_START            64
+#define ATMEL_DEVICENAME       "ttyS"
+
+#endif
+
+#define ATMEL_ISR_PASS_LIMIT   256
+
+/* UART registers. CR is write-only, hence no GET macro */
+#define UART_PUT_CR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_CR)
+#define UART_GET_MR(port)      __raw_readl((port)->membase + ATMEL_US_MR)
+#define UART_PUT_MR(port,v)    __raw_writel(v, (port)->membase + ATMEL_US_MR)
+#define UART_PUT_IER(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IER)
+#define UART_PUT_IDR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_IDR)
+#define UART_GET_IMR(port)     __raw_readl((port)->membase + ATMEL_US_IMR)
+#define UART_GET_CSR(port)     __raw_readl((port)->membase + ATMEL_US_CSR)
+#define UART_GET_CHAR(port)    __raw_readl((port)->membase + ATMEL_US_RHR)
+#define UART_PUT_CHAR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_THR)
+#define UART_GET_BRGR(port)    __raw_readl((port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_BRGR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_RTOR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
+#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+
+ /* PDC registers */
+#define UART_PUT_PTCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
+#define UART_GET_PTSR(port)    __raw_readl((port)->membase + ATMEL_PDC_PTSR)
+
+#define UART_PUT_RPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
+#define UART_GET_RPR(port)     __raw_readl((port)->membase + ATMEL_PDC_RPR)
+#define UART_PUT_RCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
+#define UART_PUT_RNPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
+#define UART_PUT_RNCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
+
+#define UART_PUT_TPR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
+#define UART_PUT_TCR(port,v)   __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
+#define UART_GET_TCR(port)     __raw_readl((port)->membase + ATMEL_PDC_TCR)
+
+static int (*atmel_open_hook)(struct uart_port *);
+static void (*atmel_close_hook)(struct uart_port *);
+
+struct atmel_dma_buffer {
+       unsigned char   *buf;
+       dma_addr_t      dma_addr;
+       unsigned int    dma_size;
+       unsigned int    ofs;
+};
+
+struct atmel_uart_char {
+       u16             status;
+       u16             ch;
+};
+
+#define ATMEL_SERIAL_RINGSIZE 1024
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct atmel_uart_port {
+       struct uart_port        uart;           /* uart */
+       struct clk              *clk;           /* uart clock */
+       int                     may_wakeup;     /* cached value of device_may_wakeup for times we need to disable it */
+       u32                     backup_imr;     /* IMR saved during suspend */
+       int                     break_active;   /* break being received */
+
+       short                   use_dma_rx;     /* enable PDC receiver */
+       short                   pdc_rx_idx;     /* current PDC RX buffer */
+       struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
+
+       short                   use_dma_tx;     /* enable PDC transmitter */
+       struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
+
+       struct tasklet_struct   tasklet;
+       unsigned int            irq_status;
+       unsigned int            irq_status_prev;
+
+       struct circ_buf         rx_ring;
+
+       struct serial_rs485     rs485;          /* rs485 settings */
+       unsigned int            tx_done_mask;
+};
+
+static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+
+#ifdef SUPPORT_SYSRQ
+static struct console atmel_console;
+#endif
+
+static inline struct atmel_uart_port *
+to_atmel_uart_port(struct uart_port *uart)
+{
+       return container_of(uart, struct atmel_uart_port, uart);
+}
+
+#ifdef CONFIG_SERIAL_ATMEL_PDC
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       return atmel_port->use_dma_rx;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       return atmel_port->use_dma_tx;
+}
+#else
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+       return false;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+       return false;
+}
+#endif
+
+/* Enable or disable the rs485 support */
+void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int mode;
+
+       spin_lock(&port->lock);
+
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+       mode = UART_GET_MR(port);
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       atmel_port->rs485 = *rs485conf;
+
+       if (rs485conf->flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+               if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+               if (atmel_use_dma_tx(port))
+                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+                               ATMEL_US_TXBUFE;
+               else
+                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+       UART_PUT_MR(port, mode);
+
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+
+       spin_unlock(&port->lock);
+
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+ */
+static u_int atmel_tx_empty(struct uart_port *port)
+{
+       return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+}
+
+/*
+ * Set state of the modem control output lines
+ */
+static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+       unsigned int control = 0;
+       unsigned int mode;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+#ifdef CONFIG_ARCH_AT91RM9200
+       if (cpu_is_at91rm9200()) {
+               /*
+                * AT91RM9200 Errata #39: RTS0 is not internally connected
+                * to PA21. We need to drive the pin manually.
+                */
+               if (port->mapbase == AT91RM9200_BASE_US0) {
+                       if (mctrl & TIOCM_RTS)
+                               at91_set_gpio_value(AT91_PIN_PA21, 0);
+                       else
+                               at91_set_gpio_value(AT91_PIN_PA21, 1);
+               }
+       }
+#endif
+
+       if (mctrl & TIOCM_RTS)
+               control |= ATMEL_US_RTSEN;
+       else
+               control |= ATMEL_US_RTSDIS;
+
+       if (mctrl & TIOCM_DTR)
+               control |= ATMEL_US_DTREN;
+       else
+               control |= ATMEL_US_DTRDIS;
+
+       UART_PUT_CR(port, control);
+
+       /* Local loopback mode? */
+       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+       if (mctrl & TIOCM_LOOP)
+               mode |= ATMEL_US_CHMODE_LOC_LOOP;
+       else
+               mode |= ATMEL_US_CHMODE_NORMAL;
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+       UART_PUT_MR(port, mode);
+}
+
+/*
+ * Get state of the modem control input lines
+ */
+static u_int atmel_get_mctrl(struct uart_port *port)
+{
+       unsigned int status, ret = 0;
+
+       status = UART_GET_CSR(port);
+
+       /*
+        * The control signals are active low.
+        */
+       if (!(status & ATMEL_US_DCD))
+               ret |= TIOCM_CD;
+       if (!(status & ATMEL_US_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & ATMEL_US_DSR))
+               ret |= TIOCM_DSR;
+       if (!(status & ATMEL_US_RI))
+               ret |= TIOCM_RI;
+
+       return ret;
+}
+
+/*
+ * Stop transmitting.
+ */
+static void atmel_stop_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               /* disable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+       }
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_start_rx(port);
+}
+
+/*
+ * Start transmitting.
+ */
+static void atmel_start_tx(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+                       /* The transmitter is already running.  Yes, we
+                          really need this.*/
+                       return;
+
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+                       atmel_stop_rx(port);
+
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+       }
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+}
+
+/*
+ * start receiving - port is in process of being opened.
+ */
+static void atmel_start_rx(struct uart_port *port)
+{
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);  /* reset status and receiver */
+
+       if (atmel_use_dma_rx(port)) {
+               /* enable PDC controller */
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+}
+
+/*
+ * Stop receiving - port is in process of being closed.
+ */
+static void atmel_stop_rx(struct uart_port *port)
+{
+       if (atmel_use_dma_rx(port)) {
+               /* disable PDC receive */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+               UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+       } else {
+               UART_PUT_IDR(port, ATMEL_US_RXRDY);
+       }
+}
+
+/*
+ * Enable modem status interrupts
+ */
+static void atmel_enable_ms(struct uart_port *port)
+{
+       UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
+                       | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+}
+
+/*
+ * Control the transmission of a break signal
+ */
+static void atmel_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state != 0)
+               UART_PUT_CR(port, ATMEL_US_STTBRK);     /* start break */
+       else
+               UART_PUT_CR(port, ATMEL_US_STPBRK);     /* stop break */
+}
+
+/*
+ * Stores the incoming character in the ring buffer
+ */
+static void
+atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
+                    unsigned int ch)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       struct atmel_uart_char *c;
+
+       if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
+               /* Buffer overflow, ignore char */
+               return;
+
+       c = &((struct atmel_uart_char *)ring->buf)[ring->head];
+       c->status       = status;
+       c->ch           = ch;
+
+       /* Make sure the character is stored before we update head. */
+       smp_wmb();
+
+       ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+}
+
+/*
+ * Deal with parity, framing and overrun errors.
+ */
+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
+{
+       /* clear error */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+       if (status & ATMEL_US_RXBRK) {
+               /* ignore side-effect */
+               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+               port->icount.brk++;
+       }
+       if (status & ATMEL_US_PARE)
+               port->icount.parity++;
+       if (status & ATMEL_US_FRAME)
+               port->icount.frame++;
+       if (status & ATMEL_US_OVRE)
+               port->icount.overrun++;
+}
+
+/*
+ * Characters received (called from interrupt handler)
+ */
+static void atmel_rx_chars(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, ch;
+
+       status = UART_GET_CSR(port);
+       while (status & ATMEL_US_RXRDY) {
+               ch = UART_GET_CHAR(port);
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+                            || atmel_port->break_active)) {
+
+                       /* clear error */
+                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+                       if (status & ATMEL_US_RXBRK
+                           && !atmel_port->break_active) {
+                               atmel_port->break_active = 1;
+                               UART_PUT_IER(port, ATMEL_US_RXBRK);
+                       } else {
+                               /*
+                                * This is either the end-of-break
+                                * condition or we've received at
+                                * least one character without RXBRK
+                                * being set. In both cases, the next
+                                * RXBRK will indicate start-of-break.
+                                */
+                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+                               status &= ~ATMEL_US_RXBRK;
+                               atmel_port->break_active = 0;
+                       }
+               }
+
+               atmel_buffer_rx_char(port, status, ch);
+               status = UART_GET_CSR(port);
+       }
+
+       tasklet_schedule(&atmel_port->tasklet);
+}
+
+/*
+ * Transmit characters (called from tasklet with TXRDY interrupt
+ * disabled)
+ */
+static void atmel_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (!uart_circ_empty(xmit))
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+}
+
+/*
+ * receive interrupt handler.
+ */
+static void
+atmel_handle_receive(struct uart_port *port, unsigned int pending)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_rx(port)) {
+               /*
+                * PDC receive. Just schedule the tasklet and let it
+                * figure out the details.
+                *
+                * TODO: We're not handling error flags correctly at
+                * the moment.
+                */
+               if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
+                       UART_PUT_IDR(port, (ATMEL_US_ENDRX
+                                               | ATMEL_US_TIMEOUT));
+                       tasklet_schedule(&atmel_port->tasklet);
+               }
+
+               if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
+                               ATMEL_US_FRAME | ATMEL_US_PARE))
+                       atmel_pdc_rxerr(port, pending);
+       }
+
+       /* Interrupt receive */
+       if (pending & ATMEL_US_RXRDY)
+               atmel_rx_chars(port);
+       else if (pending & ATMEL_US_RXBRK) {
+               /*
+                * End of break detected. If it came along with a
+                * character, atmel_rx_chars will handle it.
+                */
+               UART_PUT_CR(port, ATMEL_US_RSTSTA);
+               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+               atmel_port->break_active = 0;
+       }
+}
+
+/*
+ * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
+ */
+static void
+atmel_handle_transmit(struct uart_port *port, unsigned int pending)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (pending & atmel_port->tx_done_mask) {
+               /* Either PDC or interrupt transmission */
+               UART_PUT_IDR(port, atmel_port->tx_done_mask);
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+}
+
+/*
+ * status flags interrupt handler.
+ */
+static void
+atmel_handle_status(struct uart_port *port, unsigned int pending,
+                   unsigned int status)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
+                               | ATMEL_US_CTSIC)) {
+               atmel_port->irq_status = status;
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status, pending, pass_counter = 0;
+
+       do {
+               status = UART_GET_CSR(port);
+               pending = status & UART_GET_IMR(port);
+               if (!pending)
+                       break;
+
+               atmel_handle_receive(port, pending);
+               atmel_handle_status(port, pending, status);
+               atmel_handle_transmit(port, pending);
+       } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
+
+       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+       int count;
+
+       /* nothing left to transmit? */
+       if (UART_GET_TCR(port))
+               return;
+
+       xmit->tail += pdc->ofs;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       port->icount.tx += pdc->ofs;
+       pdc->ofs = 0;
+
+       /* more to transmit - setup next transfer */
+
+       /* disable PDC transmit */
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+               dma_sync_single_for_device(port->dev,
+                                          pdc->dma_addr,
+                                          pdc->dma_size,
+                                          DMA_TO_DEVICE);
+
+               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               pdc->ofs = count;
+
+               UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
+               UART_PUT_TCR(port, count);
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+       } else {
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+                       /* DMA done, stop TX, start RX for RS485 */
+                       atmel_start_rx(port);
+               }
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void atmel_rx_from_ring(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       unsigned int flg;
+       unsigned int status;
+
+       while (ring->head != ring->tail) {
+               struct atmel_uart_char c;
+
+               /* Make sure c is loaded after head. */
+               smp_rmb();
+
+               c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
+
+               ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+
+               port->icount.rx++;
+               status = c.status;
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+                       if (status & ATMEL_US_RXBRK) {
+                               /* ignore side-effect */
+                               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       }
+                       if (status & ATMEL_US_PARE)
+                               port->icount.parity++;
+                       if (status & ATMEL_US_FRAME)
+                               port->icount.frame++;
+                       if (status & ATMEL_US_OVRE)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+
+                       if (status & ATMEL_US_RXBRK)
+                               flg = TTY_BREAK;
+                       else if (status & ATMEL_US_PARE)
+                               flg = TTY_PARITY;
+                       else if (status & ATMEL_US_FRAME)
+                               flg = TTY_FRAME;
+               }
+
+
+               if (uart_handle_sysrq_char(port, c.ch))
+                       continue;
+
+               uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
+       }
+
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->state->port.tty);
+       spin_lock(&port->lock);
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       struct atmel_dma_buffer *pdc;
+       int rx_idx = atmel_port->pdc_rx_idx;
+       unsigned int head;
+       unsigned int tail;
+       unsigned int count;
+
+       do {
+               /* Reset the UART timeout early so that we don't miss one */
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+
+               pdc = &atmel_port->pdc_rx[rx_idx];
+               head = UART_GET_RPR(port) - pdc->dma_addr;
+               tail = pdc->ofs;
+
+               /* If the PDC has switched buffers, RPR won't contain
+                * any address within the current buffer. Since head
+                * is unsigned, we just need a one-way comparison to
+                * find out.
+                *
+                * In this case, we just need to consume the entire
+                * buffer and resubmit it for DMA. This will clear the
+                * ENDRX bit as well, so that we can safely re-enable
+                * all interrupts below.
+                */
+               head = min(head, pdc->dma_size);
+
+               if (likely(head != tail)) {
+                       dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+
+                       /*
+                        * head will only wrap around when we recycle
+                        * the DMA buffer, and when that happens, we
+                        * explicitly set tail to 0. So head will
+                        * always be greater than tail.
+                        */
+                       count = head - tail;
+
+                       tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+
+                       dma_sync_single_for_device(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+
+                       port->icount.rx += count;
+                       pdc->ofs = head;
+               }
+
+               /*
+                * If the current buffer is full, we need to check if
+                * the next one contains any additional data.
+                */
+               if (head >= pdc->dma_size) {
+                       pdc->ofs = 0;
+                       UART_PUT_RNPR(port, pdc->dma_addr);
+                       UART_PUT_RNCR(port, pdc->dma_size);
+
+                       rx_idx = !rx_idx;
+                       atmel_port->pdc_rx_idx = rx_idx;
+               }
+       } while (head >= pdc->dma_size);
+
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->lock);
+
+       UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+}
+
+/*
+ * tasklet handling tty stuff outside the interrupt handler.
+ */
+static void atmel_tasklet_func(unsigned long data)
+{
+       struct uart_port *port = (struct uart_port *)data;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status;
+       unsigned int status_change;
+
+       /* The interrupt handler does not take the lock */
+       spin_lock(&port->lock);
+
+       if (atmel_use_dma_tx(port))
+               atmel_tx_dma(port);
+       else
+               atmel_tx_chars(port);
+
+       status = atmel_port->irq_status;
+       status_change = status ^ atmel_port->irq_status_prev;
+
+       if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
+                               | ATMEL_US_DCD | ATMEL_US_CTS)) {
+               /* TODO: All reads to CSR will clear these interrupts! */
+               if (status_change & ATMEL_US_RI)
+                       port->icount.rng++;
+               if (status_change & ATMEL_US_DSR)
+                       port->icount.dsr++;
+               if (status_change & ATMEL_US_DCD)
+                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+               if (status_change & ATMEL_US_CTS)
+                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
+
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+
+               atmel_port->irq_status_prev = status;
+       }
+
+       if (atmel_use_dma_rx(port))
+               atmel_rx_from_dma(port);
+       else
+               atmel_rx_from_ring(port);
+
+       spin_unlock(&port->lock);
+}
+
+/*
+ * Perform initialization and enable port for reception
+ */
+static int atmel_startup(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int retval;
+
+       /*
+        * Ensure that no interrupts are enabled otherwise when
+        * request_irq() is called we could get stuck trying to
+        * handle an unexpected interrupt
+        */
+       UART_PUT_IDR(port, -1);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+                       tty ? tty->name : "atmel_serial", port);
+       if (retval) {
+               printk("atmel_serial: atmel_startup - Can't get irq\n");
+               return retval;
+       }
+
+       /*
+        * Initialize DMA (if necessary)
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+                       pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+                       if (pdc->buf == NULL) {
+                               if (i != 0) {
+                                       dma_unmap_single(port->dev,
+                                               atmel_port->pdc_rx[0].dma_addr,
+                                               PDC_BUFFER_SIZE,
+                                               DMA_FROM_DEVICE);
+                                       kfree(atmel_port->pdc_rx[0].buf);
+                               }
+                               free_irq(port->irq, port);
+                               return -ENOMEM;
+                       }
+                       pdc->dma_addr = dma_map_single(port->dev,
+                                                      pdc->buf,
+                                                      PDC_BUFFER_SIZE,
+                                                      DMA_FROM_DEVICE);
+                       pdc->dma_size = PDC_BUFFER_SIZE;
+                       pdc->ofs = 0;
+               }
+
+               atmel_port->pdc_rx_idx = 0;
+
+               UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+               UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+               UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+               UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+               struct circ_buf *xmit = &port->state->xmit;
+
+               pdc->buf = xmit->buf;
+               pdc->dma_addr = dma_map_single(port->dev,
+                                              pdc->buf,
+                                              UART_XMIT_SIZE,
+                                              DMA_TO_DEVICE);
+               pdc->dma_size = UART_XMIT_SIZE;
+               pdc->ofs = 0;
+       }
+
+       /*
+        * If there is a specific "open" function (to register
+        * control line interrupts)
+        */
+       if (atmel_open_hook) {
+               retval = atmel_open_hook(port);
+               if (retval) {
+                       free_irq(port->irq, port);
+                       return retval;
+               }
+       }
+
+       /* Save current CSR for comparison in atmel_tasklet_func() */
+       atmel_port->irq_status_prev = UART_GET_CSR(port);
+       atmel_port->irq_status = atmel_port->irq_status_prev;
+
+       /*
+        * Finally, enable the serial port
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       /* enable xmit & rcvr */
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       if (atmel_use_dma_rx(port)) {
+               /* set UART timeout */
+               UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+               /* enable PDC controller */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               /* enable receive only */
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+
+       return 0;
+}
+
+/*
+ * Disable the port
+ */
+static void atmel_shutdown(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       /*
+        * Ensure everything is stopped.
+        */
+       atmel_stop_rx(port);
+       atmel_stop_tx(port);
+
+       /*
+        * Shut-down the DMA.
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+                       dma_unmap_single(port->dev,
+                                        pdc->dma_addr,
+                                        pdc->dma_size,
+                                        DMA_FROM_DEVICE);
+                       kfree(pdc->buf);
+               }
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+               dma_unmap_single(port->dev,
+                                pdc->dma_addr,
+                                pdc->dma_size,
+                                DMA_TO_DEVICE);
+       }
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+       UART_PUT_IDR(port, -1);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(port->irq, port);
+
+       /*
+        * If there is a specific "close" function (to unregister
+        * control line interrupts)
+        */
+       if (atmel_close_hook)
+               atmel_close_hook(port);
+}
+
+/*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void atmel_flush_buffer(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_dma_tx(port)) {
+               UART_PUT_TCR(port, 0);
+               atmel_port->pdc_tx.ofs = 0;
+       }
+}
+
+/*
+ * Power / Clock management.
+ */
+static void atmel_serial_pm(struct uart_port *port, unsigned int state,
+                           unsigned int oldstate)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       switch (state) {
+       case 0:
+               /*
+                * Enable the peripheral clock for this serial port.
+                * This is called on uart_open() or a resume event.
+                */
+               clk_enable(atmel_port->clk);
+
+               /* re-enable interrupts if we disabled some on suspend */
+               UART_PUT_IER(port, atmel_port->backup_imr);
+               break;
+       case 3:
+               /* Back up the interrupt mask and disable all interrupts */
+               atmel_port->backup_imr = UART_GET_IMR(port);
+               UART_PUT_IDR(port, -1);
+
+               /*
+                * Disable the peripheral clock for this serial port.
+                * This is called on uart_close() or a suspend event.
+                */
+               clk_disable(atmel_port->clk);
+               break;
+       default:
+               printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+       }
+}
+
+/*
+ * Change the port parameters
+ */
+static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int mode, imr, quot, baud;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       /* Get current mode register */
+       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
+                                       | ATMEL_US_USMODE);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+
+       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
+               quot /= 8;
+               mode |= ATMEL_US_USCLKS_MCK_DIV8;
+       }
+
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               mode |= ATMEL_US_CHRL_5;
+               break;
+       case CS6:
+               mode |= ATMEL_US_CHRL_6;
+               break;
+       case CS7:
+               mode |= ATMEL_US_CHRL_7;
+               break;
+       default:
+               mode |= ATMEL_US_CHRL_8;
+               break;
+       }
+
+       /* stop bits */
+       if (termios->c_cflag & CSTOPB)
+               mode |= ATMEL_US_NBSTOP_2;
+
+       /* parity */
+       if (termios->c_cflag & PARENB) {
+               /* Mark or Space parity */
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mode |= ATMEL_US_PAR_MARK;
+                       else
+                               mode |= ATMEL_US_PAR_SPACE;
+               } else if (termios->c_cflag & PARODD)
+                       mode |= ATMEL_US_PAR_ODD;
+               else
+                       mode |= ATMEL_US_PAR_EVEN;
+       } else
+               mode |= ATMEL_US_PAR_NONE;
+
+       /* hardware handshake (RTS/CTS) */
+       if (termios->c_cflag & CRTSCTS)
+               mode |= ATMEL_US_USMODE_HWHS;
+       else
+               mode |= ATMEL_US_USMODE_NORMAL;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->read_status_mask = ATMEL_US_OVRE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= ATMEL_US_RXBRK;
+
+       if (atmel_use_dma_rx(port))
+               /* need to enable error interrupts */
+               UART_PUT_IER(port, port->read_status_mask);
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= ATMEL_US_RXBRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= ATMEL_US_OVRE;
+       }
+       /* TODO: Ignore all characters if CREAD is set.*/
+
+       /* update the per-port timeout */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * save/disable interrupts. The tty layer will ensure that the
+        * transmitter is empty if requested by the caller, so there's
+        * no need to wait for it here.
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, -1);
+
+       /* disable receiver and transmitter */
+       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+
+       /* set the parity, stop bits and data size */
+       UART_PUT_MR(port, mode);
+
+       /* set the baud rate */
+       UART_PUT_BRGR(port, quot);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       /* restore interrupts */
+       UART_PUT_IER(port, imr);
+
+       /* CTS flow-control and modem-status interrupts */
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               port->ops->enable_ms(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return string describing the specified port
+ */
+static const char *atmel_type(struct uart_port *port)
+{
+       return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void atmel_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+       release_mem_region(port->mapbase, size);
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int atmel_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+       if (!request_mem_region(port->mapbase, size, "atmel_serial"))
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void atmel_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_ATMEL;
+               atmel_request_port(port);
+       }
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
+               ret = -EINVAL;
+       if (port->irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (port->uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)port->mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (port->iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int atmel_poll_get_char(struct uart_port *port)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
+               cpu_relax();
+
+       return UART_GET_CHAR(port);
+}
+
+static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+
+       UART_PUT_CHAR(port, ch);
+}
+#endif
+
+static int
+atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+       struct serial_rs485 rs485conf;
+
+       switch (cmd) {
+       case TIOCSRS485:
+               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+
+               atmel_config_rs485(port, &rs485conf);
+               break;
+
+       case TIOCGRS485:
+               if (copy_to_user((struct serial_rs485 *) arg,
+                                       &(to_atmel_uart_port(port)->rs485),
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+
+
+static struct uart_ops atmel_pops = {
+       .tx_empty       = atmel_tx_empty,
+       .set_mctrl      = atmel_set_mctrl,
+       .get_mctrl      = atmel_get_mctrl,
+       .stop_tx        = atmel_stop_tx,
+       .start_tx       = atmel_start_tx,
+       .stop_rx        = atmel_stop_rx,
+       .enable_ms      = atmel_enable_ms,
+       .break_ctl      = atmel_break_ctl,
+       .startup        = atmel_startup,
+       .shutdown       = atmel_shutdown,
+       .flush_buffer   = atmel_flush_buffer,
+       .set_termios    = atmel_set_termios,
+       .type           = atmel_type,
+       .release_port   = atmel_release_port,
+       .request_port   = atmel_request_port,
+       .config_port    = atmel_config_port,
+       .verify_port    = atmel_verify_port,
+       .pm             = atmel_serial_pm,
+       .ioctl          = atmel_ioctl,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = atmel_poll_get_char,
+       .poll_put_char  = atmel_poll_put_char,
+#endif
+};
+
+/*
+ * Configure the port from the platform device resource info.
+ */
+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+                                     struct platform_device *pdev)
+{
+       struct uart_port *port = &atmel_port->uart;
+       struct atmel_uart_data *data = pdev->dev.platform_data;
+
+       port->iotype            = UPIO_MEM;
+       port->flags             = UPF_BOOT_AUTOCONF;
+       port->ops               = &atmel_pops;
+       port->fifosize          = 1;
+       port->line              = pdev->id;
+       port->dev               = &pdev->dev;
+       port->mapbase   = pdev->resource[0].start;
+       port->irq       = pdev->resource[1].start;
+
+       tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+                       (unsigned long)port);
+
+       memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
+
+       if (data->regs)
+               /* Already mapped by setup code */
+               port->membase = data->regs;
+       else {
+               port->flags     |= UPF_IOREMAP;
+               port->membase   = NULL;
+       }
+
+       /* for console, the clock could already be configured */
+       if (!atmel_port->clk) {
+               atmel_port->clk = clk_get(&pdev->dev, "usart");
+               clk_enable(atmel_port->clk);
+               port->uartclk = clk_get_rate(atmel_port->clk);
+               clk_disable(atmel_port->clk);
+               /* only enable clock when USART is in use */
+       }
+
+       atmel_port->use_dma_rx = data->use_dma_rx;
+       atmel_port->use_dma_tx = data->use_dma_tx;
+       atmel_port->rs485       = data->rs485;
+       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+       else if (atmel_use_dma_tx(port)) {
+               port->fifosize = PDC_BUFFER_SIZE;
+               atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
+       } else {
+               atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+}
+
+/*
+ * Register board-specific modem-control line handlers.
+ */
+void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
+{
+       if (fns->enable_ms)
+               atmel_pops.enable_ms = fns->enable_ms;
+       if (fns->get_mctrl)
+               atmel_pops.get_mctrl = fns->get_mctrl;
+       if (fns->set_mctrl)
+               atmel_pops.set_mctrl = fns->set_mctrl;
+       atmel_open_hook         = fns->open;
+       atmel_close_hook        = fns->close;
+       atmel_pops.pm           = fns->pm;
+       atmel_pops.set_wake     = fns->set_wake;
+}
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+static void atmel_console_putchar(struct uart_port *port, int ch)
+{
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+       UART_PUT_CHAR(port, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void atmel_console_write(struct console *co, const char *s, u_int count)
+{
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, imr;
+       unsigned int pdc_tx;
+
+       /*
+        * First, save IMR and then disable interrupts
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
+
+       /* Store PDC transmit status and disable it */
+       pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+
+       uart_console_write(port, s, count, atmel_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore IMR
+        */
+       do {
+               status = UART_GET_CSR(port);
+       } while (!(status & ATMEL_US_TXRDY));
+
+       /* Restore PDC transmit status */
+       if (pdc_tx)
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+
+       /* set interrupts back the way they were */
+       UART_PUT_IER(port, imr);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init atmel_console_get_options(struct uart_port *port, int *baud,
+                                            int *parity, int *bits)
+{
+       unsigned int mr, quot;
+
+       /*
+        * If the baud rate generator isn't running, the port wasn't
+        * initialized by the boot loader.
+        */
+       quot = UART_GET_BRGR(port) & ATMEL_US_CD;
+       if (!quot)
+               return;
+
+       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
+       if (mr == ATMEL_US_CHRL_8)
+               *bits = 8;
+       else
+               *bits = 7;
+
+       mr = UART_GET_MR(port) & ATMEL_US_PAR;
+       if (mr == ATMEL_US_PAR_EVEN)
+               *parity = 'e';
+       else if (mr == ATMEL_US_PAR_ODD)
+               *parity = 'o';
+
+       /*
+        * The serial core only rounds down when matching this to a
+        * supported baud rate. Make sure we don't end up slightly
+        * lower than one of those, as it would make us fall through
+        * to a much lower baud rate than we really want.
+        */
+       *baud = port->uartclk / (16 * (quot - 1));
+}
+
+static int __init atmel_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->membase == NULL) {
+               /* Port not initialized yet - delay setup */
+               return -ENODEV;
+       }
+
+       clk_enable(atmel_ports[co->index].clk);
+
+       UART_PUT_IDR(port, -1);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               atmel_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver atmel_uart;
+
+static struct console atmel_console = {
+       .name           = ATMEL_DEVICENAME,
+       .write          = atmel_console_write,
+       .device         = uart_console_device,
+       .setup          = atmel_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &atmel_uart,
+};
+
+#define ATMEL_CONSOLE_DEVICE   (&atmel_console)
+
+/*
+ * Early console initialization (before VM subsystem initialized).
+ */
+static int __init atmel_console_init(void)
+{
+       if (atmel_default_console_device) {
+               add_preferred_console(ATMEL_DEVICENAME,
+                                     atmel_default_console_device->id, NULL);
+               atmel_init_port(&atmel_ports[atmel_default_console_device->id],
+                               atmel_default_console_device);
+               register_console(&atmel_console);
+       }
+
+       return 0;
+}
+
+console_initcall(atmel_console_init);
+
+/*
+ * Late console initialization.
+ */
+static int __init atmel_late_console_init(void)
+{
+       if (atmel_default_console_device
+           && !(atmel_console.flags & CON_ENABLED))
+               register_console(&atmel_console);
+
+       return 0;
+}
+
+core_initcall(atmel_late_console_init);
+
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+       return port->cons && port->cons->index == port->line;
+}
+
+#else
+#define ATMEL_CONSOLE_DEVICE   NULL
+
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+       return false;
+}
+#endif
+
+static struct uart_driver atmel_uart = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "atmel_serial",
+       .dev_name       = ATMEL_DEVICENAME,
+       .major          = SERIAL_ATMEL_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ATMEL_MAX_UART,
+       .cons           = ATMEL_CONSOLE_DEVICE,
+};
+
+#ifdef CONFIG_PM
+static bool atmel_serial_clk_will_stop(void)
+{
+#ifdef CONFIG_ARCH_AT91
+       return at91_suspend_entering_slow_clock();
+#else
+       return false;
+#endif
+}
+
+static int atmel_serial_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_is_console_port(port) && console_suspend_enabled) {
+               /* Drain the TX shifter */
+               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+                       cpu_relax();
+       }
+
+       /* we can not wake up if we're running on slow clock */
+       atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
+       if (atmel_serial_clk_will_stop())
+               device_set_wakeup_enable(&pdev->dev, 0);
+
+       uart_suspend_port(&atmel_uart, port);
+
+       return 0;
+}
+
+static int atmel_serial_resume(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       uart_resume_port(&atmel_uart, port);
+       device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
+
+       return 0;
+}
+#else
+#define atmel_serial_suspend NULL
+#define atmel_serial_resume NULL
+#endif
+
+static int __devinit atmel_serial_probe(struct platform_device *pdev)
+{
+       struct atmel_uart_port *port;
+       void *data;
+       int ret;
+
+       BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+
+       port = &atmel_ports[pdev->id];
+       port->backup_imr = 0;
+
+       atmel_init_port(port, pdev);
+
+       if (!atmel_use_dma_rx(&port->uart)) {
+               ret = -ENOMEM;
+               data = kmalloc(sizeof(struct atmel_uart_char)
+                               * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
+               if (!data)
+                       goto err_alloc_ring;
+               port->rx_ring.buf = data;
+       }
+
+       ret = uart_add_one_port(&atmel_uart, &port->uart);
+       if (ret)
+               goto err_add_port;
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+       if (atmel_is_console_port(&port->uart)
+                       && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
+               /*
+                * The serial core enabled the clock for us, so undo
+                * the clk_enable() in atmel_console_setup()
+                */
+               clk_disable(port->clk);
+       }
+#endif
+
+       device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, port);
+
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
+               UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
+       }
+
+       return 0;
+
+err_add_port:
+       kfree(port->rx_ring.buf);
+       port->rx_ring.buf = NULL;
+err_alloc_ring:
+       if (!atmel_is_console_port(&port->uart)) {
+               clk_put(port->clk);
+               port->clk = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit atmel_serial_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       int ret = 0;
+
+       device_init_wakeup(&pdev->dev, 0);
+       platform_set_drvdata(pdev, NULL);
+
+       ret = uart_remove_one_port(&atmel_uart, port);
+
+       tasklet_kill(&atmel_port->tasklet);
+       kfree(atmel_port->rx_ring.buf);
+
+       /* "port" is allocated statically, so we shouldn't free it */
+
+       clk_put(atmel_port->clk);
+
+       return ret;
+}
+
+static struct platform_driver atmel_serial_driver = {
+       .probe          = atmel_serial_probe,
+       .remove         = __devexit_p(atmel_serial_remove),
+       .suspend        = atmel_serial_suspend,
+       .resume         = atmel_serial_resume,
+       .driver         = {
+               .name   = "atmel_usart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init atmel_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&atmel_uart);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&atmel_serial_driver);
+       if (ret)
+               uart_unregister_driver(&atmel_uart);
+
+       return ret;
+}
+
+static void __exit atmel_serial_exit(void)
+{
+       platform_driver_unregister(&atmel_serial_driver);
+       uart_unregister_driver(&atmel_uart);
+}
+
+module_init(atmel_serial_init);
+module_exit(atmel_serial_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel_usart");
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
new file mode 100644 (file)
index 0000000..a1a0e55
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * 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.
+ *
+ * Derived from many drivers using generic_serial interface.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ *  Serial driver for BCM63xx integrated UART.
+ *
+ * Hardware flow control was _not_ tested since I only have RX/TX on
+ * my board.
+ */
+
+#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <bcm63xx_clk.h>
+#include <bcm63xx_irq.h>
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+
+#define BCM63XX_NR_UARTS       2
+
+static struct uart_port ports[BCM63XX_NR_UARTS];
+
+/*
+ * rx interrupt mask / stat
+ *
+ * mask:
+ *  - rx fifo full
+ *  - rx fifo above threshold
+ *  - rx fifo not empty for too long
+ */
+#define UART_RX_INT_MASK       (UART_IR_MASK(UART_IR_RXOVER) |         \
+                               UART_IR_MASK(UART_IR_RXTHRESH) |        \
+                               UART_IR_MASK(UART_IR_RXTIMEOUT))
+
+#define UART_RX_INT_STAT       (UART_IR_STAT(UART_IR_RXOVER) |         \
+                               UART_IR_STAT(UART_IR_RXTHRESH) |        \
+                               UART_IR_STAT(UART_IR_RXTIMEOUT))
+
+/*
+ * tx interrupt mask / stat
+ *
+ * mask:
+ * - tx fifo empty
+ * - tx fifo below threshold
+ */
+#define UART_TX_INT_MASK       (UART_IR_MASK(UART_IR_TXEMPTY) |        \
+                               UART_IR_MASK(UART_IR_TXTRESH))
+
+#define UART_TX_INT_STAT       (UART_IR_STAT(UART_IR_TXEMPTY) |        \
+                               UART_IR_STAT(UART_IR_TXTRESH))
+
+/*
+ * external input interrupt
+ *
+ * mask: any edge on CTS, DCD
+ */
+#define UART_EXTINP_INT_MASK   (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \
+                                UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD))
+
+/*
+ * handy uart register accessor
+ */
+static inline unsigned int bcm_uart_readl(struct uart_port *port,
+                                        unsigned int offset)
+{
+       return bcm_readl(port->membase + offset);
+}
+
+static inline void bcm_uart_writel(struct uart_port *port,
+                                 unsigned int value, unsigned int offset)
+{
+       bcm_writel(value, port->membase + offset);
+}
+
+/*
+ * serial core request to check if uart tx fifo is empty
+ */
+static unsigned int bcm_uart_tx_empty(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
+}
+
+/*
+ * serial core request to set RTS and DTR pin state and loopback mode
+ */
+static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
+       /* invert of written value is reflected on the pin */
+       if (!(mctrl & TIOCM_DTR))
+               val |= UART_MCTL_DTR_MASK;
+       if (!(mctrl & TIOCM_RTS))
+               val |= UART_MCTL_RTS_MASK;
+       bcm_uart_writel(port, val, UART_MCTL_REG);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       if (mctrl & TIOCM_LOOP)
+               val |= UART_CTL_LOOPBACK_MASK;
+       else
+               val &= ~UART_CTL_LOOPBACK_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to return RI, CTS, DCD and DSR pin state
+ */
+static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int val, mctrl;
+
+       mctrl = 0;
+       val = bcm_uart_readl(port, UART_EXTINP_REG);
+       if (val & UART_EXTINP_RI_MASK)
+               mctrl |= TIOCM_RI;
+       if (val & UART_EXTINP_CTS_MASK)
+               mctrl |= TIOCM_CTS;
+       if (val & UART_EXTINP_DCD_MASK)
+               mctrl |= TIOCM_CD;
+       if (val & UART_EXTINP_DSR_MASK)
+               mctrl |= TIOCM_DSR;
+       return mctrl;
+}
+
+/*
+ * serial core request to disable tx ASAP (used for flow control)
+ */
+static void bcm_uart_stop_tx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~(UART_CTL_TXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to (re)enable tx
+ */
+static void bcm_uart_start_tx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val |= UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= UART_CTL_TXEN_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to stop rx, called before port shutdown
+ */
+static void bcm_uart_stop_rx(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_RX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to enable modem status interrupt reporting
+ */
+static void bcm_uart_enable_ms(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val |= UART_IR_MASK(UART_IR_EXTIP);
+       bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to start/stop emitting break char
+ */
+static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       if (ctl)
+               val |= UART_CTL_XMITBRK_MASK;
+       else
+               val &= ~UART_CTL_XMITBRK_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * return port type in string format
+ */
+static const char *bcm_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL;
+}
+
+/*
+ * read all chars in rx fifo and send them to core
+ */
+static void bcm_uart_do_rx(struct uart_port *port)
+{
+       struct tty_struct *tty;
+       unsigned int max_count;
+
+       /* limit number of char read in interrupt, should not be
+        * higher than fifo size anyway since we're much faster than
+        * serial port */
+       max_count = 32;
+       tty = port->state->port.tty;
+       do {
+               unsigned int iestat, c, cstat;
+               char flag;
+
+               /* get overrun/fifo empty information from ier
+                * register */
+               iestat = bcm_uart_readl(port, UART_IR_REG);
+               if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
+                       break;
+
+               cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
+               port->icount.rx++;
+               flag = TTY_NORMAL;
+               c &= 0xff;
+
+               if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
+                       /* do stats first */
+                       if (cstat & UART_FIFO_BRKDET_MASK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       }
+
+                       if (cstat & UART_FIFO_PARERR_MASK)
+                               port->icount.parity++;
+                       if (cstat & UART_FIFO_FRAMEERR_MASK)
+                               port->icount.frame++;
+
+                       /* update flag wrt read_status_mask */
+                       cstat &= port->read_status_mask;
+                       if (cstat & UART_FIFO_BRKDET_MASK)
+                               flag = TTY_BREAK;
+                       if (cstat & UART_FIFO_FRAMEERR_MASK)
+                               flag = TTY_FRAME;
+                       if (cstat & UART_FIFO_PARERR_MASK)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(port, c))
+                       continue;
+
+               if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
+                       port->icount.overrun++;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+
+               if ((cstat & port->ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, c, flag);
+
+       } while (--max_count);
+
+       tty_flip_buffer_push(tty);
+}
+
+/*
+ * fill tx fifo with chars to send, stop when fifo is about to be full
+ * or when all chars have been sent.
+ */
+static void bcm_uart_do_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+       unsigned int val, max_count;
+
+       if (port->x_char) {
+               bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_tx_stopped(port)) {
+               bcm_uart_stop_tx(port);
+               return;
+       }
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit))
+               goto txq_empty;
+
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
+       max_count = port->fifosize - val;
+
+       while (max_count--) {
+               unsigned int c;
+
+               c = xmit->buf[xmit->tail];
+               bcm_uart_writel(port, c, UART_FIFO_REG);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               goto txq_empty;
+       return;
+
+txq_empty:
+       /* nothing to send, disable transmit interrupt */
+       val = bcm_uart_readl(port, UART_IR_REG);
+       val &= ~UART_TX_INT_MASK;
+       bcm_uart_writel(port, val, UART_IR_REG);
+       return;
+}
+
+/*
+ * process uart interrupt
+ */
+static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port;
+       unsigned int irqstat;
+
+       port = dev_id;
+       spin_lock(&port->lock);
+
+       irqstat = bcm_uart_readl(port, UART_IR_REG);
+       if (irqstat & UART_RX_INT_STAT)
+               bcm_uart_do_rx(port);
+
+       if (irqstat & UART_TX_INT_STAT)
+               bcm_uart_do_tx(port);
+
+       if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
+               unsigned int estat;
+
+               estat = bcm_uart_readl(port, UART_EXTINP_REG);
+               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
+                       uart_handle_cts_change(port,
+                                              estat & UART_EXTINP_CTS_MASK);
+               if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
+                       uart_handle_dcd_change(port,
+                                              estat & UART_EXTINP_DCD_MASK);
+       }
+
+       spin_unlock(&port->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * enable rx & tx operation on uart
+ */
+static void bcm_uart_enable(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * disable rx & tx operation on uart
+ */
+static void bcm_uart_disable(struct uart_port *port)
+{
+       unsigned int val;
+
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
+                UART_CTL_RXEN_MASK);
+       bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * clear all unread data in rx fifo and unsent data in tx fifo
+ */
+static void bcm_uart_flush(struct uart_port *port)
+{
+       unsigned int val;
+
+       /* empty rx and tx fifo */
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       /* read any pending char to make sure all irq status are
+        * cleared */
+       (void)bcm_uart_readl(port, UART_FIFO_REG);
+}
+
+/*
+ * serial core request to initialize uart and start rx operation
+ */
+static int bcm_uart_startup(struct uart_port *port)
+{
+       unsigned int val;
+       int ret;
+
+       /* mask all irq and flush port */
+       bcm_uart_disable(port);
+       bcm_uart_writel(port, 0, UART_IR_REG);
+       bcm_uart_flush(port);
+
+       /* clear any pending external input interrupt */
+       (void)bcm_uart_readl(port, UART_EXTINP_REG);
+
+       /* set rx/tx fifo thresh to fifo half size */
+       val = bcm_uart_readl(port, UART_MCTL_REG);
+       val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
+       val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
+       val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
+       bcm_uart_writel(port, val, UART_MCTL_REG);
+
+       /* set rx fifo timeout to 1 char time */
+       val = bcm_uart_readl(port, UART_CTL_REG);
+       val &= ~UART_CTL_RXTMOUTCNT_MASK;
+       val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
+       bcm_uart_writel(port, val, UART_CTL_REG);
+
+       /* report any edge on dcd and cts */
+       val = UART_EXTINP_INT_MASK;
+       val |= UART_EXTINP_DCD_NOSENSE_MASK;
+       val |= UART_EXTINP_CTS_NOSENSE_MASK;
+       bcm_uart_writel(port, val, UART_EXTINP_REG);
+
+       /* register irq and enable rx interrupts */
+       ret = request_irq(port->irq, bcm_uart_interrupt, 0,
+                         bcm_uart_type(port), port);
+       if (ret)
+               return ret;
+       bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
+       bcm_uart_enable(port);
+       return 0;
+}
+
+/*
+ * serial core request to flush & disable uart
+ */
+static void bcm_uart_shutdown(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       bcm_uart_writel(port, 0, UART_IR_REG);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       bcm_uart_disable(port);
+       bcm_uart_flush(port);
+       free_irq(port->irq, port);
+}
+
+/*
+ * serial core request to change current uart setting
+ */
+static void bcm_uart_set_termios(struct uart_port *port,
+                                struct ktermios *new,
+                                struct ktermios *old)
+{
+       unsigned int ctl, baud, quot, ier;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* disable uart while changing speed */
+       bcm_uart_disable(port);
+       bcm_uart_flush(port);
+
+       /* update Control register */
+       ctl = bcm_uart_readl(port, UART_CTL_REG);
+       ctl &= ~UART_CTL_BITSPERSYM_MASK;
+
+       switch (new->c_cflag & CSIZE) {
+       case CS5:
+               ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       case CS6:
+               ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       case CS7:
+               ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       default:
+               ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
+               break;
+       }
+
+       ctl &= ~UART_CTL_STOPBITS_MASK;
+       if (new->c_cflag & CSTOPB)
+               ctl |= UART_CTL_STOPBITS_2;
+       else
+               ctl |= UART_CTL_STOPBITS_1;
+
+       ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+       if (new->c_cflag & PARENB)
+               ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+       ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+       if (new->c_cflag & PARODD)
+               ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+       bcm_uart_writel(port, ctl, UART_CTL_REG);
+
+       /* update Baudword register */
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud) - 1;
+       bcm_uart_writel(port, quot, UART_BAUD_REG);
+
+       /* update Interrupt register */
+       ier = bcm_uart_readl(port, UART_IR_REG);
+
+       ier &= ~UART_IR_MASK(UART_IR_EXTIP);
+       if (UART_ENABLE_MS(port, new->c_cflag))
+               ier |= UART_IR_MASK(UART_IR_EXTIP);
+
+       bcm_uart_writel(port, ier, UART_IR_REG);
+
+       /* update read/ignore mask */
+       port->read_status_mask = UART_FIFO_VALID_MASK;
+       if (new->c_iflag & INPCK) {
+               port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
+               port->read_status_mask |= UART_FIFO_PARERR_MASK;
+       }
+       if (new->c_iflag & (BRKINT))
+               port->read_status_mask |= UART_FIFO_BRKDET_MASK;
+
+       port->ignore_status_mask = 0;
+       if (new->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
+       if (new->c_iflag & IGNBRK)
+               port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
+       if (!(new->c_cflag & CREAD))
+               port->ignore_status_mask |= UART_FIFO_VALID_MASK;
+
+       uart_update_timeout(port, new->c_cflag, baud);
+       bcm_uart_enable(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * serial core request to claim uart iomem
+ */
+static int bcm_uart_request_port(struct uart_port *port)
+{
+       unsigned int size;
+
+       size = RSET_UART_SIZE;
+       if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
+               dev_err(port->dev, "Memory region busy\n");
+               return -EBUSY;
+       }
+
+       port->membase = ioremap(port->mapbase, size);
+       if (!port->membase) {
+               dev_err(port->dev, "Unable to map registers\n");
+               release_mem_region(port->mapbase, size);
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/*
+ * serial core request to release uart iomem
+ */
+static void bcm_uart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, RSET_UART_SIZE);
+       iounmap(port->membase);
+}
+
+/*
+ * serial core request to do any port required autoconfiguration
+ */
+static void bcm_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               if (bcm_uart_request_port(port))
+                       return;
+               port->type = PORT_BCM63XX;
+       }
+}
+
+/*
+ * serial core request to check that port information in serinfo are
+ * suitable
+ */
+static int bcm_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *serinfo)
+{
+       if (port->type != PORT_BCM63XX)
+               return -EINVAL;
+       if (port->irq != serinfo->irq)
+               return -EINVAL;
+       if (port->iotype != serinfo->io_type)
+               return -EINVAL;
+       if (port->mapbase != (unsigned long)serinfo->iomem_base)
+               return -EINVAL;
+       return 0;
+}
+
+/* serial core callbacks */
+static struct uart_ops bcm_uart_ops = {
+       .tx_empty       = bcm_uart_tx_empty,
+       .get_mctrl      = bcm_uart_get_mctrl,
+       .set_mctrl      = bcm_uart_set_mctrl,
+       .start_tx       = bcm_uart_start_tx,
+       .stop_tx        = bcm_uart_stop_tx,
+       .stop_rx        = bcm_uart_stop_rx,
+       .enable_ms      = bcm_uart_enable_ms,
+       .break_ctl      = bcm_uart_break_ctl,
+       .startup        = bcm_uart_startup,
+       .shutdown       = bcm_uart_shutdown,
+       .set_termios    = bcm_uart_set_termios,
+       .type           = bcm_uart_type,
+       .release_port   = bcm_uart_release_port,
+       .request_port   = bcm_uart_request_port,
+       .config_port    = bcm_uart_config_port,
+       .verify_port    = bcm_uart_verify_port,
+};
+
+
+
+#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int tmout;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       tmout = 10000;
+       while (--tmout) {
+               unsigned int val;
+
+               val = bcm_uart_readl(port, UART_IR_REG);
+               if (val & UART_IR_STAT(UART_IR_TXEMPTY))
+                       break;
+               udelay(1);
+       }
+
+       /* Wait up to 1s for flow control if necessary */
+       if (port->flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout) {
+                       unsigned int val;
+
+                       val = bcm_uart_readl(port, UART_EXTINP_REG);
+                       if (val & UART_EXTINP_CTS_MASK)
+                               break;
+                       udelay(1);
+               }
+       }
+}
+
+/*
+ * output given char
+ */
+static void bcm_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmitr(port);
+       bcm_uart_writel(port, ch, UART_FIFO_REG);
+}
+
+/*
+ * console core request to output given string
+ */
+static void bcm_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       int locked;
+
+       port = &ports[co->index];
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               /* bcm_uart_interrupt() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else {
+               spin_lock(&port->lock);
+               locked = 1;
+       }
+
+       /* call helper to deal with \r\n */
+       uart_console_write(port, s, count, bcm_console_putchar);
+
+       /* and wait for char to be transmitted */
+       wait_for_xmitr(port);
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+/*
+ * console core request to setup given console, find matching uart
+ * port and setup it.
+ */
+static int bcm_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= BCM63XX_NR_UARTS)
+               return -EINVAL;
+       port = &ports[co->index];
+       if (!port->membase)
+               return -ENODEV;
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver bcm_uart_driver;
+
+static struct console bcm63xx_console = {
+       .name           = "ttyS",
+       .write          = bcm_console_write,
+       .device         = uart_console_device,
+       .setup          = bcm_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &bcm_uart_driver,
+};
+
+static int __init bcm63xx_console_init(void)
+{
+       register_console(&bcm63xx_console);
+       return 0;
+}
+
+console_initcall(bcm63xx_console_init);
+
+#define BCM63XX_CONSOLE        (&bcm63xx_console)
+#else
+#define BCM63XX_CONSOLE        NULL
+#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
+
+static struct uart_driver bcm_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "bcm63xx_uart",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = BCM63XX_NR_UARTS,
+       .cons           = BCM63XX_CONSOLE,
+};
+
+/*
+ * platform driver probe/remove callback
+ */
+static int __devinit bcm_uart_probe(struct platform_device *pdev)
+{
+       struct resource *res_mem, *res_irq;
+       struct uart_port *port;
+       struct clk *clk;
+       int ret;
+
+       if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
+               return -EINVAL;
+
+       if (ports[pdev->id].membase)
+               return -EBUSY;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem)
+               return -ENODEV;
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res_irq)
+               return -ENODEV;
+
+       clk = clk_get(&pdev->dev, "periph");
+       if (IS_ERR(clk))
+               return -ENODEV;
+
+       port = &ports[pdev->id];
+       memset(port, 0, sizeof(*port));
+       port->iotype = UPIO_MEM;
+       port->mapbase = res_mem->start;
+       port->irq = res_irq->start;
+       port->ops = &bcm_uart_ops;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
+       port->fifosize = 16;
+       port->uartclk = clk_get_rate(clk) / 2;
+       port->line = pdev->id;
+       clk_put(clk);
+
+       ret = uart_add_one_port(&bcm_uart_driver, port);
+       if (ret) {
+               ports[pdev->id].membase = 0;
+               return ret;
+       }
+       platform_set_drvdata(pdev, port);
+       return 0;
+}
+
+static int __devexit bcm_uart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+
+       port = platform_get_drvdata(pdev);
+       uart_remove_one_port(&bcm_uart_driver, port);
+       platform_set_drvdata(pdev, NULL);
+       /* mark port as free */
+       ports[pdev->id].membase = 0;
+       return 0;
+}
+
+/*
+ * platform driver stuff
+ */
+static struct platform_driver bcm_uart_platform_driver = {
+       .probe  = bcm_uart_probe,
+       .remove = __devexit_p(bcm_uart_remove),
+       .driver = {
+               .owner = THIS_MODULE,
+               .name  = "bcm63xx_uart",
+       },
+};
+
+static int __init bcm_uart_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&bcm_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&bcm_uart_platform_driver);
+       if (ret)
+               uart_unregister_driver(&bcm_uart_driver);
+
+       return ret;
+}
+
+static void __exit bcm_uart_exit(void)
+{
+       platform_driver_unregister(&bcm_uart_platform_driver);
+       uart_unregister_driver(&bcm_uart_driver);
+}
+
+module_init(bcm_uart_init);
+module_exit(bcm_uart_exit);
+
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/bfin_5xx.c b/drivers/tty/serial/bfin_5xx.c
new file mode 100644 (file)
index 0000000..9b1ff2b
--- /dev/null
@@ -0,0 +1,1597 @@
+/*
+ * Blackfin On-Chip Serial Driver
+ *
+ * Copyright 2006-2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#define DRIVER_NAME "bfin-uart"
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kgdb.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/portmux.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+
+#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
+#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
+#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
+#include <asm/bfin_serial.h>
+
+#ifdef CONFIG_SERIAL_BFIN_MODULE
+# undef CONFIG_EARLY_PRINTK
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_MODULE
+# undef CONFIG_EARLY_PRINTK
+#endif
+
+/* UART name and device definitions */
+#define BFIN_SERIAL_DEV_NAME   "ttyBF"
+#define BFIN_SERIAL_MAJOR      204
+#define BFIN_SERIAL_MINOR      64
+
+static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS];
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+
+# ifndef CONFIG_SERIAL_BFIN_PIO
+#  error KGDB only support UART in PIO mode.
+# endif
+
+static int kgdboc_port_line;
+static int kgdboc_break_enabled;
+#endif
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+#define DMA_RX_XCOUNT          512
+#define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
+
+#define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
+#else
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
+#endif
+
+static void bfin_serial_reset_irda(struct uart_port *port);
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->cts_pin < 0)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       /* CTS PIN is negative assertive. */
+       if (UART_GET_CTS(uart))
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->rts_pin < 0)
+               return;
+
+       /* RTS PIN is negative assertive. */
+       if (mctrl & TIOCM_RTS)
+               UART_ENABLE_RTS(uart);
+       else
+               UART_DISABLE_RTS(uart);
+}
+
+/*
+ * Handle any change of modem status signal.
+ */
+static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       unsigned int status;
+
+       status = bfin_serial_get_mctrl(&uart->port);
+       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       uart->scts = 1;
+       UART_CLEAR_SCTS(uart);
+       UART_CLEAR_IER(uart, EDSSI);
+#endif
+
+       return IRQ_HANDLED;
+}
+#else
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+#endif
+
+/*
+ * interrupts are disabled on entry
+ */
+static void bfin_serial_stop_tx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       struct circ_buf *xmit = &uart->port.state->xmit;
+#endif
+
+       while (!(UART_GET_LSR(uart) & TEMT))
+               cpu_relax();
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       disable_dma(uart->tx_dma_channel);
+       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+       uart->port.icount.tx += uart->tx_count;
+       uart->tx_count = 0;
+       uart->tx_done = 1;
+#else
+#ifdef CONFIG_BF54x
+       /* Clear TFI bit */
+       UART_PUT_LSR(uart, TFI);
+#endif
+       UART_CLEAR_IER(uart, ETBEI);
+#endif
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void bfin_serial_start_tx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       struct tty_struct *tty = uart->port.state->port.tty;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
+       /*
+        * To avoid losting RX interrupt, we reset IR function
+        * before sending data.
+        */
+       if (tty->termios->c_line == N_IRDA)
+               bfin_serial_reset_irda(port);
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       if (uart->tx_done)
+               bfin_serial_dma_tx_chars(uart);
+#else
+       UART_SET_IER(uart, ETBEI);
+       bfin_serial_tx_chars(uart);
+#endif
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void bfin_serial_stop_rx(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       UART_CLEAR_IER(uart, ERBFI);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void bfin_serial_enable_ms(struct uart_port *port)
+{
+}
+
+
+#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
+# define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
+# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
+#else
+# define UART_GET_ANOMALY_THRESHOLD(uart)    0
+# define UART_SET_ANOMALY_THRESHOLD(uart, v)
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_PIO
+static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
+{
+       struct tty_struct *tty = NULL;
+       unsigned int status, ch, flg;
+       static struct timeval anomaly_start = { .tv_sec = 0 };
+
+       status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       ch = UART_GET_CHAR(uart);
+       uart->port.icount.rx++;
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdb_connected && kgdboc_port_line == uart->port.line
+               && kgdboc_break_enabled)
+               if (ch == 0x3) {/* Ctrl + C */
+                       kgdb_breakpoint();
+                       return;
+               }
+
+       if (!uart->port.state || !uart->port.state->port.tty)
+               return;
+#endif
+       tty = uart->port.state->port.tty;
+
+       if (ANOMALY_05000363) {
+               /* The BF533 (and BF561) family of processors have a nice anomaly
+                * where they continuously generate characters for a "single" break.
+                * We have to basically ignore this flood until the "next" valid
+                * character comes across.  Due to the nature of the flood, it is
+                * not possible to reliably catch bytes that are sent too quickly
+                * after this break.  So application code talking to the Blackfin
+                * which sends a break signal must allow at least 1.5 character
+                * times after the end of the break for things to stabilize.  This
+                * timeout was picked as it must absolutely be larger than 1
+                * character time +/- some percent.  So 1.5 sounds good.  All other
+                * Blackfin families operate properly.  Woo.
+                */
+               if (anomaly_start.tv_sec) {
+                       struct timeval curr;
+                       suseconds_t usecs;
+
+                       if ((~ch & (~ch + 1)) & 0xff)
+                               goto known_good_char;
+
+                       do_gettimeofday(&curr);
+                       if (curr.tv_sec - anomaly_start.tv_sec > 1)
+                               goto known_good_char;
+
+                       usecs = 0;
+                       if (curr.tv_sec != anomaly_start.tv_sec)
+                               usecs += USEC_PER_SEC;
+                       usecs += curr.tv_usec - anomaly_start.tv_usec;
+
+                       if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+                               goto known_good_char;
+
+                       if (ch)
+                               anomaly_start.tv_sec = 0;
+                       else
+                               anomaly_start = curr;
+
+                       return;
+
+ known_good_char:
+                       status &= ~BI;
+                       anomaly_start.tv_sec = 0;
+               }
+       }
+
+       if (status & BI) {
+               if (ANOMALY_05000363)
+                       if (bfin_revid() < 5)
+                               do_gettimeofday(&anomaly_start);
+               uart->port.icount.brk++;
+               if (uart_handle_break(&uart->port))
+                       goto ignore_char;
+               status &= ~(PE | FE);
+       }
+       if (status & PE)
+               uart->port.icount.parity++;
+       if (status & OE)
+               uart->port.icount.overrun++;
+       if (status & FE)
+               uart->port.icount.frame++;
+
+       status &= uart->port.read_status_mask;
+
+       if (status & BI)
+               flg = TTY_BREAK;
+       else if (status & PE)
+               flg = TTY_PARITY;
+       else if (status & FE)
+               flg = TTY_FRAME;
+       else
+               flg = TTY_NORMAL;
+
+       if (uart_handle_sysrq_char(&uart->port, ch))
+               goto ignore_char;
+
+       uart_insert_char(&uart->port, status, OE, ch, flg);
+
+ ignore_char:
+       tty_flip_buffer_push(tty);
+}
+
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
+{
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+#ifdef CONFIG_BF54x
+               /* Clear TFI bit */
+               UART_PUT_LSR(uart, TFI);
+#endif
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
+               UART_CLEAR_IER(uart, ETBEI);
+               return;
+       }
+
+       if (uart->port.x_char) {
+               UART_PUT_CHAR(uart, uart->port.x_char);
+               uart->port.icount.tx++;
+               uart->port.x_char = 0;
+       }
+
+       while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
+               UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uart->port);
+}
+
+static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+
+       while (UART_GET_LSR(uart) & DR)
+               bfin_serial_rx_chars(uart);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+       spin_lock(&uart->port.lock);
+       if (UART_GET_LSR(uart) & THRE)
+               bfin_serial_tx_chars(uart);
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
+{
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+       uart->tx_done = 0;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+               uart->tx_count = 0;
+               uart->tx_done = 1;
+               return;
+       }
+
+       if (uart->port.x_char) {
+               UART_PUT_CHAR(uart, uart->port.x_char);
+               uart->port.icount.tx++;
+               uart->port.x_char = 0;
+       }
+
+       uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
+               uart->tx_count = UART_XMIT_SIZE - xmit->tail;
+       blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
+                                       (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
+       set_dma_config(uart->tx_dma_channel,
+               set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+                       INTR_ON_BUF,
+                       DIMENSION_LINEAR,
+                       DATA_SIZE_8,
+                       DMA_SYNC_RESTART));
+       set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
+       set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
+       set_dma_x_modify(uart->tx_dma_channel, 1);
+       SSYNC();
+       enable_dma(uart->tx_dma_channel);
+
+       UART_SET_IER(uart, ETBEI);
+}
+
+static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
+{
+       struct tty_struct *tty = uart->port.state->port.tty;
+       int i, flg, status;
+
+       status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       uart->port.icount.rx +=
+               CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
+               UART_XMIT_SIZE);
+
+       if (status & BI) {
+               uart->port.icount.brk++;
+               if (uart_handle_break(&uart->port))
+                       goto dma_ignore_char;
+               status &= ~(PE | FE);
+       }
+       if (status & PE)
+               uart->port.icount.parity++;
+       if (status & OE)
+               uart->port.icount.overrun++;
+       if (status & FE)
+               uart->port.icount.frame++;
+
+       status &= uart->port.read_status_mask;
+
+       if (status & BI)
+               flg = TTY_BREAK;
+       else if (status & PE)
+               flg = TTY_PARITY;
+       else if (status & FE)
+               flg = TTY_FRAME;
+       else
+               flg = TTY_NORMAL;
+
+       for (i = uart->rx_dma_buf.tail; ; i++) {
+               if (i >= UART_XMIT_SIZE)
+                       i = 0;
+               if (i == uart->rx_dma_buf.head)
+                       break;
+               if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+                       uart_insert_char(&uart->port, status, OE,
+                               uart->rx_dma_buf.buf[i], flg);
+       }
+
+ dma_ignore_char:
+       tty_flip_buffer_push(tty);
+}
+
+void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
+{
+       int x_pos, pos;
+
+       dma_disable_irq_nosync(uart->rx_dma_channel);
+       spin_lock_bh(&uart->rx_lock);
+
+       /* 2D DMA RX buffer ring is used. Because curr_y_count and
+        * curr_x_count can't be read as an atomic operation,
+        * curr_y_count should be read before curr_x_count. When
+        * curr_x_count is read, curr_y_count may already indicate
+        * next buffer line. But, the position calculated here is
+        * still indicate the old line. The wrong position data may
+        * be smaller than current buffer tail, which cause garbages
+        * are received if it is not prohibit.
+        */
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
+               uart->rx_dma_nrows = 0;
+       x_pos = DMA_RX_XCOUNT - x_pos;
+       if (x_pos == DMA_RX_XCOUNT)
+               x_pos = 0;
+
+       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
+       /* Ignore receiving data if new position is in the same line of
+        * current buffer tail and small.
+        */
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
+               uart->rx_dma_buf.head = pos;
+               bfin_serial_dma_rx_chars(uart);
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
+       }
+
+       spin_unlock_bh(&uart->rx_lock);
+       dma_enable_irq(uart->rx_dma_channel);
+
+       mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
+}
+
+static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       struct circ_buf *xmit = &uart->port.state->xmit;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
+       spin_lock(&uart->port.lock);
+       if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
+               disable_dma(uart->tx_dma_channel);
+               clear_dma_irqstat(uart->tx_dma_channel);
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
+               UART_CLEAR_IER(uart, ETBEI);
+               xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx += uart->tx_count;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&uart->port);
+
+               bfin_serial_dma_tx_chars(uart);
+       }
+
+       spin_unlock(&uart->port.lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       unsigned short irqstat;
+       int x_pos, pos;
+
+       spin_lock(&uart->rx_lock);
+       irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
+       clear_dma_irqstat(uart->rx_dma_channel);
+
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
+               uart->rx_dma_nrows = 0;
+
+       pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
+       if (pos > uart->rx_dma_buf.tail ||
+               uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
+               uart->rx_dma_buf.head = pos;
+               bfin_serial_dma_rx_chars(uart);
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
+       }
+
+       spin_unlock(&uart->rx_lock);
+
+       return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int bfin_serial_tx_empty(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short lsr;
+
+       lsr = UART_GET_LSR(uart);
+       if (lsr & TEMT)
+               return TIOCSER_TEMT;
+       else
+               return 0;
+}
+
+static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       u16 lcr = UART_GET_LCR(uart);
+       if (break_state)
+               lcr |= SB;
+       else
+               lcr &= ~SB;
+       UART_PUT_LCR(uart, lcr);
+       SSYNC();
+}
+
+static int bfin_serial_startup(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       dma_addr_t dma_handle;
+
+       if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
+               printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
+               return -EBUSY;
+       }
+
+       if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
+               printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
+               free_dma(uart->rx_dma_channel);
+               return -EBUSY;
+       }
+
+       set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
+       set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
+
+       uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
+       uart->rx_dma_buf.head = 0;
+       uart->rx_dma_buf.tail = 0;
+       uart->rx_dma_nrows = 0;
+
+       set_dma_config(uart->rx_dma_channel,
+               set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
+                               INTR_ON_ROW, DIMENSION_2D,
+                               DATA_SIZE_8,
+                               DMA_SYNC_RESTART));
+       set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
+       set_dma_x_modify(uart->rx_dma_channel, 1);
+       set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
+       set_dma_y_modify(uart->rx_dma_channel, 1);
+       set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
+       enable_dma(uart->rx_dma_channel);
+
+       uart->rx_dma_timer.data = (unsigned long)(uart);
+       uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
+       uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+       add_timer(&(uart->rx_dma_timer));
+#else
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
+               kgdboc_break_enabled = 0;
+       else {
+# endif
+       if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+            "BFIN_UART_RX", uart)) {
+               printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
+               return -EBUSY;
+       }
+
+       if (request_irq
+           (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
+            "BFIN_UART_TX", uart)) {
+               printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
+               free_irq(uart->port.irq, uart);
+               return -EBUSY;
+       }
+
+# ifdef CONFIG_BF54x
+       {
+               /*
+                * UART2 and UART3 on BF548 share interrupt PINs and DMA
+                * controllers with SPORT2 and SPORT3. UART rx and tx
+                * interrupts are generated in PIO mode only when configure
+                * their peripheral mapping registers properly, which means
+                * request corresponding DMA channels in PIO mode as well.
+                */
+               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+               switch (uart->port.irq) {
+               case IRQ_UART3_RX:
+                       uart_dma_ch_rx = CH_UART3_RX;
+                       uart_dma_ch_tx = CH_UART3_TX;
+                       break;
+               case IRQ_UART2_RX:
+                       uart_dma_ch_rx = CH_UART2_RX;
+                       uart_dma_ch_tx = CH_UART2_TX;
+                       break;
+               default:
+                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
+                       break;
+               };
+
+               if (uart_dma_ch_rx &&
+                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+               if (uart_dma_ch_tx &&
+                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+                       free_dma(uart_dma_ch_rx);
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+       }
+# endif
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       }
+# endif
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0) {
+               if (request_irq(gpio_to_irq(uart->cts_pin),
+                       bfin_serial_mctrl_cts_int,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
+                       uart->cts_pin = -1;
+                       pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
+               }
+       }
+       if (uart->rts_pin >= 0) {
+               gpio_direction_output(uart->rts_pin, 0);
+       }
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
+               bfin_serial_mctrl_cts_int,
+               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+               uart->cts_pin = -1;
+               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
+       }
+
+       /* CTS RTS PINs are negative assertive. */
+       UART_PUT_MCR(uart, ACTS);
+       UART_SET_IER(uart, EDSSI);
+#endif
+
+       UART_SET_IER(uart, ERBFI);
+       return 0;
+}
+
+static void bfin_serial_shutdown(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       disable_dma(uart->tx_dma_channel);
+       free_dma(uart->tx_dma_channel);
+       disable_dma(uart->rx_dma_channel);
+       free_dma(uart->rx_dma_channel);
+       del_timer(&(uart->rx_dma_timer));
+       dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
+#else
+#ifdef CONFIG_BF54x
+       switch (uart->port.irq) {
+       case IRQ_UART3_RX:
+               free_dma(CH_UART3_RX);
+               free_dma(CH_UART3_TX);
+               break;
+       case IRQ_UART2_RX:
+               free_dma(CH_UART2_RX);
+               free_dma(CH_UART2_TX);
+               break;
+       default:
+               break;
+       };
+#endif
+       free_irq(uart->port.irq, uart);
+       free_irq(uart->port.irq+1, uart);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0)
+               free_irq(gpio_to_irq(uart->cts_pin), uart);
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->cts_pin >= 0)
+               free_irq(uart->status_irq, uart);
+#endif
+}
+
+static void
+bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned short val, ier, lcr = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS8:
+               lcr = WLS(8);
+               break;
+       case CS7:
+               lcr = WLS(7);
+               break;
+       case CS6:
+               lcr = WLS(6);
+               break;
+       case CS5:
+               lcr = WLS(5);
+               break;
+       default:
+               printk(KERN_ERR "%s: word lengh not supported\n",
+                       __func__);
+       }
+
+       /* Anomaly notes:
+        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
+        */
+       if (termios->c_cflag & CSTOPB) {
+               if (ANOMALY_05000231)
+                       printk(KERN_WARNING "STOP bits other than 1 is not "
+                               "supported in case of anomaly 05000231.\n");
+               else
+                       lcr |= STB;
+       }
+       if (termios->c_cflag & PARENB)
+               lcr |= PEN;
+       if (!(termios->c_cflag & PARODD))
+               lcr |= EPS;
+       if (termios->c_cflag & CMSPAR)
+               lcr |= STP;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
+
+       port->read_status_mask = OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (FE | PE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= BI;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= FE | PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= OE;
+       }
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       /* If discipline is not IRDA, apply ANOMALY_05000230 */
+       if (termios->c_line != N_IRDA)
+               quot -= ANOMALY_05000230;
+
+       UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
+
+       /* Disable UART */
+       ier = UART_GET_IER(uart);
+       UART_DISABLE_INTS(uart);
+
+       /* Set DLAB in LCR to Access DLL and DLH */
+       UART_SET_DLAB(uart);
+
+       UART_PUT_DLL(uart, quot & 0xFF);
+       UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+       SSYNC();
+
+       /* Clear DLAB in LCR to Access THR RBR IER */
+       UART_CLEAR_DLAB(uart);
+
+       UART_PUT_LCR(uart, lcr);
+
+       /* Enable UART */
+       UART_ENABLE_INTS(uart, ier);
+
+       val = UART_GET_GCTL(uart);
+       val |= UCEN;
+       UART_PUT_GCTL(uart, val);
+
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static const char *bfin_serial_type(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void bfin_serial_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int bfin_serial_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void bfin_serial_config_port(struct uart_port *port, int flags)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           bfin_serial_request_port(&uart->port) == 0)
+               uart->port.type = PORT_BFIN;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_BFIN and PORT_UNKNOWN
+ */
+static int
+bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return 0;
+}
+
+/*
+ * Enable the IrDA function if tty->ldisc.num is N_IRDA.
+ * In other cases, disable IrDA function.
+ */
+static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short val;
+
+       switch (ld) {
+       case N_IRDA:
+               val = UART_GET_GCTL(uart);
+               val |= (IREN | RPOLC);
+               UART_PUT_GCTL(uart, val);
+               break;
+       default:
+               val = UART_GET_GCTL(uart);
+               val &= ~(IREN | RPOLC);
+               UART_PUT_GCTL(uart, val);
+       }
+}
+
+static void bfin_serial_reset_irda(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned short val;
+
+       val = UART_GET_GCTL(uart);
+       val &= ~(IREN | RPOLC);
+       UART_PUT_GCTL(uart, val);
+       SSYNC();
+       val |= (IREN | RPOLC);
+       UART_PUT_GCTL(uart, val);
+       SSYNC();
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Anomaly notes:
+ *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
+ *             losing other bits of UART_LSR is not a problem here.
+ */
+static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       while (!(UART_GET_LSR(uart) & THRE))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       UART_PUT_CHAR(uart, (unsigned char)chr);
+}
+
+static int bfin_serial_poll_get_char(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned char chr;
+
+       while (!(UART_GET_LSR(uart) & DR))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       chr = UART_GET_CHAR(uart);
+
+       return chr;
+}
+#endif
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+static void bfin_kgdboc_port_shutdown(struct uart_port *port)
+{
+       if (kgdboc_break_enabled) {
+               kgdboc_break_enabled = 0;
+               bfin_serial_shutdown(port);
+       }
+}
+
+static int bfin_kgdboc_port_startup(struct uart_port *port)
+{
+       kgdboc_port_line = port->line;
+       kgdboc_break_enabled = !bfin_serial_startup(port);
+       return 0;
+}
+#endif
+
+static struct uart_ops bfin_serial_pops = {
+       .tx_empty       = bfin_serial_tx_empty,
+       .set_mctrl      = bfin_serial_set_mctrl,
+       .get_mctrl      = bfin_serial_get_mctrl,
+       .stop_tx        = bfin_serial_stop_tx,
+       .start_tx       = bfin_serial_start_tx,
+       .stop_rx        = bfin_serial_stop_rx,
+       .enable_ms      = bfin_serial_enable_ms,
+       .break_ctl      = bfin_serial_break_ctl,
+       .startup        = bfin_serial_startup,
+       .shutdown       = bfin_serial_shutdown,
+       .set_termios    = bfin_serial_set_termios,
+       .set_ldisc      = bfin_serial_set_ldisc,
+       .type           = bfin_serial_type,
+       .release_port   = bfin_serial_release_port,
+       .request_port   = bfin_serial_request_port,
+       .config_port    = bfin_serial_config_port,
+       .verify_port    = bfin_serial_verify_port,
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
+       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
+#endif
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = bfin_serial_poll_put_char,
+       .poll_get_char  = bfin_serial_poll_get_char,
+#endif
+};
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
+                          int *parity, int *bits)
+{
+       unsigned short status;
+
+       status = UART_GET_IER(uart) & (ERBFI | ETBEI);
+       if (status == (ERBFI | ETBEI)) {
+               /* ok, the port was enabled */
+               u16 lcr, dlh, dll;
+
+               lcr = UART_GET_LCR(uart);
+
+               *parity = 'n';
+               if (lcr & PEN) {
+                       if (lcr & EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+               switch (lcr & 0x03) {
+                       case 0: *bits = 5; break;
+                       case 1: *bits = 6; break;
+                       case 2: *bits = 7; break;
+                       case 3: *bits = 8; break;
+               }
+               /* Set DLAB in LCR to Access DLL and DLH */
+               UART_SET_DLAB(uart);
+
+               dll = UART_GET_DLL(uart);
+               dlh = UART_GET_DLH(uart);
+
+               /* Clear DLAB in LCR to Access THR RBR IER */
+               UART_CLEAR_DLAB(uart);
+
+               *baud = get_sclk() / (16*(dll | dlh << 8));
+       }
+       pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
+}
+
+static struct uart_driver bfin_serial_reg;
+
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       while (!(UART_GET_LSR(uart) & THRE))
+               barrier();
+       UART_PUT_CHAR(uart, ch);
+}
+
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+                defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#define CLASS_BFIN_CONSOLE     "bfin-console"
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct bfin_serial_port *uart = bfin_serial_ports[co->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
+       uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
+static int __init
+bfin_serial_console_setup(struct console *co, char *options)
+{
+       struct bfin_serial_port *uart;
+       int baud = 57600;
+       int bits = 8;
+       int parity = 'n';
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+       int flow = 'r';
+# else
+       int flow = 'n';
+# endif
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS)
+               return -ENODEV;
+
+       uart = bfin_serial_ports[co->index];
+       if (!uart)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               bfin_serial_console_get_options(uart, &baud, &parity, &bits);
+
+       return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+}
+
+static struct console bfin_serial_console = {
+       .name           = BFIN_SERIAL_DEV_NAME,
+       .write          = bfin_serial_console_write,
+       .device         = uart_console_device,
+       .setup          = bfin_serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &bfin_serial_reg,
+};
+#define BFIN_SERIAL_CONSOLE    &bfin_serial_console
+#else
+#define BFIN_SERIAL_CONSOLE    NULL
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+#ifdef CONFIG_EARLY_PRINTK
+static struct bfin_serial_port bfin_earlyprintk_port;
+#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk"
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count)
+{
+       unsigned long flags;
+
+       if (bfin_earlyprintk_port.port.line != co->index)
+               return;
+
+       spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags);
+       uart_console_write(&bfin_earlyprintk_port.port, s, count,
+               bfin_serial_console_putchar);
+       spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags);
+}
+
+/*
+ * This should have a .setup or .early_setup in it, but then things get called
+ * without the command line options, and the baud rate gets messed up - so
+ * don't let the common infrastructure play with things. (see calls to setup
+ * & earlysetup in ./kernel/printk.c:register_console()
+ */
+static struct __initdata console bfin_early_serial_console = {
+       .name = "early_BFuart",
+       .write = bfin_earlyprintk_console_write,
+       .device = uart_console_device,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data  = &bfin_serial_reg,
+};
+#endif
+
+static struct uart_driver bfin_serial_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = DRIVER_NAME,
+       .dev_name               = BFIN_SERIAL_DEV_NAME,
+       .major                  = BFIN_SERIAL_MAJOR,
+       .minor                  = BFIN_SERIAL_MINOR,
+       .nr                     = BFIN_UART_NR_PORTS,
+       .cons                   = BFIN_SERIAL_CONSOLE,
+};
+
+static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       return uart_suspend_port(&bfin_serial_reg, &uart->port);
+}
+
+static int bfin_serial_resume(struct platform_device *pdev)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       return uart_resume_port(&bfin_serial_reg, &uart->port);
+}
+
+static int bfin_serial_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct bfin_serial_port *uart = NULL;
+       int ret = 0;
+
+       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+               dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n");
+               return -ENOENT;
+       }
+
+       if (bfin_serial_ports[pdev->id] == NULL) {
+
+               uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+               if (!uart) {
+                       dev_err(&pdev->dev,
+                               "fail to malloc bfin_serial_port\n");
+                       return -ENOMEM;
+               }
+               bfin_serial_ports[pdev->id] = uart;
+
+#ifdef CONFIG_EARLY_PRINTK
+               if (!(bfin_earlyprintk_port.port.membase
+                       && bfin_earlyprintk_port.port.line == pdev->id)) {
+                       /*
+                        * If the peripheral PINs of current port is allocated
+                        * in earlyprintk probe stage, don't do it again.
+                        */
+#endif
+               ret = peripheral_request_list(
+                       (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "fail to request bfin serial peripherals\n");
+                       goto out_error_free_mem;
+               }
+#ifdef CONFIG_EARLY_PRINTK
+               }
+#endif
+
+               spin_lock_init(&uart->port.lock);
+               uart->port.uartclk   = get_sclk();
+               uart->port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
+               uart->port.ops       = &bfin_serial_pops;
+               uart->port.line      = pdev->id;
+               uart->port.iotype    = UPIO_MEM;
+               uart->port.flags     = UPF_BOOT_AUTOCONF;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+                       ret = -ENOENT;
+                       goto out_error_free_peripherals;
+               }
+
+               uart->port.membase = ioremap(res->start,
+                       res->end - res->start);
+               if (!uart->port.membase) {
+                       dev_err(&pdev->dev, "Cannot map uart IO\n");
+                       ret = -ENXIO;
+                       goto out_error_free_peripherals;
+               }
+               uart->port.mapbase = res->start;
+
+               uart->port.irq = platform_get_irq(pdev, 0);
+               if (uart->port.irq < 0) {
+                       dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+               uart->status_irq = platform_get_irq(pdev, 1);
+               if (uart->status_irq < 0) {
+                       dev_err(&pdev->dev, "No uart status IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+               spin_lock_init(&uart->rx_lock);
+               uart->tx_done       = 1;
+               uart->tx_count      = 0;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "No uart TX DMA channel specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+               uart->tx_dma_channel = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "No uart RX DMA channel specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+               uart->rx_dma_channel = res->start;
+
+               init_timer(&(uart->rx_dma_timer));
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               if (res == NULL)
+                       uart->cts_pin = -1;
+               else
+                       uart->cts_pin = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+               if (res == NULL)
+                       uart->rts_pin = -1;
+               else
+                       uart->rts_pin = res->start;
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
+               if (uart->rts_pin >= 0)
+                       gpio_request(uart->rts_pin, DRIVER_NAME);
+# endif
+#endif
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       if (!is_early_platform_device(pdev)) {
+#endif
+               uart = bfin_serial_ports[pdev->id];
+               uart->port.dev = &pdev->dev;
+               dev_set_drvdata(&pdev->dev, uart);
+               ret = uart_add_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       }
+#endif
+
+       if (!ret)
+               return 0;
+
+       if (uart) {
+out_error_unmap:
+               iounmap(uart->port.membase);
+out_error_free_peripherals:
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+               kfree(uart);
+               bfin_serial_ports[pdev->id] = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit bfin_serial_remove(struct platform_device *pdev)
+{
+       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (uart) {
+               uart_remove_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+               if (uart->rts_pin >= 0)
+                       gpio_free(uart->rts_pin);
+#endif
+               iounmap(uart->port.membase);
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+               kfree(uart);
+               bfin_serial_ports[pdev->id] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver bfin_serial_driver = {
+       .probe          = bfin_serial_probe,
+       .remove         = __devexit_p(bfin_serial_remove),
+       .suspend        = bfin_serial_suspend,
+       .resume         = bfin_serial_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
+static __initdata struct early_platform_driver early_bfin_serial_driver = {
+       .class_str = CLASS_BFIN_CONSOLE,
+       .pdrv = &bfin_serial_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init bfin_serial_rs_console_init(void)
+{
+       early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME);
+
+       early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0);
+
+       register_console(&bfin_serial_console);
+
+       return 0;
+}
+console_initcall(bfin_serial_rs_console_init);
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK
+/*
+ * Memory can't be allocated dynamically during earlyprink init stage.
+ * So, do individual probe for earlyprink with a static uart port variable.
+ */
+static int bfin_earlyprintk_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+               dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n");
+               return -ENOENT;
+       }
+
+       ret = peripheral_request_list(
+               (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+       if (ret) {
+               dev_err(&pdev->dev,
+                               "fail to request bfin serial peripherals\n");
+                       return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+               ret = -ENOENT;
+               goto out_error_free_peripherals;
+       }
+
+       bfin_earlyprintk_port.port.membase = ioremap(res->start,
+                       res->end - res->start);
+       if (!bfin_earlyprintk_port.port.membase) {
+               dev_err(&pdev->dev, "Cannot map uart IO\n");
+               ret = -ENXIO;
+               goto out_error_free_peripherals;
+       }
+       bfin_earlyprintk_port.port.mapbase = res->start;
+       bfin_earlyprintk_port.port.line = pdev->id;
+       bfin_earlyprintk_port.port.uartclk = get_sclk();
+       bfin_earlyprintk_port.port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
+       spin_lock_init(&bfin_earlyprintk_port.port.lock);
+
+       return 0;
+
+out_error_free_peripherals:
+       peripheral_free_list(
+               (unsigned short *)pdev->dev.platform_data);
+
+       return ret;
+}
+
+static struct platform_driver bfin_earlyprintk_driver = {
+       .probe          = bfin_earlyprintk_probe,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
+       .class_str = CLASS_BFIN_EARLYPRINTK,
+       .pdrv = &bfin_earlyprintk_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+                                               unsigned int cflag)
+{
+       struct ktermios t;
+       char port_name[20];
+
+       if (port < 0 || port >= BFIN_UART_NR_PORTS)
+               return NULL;
+
+       /*
+        * Only probe resource of the given port in earlyprintk boot arg.
+        * The expected port id should be indicated in port name string.
+        */
+       snprintf(port_name, 20, DRIVER_NAME ".%d", port);
+       early_platform_driver_register(&early_bfin_earlyprintk_driver,
+               port_name);
+       early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0);
+
+       if (!bfin_earlyprintk_port.port.membase)
+               return NULL;
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       /*
+        * If we are using early serial, don't let the normal console rewind
+        * log buffer, since that causes things to be printed multiple times
+        */
+       bfin_serial_console.flags &= ~CON_PRINTBUFFER;
+#endif
+
+       bfin_early_serial_console.index = port;
+       t.c_cflag = cflag;
+       t.c_iflag = 0;
+       t.c_oflag = 0;
+       t.c_lflag = ICANON;
+       t.c_line = port;
+       bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t);
+
+       return &bfin_early_serial_console;
+}
+#endif /* CONFIG_EARLY_PRINTK */
+
+static int __init bfin_serial_init(void)
+{
+       int ret;
+
+       pr_info("Blackfin serial driver\n");
+
+       ret = uart_register_driver(&bfin_serial_reg);
+       if (ret) {
+               pr_err("failed to register %s:%d\n",
+                       bfin_serial_reg.driver_name, ret);
+       }
+
+       ret = platform_driver_register(&bfin_serial_driver);
+       if (ret) {
+               pr_err("fail to register bfin uart\n");
+               uart_unregister_driver(&bfin_serial_reg);
+       }
+
+       return ret;
+}
+
+static void __exit bfin_serial_exit(void)
+{
+       platform_driver_unregister(&bfin_serial_driver);
+       uart_unregister_driver(&bfin_serial_reg);
+}
+
+
+module_init(bfin_serial_init);
+module_exit(bfin_serial_exit);
+
+MODULE_AUTHOR("Sonic Zhang, Aubrey Li");
+MODULE_DESCRIPTION("Blackfin generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
+MODULE_ALIAS("platform:bfin-uart");
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
new file mode 100644 (file)
index 0000000..e95c524
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ * Blackfin On-Chip Sport Emulated UART Driver
+ *
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
+ */
+
+/* #define DEBUG */
+
+#define DRV_NAME "bfin-sport-uart"
+#define DEVICE_NAME    "ttySS"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/bfin_sport.h>
+#include <asm/delay.h>
+#include <asm/portmux.h>
+
+#include "bfin_sport_uart.h"
+
+struct sport_uart_port {
+       struct uart_port        port;
+       int                     err_irq;
+       unsigned short          csize;
+       unsigned short          rxmask;
+       unsigned short          txmask1;
+       unsigned short          txmask2;
+       unsigned char           stopb;
+/*     unsigned char           parib; */
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       int cts_pin;
+       int rts_pin;
+#endif
+};
+
+static int sport_uart_tx_chars(struct sport_uart_port *up);
+static void sport_stop_tx(struct uart_port *port);
+
+static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+{
+       pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value,
+               up->txmask1, up->txmask2);
+
+       /* Place Start and Stop bits */
+       __asm__ __volatile__ (
+               "%[val] <<= 1;"
+               "%[val] = %[val] & %[mask1];"
+               "%[val] = %[val] | %[mask2];"
+               : [val]"+d"(value)
+               : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2)
+               : "ASTAT"
+       );
+       pr_debug("%s value:%x\n", __func__, value);
+
+       SPORT_PUT_TX(up, value);
+}
+
+static inline unsigned char rx_one_byte(struct sport_uart_port *up)
+{
+       unsigned int value;
+       unsigned char extract;
+       u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
+
+       if ((up->csize + up->stopb) > 7)
+               value = SPORT_GET_RX32(up);
+       else
+               value = SPORT_GET_RX(up);
+
+       pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value,
+               up->csize, up->rxmask);
+
+       /* Extract data */
+       __asm__ __volatile__ (
+               "%[extr] = 0;"
+               "%[mask1] = %[rxmask];"
+               "%[mask2] = 0x0200(Z);"
+               "%[shift] = 0;"
+               "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
+               ".Lloop_s:"
+               "%[tmp] = extract(%[val], %[mask1].L)(Z);"
+               "%[tmp] <<= %[shift];"
+               "%[extr] = %[extr] | %[tmp];"
+               "%[mask1] = %[mask1] - %[mask2];"
+               ".Lloop_e:"
+               "%[shift] += 1;"
+               : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp),
+                 [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2)
+               : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize)
+               : "ASTAT", "LB0", "LC0", "LT0"
+       );
+
+       pr_debug("      extract:%x\n", extract);
+       return extract;
+}
+
+static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
+{
+       int tclkdiv, rclkdiv;
+       unsigned int sclk = get_sclk();
+
+       /* Set TCR1 and TCR2, TFSR is not enabled for uart */
+       SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
+       SPORT_PUT_TCR2(up, size + 1);
+       pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+
+       /* Set RCR1 and RCR2 */
+       SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
+       SPORT_PUT_RCR2(up, (size + 1) * 2 - 1);
+       pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+
+       tclkdiv = sclk / (2 * baud_rate) - 1;
+       /* The actual uart baud rate of devices vary between +/-2%. The sport
+        * RX sample rate should be faster than the double of the worst case,
+        * otherwise, wrong data are received. So, set sport RX clock to be
+        * 3% faster.
+        */
+       rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1;
+       SPORT_PUT_TCLKDIV(up, tclkdiv);
+       SPORT_PUT_RCLKDIV(up, rclkdiv);
+       SSYNC();
+       pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n",
+                       __func__, sclk, baud_rate, tclkdiv, rclkdiv);
+
+       return 0;
+}
+
+static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch;
+
+       spin_lock(&up->port.lock);
+
+       while (SPORT_GET_STAT(up) & RXNE) {
+               ch = rx_one_byte(up);
+               up->port.icount.rx++;
+
+               if (!uart_handle_sysrq_char(&up->port, ch))
+                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+       tty_flip_buffer_push(tty);
+
+       spin_unlock(&up->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+
+       spin_lock(&up->port.lock);
+       sport_uart_tx_chars(up);
+       spin_unlock(&up->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int stat = SPORT_GET_STAT(up);
+
+       spin_lock(&up->port.lock);
+
+       /* Overflow in RX FIFO */
+       if (stat & ROVF) {
+               up->port.icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
+       }
+       /* These should not happen */
+       if (stat & (TOVF | TUVF | RUVF)) {
+               pr_err("SPORT Error:%s %s %s\n",
+                      (stat & TOVF) ? "TX overflow" : "",
+                      (stat & TUVF) ? "TX underflow" : "",
+                      (stat & RUVF) ? "RX underflow" : "");
+               SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+               SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+       }
+       SSYNC();
+
+       spin_unlock(&up->port.lock);
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       if (up->cts_pin < 0)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       /* CTS PIN is negative assertive. */
+       if (SPORT_UART_GET_CTS(up))
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       if (up->rts_pin < 0)
+               return;
+
+       /* RTS PIN is negative assertive. */
+       if (mctrl & TIOCM_RTS)
+               SPORT_UART_ENABLE_RTS(up);
+       else
+               SPORT_UART_DISABLE_RTS(up);
+}
+
+/*
+ * Handle any change of modem status signal.
+ */
+static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
+       unsigned int status;
+
+       status = sport_get_mctrl(&up->port);
+       uart_handle_cts_change(&up->port, status & TIOCM_CTS);
+
+       return IRQ_HANDLED;
+}
+#else
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+       return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       pr_debug("%s enter\n", __func__);
+}
+#endif
+
+/* Reqeust IRQ, Setup clock */
+static int sport_startup(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       ret = request_irq(up->port.irq, sport_uart_rx_irq, 0,
+               "SPORT_UART_RX", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT RX interrupt\n");
+               return ret;
+       }
+
+       ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0,
+               "SPORT_UART_TX", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT TX interrupt\n");
+               goto fail1;
+       }
+
+       ret = request_irq(up->err_irq, sport_uart_err_irq, 0,
+               "SPORT_UART_STATUS", up);
+       if (ret) {
+               dev_err(port->dev, "unable to request SPORT status interrupt\n");
+               goto fail2;
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       if (up->cts_pin >= 0) {
+               if (request_irq(gpio_to_irq(up->cts_pin),
+                       sport_mctrl_cts_int,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                       IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
+                       up->cts_pin = -1;
+                       dev_info(port->dev, "Unable to attach BlackFin UART \
+                               over SPORT CTS interrupt. So, disable it.\n");
+               }
+       }
+       if (up->rts_pin >= 0)
+               gpio_direction_output(up->rts_pin, 0);
+#endif
+
+       return 0;
+ fail2:
+       free_irq(up->port.irq+1, up);
+ fail1:
+       free_irq(up->port.irq, up);
+
+       return ret;
+}
+
+/*
+ * sport_uart_tx_chars
+ *
+ * ret 1 means need to enable sport.
+ * ret 0 means do nothing.
+ */
+static int sport_uart_tx_chars(struct sport_uart_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       if (SPORT_GET_STAT(up) & TXF)
+               return 0;
+
+       if (up->port.x_char) {
+               tx_one_byte(up, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               /* The waiting loop to stop SPORT TX from TX interrupt is
+                * too long. This may block SPORT RX interrupts and cause
+                * RX FIFO overflow. So, do stop sport TX only after the last
+                * char in TX FIFO is moved into the shift register.
+                */
+               if (SPORT_GET_STAT(up) & TXHRE)
+                       sport_stop_tx(&up->port);
+               return 0;
+       }
+
+       while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+               tx_one_byte(up, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+               up->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return 1;
+}
+
+static unsigned int sport_tx_empty(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       unsigned int stat;
+
+       stat = SPORT_GET_STAT(up);
+       pr_debug("%s stat:%04x\n", __func__, stat);
+       if (stat & TXHRE) {
+               return TIOCSER_TEMT;
+       } else
+               return 0;
+}
+
+static void sport_stop_tx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+
+       if (!(SPORT_GET_TCR1(up) & TSPEN))
+               return;
+
+       /* Although the hold register is empty, last byte is still in shift
+        * register and not sent out yet. So, put a dummy data into TX FIFO.
+        * Then, sport tx stops when last byte is shift out and the dummy
+        * data is moved into the shift register.
+        */
+       SPORT_PUT_TX(up, 0xffff);
+       while (!(SPORT_GET_STAT(up) & TXHRE))
+               cpu_relax();
+
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+       SSYNC();
+
+       return;
+}
+
+static void sport_start_tx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+
+       /* Write data into SPORT FIFO before enable SPROT to transmit */
+       if (sport_uart_tx_chars(up)) {
+               /* Enable transmit, then an interrupt will generated */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+               SSYNC();
+       }
+
+       pr_debug("%s exit\n", __func__);
+}
+
+static void sport_stop_rx(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       /* Disable sport to stop rx */
+       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+       SSYNC();
+}
+
+static void sport_enable_ms(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static void sport_break_ctl(struct uart_port *port, int break_state)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static void sport_shutdown(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       dev_dbg(port->dev, "%s enter\n", __func__);
+
+       /* Disable sport */
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+       SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+       SSYNC();
+
+       free_irq(up->port.irq, up);
+       free_irq(up->port.irq+1, up);
+       free_irq(up->err_irq, up);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       if (up->cts_pin >= 0)
+               free_irq(gpio_to_irq(up->cts_pin), up);
+#endif
+}
+
+static const char *sport_type(struct uart_port *port)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL;
+}
+
+static void sport_release_port(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+}
+
+static int sport_request_port(struct uart_port *port)
+{
+       pr_debug("%s enter\n", __func__);
+       return 0;
+}
+
+static void sport_config_port(struct uart_port *port, int flags)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       pr_debug("%s enter\n", __func__);
+       up->port.type = PORT_BFIN_SPORT;
+}
+
+static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       pr_debug("%s enter\n", __func__);
+       return 0;
+}
+
+static void sport_set_termios(struct uart_port *port,
+               struct ktermios *termios, struct ktermios *old)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+       unsigned long flags;
+       int i;
+
+       pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS8:
+               up->csize = 8;
+               break;
+       case CS7:
+               up->csize = 7;
+               break;
+       case CS6:
+               up->csize = 6;
+               break;
+       case CS5:
+               up->csize = 5;
+               break;
+       default:
+               pr_warning("requested word length not supported\n");
+       }
+
+       if (termios->c_cflag & CSTOPB) {
+               up->stopb = 1;
+       }
+       if (termios->c_cflag & PARENB) {
+               pr_warning("PAREN bits is not supported yet\n");
+               /* up->parib = 1; */
+       }
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       port->read_status_mask = 0;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+
+       /* RX extract mask */
+       up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
+       /* TX masks, 8 bit data and 1 bit stop for example:
+        * mask1 = b#0111111110
+        * mask2 = b#1000000000
+        */
+       for (i = 0, up->txmask1 = 0; i < up->csize; i++)
+               up->txmask1 |= (1<<i);
+       up->txmask2 = (1<<i);
+       if (up->stopb) {
+               ++i;
+               up->txmask2 |= (1<<i);
+       }
+       up->txmask1 <<= 1;
+       up->txmask2 <<= 1;
+       /* uart baud rate */
+       port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
+
+       /* Disable UART */
+       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+
+       sport_uart_setup(up, up->csize + up->stopb, port->uartclk);
+
+       /* driver TX line high after config, one dummy data is
+        * necessary to stop sport after shift one byte
+        */
+       SPORT_PUT_TX(up, 0xffff);
+       SPORT_PUT_TX(up, 0xffff);
+       SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+       SSYNC();
+       while (!(SPORT_GET_STAT(up) & TXHRE))
+               cpu_relax();
+       SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+       SSYNC();
+
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, port->uartclk);
+
+       /* Enable sport rx */
+       SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN);
+       SSYNC();
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+struct uart_ops sport_uart_ops = {
+       .tx_empty       = sport_tx_empty,
+       .set_mctrl      = sport_set_mctrl,
+       .get_mctrl      = sport_get_mctrl,
+       .stop_tx        = sport_stop_tx,
+       .start_tx       = sport_start_tx,
+       .stop_rx        = sport_stop_rx,
+       .enable_ms      = sport_enable_ms,
+       .break_ctl      = sport_break_ctl,
+       .startup        = sport_startup,
+       .shutdown       = sport_shutdown,
+       .set_termios    = sport_set_termios,
+       .type           = sport_type,
+       .release_port   = sport_release_port,
+       .request_port   = sport_request_port,
+       .config_port    = sport_config_port,
+       .verify_port    = sport_verify_port,
+};
+
+#define BFIN_SPORT_UART_MAX_PORTS 4
+
+static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+#define CLASS_BFIN_SPORT_CONSOLE       "bfin-sport-console"
+
+static int __init
+sport_uart_console_setup(struct console *co, char *options)
+{
+       struct sport_uart_port *up;
+       int baud = 57600;
+       int bits = 8;
+       int parity = 'n';
+# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+       int flow = 'r';
+# else
+       int flow = 'n';
+# endif
+
+       /* Check whether an invalid uart number has been specified */
+       if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
+               return -ENODEV;
+
+       up = bfin_sport_uart_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static void sport_uart_console_putchar(struct uart_port *port, int ch)
+{
+       struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+       while (SPORT_GET_STAT(up) & TXF)
+               barrier();
+
+       tx_one_byte(up, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sport_uart_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct sport_uart_port *up = bfin_sport_uart_ports[co->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (SPORT_GET_TCR1(up) & TSPEN)
+               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+       else {
+               /* dummy data to start sport */
+               while (SPORT_GET_STAT(up) & TXF)
+                       barrier();
+               SPORT_PUT_TX(up, 0xffff);
+               /* Enable transmit, then an interrupt will generated */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+               SSYNC();
+
+               uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+
+               /* Although the hold register is empty, last byte is still in shift
+                * register and not sent out yet. So, put a dummy data into TX FIFO.
+                * Then, sport tx stops when last byte is shift out and the dummy
+                * data is moved into the shift register.
+                */
+               while (SPORT_GET_STAT(up) & TXF)
+                       barrier();
+               SPORT_PUT_TX(up, 0xffff);
+               while (!(SPORT_GET_STAT(up) & TXHRE))
+                       barrier();
+
+               /* Stop sport tx transfer */
+               SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+               SSYNC();
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver sport_uart_reg;
+
+static struct console sport_uart_console = {
+       .name           = DEVICE_NAME,
+       .write          = sport_uart_console_write,
+       .device         = uart_console_device,
+       .setup          = sport_uart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &sport_uart_reg,
+};
+
+#define SPORT_UART_CONSOLE     (&sport_uart_console)
+#else
+#define SPORT_UART_CONSOLE     NULL
+#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */
+
+
+static struct uart_driver sport_uart_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRV_NAME,
+       .dev_name       = DEVICE_NAME,
+       .major          = 204,
+       .minor          = 84,
+       .nr             = BFIN_SPORT_UART_MAX_PORTS,
+       .cons           = SPORT_UART_CONSOLE,
+};
+
+#ifdef CONFIG_PM
+static int sport_uart_suspend(struct device *dev)
+{
+       struct sport_uart_port *sport = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s enter\n", __func__);
+       if (sport)
+               uart_suspend_port(&sport_uart_reg, &sport->port);
+
+       return 0;
+}
+
+static int sport_uart_resume(struct device *dev)
+{
+       struct sport_uart_port *sport = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s enter\n", __func__);
+       if (sport)
+               uart_resume_port(&sport_uart_reg, &sport->port);
+
+       return 0;
+}
+
+static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
+       .suspend        = sport_uart_suspend,
+       .resume         = sport_uart_resume,
+};
+#endif
+
+static int __devinit sport_uart_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct sport_uart_port *sport;
+       int ret = 0;
+
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
+
+       if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) {
+               dev_err(&pdev->dev, "Wrong sport uart platform device id.\n");
+               return -ENOENT;
+       }
+
+       if (bfin_sport_uart_ports[pdev->id] == NULL) {
+               bfin_sport_uart_ports[pdev->id] =
+                       kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
+               sport = bfin_sport_uart_ports[pdev->id];
+               if (!sport) {
+                       dev_err(&pdev->dev,
+                               "Fail to malloc sport_uart_port\n");
+                       return -ENOMEM;
+               }
+
+               ret = peripheral_request_list(
+                       (unsigned short *)pdev->dev.platform_data, DRV_NAME);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Fail to request SPORT peripherals\n");
+                       goto out_error_free_mem;
+               }
+
+               spin_lock_init(&sport->port.lock);
+               sport->port.fifosize  = SPORT_TX_FIFO_SIZE,
+               sport->port.ops       = &sport_uart_ops;
+               sport->port.line      = pdev->id;
+               sport->port.iotype    = UPIO_MEM;
+               sport->port.flags     = UPF_BOOT_AUTOCONF;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res == NULL) {
+                       dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+                       ret = -ENOENT;
+                       goto out_error_free_peripherals;
+               }
+
+               sport->port.membase = ioremap(res->start, resource_size(res));
+               if (!sport->port.membase) {
+                       dev_err(&pdev->dev, "Cannot map sport IO\n");
+                       ret = -ENXIO;
+                       goto out_error_free_peripherals;
+               }
+               sport->port.mapbase = res->start;
+
+               sport->port.irq = platform_get_irq(pdev, 0);
+               if (sport->port.irq < 0) {
+                       dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+               sport->err_irq = platform_get_irq(pdev, 1);
+               if (sport->err_irq < 0) {
+                       dev_err(&pdev->dev, "No sport status IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               if (res == NULL)
+                       sport->cts_pin = -1;
+               else
+                       sport->cts_pin = res->start;
+
+               res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+               if (res == NULL)
+                       sport->rts_pin = -1;
+               else
+                       sport->rts_pin = res->start;
+
+               if (sport->rts_pin >= 0)
+                       gpio_request(sport->rts_pin, DRV_NAME);
+#endif
+       }
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+       if (!is_early_platform_device(pdev)) {
+#endif
+               sport = bfin_sport_uart_ports[pdev->id];
+               sport->port.dev = &pdev->dev;
+               dev_set_drvdata(&pdev->dev, sport);
+               ret = uart_add_one_port(&sport_uart_reg, &sport->port);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+       }
+#endif
+       if (!ret)
+               return 0;
+
+       if (sport) {
+out_error_unmap:
+               iounmap(sport->port.membase);
+out_error_free_peripherals:
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+               kfree(sport);
+               bfin_sport_uart_ports[pdev->id] = NULL;
+       }
+
+       return ret;
+}
+
+static int __devexit sport_uart_remove(struct platform_device *pdev)
+{
+       struct sport_uart_port *sport = platform_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (sport) {
+               uart_remove_one_port(&sport_uart_reg, &sport->port);
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+               if (sport->rts_pin >= 0)
+                       gpio_free(sport->rts_pin);
+#endif
+               iounmap(sport->port.membase);
+               peripheral_free_list(
+                       (unsigned short *)pdev->dev.platform_data);
+               kfree(sport);
+               bfin_sport_uart_ports[pdev->id] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver sport_uart_driver = {
+       .probe          = sport_uart_probe,
+       .remove         = __devexit_p(sport_uart_remove),
+       .driver         = {
+               .name   = DRV_NAME,
+#ifdef CONFIG_PM
+               .pm     = &bfin_sport_uart_dev_pm_ops,
+#endif
+       },
+};
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+static __initdata struct early_platform_driver early_sport_uart_driver = {
+       .class_str = CLASS_BFIN_SPORT_CONSOLE,
+       .pdrv = &sport_uart_driver,
+       .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init sport_uart_rs_console_init(void)
+{
+       early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
+
+       early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
+               BFIN_SPORT_UART_MAX_PORTS, 0);
+
+       register_console(&sport_uart_console);
+
+       return 0;
+}
+console_initcall(sport_uart_rs_console_init);
+#endif
+
+static int __init sport_uart_init(void)
+{
+       int ret;
+
+       pr_info("Blackfin uart over sport driver\n");
+
+       ret = uart_register_driver(&sport_uart_reg);
+       if (ret) {
+               pr_err("failed to register %s:%d\n",
+                               sport_uart_reg.driver_name, ret);
+               return ret;
+       }
+
+       ret = platform_driver_register(&sport_uart_driver);
+       if (ret) {
+               pr_err("failed to register sport uart driver:%d\n", ret);
+               uart_unregister_driver(&sport_uart_reg);
+       }
+
+       return ret;
+}
+module_init(sport_uart_init);
+
+static void __exit sport_uart_exit(void)
+{
+       platform_driver_unregister(&sport_uart_driver);
+       uart_unregister_driver(&sport_uart_reg);
+}
+module_exit(sport_uart_exit);
+
+MODULE_AUTHOR("Sonic Zhang, Roy Huang");
+MODULE_DESCRIPTION("Blackfin serial over SPORT driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/bfin_sport_uart.h b/drivers/tty/serial/bfin_sport_uart.h
new file mode 100644 (file)
index 0000000..6d06ce1
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Blackfin On-Chip Sport Emulated UART Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf 
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
+ */
+
+#ifndef _BFIN_SPORT_UART_H
+#define _BFIN_SPORT_UART_H
+
+#define OFFSET_TCR1            0x00    /* Transmit Configuration 1 Register */
+#define OFFSET_TCR2            0x04    /* Transmit Configuration 2 Register */
+#define OFFSET_TCLKDIV         0x08    /* Transmit Serial Clock Divider Register */
+#define OFFSET_TFSDIV          0x0C    /* Transmit Frame Sync Divider Register */
+#define OFFSET_TX              0x10    /* Transmit Data Register               */
+#define OFFSET_RX              0x18    /* Receive Data Register                */
+#define OFFSET_RCR1            0x20    /* Receive Configuration 1 Register     */
+#define OFFSET_RCR2            0x24    /* Receive Configuration 2 Register     */
+#define OFFSET_RCLKDIV         0x28    /* Receive Serial Clock Divider Register */
+#define OFFSET_RFSDIV          0x2c    /* Receive Frame Sync Divider Register */
+#define OFFSET_STAT            0x30    /* Status Register                      */
+
+#define SPORT_GET_TCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR1))
+#define SPORT_GET_TCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_TCR2))
+#define SPORT_GET_TCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
+#define SPORT_GET_TFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+#define SPORT_GET_TX(sport)            bfin_read16(((sport)->port.membase + OFFSET_TX))
+#define SPORT_GET_RX(sport)            bfin_read16(((sport)->port.membase + OFFSET_RX))
+/*
+ * If another interrupt fires while doing a 32-bit read from RX FIFO,
+ * a fake RX underflow error will be generated.  So disable interrupts
+ * to prevent interruption while reading the FIFO.
+ */
+#define SPORT_GET_RX32(sport) \
+({ \
+       unsigned int __ret; \
+       if (ANOMALY_05000473) \
+               local_irq_disable(); \
+       __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
+       if (ANOMALY_05000473) \
+               local_irq_enable(); \
+       __ret; \
+})
+#define SPORT_GET_RCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+#define SPORT_GET_RCR2(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+#define SPORT_GET_RCLKDIV(sport)       bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
+#define SPORT_GET_RFSDIV(sport)                bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
+#define SPORT_GET_STAT(sport)          bfin_read16(((sport)->port.membase + OFFSET_STAT))
+
+#define SPORT_PUT_TCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
+#define SPORT_PUT_TCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
+#define SPORT_PUT_TCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
+#define SPORT_PUT_TFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
+#define SPORT_PUT_TX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_TX), v)
+#define SPORT_PUT_RX(sport, v)         bfin_write16(((sport)->port.membase + OFFSET_RX), v)
+#define SPORT_PUT_RCR1(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
+#define SPORT_PUT_RCR2(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
+#define SPORT_PUT_RCLKDIV(sport, v)    bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
+#define SPORT_PUT_RFSDIV(sport, v)     bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
+#define SPORT_PUT_STAT(sport, v)       bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
+
+#define SPORT_TX_FIFO_SIZE     8
+
+#define SPORT_UART_GET_CTS(x)          gpio_get_value(x->cts_pin)
+#define SPORT_UART_DISABLE_RTS(x)      gpio_set_value(x->rts_pin, 1)
+#define SPORT_UART_ENABLE_RTS(x)       gpio_set_value(x->rts_pin, 0)
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
+       || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
+# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+#endif
+
+#endif /* _BFIN_SPORT_UART_H */
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
new file mode 100644 (file)
index 0000000..b6acd19
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ *  linux/drivers/char/clps711x.c
+ *
+ *  Driver for CLPS711x serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/hardware/clps7111.h>
+
+#define UART_NR                2
+
+#define SERIAL_CLPS711X_MAJOR  204
+#define SERIAL_CLPS711X_MINOR  40
+#define SERIAL_CLPS711X_NR     UART_NR
+
+/*
+ * We use the relevant SYSCON register as a base address for these ports.
+ */
+#define UBRLCR(port)           ((port)->iobase + UBRLCR1 - SYSCON1)
+#define UARTDR(port)           ((port)->iobase + UARTDR1 - SYSCON1)
+#define SYSFLG(port)           ((port)->iobase + SYSFLG1 - SYSCON1)
+#define SYSCON(port)           ((port)->iobase + SYSCON1 - SYSCON1)
+
+#define TX_IRQ(port)           ((port)->irq)
+#define RX_IRQ(port)           ((port)->irq + 1)
+
+#define UART_ANY_ERR           (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
+
+#define tx_enabled(port)       ((port)->unused[0])
+
+static void clps711xuart_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               disable_irq(TX_IRQ(port));
+               tx_enabled(port) = 0;
+       }
+}
+
+static void clps711xuart_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(TX_IRQ(port));
+               tx_enabled(port) = 1;
+       }
+}
+
+static void clps711xuart_stop_rx(struct uart_port *port)
+{
+       disable_irq(RX_IRQ(port));
+}
+
+static void clps711xuart_enable_ms(struct uart_port *port)
+{
+}
+
+static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = clps_readl(SYSFLG(port));
+       while (!(status & SYSFLG_URXFE)) {
+               ch = clps_readl(UARTDR(port));
+
+               port->icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(ch & UART_ANY_ERR)) {
+                       if (ch & UARTDR_PARERR)
+                               port->icount.parity++;
+                       else if (ch & UARTDR_FRMERR)
+                               port->icount.frame++;
+                       if (ch & UARTDR_OVERR)
+                               port->icount.overrun++;
+
+                       ch &= port->read_status_mask;
+
+                       if (ch & UARTDR_PARERR)
+                               flg = TTY_PARITY;
+                       else if (ch & UARTDR_FRMERR)
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       port->sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               /*
+                * CHECK: does overrun affect the current character?
+                * ASSUMPTION: it does not.
+                */
+               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+
+       ignore_char:
+               status = clps_readl(SYSFLG(port));
+       }
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count;
+
+       if (port->x_char) {
+               clps_writel(port->x_char, UARTDR(port));
+               port->icount.tx++;
+               port->x_char = 0;
+               return IRQ_HANDLED;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               clps711xuart_stop_tx(port);
+               return IRQ_HANDLED;
+       }
+
+       count = port->fifosize >> 1;
+       do {
+               clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               clps711xuart_stop_tx(port);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+{
+       unsigned int status = clps_readl(SYSFLG(port));
+       return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+{
+       unsigned int port_addr;
+       unsigned int result = 0;
+       unsigned int status;
+
+       port_addr = SYSFLG(port);
+       if (port_addr == SYSFLG1) {
+               status = clps_readl(SYSFLG1);
+               if (status & SYSFLG1_DCD)
+                       result |= TIOCM_CAR;
+               if (status & SYSFLG1_DSR)
+                       result |= TIOCM_DSR;
+               if (status & SYSFLG1_CTS)
+                       result |= TIOCM_CTS;
+       }
+
+       return result;
+}
+
+static void
+clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int ubrlcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ubrlcr = clps_readl(UBRLCR(port));
+       if (break_state == -1)
+               ubrlcr |= UBRLCR_BREAK;
+       else
+               ubrlcr &= ~UBRLCR_BREAK;
+       clps_writel(ubrlcr, UBRLCR(port));
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int clps711xuart_startup(struct uart_port *port)
+{
+       unsigned int syscon;
+       int retval;
+
+       tx_enabled(port) = 1;
+
+       /*
+        * Allocate the IRQs
+        */
+       retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
+                            "clps711xuart_tx", port);
+       if (retval)
+               return retval;
+
+       retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
+                            "clps711xuart_rx", port);
+       if (retval) {
+               free_irq(TX_IRQ(port), port);
+               return retval;
+       }
+
+       /*
+        * enable the port
+        */
+       syscon = clps_readl(SYSCON(port));
+       syscon |= SYSCON_UARTEN;
+       clps_writel(syscon, SYSCON(port));
+
+       return 0;
+}
+
+static void clps711xuart_shutdown(struct uart_port *port)
+{
+       unsigned int ubrlcr, syscon;
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(TX_IRQ(port), port);   /* TX interrupt */
+       free_irq(RX_IRQ(port), port);   /* RX interrupt */
+
+       /*
+        * disable the port
+        */
+       syscon = clps_readl(SYSCON(port));
+       syscon &= ~SYSCON_UARTEN;
+       clps_writel(syscon, SYSCON(port));
+
+       /*
+        * disable break condition and fifos
+        */
+       ubrlcr = clps_readl(UBRLCR(port));
+       ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
+       clps_writel(ubrlcr, UBRLCR(port));
+}
+
+static void
+clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
+                        struct ktermios *old)
+{
+       unsigned int ubrlcr, baud, quot;
+       unsigned long flags;
+
+       /*
+        * We don't implement CREAD.
+        */
+       termios->c_cflag |= CREAD;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               ubrlcr = UBRLCR_WRDLEN5;
+               break;
+       case CS6:
+               ubrlcr = UBRLCR_WRDLEN6;
+               break;
+       case CS7:
+               ubrlcr = UBRLCR_WRDLEN7;
+               break;
+       default: // CS8
+               ubrlcr = UBRLCR_WRDLEN8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               ubrlcr |= UBRLCR_XSTOP;
+       if (termios->c_cflag & PARENB) {
+               ubrlcr |= UBRLCR_PRTEN;
+               if (!(termios->c_cflag & PARODD))
+                       ubrlcr |= UBRLCR_EVENPRT;
+       }
+       if (port->fifosize > 1)
+               ubrlcr |= UBRLCR_FIFOEN;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = UARTDR_OVERR;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
+       if (termios->c_iflag & IGNBRK) {
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns to (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UARTDR_OVERR;
+       }
+
+       quot -= 1;
+
+       clps_writel(ubrlcr | quot, UBRLCR(port));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *clps711xuart_type(struct uart_port *port)
+{
+       return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void clps711xuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE)
+               port->type = PORT_CLPS711X;
+}
+
+static void clps711xuart_release_port(struct uart_port *port)
+{
+}
+
+static int clps711xuart_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static struct uart_ops clps711x_pops = {
+       .tx_empty       = clps711xuart_tx_empty,
+       .set_mctrl      = clps711xuart_set_mctrl_null,
+       .get_mctrl      = clps711xuart_get_mctrl,
+       .stop_tx        = clps711xuart_stop_tx,
+       .start_tx       = clps711xuart_start_tx,
+       .stop_rx        = clps711xuart_stop_rx,
+       .enable_ms      = clps711xuart_enable_ms,
+       .break_ctl      = clps711xuart_break_ctl,
+       .startup        = clps711xuart_startup,
+       .shutdown       = clps711xuart_shutdown,
+       .set_termios    = clps711xuart_set_termios,
+       .type           = clps711xuart_type,
+       .config_port    = clps711xuart_config_port,
+       .release_port   = clps711xuart_release_port,
+       .request_port   = clps711xuart_request_port,
+};
+
+static struct uart_port clps711x_ports[UART_NR] = {
+       {
+               .iobase         = SYSCON1,
+               .irq            = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
+               .uartclk        = 3686400,
+               .fifosize       = 16,
+               .ops            = &clps711x_pops,
+               .line           = 0,
+               .flags          = UPF_BOOT_AUTOCONF,
+       },
+       {
+               .iobase         = SYSCON2,
+               .irq            = IRQ_UTXINT2, /* IRQ_URXINT2 */
+               .uartclk        = 3686400,
+               .fifosize       = 16,
+               .ops            = &clps711x_pops,
+               .line           = 1,
+               .flags          = UPF_BOOT_AUTOCONF,
+       }
+};
+
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+static void clps711xuart_console_putchar(struct uart_port *port, int ch)
+{
+       while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
+               barrier();
+       clps_writel(ch, UARTDR(port));
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ *
+ *     Note that this is called with interrupts already disabled
+ */
+static void
+clps711xuart_console_write(struct console *co, const char *s,
+                          unsigned int count)
+{
+       struct uart_port *port = clps711x_ports + co->index;
+       unsigned int status, syscon;
+
+       /*
+        *      Ensure that the port is enabled.
+        */
+       syscon = clps_readl(SYSCON(port));
+       clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
+
+       uart_console_write(port, s, count, clps711xuart_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the uart state.
+        */
+       do {
+               status = clps_readl(SYSFLG(port));
+       } while (status & SYSFLG_UBUSY);
+
+       clps_writel(syscon, SYSCON(port));
+}
+
+static void __init
+clps711xuart_console_get_options(struct uart_port *port, int *baud,
+                                int *parity, int *bits)
+{
+       if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
+               unsigned int ubrlcr, quot;
+
+               ubrlcr = clps_readl(UBRLCR(port));
+
+               *parity = 'n';
+               if (ubrlcr & UBRLCR_PRTEN) {
+                       if (ubrlcr & UBRLCR_EVENPRT)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
+                       *bits = 7;
+               else
+                       *bits = 8;
+
+               quot = ubrlcr & UBRLCR_BAUD_MASK;
+               *baud = port->uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init clps711xuart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       port = uart_get_console(clps711x_ports, UART_NR, co);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               clps711xuart_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver clps711x_reg;
+static struct console clps711x_console = {
+       .name           = "ttyCL",
+       .write          = clps711xuart_console_write,
+       .device         = uart_console_device,
+       .setup          = clps711xuart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &clps711x_reg,
+};
+
+static int __init clps711xuart_console_init(void)
+{
+       register_console(&clps711x_console);
+       return 0;
+}
+console_initcall(clps711xuart_console_init);
+
+#define CLPS711X_CONSOLE       &clps711x_console
+#else
+#define CLPS711X_CONSOLE       NULL
+#endif
+
+static struct uart_driver clps711x_reg = {
+       .driver_name            = "ttyCL",
+       .dev_name               = "ttyCL",
+       .major                  = SERIAL_CLPS711X_MAJOR,
+       .minor                  = SERIAL_CLPS711X_MINOR,
+       .nr                     = UART_NR,
+
+       .cons                   = CLPS711X_CONSOLE,
+};
+
+static int __init clps711xuart_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: CLPS711x driver\n");
+
+       ret = uart_register_driver(&clps711x_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+       return 0;
+}
+
+static void __exit clps711xuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+       uart_unregister_driver(&clps711x_reg);
+}
+
+module_init(clps711xuart_init);
+module_exit(clps711xuart_exit);
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("CLPS-711x generic serial driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile
new file mode 100644 (file)
index 0000000..e072724
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the Motorola 8xx FEC ethernet controller
+#
+
+obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
+
+# Select the correct platform objects.
+cpm_uart-objs-$(CONFIG_CPM2)   += cpm_uart_cpm2.o
+cpm_uart-objs-$(CONFIG_8xx)    += cpm_uart_cpm1.o
+
+cpm_uart-objs  := cpm_uart_core.o $(cpm_uart-objs-y)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
new file mode 100644 (file)
index 0000000..b754dcf
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  linux/drivers/serial/cpm_uart.h
+ *
+ *  Driver for CPM (SCC/SMC) serial ports
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *
+ *  2006 (c) MontaVista Software, Inc.
+ *     Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#ifndef CPM_UART_H
+#define CPM_UART_H
+
+#include <linux/platform_device.h>
+#include <linux/fs_uart_pd.h>
+
+#if defined(CONFIG_CPM2)
+#include "cpm_uart_cpm2.h"
+#elif defined(CONFIG_8xx)
+#include "cpm_uart_cpm1.h"
+#endif
+
+#define SERIAL_CPM_MAJOR       204
+#define SERIAL_CPM_MINOR       46
+
+#define IS_SMC(pinfo)          (pinfo->flags & FLAG_SMC)
+#define IS_DISCARDING(pinfo)   (pinfo->flags & FLAG_DISCARDING)
+#define FLAG_DISCARDING        0x00000004      /* when set, don't discard */
+#define FLAG_SMC       0x00000002
+#define FLAG_CONSOLE   0x00000001
+
+#define UART_SMC1      fsid_smc1_uart
+#define UART_SMC2      fsid_smc2_uart
+#define UART_SCC1      fsid_scc1_uart
+#define UART_SCC2      fsid_scc2_uart
+#define UART_SCC3      fsid_scc3_uart
+#define UART_SCC4      fsid_scc4_uart
+
+#define UART_NR                fs_uart_nr
+
+#define RX_NUM_FIFO    4
+#define RX_BUF_SIZE    32
+#define TX_NUM_FIFO    4
+#define TX_BUF_SIZE    32
+
+#define SCC_WAIT_CLOSING 100
+
+#define GPIO_CTS       0
+#define GPIO_RTS       1
+#define GPIO_DCD       2
+#define GPIO_DSR       3
+#define GPIO_DTR       4
+#define GPIO_RI                5
+
+#define NUM_GPIOS      (GPIO_RI+1)
+
+struct uart_cpm_port {
+       struct uart_port        port;
+       u16                     rx_nrfifos;
+       u16                     rx_fifosize;
+       u16                     tx_nrfifos;
+       u16                     tx_fifosize;
+       smc_t __iomem           *smcp;
+       smc_uart_t __iomem      *smcup;
+       scc_t __iomem           *sccp;
+       scc_uart_t __iomem      *sccup;
+       cbd_t __iomem           *rx_bd_base;
+       cbd_t __iomem           *rx_cur;
+       cbd_t __iomem           *tx_bd_base;
+       cbd_t __iomem           *tx_cur;
+       unsigned char           *tx_buf;
+       unsigned char           *rx_buf;
+       u32                     flags;
+       struct clk              *clk;
+       u8                      brg;
+       uint                     dp_addr;
+       void                    *mem_addr;
+       dma_addr_t               dma_addr;
+       u32                     mem_size;
+       /* wait on close if needed */
+       int                     wait_closing;
+       /* value to combine with opcode to form cpm command */
+       u32                     command;
+       int                     gpios[NUM_GPIOS];
+};
+
+extern int cpm_uart_nr;
+extern struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+/* these are located in their respective files */
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np);
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram);
+int cpm_uart_init_portdesc(void);
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
+
+void smc1_lineif(struct uart_cpm_port *pinfo);
+void smc2_lineif(struct uart_cpm_port *pinfo);
+void scc1_lineif(struct uart_cpm_port *pinfo);
+void scc2_lineif(struct uart_cpm_port *pinfo);
+void scc3_lineif(struct uart_cpm_port *pinfo);
+void scc4_lineif(struct uart_cpm_port *pinfo);
+
+/*
+   virtual to phys transtalion
+*/
+static inline unsigned long cpu2cpm_addr(void *addr,
+                                         struct uart_cpm_port *pinfo)
+{
+       int offset;
+       u32 val = (u32)addr;
+       u32 mem = (u32)pinfo->mem_addr;
+       /* sane check */
+       if (likely(val >= mem && val < mem + pinfo->mem_size)) {
+               offset = val - mem;
+               return pinfo->dma_addr + offset;
+       }
+       /* something nasty happened */
+       BUG();
+       return 0;
+}
+
+static inline void *cpm2cpu_addr(unsigned long addr,
+                                 struct uart_cpm_port *pinfo)
+{
+       int offset;
+       u32 val = addr;
+       u32 dma = (u32)pinfo->dma_addr;
+       /* sane check */
+       if (likely(val >= dma && val < dma + pinfo->mem_size)) {
+               offset = val - dma;
+               return pinfo->mem_addr + offset;
+       }
+       /* something nasty happened */
+       BUG();
+       return NULL;
+}
+
+
+#endif /* CPM_UART_H */
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
new file mode 100644 (file)
index 0000000..8692ff9
--- /dev/null
@@ -0,0 +1,1443 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; core driver
+ *
+ *  Based on arch/ppc/cpm2_io/uart.c by Dan Malek
+ *  Based on ppc8xx.c by Thomas Gleixner
+ *  Based on drivers/serial/amba.c by Russell King
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2005-2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+
+/**************************************************************/
+
+static int  cpm_uart_tx_pump(struct uart_port *port);
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo);
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo);
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
+
+/**************************************************************/
+
+#define HW_BUF_SPD_THRESHOLD    9600
+
+/*
+ * Check, if transmit buffers are processed
+*/
+static unsigned int cpm_uart_tx_empty(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       cbd_t __iomem *bdp = pinfo->tx_bd_base;
+       int ret = 0;
+
+       while (1) {
+               if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
+                       break;
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
+                       ret = TIOCSER_TEMT;
+                       break;
+               }
+               bdp++;
+       }
+
+       pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
+
+       return ret;
+}
+
+static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (pinfo->gpios[GPIO_RTS] >= 0)
+               gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
+
+       if (pinfo->gpios[GPIO_DTR] >= 0)
+               gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
+}
+
+static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       if (pinfo->gpios[GPIO_CTS] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
+                       mctrl &= ~TIOCM_CTS;
+       }
+
+       if (pinfo->gpios[GPIO_DSR] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
+                       mctrl &= ~TIOCM_DSR;
+       }
+
+       if (pinfo->gpios[GPIO_DCD] >= 0) {
+               if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
+                       mctrl &= ~TIOCM_CAR;
+       }
+
+       if (pinfo->gpios[GPIO_RI] >= 0) {
+               if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
+                       mctrl |= TIOCM_RNG;
+       }
+
+       return mctrl;
+}
+
+/*
+ * Stop transmitter
+ */
+static void cpm_uart_stop_tx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop tx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               clrbits8(&smcp->smc_smcm, SMCM_TX);
+       else
+               clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
+}
+
+/*
+ * Start transmitter
+ */
+static void cpm_uart_start_tx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:start tx\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               if (in_8(&smcp->smc_smcm) & SMCM_TX)
+                       return;
+       } else {
+               if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
+                       return;
+       }
+
+       if (cpm_uart_tx_pump(port) != 0) {
+               if (IS_SMC(pinfo)) {
+                       setbits8(&smcp->smc_smcm, SMCM_TX);
+               } else {
+                       setbits16(&sccp->scc_sccm, UART_SCCM_TX);
+               }
+       }
+}
+
+/*
+ * Stop receiver
+ */
+static void cpm_uart_stop_rx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop rx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               clrbits8(&smcp->smc_smcm, SMCM_RX);
+       else
+               clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
+}
+
+/*
+ * Enable Modem status interrupts
+ */
+static void cpm_uart_enable_ms(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:enable ms\n", port->line);
+}
+
+/*
+ * Generate a break.
+ */
+static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
+               break_state);
+
+       if (break_state)
+               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+       else
+               cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static void cpm_uart_int_tx(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:TX INT\n", port->line);
+
+       cpm_uart_tx_pump(port);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
+/*
+ * Receive characters
+ */
+static void cpm_uart_int_rx(struct uart_port *port)
+{
+       int i;
+       unsigned char ch;
+       u8 *cp;
+       struct tty_struct *tty = port->state->port.tty;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       cbd_t __iomem *bdp;
+       u16 status;
+       unsigned int flg;
+
+       pr_debug("CPM uart[%d]:RX INT\n", port->line);
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = pinfo->rx_cur;
+       for (;;) {
+#ifdef CONFIG_CONSOLE_POLL
+               if (unlikely(serial_polled)) {
+                       serial_polled = 0;
+                       return;
+               }
+#endif
+               /* get status */
+               status = in_be16(&bdp->cbd_sc);
+               /* If this one is empty, return happy */
+               if (status & BD_SC_EMPTY)
+                       break;
+
+               /* get number of characters, and check spce in flip-buffer */
+               i = in_be16(&bdp->cbd_datlen);
+
+               /* If we have not enough room in tty flip buffer, then we try
+                * later, which will be the next rx-interrupt or a timeout
+                */
+               if(tty_buffer_request_room(tty, i) < i) {
+                       printk(KERN_WARNING "No room in flip buffer\n");
+                       return;
+               }
+
+               /* get pointer */
+               cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+
+               /* loop through the buffer */
+               while (i-- > 0) {
+                       ch = *cp++;
+                       port->icount.rx++;
+                       flg = TTY_NORMAL;
+
+                       if (status &
+                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+                               goto handle_error;
+                       if (uart_handle_sysrq_char(port, ch))
+                               continue;
+#ifdef CONFIG_CONSOLE_POLL
+                       if (unlikely(serial_polled)) {
+                               serial_polled = 0;
+                               return;
+                       }
+#endif
+                     error_return:
+                       tty_insert_flip_char(tty, ch, flg);
+
+               }               /* End while (i--) */
+
+               /* This BD is ready to be used again. Clear status. get next */
+               clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+                                       BD_SC_OV | BD_SC_ID);
+               setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->rx_bd_base;
+               else
+                       bdp++;
+
+       } /* End for (;;) */
+
+       /* Write back buffer pointer */
+       pinfo->rx_cur = bdp;
+
+       /* activate BH processing */
+       tty_flip_buffer_push(tty);
+
+       return;
+
+       /* Error processing */
+
+      handle_error:
+       /* Statistics */
+       if (status & BD_SC_BR)
+               port->icount.brk++;
+       if (status & BD_SC_PR)
+               port->icount.parity++;
+       if (status & BD_SC_FR)
+               port->icount.frame++;
+       if (status & BD_SC_OV)
+               port->icount.overrun++;
+
+       /* Mask out ignored conditions */
+       status &= port->read_status_mask;
+
+       /* Handle the remaining ones */
+       if (status & BD_SC_BR)
+               flg = TTY_BREAK;
+       else if (status & BD_SC_PR)
+               flg = TTY_PARITY;
+       else if (status & BD_SC_FR)
+               flg = TTY_FRAME;
+
+       /* overrun does not affect the current character ! */
+       if (status & BD_SC_OV) {
+               ch = 0;
+               flg = TTY_OVERRUN;
+               /* We skip this buffer */
+               /* CHECK: Is really nothing senseful there */
+               /* ASSUMPTION: it contains nothing valid */
+               i = 0;
+       }
+#ifdef SUPPORT_SYSRQ
+       port->sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/*
+ * Asynchron mode interrupt handler
+ */
+static irqreturn_t cpm_uart_int(int irq, void *data)
+{
+       u8 events;
+       struct uart_port *port = data;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:IRQ\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               events = in_8(&smcp->smc_smce);
+               out_8(&smcp->smc_smce, events);
+               if (events & SMCM_BRKE)
+                       uart_handle_break(port);
+               if (events & SMCM_RX)
+                       cpm_uart_int_rx(port);
+               if (events & SMCM_TX)
+                       cpm_uart_int_tx(port);
+       } else {
+               events = in_be16(&sccp->scc_scce);
+               out_be16(&sccp->scc_scce, events);
+               if (events & UART_SCCM_BRKE)
+                       uart_handle_break(port);
+               if (events & UART_SCCM_RX)
+                       cpm_uart_int_rx(port);
+               if (events & UART_SCCM_TX)
+                       cpm_uart_int_tx(port);
+       }
+       return (events) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int cpm_uart_startup(struct uart_port *port)
+{
+       int retval;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:startup\n", port->line);
+
+       /* If the port is not the console, make sure rx is disabled. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Disable UART rx */
+               if (IS_SMC(pinfo)) {
+                       clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN);
+                       clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+               } else {
+                       clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
+                       clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+               }
+               cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+       }
+       /* Install interrupt handler. */
+       retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
+       if (retval)
+               return retval;
+
+       /* Startup rx-int */
+       if (IS_SMC(pinfo)) {
+               setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+               setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
+       } else {
+               setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+               setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
+       }
+
+       return 0;
+}
+
+inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
+{
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(pinfo->wait_closing);
+}
+
+/*
+ * Shutdown the uart
+ */
+static void cpm_uart_shutdown(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:shutdown\n", port->line);
+
+       /* free interrupt handler */
+       free_irq(port->irq, port);
+
+       /* If the port is not the console, disable Rx and Tx. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Wait for all the BDs marked sent */
+               while(!cpm_uart_tx_empty(port)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(2);
+               }
+
+               if (pinfo->wait_closing)
+                       cpm_uart_wait_until_send(pinfo);
+
+               /* Stop uarts */
+               if (IS_SMC(pinfo)) {
+                       smc_t __iomem *smcp = pinfo->smcp;
+                       clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+                       clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               } else {
+                       scc_t __iomem *sccp = pinfo->sccp;
+                       clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+                       clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               }
+
+               /* Shut them really down and reinit buffer descriptors */
+               if (IS_SMC(pinfo)) {
+                       out_be16(&pinfo->smcup->smc_brkcr, 0);
+                       cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+               } else {
+                       out_be16(&pinfo->sccup->scc_brkcr, 0);
+                       cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
+               }
+
+               cpm_uart_initbd(pinfo);
+       }
+}
+
+static void cpm_uart_set_termios(struct uart_port *port,
+                                 struct ktermios *termios,
+                                 struct ktermios *old)
+{
+       int baud;
+       unsigned long flags;
+       u16 cval, scval, prev_mode;
+       int bits, sbits;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       smc_t __iomem *smcp = pinfo->smcp;
+       scc_t __iomem *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:set_termios\n", port->line);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       if (baud <= HW_BUF_SPD_THRESHOLD ||
+           (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
+               pinfo->rx_fifosize = 1;
+       else
+               pinfo->rx_fifosize = RX_BUF_SIZE;
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+       scval = 0;
+
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               bits = 5;
+               break;
+       case CS6:
+               bits = 6;
+               break;
+       case CS7:
+               bits = 7;
+               break;
+       case CS8:
+               bits = 8;
+               break;
+               /* Never happens, but GCC is too dumb to figure it out */
+       default:
+               bits = 8;
+               break;
+       }
+       sbits = bits - 5;
+
+       if (termios->c_cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               scval |= SCU_PSMR_SL;
+               bits++;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               scval |= SCU_PSMR_PEN;
+               bits++;
+               if (!(termios->c_cflag & PARODD)) {
+                       cval |= SMCMR_PM_EVEN;
+                       scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
+               }
+       }
+
+       /*
+        * Update the timeout
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
+               port->read_status_mask |= BD_SC_BR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->read_status_mask &= ~BD_SC_EMPTY;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Start bit has not been added (so don't, because we would just
+        * subtract it later), and we need to add one for the number of
+        * stops bits (there is always at least one).
+        */
+       bits++;
+       if (IS_SMC(pinfo)) {
+               /*
+                * MRBLR can be changed while an SMC/SCC is operating only
+                * if it is done in a single bus cycle with one 16-bit move
+                * (not two 8-bit bus cycles back-to-back). This occurs when
+                * the cp shifts control to the next RxBD, so the change does
+                * not take effect immediately. To guarantee the exact RxBD
+                * on which the change occurs, change MRBLR only while the
+                * SMC/SCC receiver is disabled.
+                */
+               out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN);
+               /* Output in *one* operation, so we don't interrupt RX/TX if they
+                * were already enabled. */
+               out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
+                   SMCMR_SM_UART | prev_mode);
+       } else {
+               out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+               out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
+       }
+
+       if (pinfo->clk)
+               clk_set_rate(pinfo->clk, baud);
+       else
+               cpm_set_brg(pinfo->brg - 1, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *cpm_uart_type(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:uart_type\n", port->line);
+
+       return port->type == PORT_CPM ? "CPM UART" : NULL;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int cpm_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *ser)
+{
+       int ret = 0;
+
+       pr_debug("CPM uart[%d]:verify_port\n", port->line);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static int cpm_uart_tx_pump(struct uart_port *port)
+{
+       cbd_t __iomem *bdp;
+       u8 *p;
+       int count;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       /* Handle xon/xoff */
+       if (port->x_char) {
+               /* Pick next descriptor and fill from buffer */
+               bdp = pinfo->tx_cur;
+
+               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+
+               *p++ = port->x_char;
+
+               out_be16(&bdp->cbd_datlen, 1);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+               pinfo->tx_cur = bdp;
+
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               cpm_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Pick next descriptor and fill from buffer */
+       bdp = pinfo->tx_cur;
+
+       while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+              xmit->tail != xmit->head) {
+               count = 0;
+               p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
+               while (count < pinfo->tx_fifosize) {
+                       *p++ = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                       port->icount.tx++;
+                       count++;
+                       if (xmit->head == xmit->tail)
+                               break;
+               }
+               out_be16(&bdp->cbd_datlen, count);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+       }
+       pinfo->tx_cur = bdp;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit)) {
+               cpm_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * init buffer descriptors
+ */
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
+{
+       int i;
+       u8 *mem_addr;
+       cbd_t __iomem *bdp;
+
+       pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr;
+       bdp = pinfo->rx_cur = pinfo->rx_bd_base;
+       for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
+               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+               out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+               mem_addr += pinfo->rx_fifosize;
+       }
+
+       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
+       bdp = pinfo->tx_cur = pinfo->tx_bd_base;
+       for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
+               out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+               out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
+               mem_addr += pinfo->tx_fifosize;
+       }
+
+       out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+       out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
+}
+
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
+{
+       scc_t __iomem *scp;
+       scc_uart_t __iomem *sup;
+
+       pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
+
+       scp = pinfo->sccp;
+       sup = pinfo->sccup;
+
+       /* Store address */
+       out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
+                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+       out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
+                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+
+       cpm_set_scc_fcr(sup);
+
+       out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+       out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+       out_be16(&sup->scc_brkcr, 1);
+       out_be16(&sup->scc_parec, 0);
+       out_be16(&sup->scc_frmec, 0);
+       out_be16(&sup->scc_nosec, 0);
+       out_be16(&sup->scc_brkec, 0);
+       out_be16(&sup->scc_uaddr1, 0);
+       out_be16(&sup->scc_uaddr2, 0);
+       out_be16(&sup->scc_toseq, 0);
+       out_be16(&sup->scc_char1, 0x8000);
+       out_be16(&sup->scc_char2, 0x8000);
+       out_be16(&sup->scc_char3, 0x8000);
+       out_be16(&sup->scc_char4, 0x8000);
+       out_be16(&sup->scc_char5, 0x8000);
+       out_be16(&sup->scc_char6, 0x8000);
+       out_be16(&sup->scc_char7, 0x8000);
+       out_be16(&sup->scc_char8, 0x8000);
+       out_be16(&sup->scc_rccm, 0xc0ff);
+
+       /* Send the CPM an initialize command.
+        */
+       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       out_be32(&scp->scc_gsmrh, 0);
+       out_be32(&scp->scc_gsmrl,
+                SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+       /* Enable rx interrupts  and clear all pending events.  */
+       out_be16(&scp->scc_sccm, 0);
+       out_be16(&scp->scc_scce, 0xffff);
+       out_be16(&scp->scc_dsr, 0x7e7e);
+       out_be16(&scp->scc_psmr, 0x3000);
+
+       setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
+{
+       smc_t __iomem *sp;
+       smc_uart_t __iomem *up;
+
+       pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
+
+       sp = pinfo->smcp;
+       up = pinfo->smcup;
+
+       /* Store address */
+       out_be16(&pinfo->smcup->smc_rbase,
+                (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+       out_be16(&pinfo->smcup->smc_tbase,
+                (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
+
+/*
+ *  In case SMC1 is being relocated...
+ */
+#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+       out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
+       out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
+       out_be32(&up->smc_rstate, 0);
+       out_be32(&up->smc_tstate, 0);
+       out_be16(&up->smc_brkcr, 1);              /* number of break chars */
+       out_be16(&up->smc_brkec, 0);
+#endif
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+       cpm_set_smc_fcr(up);
+
+       /* Using idle character time requires some additional tuning.  */
+       out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
+       out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+       out_be16(&up->smc_brklen, 0);
+       out_be16(&up->smc_brkec, 0);
+       out_be16(&up->smc_brkcr, 1);
+
+       cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
+
+       /* Enable only rx interrupts clear all pending events. */
+       out_8(&sp->smc_smcm, 0);
+       out_8(&sp->smc_smce, 0xff);
+
+       setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+}
+
+/*
+ * Initialize port. This is called from early_console stuff
+ * so we have to be careful here !
+ */
+static int cpm_uart_request_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       int ret;
+
+       pr_debug("CPM uart[%d]:request port\n", port->line);
+
+       if (pinfo->flags & FLAG_CONSOLE)
+               return 0;
+
+       if (IS_SMC(pinfo)) {
+               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+       } else {
+               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 0);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+       if (IS_SMC(pinfo))
+               cpm_uart_init_smc(pinfo);
+       else
+               cpm_uart_init_scc(pinfo);
+
+       return 0;
+}
+
+static void cpm_uart_release_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (!(pinfo->flags & FLAG_CONSOLE))
+               cpm_uart_freebuf(pinfo);
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void cpm_uart_config_port(struct uart_port *port, int flags)
+{
+       pr_debug("CPM uart[%d]:config_port\n", port->line);
+
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_CPM;
+               cpm_uart_request_port(port);
+       }
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE)
+/*
+ * Write a string to the serial port
+ * Note that this is called with interrupts already disabled
+ */
+static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
+               const char *string, u_int count)
+{
+       unsigned int i;
+       cbd_t __iomem *bdp, *bdbase;
+       unsigned char *cpm_outp_addr;
+
+       /* Get the address of the host memory buffer.
+        */
+       bdp = pinfo->tx_cur;
+       bdbase = pinfo->tx_bd_base;
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, string++) {
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+                       ;
+
+               /* Send the character out.
+                * If the buffer address is in the CPM DPRAM, don't
+                * convert it.
+                */
+               cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
+                                       pinfo);
+               *cpm_outp_addr = *string;
+
+               out_be16(&bdp->cbd_datlen, 1);
+               setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+               if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*string == 10) {
+                       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+                               ;
+
+                       cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr),
+                                               pinfo);
+                       *cpm_outp_addr = 13;
+
+                       out_be16(&bdp->cbd_datlen, 1);
+                       setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+                       if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
+                               bdp = bdbase;
+                       else
+                               bdp++;
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
+               ;
+
+       pinfo->tx_cur = bdp;
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+#define GDB_BUF_SIZE   512     /* power of 2, please */
+
+static char poll_buf[GDB_BUF_SIZE];
+static char *pollp;
+static int poll_chars;
+
+static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
+{
+       u_char          c, *cp;
+       volatile cbd_t  *bdp;
+       int             i;
+
+       /* Get the address of the host memory buffer.
+        */
+       bdp = pinfo->rx_cur;
+       while (bdp->cbd_sc & BD_SC_EMPTY)
+               ;
+
+       /* If the buffer address is in the CPM DPRAM, don't
+        * convert it.
+        */
+       cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+
+       if (obuf) {
+               i = c = bdp->cbd_datlen;
+               while (i-- > 0)
+                       *obuf++ = *cp++;
+       } else
+               c = *cp;
+       bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
+       bdp->cbd_sc |= BD_SC_EMPTY;
+
+       if (bdp->cbd_sc & BD_SC_WRAP)
+               bdp = pinfo->rx_bd_base;
+       else
+               bdp++;
+       pinfo->rx_cur = (cbd_t *)bdp;
+
+       return (int)c;
+}
+
+static int cpm_get_poll_char(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (!serial_polled) {
+               serial_polled = 1;
+               poll_chars = 0;
+       }
+       if (poll_chars <= 0) {
+               poll_chars = poll_wait_key(poll_buf, pinfo);
+               pollp = poll_buf;
+       }
+       poll_chars--;
+       return *pollp++;
+}
+
+static void cpm_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       static char ch[2];
+
+       ch[0] = (char)c;
+       cpm_uart_early_write(pinfo, ch, 1);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops cpm_uart_pops = {
+       .tx_empty       = cpm_uart_tx_empty,
+       .set_mctrl      = cpm_uart_set_mctrl,
+       .get_mctrl      = cpm_uart_get_mctrl,
+       .stop_tx        = cpm_uart_stop_tx,
+       .start_tx       = cpm_uart_start_tx,
+       .stop_rx        = cpm_uart_stop_rx,
+       .enable_ms      = cpm_uart_enable_ms,
+       .break_ctl      = cpm_uart_break_ctl,
+       .startup        = cpm_uart_startup,
+       .shutdown       = cpm_uart_shutdown,
+       .set_termios    = cpm_uart_set_termios,
+       .type           = cpm_uart_type,
+       .release_port   = cpm_uart_release_port,
+       .request_port   = cpm_uart_request_port,
+       .config_port    = cpm_uart_config_port,
+       .verify_port    = cpm_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = cpm_get_poll_char,
+       .poll_put_char = cpm_put_poll_char,
+#endif
+};
+
+struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+static int cpm_uart_init_port(struct device_node *np,
+                              struct uart_cpm_port *pinfo)
+{
+       const u32 *data;
+       void __iomem *mem, *pram;
+       int len;
+       int ret;
+       int i;
+
+       data = of_get_property(np, "clock", NULL);
+       if (data) {
+               struct clk *clk = clk_get(NULL, (const char*)data);
+               if (!IS_ERR(clk))
+                       pinfo->clk = clk;
+       }
+       if (!pinfo->clk) {
+               data = of_get_property(np, "fsl,cpm-brg", &len);
+               if (!data || len != 4) {
+                       printk(KERN_ERR "CPM UART %s has no/invalid "
+                                       "fsl,cpm-brg property.\n", np->name);
+                       return -EINVAL;
+               }
+               pinfo->brg = *data;
+       }
+
+       data = of_get_property(np, "fsl,cpm-command", &len);
+       if (!data || len != 4) {
+               printk(KERN_ERR "CPM UART %s has no/invalid "
+                               "fsl,cpm-command property.\n", np->name);
+               return -EINVAL;
+       }
+       pinfo->command = *data;
+
+       mem = of_iomap(np, 0);
+       if (!mem)
+               return -ENOMEM;
+
+       if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
+           of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
+               pinfo->sccp = mem;
+               pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np);
+       } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
+                  of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
+               pinfo->flags |= FLAG_SMC;
+               pinfo->smcp = mem;
+               pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np);
+       } else {
+               ret = -ENODEV;
+               goto out_mem;
+       }
+
+       if (!pram) {
+               ret = -ENOMEM;
+               goto out_mem;
+       }
+
+       pinfo->tx_nrfifos = TX_NUM_FIFO;
+       pinfo->tx_fifosize = TX_BUF_SIZE;
+       pinfo->rx_nrfifos = RX_NUM_FIFO;
+       pinfo->rx_fifosize = RX_BUF_SIZE;
+
+       pinfo->port.uartclk = ppc_proc_freq;
+       pinfo->port.mapbase = (unsigned long)mem;
+       pinfo->port.type = PORT_CPM;
+       pinfo->port.ops = &cpm_uart_pops,
+       pinfo->port.iotype = UPIO_MEM;
+       pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
+       spin_lock_init(&pinfo->port.lock);
+
+       pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+       if (pinfo->port.irq == NO_IRQ) {
+               ret = -EINVAL;
+               goto out_pram;
+       }
+
+       for (i = 0; i < NUM_GPIOS; i++)
+               pinfo->gpios[i] = of_get_gpio(np, i);
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+       udbg_putc = NULL;
+#endif
+
+       return cpm_uart_request_port(&pinfo->port);
+
+out_pram:
+       cpm_uart_unmap_pram(pinfo, pram);
+out_mem:
+       iounmap(mem);
+       return ret;
+}
+
+#ifdef CONFIG_SERIAL_CPM_CONSOLE
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     Note that this is called with interrupts already disabled
+ */
+static void cpm_uart_console_write(struct console *co, const char *s,
+                                  u_int count)
+{
+       struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
+       unsigned long flags;
+       int nolock = oops_in_progress;
+
+       if (unlikely(nolock)) {
+               local_irq_save(flags);
+       } else {
+               spin_lock_irqsave(&pinfo->port.lock, flags);
+       }
+
+       cpm_uart_early_write(pinfo, s, count);
+
+       if (unlikely(nolock)) {
+               local_irq_restore(flags);
+       } else {
+               spin_unlock_irqrestore(&pinfo->port.lock, flags);
+       }
+}
+
+
+static int __init cpm_uart_console_setup(struct console *co, char *options)
+{
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+       struct uart_cpm_port *pinfo;
+       struct uart_port *port;
+
+       struct device_node *np = NULL;
+       int i = 0;
+
+       if (co->index >= UART_NR) {
+               printk(KERN_ERR "cpm_uart: console index %d too high\n",
+                      co->index);
+               return -ENODEV;
+       }
+
+       do {
+               np = of_find_node_by_type(np, "serial");
+               if (!np)
+                       return -ENODEV;
+
+               if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
+                   !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
+                       i--;
+       } while (i++ != co->index);
+
+       pinfo = &cpm_uart_ports[co->index];
+
+       pinfo->flags |= FLAG_CONSOLE;
+       port = &pinfo->port;
+
+       ret = cpm_uart_init_port(np, pinfo);
+       of_node_put(np);
+       if (ret)
+               return ret;
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       } else {
+               if ((baud = uart_baudrate()) == -1)
+                       baud = 9600;
+       }
+
+       if (IS_SMC(pinfo)) {
+               out_be16(&pinfo->smcup->smc_brkcr, 0);
+               cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+               clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+               clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+       } else {
+               out_be16(&pinfo->sccup->scc_brkcr, 0);
+               cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
+               clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+               clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 1);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+
+       if (IS_SMC(pinfo))
+               cpm_uart_init_smc(pinfo);
+       else
+               cpm_uart_init_scc(pinfo);
+
+       uart_set_options(port, co, baud, parity, bits, flow);
+       cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
+
+       return 0;
+}
+
+static struct uart_driver cpm_reg;
+static struct console cpm_scc_uart_console = {
+       .name           = "ttyCPM",
+       .write          = cpm_uart_console_write,
+       .device         = uart_console_device,
+       .setup          = cpm_uart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &cpm_reg,
+};
+
+static int __init cpm_uart_console_init(void)
+{
+       register_console(&cpm_scc_uart_console);
+       return 0;
+}
+
+console_initcall(cpm_uart_console_init);
+
+#define CPM_UART_CONSOLE       &cpm_scc_uart_console
+#else
+#define CPM_UART_CONSOLE       NULL
+#endif
+
+static struct uart_driver cpm_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyCPM",
+       .dev_name       = "ttyCPM",
+       .major          = SERIAL_CPM_MAJOR,
+       .minor          = SERIAL_CPM_MINOR,
+       .cons           = CPM_UART_CONSOLE,
+       .nr             = UART_NR,
+};
+
+static int probe_index;
+
+static int __devinit cpm_uart_probe(struct platform_device *ofdev,
+                                    const struct of_device_id *match)
+{
+       int index = probe_index++;
+       struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
+       int ret;
+
+       pinfo->port.line = index;
+
+       if (index >= UART_NR)
+               return -ENODEV;
+
+       dev_set_drvdata(&ofdev->dev, pinfo);
+
+       /* initialize the device pointer for the port */
+       pinfo->port.dev = &ofdev->dev;
+
+       ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
+       if (ret)
+               return ret;
+
+       return uart_add_one_port(&cpm_reg, &pinfo->port);
+}
+
+static int __devexit cpm_uart_remove(struct platform_device *ofdev)
+{
+       struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+       return uart_remove_one_port(&cpm_reg, &pinfo->port);
+}
+
+static struct of_device_id cpm_uart_match[] = {
+       {
+               .compatible = "fsl,cpm1-smc-uart",
+       },
+       {
+               .compatible = "fsl,cpm1-scc-uart",
+       },
+       {
+               .compatible = "fsl,cpm2-smc-uart",
+       },
+       {
+               .compatible = "fsl,cpm2-scc-uart",
+       },
+       {}
+};
+
+static struct of_platform_driver cpm_uart_driver = {
+       .driver = {
+               .name = "cpm_uart",
+               .owner = THIS_MODULE,
+               .of_match_table = cpm_uart_match,
+       },
+       .probe = cpm_uart_probe,
+       .remove = cpm_uart_remove,
+ };
+
+static int __init cpm_uart_init(void)
+{
+       int ret = uart_register_driver(&cpm_reg);
+       if (ret)
+               return ret;
+
+       ret = of_register_platform_driver(&cpm_uart_driver);
+       if (ret)
+               uart_unregister_driver(&cpm_reg);
+
+       return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+       of_unregister_platform_driver(&cpm_uart_driver);
+       uart_unregister_driver(&cpm_reg);
+}
+
+module_init(cpm_uart_init);
+module_exit(cpm_uart_exit);
+
+MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
+MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
new file mode 100644 (file)
index 0000000..3fc1d66
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/gfp.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/fs_pd.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include <linux/of.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+       cpm_command(port->command, cmd);
+}
+
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np)
+{
+       return of_iomap(np, 1);
+}
+
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
+{
+       iounmap(pram);
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 *dp_mem;
+       unsigned long dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_ERR_VALUE(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con) {
+               /* was hostalloc but changed cause it blows away the */
+               /* large tlb mapping when pinning the kernel area    */
+               mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
+               dma_addr = (u32)cpm_dpram_phys(mem_addr);
+       } else
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;             /*  virtual address*/
+       pinfo->dma_addr = dma_addr;             /*  physical address*/
+       pinfo->mem_size = memsz;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
new file mode 100644 (file)
index 0000000..10eecd6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+ * definitions for cpm1
+ *
+ */
+
+#ifndef CPM_UART_CPM1_H
+#define CPM_UART_CPM1_H
+
+#include <asm/cpm1.h>
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
+{
+       out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
+       out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
+}
+
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
+{
+       out_8(&up->smc_rfcr, SMC_EB);
+       out_8(&up->smc_tfcr, SMC_EB);
+}
+
+#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
+
+#endif
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
new file mode 100644 (file)
index 0000000..814ac00
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  linux/drivers/serial/cpm_uart_cpm2.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
+ *
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ *
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *            (C) 2006 MontaVista Software, Inc.
+ *             Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+       cpm_command(port->command, cmd);
+}
+
+void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port,
+                               struct device_node *np)
+{
+       void __iomem *pram;
+       unsigned long offset;
+       struct resource res;
+       resource_size_t len;
+
+       /* Don't remap parameter RAM if it has already been initialized
+        * during console setup.
+        */
+       if (IS_SMC(port) && port->smcup)
+               return port->smcup;
+       else if (!IS_SMC(port) && port->sccup)
+               return port->sccup;
+
+       if (of_address_to_resource(np, 1, &res))
+               return NULL;
+
+       len = resource_size(&res);
+       pram = ioremap(res.start, len);
+       if (!pram)
+               return NULL;
+
+       if (!IS_SMC(port))
+               return pram;
+
+       if (len != 2) {
+               printk(KERN_WARNING "cpm_uart[%d]: device tree references "
+                       "SMC pram, using boot loader/wrapper pram mapping. "
+                       "Please fix your device tree to reference the pram "
+                       "base register instead.\n",
+                       port->port.line);
+               return pram;
+       }
+
+       offset = cpm_dpalloc(PROFF_SMC_SIZE, 64);
+       out_be16(pram, offset);
+       iounmap(pram);
+       return cpm_muram_addr(offset);
+}
+
+void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram)
+{
+       if (!IS_SMC(port))
+               iounmap(pram);
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 __iomem *dp_mem;
+       unsigned long dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_ERR_VALUE(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con) {
+               mem_addr = kzalloc(memsz, GFP_NOWAIT);
+               dma_addr = virt_to_bus(mem_addr);
+       }
+       else
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;
+       pinfo->dma_addr = dma_addr;
+       pinfo->mem_size = memsz;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
new file mode 100644 (file)
index 0000000..7194c63
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ *
+ * definitions for cpm2
+ *
+ */
+
+#ifndef CPM_UART_CPM2_H
+#define CPM_UART_CPM2_H
+
+#include <asm/cpm2.h>
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
+{
+       out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+       out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
+}
+
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
+{
+       out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+       out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
+}
+
+#define DPRAM_BASE     ((u8 __iomem __force *)cpm_dpram_addr(0))
+
+#endif
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
new file mode 100644 (file)
index 0000000..bcc31f2
--- /dev/null
@@ -0,0 +1,4573 @@
+/*
+ * Serial port driver for the ETRAX 100LX chip
+ *
+ *    Copyright (C) 1998-2007  Axis Communications AB
+ *
+ *    Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+ */
+
+static char *serial_version = "$Revision: 1.25 $";
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+
+#include <arch/svinto.h>
+
+/* non-arch dependent serial structures are in linux/serial.h */
+#include <linux/serial.h>
+/* while we keep our own stuff (struct e100_serial) in a local .h file */
+#include "crisv10.h"
+#include <asm/fasttimer.h>
+#include <arch/io_interface_mux.h>
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
+
+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
+           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
+#endif
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS)
+#include "serial_compat.h"
+#endif
+
+struct tty_driver *serial_driver;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+//#define SERIAL_DEBUG_INTR
+//#define SERIAL_DEBUG_OPEN
+//#define SERIAL_DEBUG_FLOW
+//#define SERIAL_DEBUG_DATA
+//#define SERIAL_DEBUG_THROTTLE
+//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
+
+/* Enable this to use serial interrupts to handle when you
+   expect the first received event on the serial port to
+   be an error, break or similar. Used to be able to flash IRMA
+   from eLinux */
+#define SERIAL_HANDLE_EARLY_ERRORS
+
+/* Currently 16 descriptors x 128 bytes = 2048 bytes */
+#define SERIAL_DESCR_BUF_SIZE 256
+
+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
+
+/* We don't want to load the system with massive fast timer interrupt
+ * on high baudrates so limit it to 250 us (4kHz) */
+#define MIN_FLUSH_TIME_USEC 250
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+/* Debug details of interrupt handling */
+#define DINTR1(x)  /* irq on/off, errors */
+#define DINTR2(x)    /* tx and rx */
+/* Debug flip buffer stuff */
+#define DFLIP(x)
+/* Debug flow control and overview of data flow */
+#define DFLOW(x)
+#define DBAUD(x)
+#define DLOG_INT_TRIG(x)
+
+//#define DEBUG_LOG_INCLUDED
+#ifndef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG(line, string, value)
+#else
+struct debug_log_info
+{
+       unsigned long time;
+       unsigned long timer_data;
+//  int line;
+       const char *string;
+       int value;
+};
+#define DEBUG_LOG_SIZE 4096
+
+struct debug_log_info debug_log[DEBUG_LOG_SIZE];
+int debug_log_pos = 0;
+
+#define DEBUG_LOG(_line, _string, _value) do { \
+  if ((_line) == SERIAL_DEBUG_LINE) {\
+    debug_log_func(_line, _string, _value); \
+  }\
+}while(0)
+
+void debug_log_func(int line, const char *string, int value)
+{
+       if (debug_log_pos < DEBUG_LOG_SIZE) {
+               debug_log[debug_log_pos].time = jiffies;
+               debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
+//    debug_log[debug_log_pos].line = line;
+               debug_log[debug_log_pos].string = string;
+               debug_log[debug_log_pos].value = value;
+               debug_log_pos++;
+       }
+       /*printk(string, value);*/
+}
+#endif
+
+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
+/* Default number of timer ticks before flushing rx fifo
+ * When using "little data, low latency applications: use 0
+ * When using "much data applications (PPP)" use ~5
+ */
+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
+#endif
+
+unsigned long timer_data_to_ns(unsigned long timer_data);
+
+static void change_speed(struct e100_serial *info);
+static void rs_throttle(struct tty_struct * tty);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static int rs_write(struct tty_struct *tty,
+               const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
+static int e100_write_rs485(struct tty_struct *tty,
+               const unsigned char *buf, int count);
+#endif
+static int get_lsr_info(struct e100_serial *info, unsigned int *value);
+
+
+#define DEF_BAUD 115200   /* 115.2 kbit/s */
+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
+#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
+
+/* offsets from R_SERIALx_CTRL */
+
+#define REG_DATA 0
+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
+#define REG_TR_DATA 0
+#define REG_STATUS 1
+#define REG_TR_CTRL 1
+#define REG_REC_CTRL 2
+#define REG_BAUD 3
+#define REG_XOFF 4  /* this is a 32 bit register */
+
+/* The bitfields are the same for all serial ports */
+#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
+#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
+#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
+#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
+
+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
+
+/* Values for info->errorcode */
+#define ERRCODE_SET_BREAK    (TTY_BREAK)
+#define ERRCODE_INSERT        0x100
+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
+
+#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
+
+/*
+ * General note regarding the use of IO_* macros in this file:
+ *
+ * We will use the bits defined for DMA channel 6 when using various
+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
+ * the same for all channels (which of course they are).
+ *
+ * We will also use the bits defined for serial port 0 when writing commands
+ * to the different ports, as these bits too are the same for all ports.
+ */
+
+
+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
+static const unsigned long e100_ser_int_mask = 0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
+#endif
+;
+unsigned long r_alt_ser_baudrate_shadow = 0;
+
+/* this is the data for the four serial ports in the etrax100 */
+/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
+
+static struct e100_serial rs_table[] = {
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL0_CTRL,
+         .irq         = 1U << 12, /* uses DMA 6 and 7 */
+         .oclrintradr = R_DMA_CH6_CLR_INTR,
+         .ofirstadr   = R_DMA_CH6_FIRST,
+         .ocmdadr     = R_DMA_CH6_CMD,
+         .ostatusadr  = R_DMA_CH6_STATUS,
+         .iclrintradr = R_DMA_CH7_CLR_INTR,
+         .ifirstadr   = R_DMA_CH7_FIRST,
+         .icmdadr     = R_DMA_CH7_CMD,
+         .idescradr   = R_DMA_CH7_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 2,
+         .dma_owner   = dma_ser0,
+         .io_if       = if_serial_0,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER0_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 0 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER0_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 0 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+
+},  /* ttyS0 */
+#ifndef CONFIG_SVINTO_SIM
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL1_CTRL,
+         .irq         = 1U << 16, /* uses DMA 8 and 9 */
+         .oclrintradr = R_DMA_CH8_CLR_INTR,
+         .ofirstadr   = R_DMA_CH8_FIRST,
+         .ocmdadr     = R_DMA_CH8_CMD,
+         .ostatusadr  = R_DMA_CH8_STATUS,
+         .iclrintradr = R_DMA_CH9_CLR_INTR,
+         .ifirstadr   = R_DMA_CH9_FIRST,
+         .icmdadr     = R_DMA_CH9_CMD,
+         .idescradr   = R_DMA_CH9_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 3,
+         .dma_owner   = dma_ser1,
+         .io_if       = if_serial_1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+          .enabled  = 1,
+         .io_if_description = "ser1",
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER1_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 1 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER1_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 1 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_in_irq_nbr = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+},  /* ttyS1 */
+
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL2_CTRL,
+         .irq         = 1U << 4,  /* uses DMA 2 and 3 */
+         .oclrintradr = R_DMA_CH2_CLR_INTR,
+         .ofirstadr   = R_DMA_CH2_FIRST,
+         .ocmdadr     = R_DMA_CH2_CMD,
+         .ostatusadr  = R_DMA_CH2_STATUS,
+         .iclrintradr = R_DMA_CH3_CLR_INTR,
+         .ifirstadr   = R_DMA_CH3_FIRST,
+         .icmdadr     = R_DMA_CH3_CMD,
+         .idescradr   = R_DMA_CH3_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 0,
+         .dma_owner   = dma_ser2,
+         .io_if       = if_serial_2,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+          .enabled  = 1,
+         .io_if_description = "ser2",
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER2_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 2 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER2_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 2 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL,
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ },  /* ttyS2 */
+
+       { .baud        = DEF_BAUD,
+         .ioport        = (unsigned char *)R_SERIAL3_CTRL,
+         .irq         = 1U << 8,  /* uses DMA 4 and 5 */
+         .oclrintradr = R_DMA_CH4_CLR_INTR,
+         .ofirstadr   = R_DMA_CH4_FIRST,
+         .ocmdadr     = R_DMA_CH4_CMD,
+         .ostatusadr  = R_DMA_CH4_STATUS,
+         .iclrintradr = R_DMA_CH5_CLR_INTR,
+         .ifirstadr   = R_DMA_CH5_FIRST,
+         .icmdadr     = R_DMA_CH5_CMD,
+         .idescradr   = R_DMA_CH5_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 1,
+         .dma_owner   = dma_ser3,
+         .io_if       = if_serial_3,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+          .enabled  = 1,
+         .io_if_description = "ser3",
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+         .dma_out_enabled = 1,
+         .dma_out_nbr = SER3_TX_DMA_NBR,
+         .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
+         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_description = "serial 3 dma tr",
+#else
+         .dma_out_enabled = 0,
+         .dma_out_nbr = UINT_MAX,
+         .dma_out_irq_nbr = 0,
+         .dma_out_irq_flags = 0,
+         .dma_out_irq_description = NULL,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+         .dma_in_enabled = 1,
+         .dma_in_nbr = SER3_RX_DMA_NBR,
+         .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
+         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_description = "serial 3 dma rec",
+#else
+         .dma_in_enabled = 0,
+         .dma_in_nbr = UINT_MAX,
+         .dma_in_irq_nbr = 0,
+         .dma_in_irq_flags = 0,
+         .dma_in_irq_description = NULL
+#endif
+#else
+          .enabled  = 0,
+         .io_if_description = NULL,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ }   /* ttyS3 */
+#endif
+};
+
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
+#define PROCSTAT(x) x
+struct ser_statistics_type {
+       int overrun_cnt;
+       int early_errors_cnt;
+       int ser_ints_ok_cnt;
+       int errors_cnt;
+       unsigned long int processing_flip;
+       unsigned long processing_flip_still_room;
+       unsigned long int timeout_flush_cnt;
+       int rx_dma_ints;
+       int tx_dma_ints;
+       int rx_tot;
+       int tx_tot;
+};
+
+static struct ser_statistics_type ser_stat[NR_PORTS];
+
+#else
+
+#define PROCSTAT(x)
+
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
+
+/* RS-485 */
+#if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
+#endif
+#endif
+
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (R_PORT_PB_DATA):&dummy_ser[line]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+/* If not all status pins are used or disabled, use mixed mode */
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+
+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
+
+#if SER0_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
+
+#if SER0_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT0 */
+
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+
+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
+
+#if SER1_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
+
+#if SER1_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT1 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+
+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
+
+#if SER2_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
+
+#if SER2_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT2 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+
+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
+
+#if SER3_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
+
+#if SER3_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT3 */
+
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *dtr_port;
+       unsigned char          *dtr_shadow;
+       volatile unsigned char *ri_port;
+       unsigned char          *ri_shadow;
+       volatile unsigned char *dsr_port;
+       unsigned char          *dsr_shadow;
+       volatile unsigned char *cd_port;
+       unsigned char          *cd_shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+       E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+       E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+       E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+       E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+       E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+       E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+       E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+       E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *port;
+       unsigned char          *shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+#define E100_RTS_MASK 0x20
+#define E100_CTS_MASK 0x40
+
+/* All serial port signals are active low:
+ * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
+ * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
+ *
+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
+ */
+
+/* Output */
+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
+/* Input */
+#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK)
+
+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
+/* Is an output */
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
+
+/* Normally inputs */
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
+
+/* Input */
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static DEFINE_MUTEX(tmp_buf_mutex);
+
+/* Calculate the chartime depending on baudrate, numbor of bits etc. */
+static void update_char_time(struct e100_serial * info)
+{
+       tcflag_t cflags = info->port.tty->termios->c_cflag;
+       int bits;
+
+       /* calc. number of bits / data byte */
+       /* databits + startbit and 1 stopbit */
+       if ((cflags & CSIZE) == CS7)
+               bits = 9;
+       else
+               bits = 10;
+
+       if (cflags & CSTOPB)     /* 2 stopbits ? */
+               bits++;
+
+       if (cflags & PARENB)     /* parity bit ? */
+               bits++;
+
+       /* calc timeout */
+       info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
+       info->flush_time_usec = 4*info->char_time_usec;
+       if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
+               info->flush_time_usec = MIN_FLUSH_TIME_USEC;
+
+}
+
+/*
+ * This function maps from the Bxxxx defines in asm/termbits.h into real
+ * baud rates.
+ */
+
+static int
+cflag_to_baud(unsigned int cflag)
+{
+       static int baud_table[] = {
+               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+               4800, 9600, 19200, 38400 };
+
+       static int ext_baud_table[] = {
+               0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
+                0, 0, 0, 0, 0, 0, 0, 0 };
+
+       if (cflag & CBAUDEX)
+               return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               return baud_table[cflag & CBAUD];
+}
+
+/* and this maps to an etrax100 hardware baud constant */
+
+static unsigned char
+cflag_to_etrax_baud(unsigned int cflag)
+{
+       char retval;
+
+       static char baud_table[] = {
+               -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
+
+       static char ext_baud_table[] = {
+               -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+       if (cflag & CBAUDEX)
+               retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               retval = baud_table[cflag & CBAUD];
+
+       if (retval < 0) {
+               printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
+               retval = 5; /* choose default 9600 instead */
+       }
+
+       return retval | (retval << 4); /* choose same for both TX and RX */
+}
+
+
+/* Various static support functions */
+
+/* Functions to set or clear DTR/RTS on the requested line */
+/* It is complicated by the fact that RTS is a serial port register, while
+ * DTR might not be implemented in the HW at all, and if it is, it can be on
+ * any general port.
+ */
+
+
+static inline void
+e100_dtr(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned char mask = e100_modem_pins[info->line].dtr_mask;
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
+       printk("ser%i shadow before 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+       /* DTR is active low */
+       {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].dtr_shadow &= ~mask;
+               *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
+               local_irq_restore(flags);
+       }
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i shadow after 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+#endif
+}
+
+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ *                                          0=0V    , 1=3.3V
+ */
+static inline void
+e100_rts(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long flags;
+       local_irq_save(flags);
+       info->rx_ctrl &= ~E100_RTS_MASK;
+       info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
+       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
+       local_irq_restore(flags);
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i rts %i\n", info->line, set);
+#endif
+#endif
+}
+
+
+/* If this behaves as a modem, RI and CD is an output */
+static inline void
+e100_ri_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* RI is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].ri_mask;
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].ri_shadow &= ~mask;
+               *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
+               local_irq_restore(flags);
+       }
+#endif
+}
+static inline void
+e100_cd_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* CD is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].cd_mask;
+               unsigned long flags;
+
+               local_irq_save(flags);
+               *e100_modem_pins[info->line].cd_shadow &= ~mask;
+               *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
+               local_irq_restore(flags);
+       }
+#endif
+}
+
+static inline void
+e100_disable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* disable the receiver */
+       info->ioport[REG_REC_CTRL] =
+               (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+static inline void
+e100_enable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* enable the receiver */
+       info->ioport[REG_REC_CTRL] =
+               (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
+
+static inline void
+e100_disable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
+}
+
+static inline void
+e100_enable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
+}
+
+/* the tx DMA uses only dma_descr interrupt */
+
+static void e100_disable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = info->irq;
+}
+
+static void e100_enable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = info->irq;
+}
+
+static void e100_disable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable output DMA channel for the serial port in question
+        * ( set to something other than serialX)
+        */
+       local_irq_save(flags);
+       DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
+                   IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
+                   IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
+                   IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
+                   IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+
+static void e100_enable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
+       /* Enable output DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+static void e100_disable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable input DMA channel for the serial port in question
+        * ( set to something other than serialX)
+        */
+       local_irq_save(flags);
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
+                   IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
+                   IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
+                   IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
+                   IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+
+static void e100_enable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       /* Enable input DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       local_irq_restore(flags);
+}
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+/* in order to detect and fix errors on the first byte
+   we have to use the serial interrupts as well. */
+
+static inline void
+e100_disable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
+}
+
+static inline void
+e100_enable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+2*info->line),
+              (1U << (8+2*info->line)));
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
+}
+#endif
+
+static inline void
+e100_disable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
+}
+
+static inline void
+e100_enable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+1+2*info->line),
+              (1U << (8+1+2*info->line)));
+#endif
+       DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
+}
+
+static inline void e100_enable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_enable_rxdma_irq(info);
+       else
+               e100_enable_serial_data_irq(info);
+}
+static inline void e100_disable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_disable_rxdma_irq(info);
+       else
+               e100_disable_serial_data_irq(info);
+}
+
+#if defined(CONFIG_ETRAX_RS485)
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+       *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+       REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
+                      rs485_port_g_bit, 1);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
+#endif
+
+       info->rs485 = *r;
+
+       /* Maximum delay before RTS equal to 1000 */
+       if (info->rs485.delay_rts_before_send >= 1000)
+               info->rs485.delay_rts_before_send = 1000;
+
+/*     printk("rts: on send = %i, after = %i, enabled = %i",
+                   info->rs485.rts_on_send,
+                   info->rs485.rts_after_sent,
+                   info->rs485.enabled
+       );
+*/
+       return 0;
+}
+
+static int
+e100_write_rs485(struct tty_struct *tty,
+                 const unsigned char *buf, int count)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       int old_value = (info->rs485.flags) & SER_RS485_ENABLED;
+
+       /* rs485 is always implicitly enabled if we're using the ioctl()
+        * but it doesn't have to be set in the serial_rs485
+        * (to be backward compatible with old apps)
+        * So we store, set and restore it.
+        */
+       info->rs485.flags |= SER_RS485_ENABLED;
+       /* rs_write now deals with RS485 if enabled */
+       count = rs_write(tty, buf, count);
+       if (!old_value)
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+       return count;
+}
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers_rs485[info->line].function = NULL;
+       e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+       e100_enable_rx(info);
+       e100_enable_rx_irq(info);
+#endif
+}
+#endif
+#endif /* CONFIG_ETRAX_RS485 */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void
+rs_stop(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               local_irq_save(flags);
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
+                               STOP_CHAR(info->port.tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+               local_irq_restore(flags);
+       }
+}
+
+static void
+rs_start(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               local_irq_save(flags);
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+               if (!info->uses_dma_out &&
+                   info->xmit.head != info->xmit.tail && info->xmit.buf)
+                       e100_enable_serial_tx_ready_irq(info);
+
+               local_irq_restore(flags);
+       }
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static void rs_sched_event(struct e100_serial *info, int event)
+{
+       if (info->event & (1 << event))
+               return;
+       info->event |= 1 << event;
+       schedule_work(&info->work);
+}
+
+/* The output DMA channel is free - use it to send as many chars as possible
+ * NOTES:
+ *   We don't pay attention to info->x_char, which means if the TTY wants to
+ *   use XON/XOFF it will set info->x_char but we won't send any X char!
+ *
+ *   To implement this, we'd just start a DMA send of 1 byte pointing at a
+ *   buffer containing the X char, and skip updating xmit. We'd also have to
+ *   check if the last sent char was the X char when we enter this function
+ *   the next time, to avoid updating xmit with the sent X value.
+ */
+
+static void
+transmit_chars_dma(struct e100_serial *info)
+{
+       unsigned int c, sentl;
+       struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* This will output too little if tail is not 0 always since
+        * we don't reloop to send the other part. Anyway this SHOULD be a
+        * no-op - transmit_chars_dma would never really be called during sim
+        * since rs_write does not write into the xmit buffer then.
+        */
+       if (info->xmit.tail)
+               printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
+       if (info->xmit.head != info->xmit.tail) {
+               SIMCOUT(info->xmit.buf + info->xmit.tail,
+                       CIRC_CNT(info->xmit.head,
+                                info->xmit.tail,
+                                SERIAL_XMIT_SIZE));
+               info->xmit.head = info->xmit.tail;  /* move back head */
+               info->tr_running = 0;
+       }
+       return;
+#endif
+       /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->oclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+#ifdef SERIAL_DEBUG_INTR
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("tc\n");
+#endif
+       if (!info->tr_running) {
+               /* weirdo... we shouldn't get here! */
+               printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
+               return;
+       }
+
+       descr = &info->tr_descr;
+
+       /* first get the amount of bytes sent during the last DMA transfer,
+          and update xmit accordingly */
+
+       /* if the stop bit was not set, all data has been sent */
+       if (!(descr->status & d_stop)) {
+               sentl = descr->sw_len;
+       } else
+               /* otherwise we find the amount of data sent here */
+               sentl = descr->hw_len;
+
+       DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
+
+       /* update stats */
+       info->icount.tx += sentl;
+
+       /* update xmit buffer */
+       info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
+
+       /* if there is only a few chars left in the buf, wake up the blocked
+          write if any */
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+       /* find out the largest amount of consecutive bytes we want to send now */
+
+       c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+
+       /* Don't send all in one DMA transfer - divide it so we wake up
+        * application before all is sent
+        */
+
+       if (c >= 4*WAKEUP_CHARS)
+               c = c/2;
+
+       if (c <= 0) {
+               /* our job here is done, don't schedule any new DMA transfer */
+               info->tr_running = 0;
+
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.flags & SER_RS485_ENABLED) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               return;
+       }
+
+       /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
+       /* set up the descriptor correctly for output */
+       DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
+       descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
+       descr->sw_len = c;
+       descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
+       descr->status = 0;
+
+       *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
+       *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* DMA is now running (hopefully) */
+} /* transmit_chars_dma */
+
+static void
+start_transmit(struct e100_serial *info)
+{
+#if 0
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("x\n");
+#endif
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+       info->tr_running = 1;
+       if (info->uses_dma_out)
+               transmit_chars_dma(info);
+       else
+               e100_enable_serial_tx_ready_irq(info);
+} /* start_transmit */
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
+  unsigned long timer_flags; \
+  local_irq_save(timer_flags); \
+  if (fast_timers[info->line].function == NULL) { \
+    serial_fast_timer_started++; \
+    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+    start_one_shot_timer(&fast_timers[info->line], \
+                         flush_timeout_function, \
+                         (unsigned long)info, \
+                         (usec), \
+                         string); \
+  } \
+  else { \
+    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+  } \
+  local_irq_restore(timer_flags); \
+}
+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
+
+#else
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static struct etrax_recv_buffer *
+alloc_recv_buffer(unsigned int size)
+{
+       struct etrax_recv_buffer *buffer;
+
+       if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+               return NULL;
+
+       buffer->next = NULL;
+       buffer->length = 0;
+       buffer->error = TTY_NORMAL;
+
+       return buffer;
+}
+
+static void
+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (!info->first_recv_buffer)
+               info->first_recv_buffer = buffer;
+       else
+               info->last_recv_buffer->next = buffer;
+
+       info->last_recv_buffer = buffer;
+
+       info->recv_cnt += buffer->length;
+       if (info->recv_cnt > info->max_recv_cnt)
+               info->max_recv_cnt = info->recv_cnt;
+
+       local_irq_restore(flags);
+}
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+       struct etrax_recv_buffer *buffer;
+       if (info->uses_dma_in) {
+               if (!(buffer = alloc_recv_buffer(4)))
+                       return 0;
+
+               buffer->length = 1;
+               buffer->error = flag;
+               buffer->buffer[0] = data;
+
+               append_recv_buffer(info, buffer);
+
+               info->icount.rx++;
+       } else {
+               struct tty_struct *tty = info->port.tty;
+               tty_insert_flip_char(tty, data, flag);
+               info->icount.rx++;
+       }
+
+       return 1;
+}
+
+static unsigned int handle_descr_data(struct e100_serial *info,
+                                     struct etrax_dma_descr *descr,
+                                     unsigned int recvl)
+{
+       struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
+
+       if (info->recv_cnt + recvl > 65536) {
+               printk(KERN_CRIT
+                      "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
+               return 0;
+       }
+
+       buffer->length = recvl;
+
+       if (info->errorcode == ERRCODE_SET_BREAK)
+               buffer->error = TTY_BREAK;
+       info->errorcode = 0;
+
+       append_recv_buffer(info, buffer);
+
+       if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+               panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
+
+       descr->buf = virt_to_phys(buffer->buffer);
+
+       return recvl;
+}
+
+static unsigned int handle_all_descr_data(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr;
+       unsigned int recvl;
+       unsigned int ret = 0;
+
+       while (1)
+       {
+               descr = &info->rec_descr[info->cur_rec_descr];
+
+               if (descr == phys_to_virt(*info->idescradr))
+                       break;
+
+               if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+                       info->cur_rec_descr = 0;
+
+               /* find out how many bytes were read */
+
+               /* if the eop bit was not set, all data has been received */
+               if (!(descr->status & d_eop)) {
+                       recvl = descr->sw_len;
+               } else {
+                       /* otherwise we find the amount of data received here */
+                       recvl = descr->hw_len;
+               }
+
+               /* Reset the status information */
+               descr->status = 0;
+
+               DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
+                       if (info->port.tty->stopped) {
+                               unsigned char *buf = phys_to_virt(descr->buf);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
+                       }
+                       );
+
+               /* update stats */
+               info->icount.rx += recvl;
+
+               ret += handle_descr_data(info, descr, recvl);
+       }
+
+       return ret;
+}
+
+static void receive_chars_dma(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       unsigned char rstat;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+
+       /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->iclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+       tty = info->port.tty;
+       if (!tty) /* Something wrong... */
+               return;
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       if (info->uses_dma_in)
+               e100_enable_serial_data_irq(info);
+#endif
+
+       if (info->errorcode == ERRCODE_INSERT_BREAK)
+               add_char_and_flag(info, '\0', TTY_BREAK);
+
+       handle_all_descr_data(info);
+
+       /* Read the status register to detect errors */
+       rstat = info->ioport[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               unsigned char data = info->ioport[REG_DATA];
+
+               PROCSTAT(ser_stat[info->line].errors_cnt++);
+               DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
+                         ((rstat & SER_ERROR_MASK) << 8) | data);
+
+               if (rstat & SER_PAR_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_PARITY);
+               else if (rstat & SER_OVERRUN_MASK)
+                       add_char_and_flag(info, data, TTY_OVERRUN);
+               else if (rstat & SER_FRAMING_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_FRAME);
+       }
+
+       START_FLUSH_FAST_TIMER(info, "receive_chars");
+
+       /* Restart the receiving DMA */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
+
+static int start_recv_dma(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+        int i;
+
+       /* Set up the receiving descriptors */
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+               if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+                       panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
+
+               descr[i].ctrl = d_int;
+               descr[i].buf = virt_to_phys(buffer->buffer);
+               descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+               descr[i].hw_len = 0;
+               descr[i].status = 0;
+               descr[i].next = virt_to_phys(&descr[i+1]);
+       }
+
+       /* Link the last descriptor to the first */
+       descr[i-1].next = virt_to_phys(&descr[0]);
+
+       /* Start with the first descriptor in the list */
+       info->cur_rec_descr = 0;
+
+       /* Start the DMA */
+       *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* Input DMA should be running now */
+       return 1;
+}
+
+static void
+start_receive(struct e100_serial *info)
+{
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+       if (info->uses_dma_in) {
+               /* reset the input dma channel to be sure it works */
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               start_recv_dma(info);
+       }
+}
+
+
+/* the bits in the MASK2 register are laid out like this:
+   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
+   where I is the input channel and O is the output channel for the port.
+   info->irq is the bit number for the DMAO_DESCR so to check the others we
+   shift info->irq to the left.
+*/
+
+/* dma output channel interrupt handler
+   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
+   DMA8(ser1) when they have finished a descriptor with the intr flag set.
+*/
+
+static irqreturn_t
+tr_interrupt(int irq, void *dev_id)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? tr_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_out)
+                       continue;
+               /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
+               if (ireg & info->irq) {
+                       handled = 1;
+                       /* we can send a new dma bunch. make it so. */
+                       DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
+                       /* Read jiffies_usec first,
+                        * we want this time to be as late as possible
+                        */
+                       PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+                       info->last_tx_active_usec = GET_JIFFIES_USEC();
+                       info->last_tx_active = jiffies;
+                       transmit_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* tr_interrupt */
+
+/* dma input channel interrupt handler */
+
+static irqreturn_t
+rec_interrupt(int irq, void *dev_id)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? rec_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_in)
+                       continue;
+               /* check for both dma_eop and dma_descr for the input dma channel */
+               if (ireg & ((info->irq << 2) | (info->irq << 3))) {
+                       handled = 1;
+                       /* we have received something */
+                       receive_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* rec_interrupt */
+
+static int force_eop_if_needed(struct e100_serial *info)
+{
+       /* We check data_avail bit to determine if data has
+        * arrived since last time
+        */
+       unsigned char rstat = info->ioport[REG_STATUS];
+
+       /* error or datavail? */
+       if (rstat & SER_ERROR_MASK) {
+               /* Some error has occurred. If there has been valid data, an
+                * EOP interrupt will be made automatically. If no data, the
+                * normal ser_interrupt should be enabled and handle it.
+                * So do nothing!
+                */
+               DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
+                         rstat | (info->line << 8));
+               return 0;
+       }
+
+       if (rstat & SER_DATA_AVAIL_MASK) {
+               /* Ok data, no error, count it */
+               TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
+                         rstat | (info->line << 8)));
+               /* Read data to clear status flags */
+               (void)info->ioport[REG_DATA];
+
+               info->forced_eop = 0;
+               START_FLUSH_FAST_TIMER(info, "magic");
+               return 0;
+       }
+
+       /* hit the timeout, force an EOP for the input
+        * dma channel if we haven't already
+        */
+       if (!info->forced_eop) {
+               info->forced_eop = 1;
+               PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+               TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
+               FORCE_EOP(info);
+       }
+
+       return 1;
+}
+
+static void flush_to_flip_buffer(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       struct etrax_recv_buffer *buffer;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       tty = info->port.tty;
+
+       if (!tty) {
+               local_irq_restore(flags);
+               return;
+       }
+
+       while ((buffer = info->first_recv_buffer) != NULL) {
+               unsigned int count = buffer->length;
+
+               tty_insert_flip_string(tty, buffer->buffer, count);
+               info->recv_cnt -= count;
+
+               if (count == buffer->length) {
+                       info->first_recv_buffer = buffer->next;
+                       kfree(buffer);
+               } else {
+                       buffer->length -= count;
+                       memmove(buffer->buffer, buffer->buffer + count, buffer->length);
+                       buffer->error = TTY_NORMAL;
+               }
+       }
+
+       if (!info->first_recv_buffer)
+               info->last_recv_buffer = NULL;
+
+       local_irq_restore(flags);
+
+       /* This includes a check for low-latency */
+       tty_flip_buffer_push(tty);
+}
+
+static void check_flush_timeout(struct e100_serial *info)
+{
+       /* Flip what we've got (if we can) */
+       flush_to_flip_buffer(info);
+
+       /* We might need to flip later, but not to fast
+        * since the system is busy processing input... */
+       if (info->first_recv_buffer)
+               START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
+
+       /* Force eop last, since data might have come while we're processing
+        * and if we started the slow timer above, we won't start a fast
+        * below.
+        */
+       force_eop_if_needed(info);
+}
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static void flush_timeout_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers[info->line].function = NULL;
+       serial_fast_timer_expired++;
+       TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
+       TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
+       check_flush_timeout(info);
+}
+
+#else
+
+/* dma fifo/buffer timeout handler
+   forces an end-of-packet for the dma input channel if no chars
+   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
+*/
+
+static struct timer_list flush_timer;
+
+static void
+timed_flush_handler(unsigned long ptr)
+{
+       struct e100_serial *info;
+       int i;
+
+#ifdef CONFIG_SVINTO_SIM
+       return;
+#endif
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (info->uses_dma_in)
+                       check_flush_timeout(info);
+       }
+
+       /* restart flush timer */
+       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+}
+#endif
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+
+/* If there is an error (ie break) when the DMA is running and
+ * there are no bytes in the fifo the DMA is stopped and we get no
+ * eop interrupt. Thus we have to monitor the first bytes on a DMA
+ * transfer, and if it is without error we can turn the serial
+ * interrupts off.
+ */
+
+/*
+BREAK handling on ETRAX 100:
+ETRAX will generate interrupt although there is no stop bit between the
+characters.
+
+Depending on how long the break sequence is, the end of the breaksequence
+will look differently:
+| indicates start/end of a character.
+
+B= Break character (0x00) with framing error.
+E= Error byte with parity error received after B characters.
+F= "Faked" valid byte received immediately after B characters.
+V= Valid byte
+
+1.
+    B          BL         ___________________________ V
+.._|__________|__________|                           |valid data |
+
+Multiple frame errors with data == 0x00 (B),
+the timing matches up "perfectly" so no extra ending char is detected.
+The RXD pin is 1 in the last interrupt, in that case
+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
+know if another byte will come and this really is case 2. below
+(e.g F=0xFF or 0xFE)
+If RXD pin is 0 we can expect another character (see 2. below).
+
+
+2.
+
+    B          B          E or F__________________..__ V
+.._|__________|__________|______    |                 |valid data
+                          "valid" or
+                          parity error
+
+Multiple frame errors with data == 0x00 (B),
+but the part of the break trigs is interpreted as a start bit (and possibly
+some 0 bits followed by a number of 1 bits and a stop bit).
+Depending on parity settings etc. this last character can be either
+a fake "valid" char (F) or have a parity error (E).
+
+If the character is valid it will be put in the buffer,
+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
+will set the flags so the tty will handle it,
+if it's an error byte it will not be put in the buffer
+and we set info->errorcode = ERRCODE_INSERT_BREAK.
+
+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
+of the last faulty char (B) and compares it with the current time:
+If the time elapsed time is less then 2*char_time_usec we will assume
+it's a faked F char and not a Valid char and set
+info->errorcode = ERRCODE_SET_BREAK.
+
+Flaws in the above solution:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We use the timer to distinguish a F character from a V character,
+if a V character is to close after the break we might make the wrong decision.
+
+TODO: The break will be delayed until an F or V character is received.
+
+*/
+
+static
+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
+{
+       unsigned long data_read;
+       struct tty_struct *tty = info->port.tty;
+
+       if (!tty) {
+               printk("!NO TTY!\n");
+               return info;
+       }
+
+       /* Read data and status at the same time */
+       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
+more_data:
+       if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+       DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
+
+       if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
+                         IO_MASK(R_SERIAL0_READ, par_err) |
+                         IO_MASK(R_SERIAL0_READ, overrun) )) {
+               /* An error */
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       log_int_trig1_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+
+
+               if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
+                    (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               unsigned char data = IO_EXTRACT(R_SERIAL0_READ,
+                                       data_in, data_read);
+                               char flag = TTY_NORMAL;
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       struct tty_struct *tty = info->port.tty;
+                                       tty_insert_flip_char(tty, 0, flag);
+                                       info->icount.rx++;
+                               }
+
+                               if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
+                                       info->icount.parity++;
+                                       flag = TTY_PARITY;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
+                                       info->icount.overrun++;
+                                       flag = TTY_OVERRUN;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
+                                       info->icount.frame++;
+                                       flag = TTY_FRAME;
+                               }
+                               tty_insert_flip_char(tty, data, flag);
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+               }
+       } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               /* No error */
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       if (log_int_pos >= log_int_size) {
+                               log_int_pos = 0;
+                       }
+                       log_int_trig0_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+               tty_insert_flip_char(tty,
+                       IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
+                       TTY_NORMAL);
+       } else {
+               DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
+       }
+
+
+       info->icount.rx++;
+       data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
+       if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
+               goto more_data;
+       }
+
+       tty_flip_buffer_push(info->port.tty);
+       return info;
+}
+
+static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
+{
+       unsigned char rstat;
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("Interrupt from serport %d\n", i);
+#endif
+/*     DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
+       if (!info->uses_dma_in) {
+               return handle_ser_rx_interrupt_no_dma(info);
+       }
+       /* DMA is used */
+       rstat = info->ioport[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               unsigned char data;
+
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               data = info->ioport[REG_DATA];
+               DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
+               if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (rstat & SER_RXD_MASK) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       info->icount.brk++;
+                                       add_char_and_flag(info, '\0', TTY_BREAK);
+                               }
+
+                               if (rstat & SER_PAR_ERR_MASK) {
+                                       info->icount.parity++;
+                                       add_char_and_flag(info, data, TTY_PARITY);
+                               } else if (rstat & SER_OVERRUN_MASK) {
+                                       info->icount.overrun++;
+                                       add_char_and_flag(info, data, TTY_OVERRUN);
+                               } else if (rstat & SER_FRAMING_ERR_MASK) {
+                                       info->icount.frame++;
+                                       add_char_and_flag(info, data, TTY_FRAME);
+                               }
+
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+                       DEBUG_LOG(info->line, "#iERR s d %04X\n",
+                                 ((rstat & SER_ERROR_MASK) << 8) | data);
+               }
+               PROCSTAT(ser_stat[info->line].early_errors_cnt++);
+       } else { /* It was a valid byte, now let the DMA do the rest */
+               unsigned long curr_time_u = GET_JIFFIES_USEC();
+               unsigned long curr_time = jiffies;
+
+               if (info->break_detected_cnt) {
+                       /* Detect if this character is a new valid char or the
+                        * last char in a break sequence: If LSBits are 0 and
+                        * MSBits are high AND the time is close to the
+                        * previous interrupt we should discard it.
+                        */
+                       long elapsed_usec =
+                         (curr_time - info->last_rx_active) * (1000000/HZ) +
+                         curr_time_u - info->last_rx_active_usec;
+                       if (elapsed_usec < 2*info->char_time_usec) {
+                               DEBUG_LOG(info->line, "FBRK %i\n", info->line);
+                               /* Report as BREAK (error) and let
+                                * receive_chars_dma() handle it
+                                */
+                               info->errorcode = ERRCODE_SET_BREAK;
+                       } else {
+                               DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
+                       }
+                       DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
+               }
+
+#ifdef SERIAL_DEBUG_INTR
+               printk("** OK, disabling ser_interrupts\n");
+#endif
+               e100_disable_serial_data_irq(info);
+               DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
+               info->break_detected_cnt = 0;
+
+               PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+       }
+       /* Restarting the DMA never hurts */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+       START_FLUSH_FAST_TIMER(info, "ser_int");
+       return info;
+} /* handle_ser_rx_interrupt */
+
+static void handle_ser_tx_interrupt(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       if (info->x_char) {
+               unsigned char rstat;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
+               local_irq_save(flags);
+               rstat = info->ioport[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+
+               info->ioport[REG_TR_DATA] = info->x_char;
+               info->icount.tx++;
+               info->x_char = 0;
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+               local_irq_restore(flags);
+               return;
+       }
+       if (info->uses_dma_out) {
+               unsigned char rstat;
+               int i;
+               /* We only use normal tx interrupt when sending x_char */
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
+               local_irq_save(flags);
+               rstat = info->ioport[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+               e100_disable_serial_tx_ready_irq(info);
+               if (info->port.tty->stopped)
+                       rs_stop(info->port.tty);
+               /* Enable the DMA channel and tell it to continue */
+               e100_enable_txdma_channel(info);
+               /* Wait 12 cycles before doing the DMA command */
+               for(i = 6;  i > 0; i--)
+                       nop();
+
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
+               local_irq_restore(flags);
+               return;
+       }
+       /* Normal char-by-char interrupt */
+       if (info->xmit.head == info->xmit.tail
+           || info->port.tty->stopped
+           || info->port.tty->hw_stopped) {
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
+                               info->port.tty->stopped));
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               return;
+       }
+       DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
+       /* Send a byte, rs485 timing is critical so turn of ints */
+       local_irq_save(flags);
+       info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
+       info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+       info->icount.tx++;
+       if (info->xmit.head == info->xmit.tail) {
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.flags & SER_RS485_ENABLED) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               info->last_tx_active_usec = GET_JIFFIES_USEC();
+               info->last_tx_active = jiffies;
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
+       } else {
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+       }
+       local_irq_restore(flags);
+
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+} /* handle_ser_tx_interrupt */
+
+/* result of time measurements:
+ * RX duration 54-60 us when doing something, otherwise 6-9 us
+ * ser_int duration: just sending: 8-15 us normally, up to 73 us
+ */
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id)
+{
+       static volatile int tx_started = 0;
+       struct e100_serial *info;
+       int i;
+       unsigned long flags;
+       unsigned long irq_mask1_rd;
+       unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
+       int handled = 0;
+       static volatile unsigned long reentered_ready_mask = 0;
+
+       local_irq_save(flags);
+       irq_mask1_rd = *R_IRQ_MASK1_RD;
+       /* First handle all rx interrupts with ints disabled */
+       info = rs_table;
+       irq_mask1_rd &= e100_ser_int_mask;
+       for (i = 0; i < NR_PORTS; i++) {
+               /* Which line caused the data irq? */
+               if (irq_mask1_rd & data_mask) {
+                       handled = 1;
+                       handle_ser_rx_interrupt(info);
+               }
+               info += 1;
+               data_mask <<= 2;
+       }
+       /* Handle tx interrupts with interrupts enabled so we
+        * can take care of new data interrupts while transmitting
+        * We protect the tx part with the tx_started flag.
+        * We disable the tr_ready interrupts we are about to handle and
+        * unblock the serial interrupt so new serial interrupts may come.
+        *
+        * If we get a new interrupt:
+        *  - it migth be due to synchronous serial ports.
+        *  - serial irq will be blocked by general irq handler.
+        *  - async data will be handled above (sync will be ignored).
+        *  - tx_started flag will prevent us from trying to send again and
+        *    we will exit fast - no need to unblock serial irq.
+        *  - Next (sync) serial interrupt handler will be runned with
+        *    disabled interrupt due to restore_flags() at end of function,
+        *    so sync handler will not be preempted or reentered.
+        */
+       if (!tx_started) {
+               unsigned long ready_mask;
+               unsigned long
+               tx_started = 1;
+               /* Only the tr_ready interrupts left */
+               irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               while (irq_mask1_rd) {
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = irq_mask1_rd;
+                       /* Unblock the serial interrupt */
+                       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+                       local_irq_enable();
+                       ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
+                       info = rs_table;
+                       for (i = 0; i < NR_PORTS; i++) {
+                               /* Which line caused the ready irq? */
+                               if (irq_mask1_rd & ready_mask) {
+                                       handled = 1;
+                                       handle_ser_tx_interrupt(info);
+                               }
+                               info += 1;
+                               ready_mask <<= 2;
+                       }
+                       /* handle_ser_tx_interrupt enables tr_ready interrupts */
+                       local_irq_disable();
+                       /* Handle reentered TX interrupt */
+                       irq_mask1_rd = reentered_ready_mask;
+               }
+               local_irq_disable();
+               tx_started = 0;
+       } else {
+               unsigned long ready_mask;
+               ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               if (ready_mask) {
+                       reentered_ready_mask |= ready_mask;
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = ready_mask;
+                       DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
+               }
+       }
+
+       local_irq_restore(flags);
+       return IRQ_RETVAL(handled);
+} /* ser_interrupt */
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void
+do_softint(struct work_struct *work)
+{
+       struct e100_serial      *info;
+       struct tty_struct       *tty;
+
+       info = container_of(work, struct e100_serial, work);
+
+       tty = info->port.tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
+               tty_wakeup(tty);
+}
+
+static int
+startup(struct e100_serial * info)
+{
+       unsigned long flags;
+       unsigned long xmit_page;
+       int i;
+
+       xmit_page = get_zeroed_page(GFP_KERNEL);
+       if (!xmit_page)
+               return -ENOMEM;
+
+       local_irq_save(flags);
+
+       /* if it was already initialized, skip this */
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               local_irq_restore(flags);
+               free_page(xmit_page);
+               return 0;
+       }
+
+       if (info->xmit.buf)
+               free_page(xmit_page);
+       else
+               info->xmit.buf = (unsigned char *) xmit_page;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Bits and pieces collected from below.  Better to have them
+          in one ifdef:ed clause than to mix in a lot of ifdefs,
+          right? */
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = NULL;
+
+       /* No real action in the simulator, but may set info important
+          to ioctl. */
+       change_speed(info);
+#else
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+
+       /*
+        * Reset the DMA channels and make sure their interrupts are cleared
+        */
+
+       if (info->dma_in_enabled) {
+               info->uses_dma_in = 1;
+               e100_enable_rxdma_channel(info);
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               /* Wait until reset cycle is complete */
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->iclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_rxdma_channel(info);
+       }
+
+       if (info->dma_out_enabled) {
+               info->uses_dma_out = 1;
+               e100_enable_txdma_channel(info);
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->oclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_txdma_channel(info);
+       }
+
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = 0;
+
+       /*
+        * and set the speed and other flags of the serial port
+        * this will start the rx/tx as well
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_enable_serial_data_irq(info);
+#endif
+       change_speed(info);
+
+       /* dummy read to reset any serial errors */
+
+       (void)info->ioport[REG_DATA];
+
+       /* enable the interrupts */
+       if (info->uses_dma_out)
+               e100_enable_txdma_irq(info);
+
+       e100_enable_rx_irq(info);
+
+       info->tr_running = 0; /* to be sure we don't lock up the transmitter */
+
+       /* setup the dma input descriptor and start dma */
+
+       start_receive(info);
+
+       /* for safety, make sure the descriptors last result is 0 bytes written */
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+
+       /* enable RTS/DTR last */
+
+       e100_rts(info, 1);
+       e100_dtr(info, 1);
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       info->flags |= ASYNC_INITIALIZED;
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void
+shutdown(struct e100_serial * info)
+{
+       unsigned long flags;
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+       int i;
+
+#ifndef CONFIG_SVINTO_SIM
+       /* shut down the transmitter and receiver */
+       DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
+       e100_disable_rx(info);
+       info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
+
+       /* disable interrupts, reset dma channels */
+       if (info->uses_dma_in) {
+               e100_disable_rxdma_irq(info);
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_in = 0;
+       } else {
+               e100_disable_serial_data_irq(info);
+       }
+
+       if (info->uses_dma_out) {
+               e100_disable_txdma_irq(info);
+               info->tr_running = 0;
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_out = 0;
+       } else {
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+       }
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....\n", info->line,
+              info->irq);
+#endif
+
+       local_irq_save(flags);
+
+       if (info->xmit.buf) {
+               free_page((unsigned long)info->xmit.buf);
+               info->xmit.buf = NULL;
+       }
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               if (descr[i].buf) {
+                       buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
+                       kfree(buffer);
+                       descr[i].buf = 0;
+               }
+
+       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+               /* hang up DTR and RTS if HUPCL is enabled */
+               e100_dtr(info, 0);
+               e100_rts(info, 0); /* could check CRTSCTS before doing this */
+       }
+
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       local_irq_restore(flags);
+}
+
+
+/* change baud rate and other assorted parameters */
+
+static void
+change_speed(struct e100_serial *info)
+{
+       unsigned int cflag;
+       unsigned long xoff;
+       unsigned long flags;
+       /* first some safety checks */
+
+       if (!info->port.tty || !info->port.tty->termios)
+               return;
+       if (!info->ioport)
+               return;
+
+       cflag = info->port.tty->termios->c_cflag;
+
+       /* possibly, the tx/rx should be disabled first to do this safely */
+
+       /* change baud-rate and write it to the hardware */
+       if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+               /* Special baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               /* R_ALT_SER_BAUDRATE selects the source */
+               DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
+                      (unsigned long)info->baud_base, info->custom_divisor));
+               if (info->baud_base == SERIAL_PRESCALE_BASE) {
+                       /* 0, 2-65535 (0=65536) */
+                       u16 divisor = info->custom_divisor;
+                       /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
+                       /* baudrate is 3.125MHz/custom_divisor */
+                       alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
+                       alt_source = 0x11;
+                       DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
+                       *R_SERIAL_PRESCALE = divisor;
+                       info->baud = SERIAL_PRESCALE_BASE/divisor;
+               }
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+               else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
+                         info->custom_divisor == 1) ||
+                        (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
+                         info->custom_divisor == 8)) {
+                               /* ext_clk selected */
+                               alt_source =
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
+                               DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
+                               info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
+                       }
+#endif
+               else
+               {
+                       /* Bad baudbase, we don't support using timer0
+                        * for baudrate.
+                        */
+                       printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
+                              (unsigned long)info->baud_base, info->custom_divisor);
+               }
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+       } else {
+               /* Normal baudrate */
+               /* Make sure we use normal baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+#ifndef CONFIG_SVINTO_SIM
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+#endif /* CONFIG_SVINTO_SIM */
+
+               info->baud = cflag_to_baud(cflag);
+#ifndef CONFIG_SVINTO_SIM
+               info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
+#endif /* CONFIG_SVINTO_SIM */
+       }
+
+#ifndef CONFIG_SVINTO_SIM
+       /* start with default settings and then fill in changes */
+       local_irq_save(flags);
+       /* 8 bit, no/even parity */
+       info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
+
+       /* 8 bit, no/even parity, 1 stop bit, no cts */
+       info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
+
+       if ((cflag & CSIZE) == CS7) {
+               /* set 7 bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+       }
+
+       if (cflag & CSTOPB) {
+               /* set 2 stop bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
+       }
+
+       if (cflag & PARENB) {
+               /* enable parity */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+       }
+
+       if (cflag & CMSPAR) {
+               /* enable stick parity, PARODD mean Mark which matches ETRAX */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
+       }
+       if (cflag & PARODD) {
+               /* set odd parity (or Mark if CMSPAR) */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable automatic CTS handling */
+               DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
+       }
+
+       /* make sure the tx and rx are enabled */
+
+       info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
+       info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+
+       /* actually write the control regs to the hardware */
+
+       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
+       info->ioport[REG_REC_CTRL] = info->rx_ctrl;
+       xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
+       xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+       if (info->port.tty->termios->c_iflag & IXON ) {
+               DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
+                               STOP_CHAR(info->port.tty)));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+       }
+
+       *((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
+       local_irq_restore(flags);
+#endif /* !CONFIG_SVINTO_SIM */
+
+       update_char_time(info);
+
+} /* change_speed */
+
+/* start transmitting chars NOW */
+
+static void
+rs_flush_chars(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (info->tr_running ||
+           info->xmit.head == info->xmit.tail ||
+           tty->stopped ||
+           tty->hw_stopped ||
+           !info->xmit.buf)
+               return;
+
+#ifdef SERIAL_DEBUG_FLOW
+       printk("rs_flush_chars\n");
+#endif
+
+       /* this protection might not exactly be necessary here */
+
+       local_irq_save(flags);
+       start_transmit(info);
+       local_irq_restore(flags);
+}
+
+static int rs_raw_write(struct tty_struct *tty,
+                       const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       /* first some sanity checks */
+
+       if (!tty || !info->xmit.buf || !tmp_buf)
+               return 0;
+
+#ifdef SERIAL_DEBUG_DATA
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("rs_raw_write (%d), status %d\n",
+                      count, info->ioport[REG_STATUS]);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Really simple.  The output is here and now. */
+       SIMCOUT(buf, count);
+       return count;
+#endif
+       local_save_flags(flags);
+       DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
+       DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+
+
+       /* The local_irq_disable/restore_flags pairs below are needed
+        * because the DMA interrupt handler moves the info->xmit values.
+        * the memcpy needs to be in the critical region unfortunately,
+        * because we need to read xmit values, memcpy, write xmit values
+        * in one atomic operation... this could perhaps be avoided by
+        * more clever design.
+        */
+       local_irq_disable();
+               while (count) {
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+
+                       if (count < c)
+                               c = count;
+                       if (c <= 0)
+                               break;
+
+                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
+                       info->xmit.head = (info->xmit.head + c) &
+                               (SERIAL_XMIT_SIZE-1);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+       local_irq_restore(flags);
+
+       /* enable transmitter if not running, unless the tty is stopped
+        * this does not need IRQ protection since if tr_running == 0
+        * the IRQ's are not running anyway for this port.
+        */
+       DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
+
+       if (info->xmit.head != info->xmit.tail &&
+           !tty->stopped &&
+           !tty->hw_stopped &&
+           !info->tr_running) {
+               start_transmit(info);
+       }
+
+       return ret;
+} /* raw_raw_write() */
+
+static int
+rs_write(struct tty_struct *tty,
+        const unsigned char *buf, int count)
+{
+#if defined(CONFIG_ETRAX_RS485)
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       if (info->rs485.flags & SER_RS485_ENABLED)
+       {
+               /* If we are in RS-485 mode, we need to toggle RTS and disable
+                * the receiver before initiating a DMA transfer
+                */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Abort any started timer */
+               fast_timers_rs485[info->line].function = NULL;
+               del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
+               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND));
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_disable_rx(info);
+               e100_enable_rx_irq(info);
+#endif
+               if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
+                       (info->rs485.delay_rts_before_send > 0))
+                               msleep(info->rs485.delay_rts_before_send);
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       count = rs_raw_write(tty, buf, count);
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.flags & SER_RS485_ENABLED)
+       {
+               unsigned int val;
+               /* If we are in RS-485 mode the following has to be done:
+                * wait until DMA is ready
+                * wait on transmit shift register
+                * toggle RTS
+                * enable the receiver
+                */
+
+               /* Sleep until all sent */
+               tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Now sleep a little more so that shift register is empty */
+               schedule_usleep(info->char_time_usec * 2);
+#endif
+               /* wait on transmit shift register */
+               do{
+                       get_lsr_info(info, &val);
+               }while (!(val & TIOCSER_TEMT));
+
+               e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND));
+
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_enable_rx(info);
+               e100_enable_rxdma_irq(info);
+#endif
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       return count;
+} /* rs_write */
+
+
+/* how much space is available in the xmit buffer? */
+
+static int
+rs_write_room(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* How many chars are in the xmit buffer?
+ * This does not include any chars in the transmitter FIFO.
+ * Use wait_until_sent for waiting for FIFO drain.
+ */
+
+static int
+rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* discard everything in the xmit buffer */
+
+static void
+rs_flush_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       info->xmit.head = info->xmit.tail = 0;
+       local_irq_restore(flags);
+
+       tty_wakeup(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ *
+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
+ * but we do it in handle_ser_tx_interrupt().
+ * We disable DMA channel and enable tx ready interrupt and write the
+ * character when possible.
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+       local_irq_save(flags);
+       if (info->uses_dma_out) {
+               /* Put the DMA on hold and disable the channel */
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
+               e100_disable_txdma_channel(info);
+       }
+
+       /* Must make sure transmitter is not stopped before we can transmit */
+       if (tty->stopped)
+               rs_start(tty);
+
+       /* Enable manual transmit interrupt and send from there */
+       DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
+       info->x_char = ch;
+       e100_enable_serial_tx_ready_irq(info);
+       local_irq_restore(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+rs_throttle(struct tty_struct * tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("throttle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Turn off RTS line */
+               e100_rts(info, 0);
+       }
+       if (I_IXOFF(tty))
+               rs_send_xchar(tty, STOP_CHAR(tty));
+
+}
+
+static void
+rs_unthrottle(struct tty_struct * tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Assert RTS line  */
+               e100_rts(info, 1);
+       }
+
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_send_xchar(tty, START_CHAR(tty));
+       }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_serial_info(struct e100_serial * info,
+               struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+
+       /* this is all probably wrong, there are a lot of fields
+        * here that we don't have in e100_serial and maybe we
+        * should set them to something else than 0.
+        */
+
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = (int)info->ioport;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int
+set_serial_info(struct e100_serial *info,
+               struct serial_struct *new_info)
+{
+       struct serial_struct new_serial;
+       struct e100_serial old_info;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+               return -EFAULT;
+
+       old_info = *info;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((new_serial.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
+                    (info->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               goto check_and_exit;
+       }
+
+       if (info->count > 1)
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       info->baud_base = new_serial.baud_base;
+       info->flags = ((info->flags & ~ASYNC_FLAGS) |
+                      (new_serial.flags & ASYNC_FLAGS));
+       info->custom_divisor = new_serial.custom_divisor;
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+       if (info->flags & ASYNC_INITIALIZED) {
+               change_speed(info);
+       } else
+               retval = startup(info);
+       return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static int
+get_lsr_info(struct e100_serial * info, unsigned int *value)
+{
+       unsigned int result = TIOCSER_TEMT;
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       unsigned long elapsed_usec =
+               (curr_time - info->last_tx_active) * 1000000/HZ +
+               curr_time_usec - info->last_tx_active_usec;
+
+       if (info->xmit.head != info->xmit.tail ||
+           elapsed_usec < 2*info->char_time_usec) {
+               result = 0;
+       }
+#endif
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+#ifdef SERIAL_DEBUG_IO
+struct state_str
+{
+       int state;
+       const char *str;
+};
+
+const struct state_str control_state_str[] = {
+       {TIOCM_DTR, "DTR" },
+       {TIOCM_RTS, "RTS"},
+       {TIOCM_ST, "ST?" },
+       {TIOCM_SR, "SR?" },
+       {TIOCM_CTS, "CTS" },
+       {TIOCM_CD, "CD" },
+       {TIOCM_RI, "RI" },
+       {TIOCM_DSR, "DSR" },
+       {0, NULL }
+};
+
+char *get_control_state_str(int MLines, char *s)
+{
+       int i = 0;
+
+       s[0]='\0';
+       while (control_state_str[i].str != NULL) {
+               if (MLines & control_state_str[i].state) {
+                       if (s[0] != '\0') {
+                               strcat(s, ", ");
+                       }
+                       strcat(s, control_state_str[i].str);
+               }
+               i++;
+       }
+       return s;
+}
+#endif
+
+static int
+rs_break(struct tty_struct *tty, int break_state)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info->ioport)
+               return -EIO;
+
+       local_irq_save(flags);
+       if (break_state == -1) {
+               /* Go to manual mode and set the txd pin to 0 */
+               /* Clear bit 7 (txd) and 6 (tr_enable) */
+               info->tx_ctrl &= 0x3F;
+       } else {
+               /* Set bit 7 (txd) and 6 (tr_enable) */
+               info->tx_ctrl |= (0x80 | 0x40);
+       }
+       info->ioport[REG_TR_CTRL] = info->tx_ctrl;
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int
+rs_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (clear & TIOCM_RTS)
+               e100_rts(info, 0);
+       if (clear & TIOCM_DTR)
+               e100_dtr(info, 0);
+       /* Handle FEMALE behaviour */
+       if (clear & TIOCM_RI)
+               e100_ri_out(info, 0);
+       if (clear & TIOCM_CD)
+               e100_cd_out(info, 0);
+
+       if (set & TIOCM_RTS)
+               e100_rts(info, 1);
+       if (set & TIOCM_DTR)
+               e100_dtr(info, 1);
+       /* Handle FEMALE behaviour */
+       if (set & TIOCM_RI)
+               e100_ri_out(info, 1);
+       if (set & TIOCM_CD)
+               e100_cd_out(info, 1);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int
+rs_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned int result;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       result =
+               (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
+               | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
+               | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
+               | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+               | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
+               | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+
+       local_irq_restore(flags);
+
+#ifdef SERIAL_DEBUG_IO
+       printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
+               info->line, result, result);
+       {
+               char s[100];
+
+               get_control_state_str(result, s);
+               printk(KERN_DEBUG "state: %s\n", s);
+       }
+#endif
+       return result;
+
+}
+
+
+static int
+rs_ioctl(struct tty_struct *tty, struct file * file,
+        unsigned int cmd, unsigned long arg)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                       return -EIO;
+       }
+
+       switch (cmd) {
+       case TIOCGSERIAL:
+               return get_serial_info(info,
+                                      (struct serial_struct *) arg);
+       case TIOCSSERIAL:
+               return set_serial_info(info,
+                                      (struct serial_struct *) arg);
+       case TIOCSERGETLSR: /* Get line status register */
+               return get_lsr_info(info, (unsigned int *) arg);
+
+       case TIOCSERGSTRUCT:
+               if (copy_to_user((struct e100_serial *) arg,
+                                info, sizeof(struct e100_serial)))
+                       return -EFAULT;
+               return 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+       case TIOCSERSETRS485:
+       {
+               /* In this ioctl we still use the old structure
+                * rs485_control for backward compatibility
+                * (if we use serial_rs485, then old user-level code
+                * wouldn't work anymore...).
+                * The use of this ioctl is deprecated: use TIOCSRS485
+                * instead.*/
+               struct rs485_control rs485ctrl;
+               struct serial_rs485 rs485data;
+               printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n");
+               if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg,
+                               sizeof(rs485ctrl)))
+                       return -EFAULT;
+
+               rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
+               rs485data.flags = 0;
+               if (rs485data.delay_rts_before_send != 0)
+                       rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+
+               if (rs485ctrl.enabled)
+                       rs485data.flags |= SER_RS485_ENABLED;
+               else
+                       rs485data.flags &= ~(SER_RS485_ENABLED);
+
+               if (rs485ctrl.rts_on_send)
+                       rs485data.flags |= SER_RS485_RTS_ON_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_ON_SEND);
+
+               if (rs485ctrl.rts_after_sent)
+                       rs485data.flags |= SER_RS485_RTS_AFTER_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND);
+
+               return e100_enable_rs485(tty, &rs485data);
+       }
+
+       case TIOCSRS485:
+       {
+               /* This is the new version of TIOCSRS485, with new
+                * data structure serial_rs485 */
+               struct serial_rs485 rs485data;
+               if (copy_from_user(&rs485data, (struct rs485_control *)arg,
+                               sizeof(rs485data)))
+                       return -EFAULT;
+
+               return e100_enable_rs485(tty, &rs485data);
+       }
+
+       case TIOCGRS485:
+       {
+               struct serial_rs485 *rs485data =
+                       &(((struct e100_serial *)tty->driver_data)->rs485);
+               /* This is the ioctl to get RS485 data from user-space */
+               if (copy_to_user((struct serial_rs485 *) arg,
+                                       rs485data,
+                                       sizeof(struct serial_rs485)))
+                       return -EFAULT;
+               break;
+       }
+
+       case TIOCSERWRRS485:
+       {
+               struct rs485_write rs485wr;
+               if (copy_from_user(&rs485wr, (struct rs485_write *)arg,
+                               sizeof(rs485wr)))
+                       return -EFAULT;
+
+               return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
+       }
+#endif
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static void
+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       change_speed(info);
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+rs_close(struct tty_struct *tty, struct file * filp)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info)
+               return;
+
+       /* interrupts are disabled for this entire function */
+
+       local_irq_save(flags);
+
+       if (tty_hung_up_p(filp)) {
+               local_irq_restore(flags);
+               return;
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
+              info->line, info->count);
+#endif
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  Info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk(KERN_CRIT
+                      "rs_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               local_irq_restore(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the serial receiver and the DMA receive interrupt.
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_disable_serial_data_irq(info);
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+       e100_disable_rx(info);
+       e100_disable_rx_irq(info);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important as we have a transmit FIFO!
+                */
+               rs_wait_until_sent(tty, HZ);
+       }
+#endif
+
+       shutdown(info);
+       rs_flush_buffer(tty);
+       tty_ldisc_flush(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->port.tty = NULL;
+       if (info->blocked_open) {
+               if (info->close_delay)
+                       schedule_timeout_interruptible(info->close_delay);
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       local_irq_restore(flags);
+
+       /* port closed */
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.flags & SER_RS485_ENABLED) {
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+               *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              rs485_port_g_bit, 0);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
+#endif
+       }
+#endif
+
+       /*
+        * Release any allocated DMA irq's.
+        */
+       if (info->dma_in_enabled) {
+               free_irq(info->dma_in_irq_nbr, info);
+               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+               info->uses_dma_in = 0;
+#ifdef SERIAL_DEBUG_OPEN
+               printk(KERN_DEBUG "DMA irq '%s' freed\n",
+                       info->dma_in_irq_description);
+#endif
+       }
+       if (info->dma_out_enabled) {
+               free_irq(info->dma_out_irq_nbr, info);
+               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+               info->uses_dma_out = 0;
+#ifdef SERIAL_DEBUG_OPEN
+               printk(KERN_DEBUG "DMA irq '%s' freed\n",
+                       info->dma_out_irq_description);
+#endif
+       }
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       unsigned long orig_jiffies;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       long elapsed_usec =
+               (curr_time - info->last_tx_active) * (1000000/HZ) +
+               curr_time_usec - info->last_tx_active_usec;
+
+       /*
+        * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+        * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+        */
+       orig_jiffies = jiffies;
+       while (info->xmit.head != info->xmit.tail || /* More in send queue */
+              (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
+              (elapsed_usec < 2*info->char_time_usec)) {
+               schedule_timeout_interruptible(1);
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
+               curr_time = jiffies;
+               curr_time_usec = GET_JIFFIES_USEC();
+               elapsed_usec =
+                       (curr_time - info->last_tx_active) * (1000000/HZ) +
+                       curr_time_usec - info->last_tx_active_usec;
+       }
+       set_current_state(TASK_RUNNING);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void
+rs_hangup(struct tty_struct *tty)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~ASYNC_NORMAL_ACTIVE;
+       info->port.tty = NULL;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+               struct e100_serial *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long   flags;
+       int             retval;
+       int             do_clocal = 0, extra_count = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               wait_event_interruptible_tty(info->close_wait,
+                       !(info->flags & ASYNC_CLOSING));
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR))) {
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (tty->termios->c_cflag & CLOCAL) {
+                       do_clocal = 1;
+       }
+
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       local_irq_save(flags);
+       if (!tty_hung_up_p(filp)) {
+               extra_count++;
+               info->count--;
+       }
+       local_irq_restore(flags);
+       info->blocked_open++;
+       while (1) {
+               local_irq_save(flags);
+               /* assert RTS and DTR */
+               e100_rts(info, 1);
+               e100_dtr(info, 1);
+               local_irq_restore(flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CLOSING) && do_clocal)
+                       /* && (do_clocal || DCD_IS_ASSERTED) */
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttyS%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&info->open_wait, &wait);
+       if (extra_count)
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static void
+deinit_port(struct e100_serial *info)
+{
+       if (info->dma_out_enabled) {
+               cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+               free_irq(info->dma_out_irq_nbr, info);
+       }
+       if (info->dma_in_enabled) {
+               cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+               free_irq(info->dma_in_irq_nbr, info);
+       }
+}
+
+/*
+ * This routine is called whenever a serial port is opened.
+ * It performs the serial-specific initialization for the tty structure.
+ */
+static int
+rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct e100_serial      *info;
+       int                     retval, line;
+       unsigned long           page;
+       int                     allocated_resources = 0;
+
+       /* find which port we want to open */
+       line = tty->index;
+
+       if (line < 0 || line >= NR_PORTS)
+               return -ENODEV;
+
+       /* find the corresponding e100_serial struct in the table */
+       info = rs_table + line;
+
+       /* don't allow the opening of ports that are not enabled in the HW config */
+       if (!info->enabled)
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
+              info->count);
+#endif
+
+       info->count++;
+       tty->driver_data = info;
+       info->port.tty = tty;
+
+       info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       if (!tmp_buf) {
+               page = get_zeroed_page(GFP_KERNEL);
+               if (!page) {
+                       return -ENOMEM;
+               }
+               if (tmp_buf)
+                       free_page(page);
+               else
+                       tmp_buf = (unsigned char *) page;
+       }
+
+       /*
+        * If the port is in the middle of closing, bail out now
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               wait_event_interruptible_tty(info->close_wait,
+                       !(info->flags & ASYNC_CLOSING));
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If DMA is enabled try to allocate the irq's.
+        */
+       if (info->count == 1) {
+               allocated_resources = 1;
+               if (info->dma_in_enabled) {
+                       if (request_irq(info->dma_in_irq_nbr,
+                                       rec_interrupt,
+                                       info->dma_in_irq_flags,
+                                       info->dma_in_irq_description,
+                                       info)) {
+                               printk(KERN_WARNING "DMA irq '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_in_irq_description);
+                               /* Make sure we never try to use DMA in */
+                               /* for the port again. */
+                               info->dma_in_enabled = 0;
+                       } else if (cris_request_dma(info->dma_in_nbr,
+                                       info->dma_in_irq_description,
+                                       DMA_VERBOSE_ON_ERROR,
+                                       info->dma_owner)) {
+                               free_irq(info->dma_in_irq_nbr, info);
+                               printk(KERN_WARNING "DMA '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_in_irq_description);
+                               /* Make sure we never try to use DMA in */
+                               /* for the port again. */
+                               info->dma_in_enabled = 0;
+                       }
+#ifdef SERIAL_DEBUG_OPEN
+                       else
+                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+                                       info->dma_in_irq_description);
+#endif
+               }
+               if (info->dma_out_enabled) {
+                       if (request_irq(info->dma_out_irq_nbr,
+                                              tr_interrupt,
+                                              info->dma_out_irq_flags,
+                                              info->dma_out_irq_description,
+                                              info)) {
+                               printk(KERN_WARNING "DMA irq '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_out_irq_description);
+                               /* Make sure we never try to use DMA out */
+                               /* for the port again. */
+                               info->dma_out_enabled = 0;
+                       } else if (cris_request_dma(info->dma_out_nbr,
+                                            info->dma_out_irq_description,
+                                            DMA_VERBOSE_ON_ERROR,
+                                            info->dma_owner)) {
+                               free_irq(info->dma_out_irq_nbr, info);
+                               printk(KERN_WARNING "DMA '%s' busy; "
+                                       "falling back to non-DMA mode\n",
+                                       info->dma_out_irq_description);
+                               /* Make sure we never try to use DMA out */
+                               /* for the port again. */
+                               info->dma_out_enabled = 0;
+                       }
+#ifdef SERIAL_DEBUG_OPEN
+                       else
+                               printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+                                       info->dma_out_irq_description);
+#endif
+               }
+       }
+
+       /*
+        * Start up the serial port
+        */
+
+       retval = startup(info);
+       if (retval) {
+               if (allocated_resources)
+                       deinit_port(info);
+
+               /* FIXME Decrease count info->count here too? */
+               return retval;
+       }
+
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               if (allocated_resources)
+                       deinit_port(info);
+
+               return retval;
+       }
+
+       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               *tty->termios = info->normal_termios;
+               change_speed(info);
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttyS%d successful...\n", info->line);
+#endif
+       DLOG_INT_TRIG( log_int_pos = 0);
+
+       DFLIP(  if (info->line == SERIAL_DEBUG_LINE) {
+                       info->icount.rx = 0;
+               } );
+
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * /proc fs routines....
+ */
+
+static void seq_line_info(struct seq_file *m, struct e100_serial *info)
+{
+       unsigned long tmp;
+
+       seq_printf(m, "%d: uart:E100 port:%lX irq:%d",
+                  info->line, (unsigned long)info->ioport, info->irq);
+
+       if (!info->ioport || (info->type == PORT_UNKNOWN)) {
+               seq_printf(m, "\n");
+               return;
+       }
+
+       seq_printf(m, " baud:%d", info->baud);
+       seq_printf(m, " tx:%lu rx:%lu",
+                      (unsigned long)info->icount.tx,
+                      (unsigned long)info->icount.rx);
+       tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+       if (tmp)
+               seq_printf(m, " tx_pend:%lu/%lu",
+                          (unsigned long)tmp,
+                          (unsigned long)SERIAL_XMIT_SIZE);
+
+       seq_printf(m, " rx_pend:%lu/%lu",
+                  (unsigned long)info->recv_cnt,
+                  (unsigned long)info->max_recv_cnt);
+
+#if 1
+       if (info->port.tty) {
+               if (info->port.tty->stopped)
+                       seq_printf(m, " stopped:%i",
+                                  (int)info->port.tty->stopped);
+               if (info->port.tty->hw_stopped)
+                       seq_printf(m, " hw_stopped:%i",
+                                  (int)info->port.tty->hw_stopped);
+       }
+
+       {
+               unsigned char rstat = info->ioport[REG_STATUS];
+               if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect))
+                       seq_printf(m, " xoff_detect:1");
+       }
+
+#endif
+
+       if (info->icount.frame)
+               seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame);
+
+       if (info->icount.parity)
+               seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity);
+
+       if (info->icount.brk)
+               seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk);
+
+       if (info->icount.overrun)
+               seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       if (!E100_RTS_GET(info))
+               seq_puts(m, "|RTS");
+       if (!E100_CTS_GET(info))
+               seq_puts(m, "|CTS");
+       if (!E100_DTR_GET(info))
+               seq_puts(m, "|DTR");
+       if (!E100_DSR_GET(info))
+               seq_puts(m, "|DSR");
+       if (!E100_CD_GET(info))
+               seq_puts(m, "|CD");
+       if (!E100_RI_GET(info))
+               seq_puts(m, "|RI");
+       seq_puts(m, "\n");
+}
+
+
+static int crisv10_proc_show(struct seq_file *m, void *v)
+{
+       int i;
+
+       seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
+
+       for (i = 0; i < NR_PORTS; i++) {
+               if (!rs_table[i].enabled)
+                       continue;
+               seq_line_info(m, &rs_table[i]);
+       }
+#ifdef DEBUG_LOG_INCLUDED
+       for (i = 0; i < debug_log_pos; i++) {
+               seq_printf(m, "%-4i %lu.%lu ",
+                        i, debug_log[i].time,
+                        timer_data_to_ns(debug_log[i].timer_data));
+               seq_printf(m, debug_log[i].string, debug_log[i].value);
+       }
+       seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE);
+       debug_log_pos = 0;
+#endif
+       return 0;
+}
+
+static int crisv10_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, crisv10_proc_show, NULL);
+}
+
+static const struct file_operations crisv10_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = crisv10_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+       printk(KERN_INFO
+              "ETRAX 100LX serial-driver %s, "
+              "(c) 2000-2004 Axis Communications AB\r\n",
+              &serial_version[11]); /* "$Revision: x.yy" */
+}
+
+/* rs_init inits the driver at boot (using the module_init chain) */
+
+static const struct tty_operations rs_ops = {
+       .open = rs_open,
+       .close = rs_close,
+       .write = rs_write,
+       .flush_chars = rs_flush_chars,
+       .write_room = rs_write_room,
+       .chars_in_buffer = rs_chars_in_buffer,
+       .flush_buffer = rs_flush_buffer,
+       .ioctl = rs_ioctl,
+       .throttle = rs_throttle,
+        .unthrottle = rs_unthrottle,
+       .set_termios = rs_set_termios,
+       .stop = rs_stop,
+       .start = rs_start,
+       .hangup = rs_hangup,
+       .break_ctl = rs_break,
+       .send_xchar = rs_send_xchar,
+       .wait_until_sent = rs_wait_until_sent,
+       .tiocmget = rs_tiocmget,
+       .tiocmset = rs_tiocmset,
+#ifdef CONFIG_PROC_FS
+       .proc_fops = &crisv10_proc_fops,
+#endif
+};
+
+static int __init rs_init(void)
+{
+       int i;
+       struct e100_serial *info;
+       struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
+
+       if (!driver)
+               return -ENOMEM;
+
+       show_serial_version();
+
+       /* Setup the timed flush handler system */
+
+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
+       setup_timer(&flush_timer, timed_flush_handler, 0);
+       mod_timer(&flush_timer, jiffies + 5);
+#endif
+
+#if defined(CONFIG_ETRAX_RS485)
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+       if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
+                       rs485_pa_bit)) {
+               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+                       "RS485 pin\n");
+               put_tty_driver(driver);
+               return -EBUSY;
+       }
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+       if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
+                       rs485_port_g_bit)) {
+               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+                       "RS485 pin\n");
+               put_tty_driver(driver);
+               return -EBUSY;
+       }
+#endif
+#endif
+
+       /* Initialize the tty_driver structure */
+
+       driver->driver_name = "serial";
+       driver->name = "ttyS";
+       driver->major = TTY_MAJOR;
+       driver->minor_start = 64;
+       driver->type = TTY_DRIVER_TYPE_SERIAL;
+       driver->subtype = SERIAL_TYPE_NORMAL;
+       driver->init_termios = tty_std_termios;
+       driver->init_termios.c_cflag =
+               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+       driver->init_termios.c_ispeed = 115200;
+       driver->init_termios.c_ospeed = 115200;
+       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+
+       tty_set_operations(driver, &rs_ops);
+        serial_driver = driver;
+       if (tty_register_driver(driver))
+               panic("Couldn't register serial driver\n");
+       /* do some initializing for the separate ports */
+
+       for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+               if (info->enabled) {
+                       if (cris_request_io_interface(info->io_if,
+                                       info->io_if_description)) {
+                               printk(KERN_CRIT "ETRAX100LX async serial: "
+                                       "Could not allocate IO pins for "
+                                       "%s, port %d\n",
+                                       info->io_if_description, i);
+                               info->enabled = 0;
+                       }
+               }
+               info->uses_dma_in = 0;
+               info->uses_dma_out = 0;
+               info->line = i;
+               info->port.tty = NULL;
+               info->type = PORT_ETRAX;
+               info->tr_running = 0;
+               info->forced_eop = 0;
+               info->baud_base = DEF_BAUD_BASE;
+               info->custom_divisor = 0;
+               info->flags = 0;
+               info->close_delay = 5*HZ/10;
+               info->closing_wait = 30*HZ;
+               info->x_char = 0;
+               info->event = 0;
+               info->count = 0;
+               info->blocked_open = 0;
+               info->normal_termios = driver->init_termios;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->close_wait);
+               info->xmit.buf = NULL;
+               info->xmit.tail = info->xmit.head = 0;
+               info->first_recv_buffer = info->last_recv_buffer = NULL;
+               info->recv_cnt = info->max_recv_cnt = 0;
+               info->last_tx_active_usec = 0;
+               info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+               /* Set sane defaults */
+               info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
+               info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
+               info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+               info->rs485.delay_rts_before_send = 0;
+               info->rs485.flags &= ~(SER_RS485_ENABLED);
+#endif
+               INIT_WORK(&info->work, do_softint);
+
+               if (info->enabled) {
+                       printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
+                              serial_driver->name, info->line, info->ioport);
+               }
+       }
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+       memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+       memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+       fast_timer_init();
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+#ifndef CONFIG_ETRAX_KGDB
+       /* Not needed in simulator.  May only complicate stuff. */
+       /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
+
+       if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
+                       IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
+               panic("%s: Failed to request irq8", __func__);
+
+#endif
+#endif /* CONFIG_SVINTO_SIM */
+
+       return 0;
+}
+
+/* this makes sure that rs_init is called during kernel boot */
+
+module_init(rs_init);
diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h
new file mode 100644 (file)
index 0000000..ea0beb4
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998-2007 Axis Communications AB
+ */
+
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
+
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+#include <asm/dma.h>
+#include <arch/io_interface_mux.h>
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#define SERIAL_RECV_DESCRIPTORS 8
+
+struct etrax_recv_buffer {
+       struct etrax_recv_buffer *next;
+       unsigned short length;
+       unsigned char error;
+       unsigned char pad;
+
+       unsigned char buffer[0];
+};
+
+struct e100_serial {
+       struct tty_port port;
+       int baud;
+       volatile u8     *ioport;        /* R_SERIALx_CTRL */
+       u32             irq;    /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+       /* Output registers */
+       volatile u8 *oclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32 *ofirstadr;        /* adr to R_DMA_CHx_FIRST */
+       volatile u8 *ocmdadr;           /* adr to R_DMA_CHx_CMD */
+       const volatile u8 *ostatusadr;  /* adr to R_DMA_CHx_STATUS */
+
+       /* Input registers */
+       volatile u8 *iclrintradr;       /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32 *ifirstadr;        /* adr to R_DMA_CHx_FIRST */
+       volatile u8 *icmdadr;           /* adr to R_DMA_CHx_CMD */
+       volatile u32 *idescradr;        /* adr to R_DMA_CHx_DESCR */
+
+       int flags;      /* defined in tty.h */
+
+       u8 rx_ctrl;     /* shadow for R_SERIALx_REC_CTRL */
+       u8 tx_ctrl;     /* shadow for R_SERIALx_TR_CTRL */
+       u8 iseteop;     /* bit number for R_SET_EOP for the input dma */
+       int enabled;    /* Set to 1 if the port is enabled in HW config */
+
+       u8 dma_out_enabled;     /* Set to 1 if DMA should be used */
+       u8 dma_in_enabled;      /* Set to 1 if DMA should be used */
+
+       /* end of fields defined in rs_table[] in .c-file */
+       int             dma_owner;
+       unsigned int    dma_in_nbr;
+       unsigned int    dma_out_nbr;
+       unsigned int    dma_in_irq_nbr;
+       unsigned int    dma_out_irq_nbr;
+       unsigned long   dma_in_irq_flags;
+       unsigned long   dma_out_irq_flags;
+       char            *dma_in_irq_description;
+       char            *dma_out_irq_description;
+
+       enum cris_io_interface io_if;
+       char            *io_if_description;
+
+       u8              uses_dma_in;  /* Set to 1 if DMA is used */
+       u8              uses_dma_out; /* Set to 1 if DMA is used */
+       u8              forced_eop;   /* a fifo eop has been forced */
+       int                     baud_base;     /* For special baudrates */
+       int                     custom_divisor; /* For special baudrates */
+       struct etrax_dma_descr  tr_descr;
+       struct etrax_dma_descr  rec_descr[SERIAL_RECV_DESCRIPTORS];
+       int                     cur_rec_descr;
+
+       volatile int            tr_running; /* 1 if output is running */
+
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+       int                     type;  /* PORT_ETRAX */
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       struct circ_buf         xmit;
+       struct etrax_recv_buffer *first_recv_buffer;
+       struct etrax_recv_buffer *last_recv_buffer;
+       unsigned int            recv_cnt;
+       unsigned int            max_recv_cnt;
+
+       struct work_struct      work;
+       struct async_icount     icount;   /* error-statistics etc.*/
+       struct ktermios         normal_termios;
+       struct ktermios         callout_termios;
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+
+       unsigned long char_time_usec;       /* The time for 1 char, in usecs */
+       unsigned long flush_time_usec;      /* How often we should flush */
+       unsigned long last_tx_active_usec;  /* Last tx usec in the jiffies */
+       unsigned long last_tx_active;       /* Last tx time in jiffies */
+       unsigned long last_rx_active_usec;  /* Last rx usec in the jiffies */
+       unsigned long last_rx_active;       /* Last rx time in jiffies */
+
+       int break_detected_cnt;
+       int errorcode;
+
+#ifdef CONFIG_ETRAX_RS485
+       struct serial_rs485     rs485;  /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX 1
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+#endif /* __KERNEL__ */
+
+#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
new file mode 100644 (file)
index 0000000..57421d7
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * dz.c: Serial port driver for DECstations equipped
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * Copyright (C) 2004, 2006, 2007  Maciej W. Rozycki
+ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+ * Changed name of dz_init to rs_init to be consistent with tc code
+ * [13-NOV-98] triemer fixed code to receive characters
+ *    after patches by harald to irq code.
+ * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
+ *            field from "current" - somewhere between 2.1.121 and 2.1.131
+ Qua Jun 27 15:02:26 BRT 2001
+ * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
+ *
+ * Parts (C) 1999 David Airlie, airlied@linux.ie
+ * [07-SEP-99] Bugfixes
+ *
+ * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
+ * Converted to new serial core
+ */
+
+#undef DEBUG_DZ
+
+#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+
+#include <asm/atomic.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
+#include <asm/dec/system.h>
+
+#include "dz.h"
+
+
+MODULE_DESCRIPTION("DECstation DZ serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char dz_name[] __initdata = "DECstation DZ serial driver version ";
+static char dz_version[] __initdata = "1.04";
+
+struct dz_port {
+       struct dz_mux           *mux;
+       struct uart_port        port;
+       unsigned int            cflag;
+};
+
+struct dz_mux {
+       struct dz_port          dport[DZ_NB_PORT];
+       atomic_t                map_guard;
+       atomic_t                irq_guard;
+       int                     initialised;
+};
+
+static struct dz_mux dz_mux;
+
+static inline struct dz_port *to_dport(struct uart_port *uport)
+{
+       return container_of(uport, struct dz_port, port);
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+ *
+ * These routines are used to access the registers of the DZ
+ * chip, hiding relocation differences between implementation.
+ * ------------------------------------------------------------
+ */
+
+static u16 dz_in(struct dz_port *dport, unsigned offset)
+{
+       void __iomem *addr = dport->port.membase + offset;
+
+       return readw(addr);
+}
+
+static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
+{
+       void __iomem *addr = dport->port.membase + offset;
+
+       writew(value, addr);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop () and rs_start ()
+ *
+ * These routines are called before setting or resetting
+ * tty->stopped. They enable or disable transmitter interrupts,
+ * as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void dz_stop_tx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
+       tmp &= ~mask;                   /* clear the TX flag */
+       dz_out(dport, DZ_TCR, tmp);
+}
+
+static void dz_start_tx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);     /* read the TX flag */
+       tmp |= mask;                    /* set the TX flag */
+       dz_out(dport, DZ_TCR, tmp);
+}
+
+static void dz_stop_rx(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+
+       dport->cflag &= ~DZ_RXENAB;
+       dz_out(dport, DZ_LPR, dport->cflag);
+}
+
+static void dz_enable_ms(struct uart_port *uport)
+{
+       /* nothing to do */
+}
+
+/*
+ * ------------------------------------------------------------
+ *
+ * Here start the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * dz_interrupt.  They were separated out for readability's sake.
+ *
+ * Note: dz_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * dz_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ *     make drivers/serial/dz.s
+ *
+ * and look at the resulting assemble code in dz.s.
+ *
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * receive_char ()
+ *
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_receive_chars(struct dz_mux *mux)
+{
+       struct uart_port *uport;
+       struct dz_port *dport = &mux->dport[0];
+       struct tty_struct *tty = NULL;
+       struct uart_icount *icount;
+       int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
+       unsigned char ch, flag;
+       u16 status;
+       int i;
+
+       while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
+               dport = &mux->dport[LINE(status)];
+               uport = &dport->port;
+               tty = uport->state->port.tty;   /* point to the proper dev */
+
+               ch = UCHAR(status);             /* grab the char */
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
+
+                       /*
+                        * There is no separate BREAK status bit, so treat
+                        * null characters with framing errors as BREAKs;
+                        * normally, otherwise.  For this move the Framing
+                        * Error bit to a simulated BREAK bit.
+                        */
+                       if (!ch) {
+                               status |= (status & DZ_FERR) >>
+                                         (ffs(DZ_FERR) - ffs(DZ_BREAK));
+                               status &= ~DZ_FERR;
+                       }
+
+                       /* Handle SysRq/SAK & keep track of the statistics. */
+                       if (status & DZ_BREAK) {
+                               icount->brk++;
+                               if (uart_handle_break(uport))
+                                       continue;
+                       } else if (status & DZ_FERR)
+                               icount->frame++;
+                       else if (status & DZ_PERR)
+                               icount->parity++;
+                       if (status & DZ_OERR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & DZ_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & DZ_FERR)
+                               flag = TTY_FRAME;
+                       else if (status & DZ_PERR)
+                               flag = TTY_PARITY;
+
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, DZ_OERR, ch, flag);
+               lines_rx[LINE(status)] = 1;
+       }
+       for (i = 0; i < DZ_NB_PORT; i++)
+               if (lines_rx[i])
+                       tty_flip_buffer_push(mux->dport[i].port.state->port.tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * transmit_char ()
+ *
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_transmit_chars(struct dz_mux *mux)
+{
+       struct dz_port *dport = &mux->dport[0];
+       struct circ_buf *xmit;
+       unsigned char tmp;
+       u16 status;
+
+       status = dz_in(dport, DZ_CSR);
+       dport = &mux->dport[LINE(status)];
+       xmit = &dport->port.state->xmit;
+
+       if (dport->port.x_char) {               /* XON/XOFF chars */
+               dz_out(dport, DZ_TDR, dport->port.x_char);
+               dport->port.icount.tx++;
+               dport->port.x_char = 0;
+               return;
+       }
+       /* If nothing to do or stopped or hardware stopped. */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
+               spin_lock(&dport->port.lock);
+               dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
+               return;
+       }
+
+       /*
+        * If something to do... (remember the dz has no output fifo,
+        * so we go one char at a time) :-<
+        */
+       tmp = xmit->buf[xmit->tail];
+       xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
+       dz_out(dport, DZ_TDR, tmp);
+       dport->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
+               uart_write_wakeup(&dport->port);
+
+       /* Are we are done. */
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&dport->port.lock);
+               dz_stop_tx(&dport->port);
+               spin_unlock(&dport->port.lock);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * check_modem_status()
+ *
+ * DS 3100 & 5100: Only valid for the MODEM line, duh!
+ * DS 5000/200: Valid for the MODEM and PRINTER line.
+ * ------------------------------------------------------------
+ */
+static inline void check_modem_status(struct dz_port *dport)
+{
+       /*
+        * FIXME:
+        * 1. No status change interrupt; use a timer.
+        * 2. Handle the 3100/5000 as appropriate. --macro
+        */
+       u16 status;
+
+       /* If not the modem line just return.  */
+       if (dport->port.line != DZ_MODEM)
+               return;
+
+       status = dz_in(dport, DZ_MSR);
+
+       /* it's easy, since DSR2 is the only bit in the register */
+       if (status)
+               dport->port.icount.dsr++;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_interrupt ()
+ *
+ * this is the main interrupt routine for the DZ chip.
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+static irqreturn_t dz_interrupt(int irq, void *dev_id)
+{
+       struct dz_mux *mux = dev_id;
+       struct dz_port *dport = &mux->dport[0];
+       u16 status;
+
+       /* get the reason why we just got an irq */
+       status = dz_in(dport, DZ_CSR);
+
+       if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
+               dz_receive_chars(mux);
+
+       if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
+               dz_transmit_chars(mux);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the DZ interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+static unsigned int dz_get_mctrl(struct uart_port *uport)
+{
+       /*
+        * FIXME: Handle the 3100/5000 as appropriate. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+
+       if (dport->port.line == DZ_MODEM) {
+               if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
+                       mctrl &= ~TIOCM_DSR;
+       }
+
+       return mctrl;
+}
+
+static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       /*
+        * FIXME: Handle the 3100/5000 as appropriate. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       u16 tmp;
+
+       if (dport->port.line == DZ_MODEM) {
+               tmp = dz_in(dport, DZ_TCR);
+               if (mctrl & TIOCM_DTR)
+                       tmp &= ~DZ_MODEM_DTR;
+               else
+                       tmp |= DZ_MODEM_DTR;
+               dz_out(dport, DZ_TCR, tmp);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * startup ()
+ *
+ * various initialization tasks
+ * -------------------------------------------------------------------
+ */
+static int dz_startup(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
+       unsigned long flags;
+       int irq_guard;
+       int ret;
+       u16 tmp;
+
+       irq_guard = atomic_add_return(1, &mux->irq_guard);
+       if (irq_guard != 1)
+               return 0;
+
+       ret = request_irq(dport->port.irq, dz_interrupt,
+                         IRQF_SHARED, "dz", mux);
+       if (ret) {
+               atomic_add(-1, &mux->irq_guard);
+               printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
+               return ret;
+       }
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+
+       /* Enable interrupts.  */
+       tmp = dz_in(dport, DZ_CSR);
+       tmp |= DZ_RIE | DZ_TIE;
+       dz_out(dport, DZ_CSR, tmp);
+
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       return 0;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * shutdown ()
+ *
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ * -------------------------------------------------------------------
+ */
+static void dz_shutdown(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       struct dz_mux *mux = dport->mux;
+       unsigned long flags;
+       int irq_guard;
+       u16 tmp;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       dz_stop_tx(&dport->port);
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       irq_guard = atomic_add_return(-1, &mux->irq_guard);
+       if (!irq_guard) {
+               /* Disable interrupts.  */
+               tmp = dz_in(dport, DZ_CSR);
+               tmp &= ~(DZ_RIE | DZ_TIE);
+               dz_out(dport, DZ_CSR, tmp);
+
+               free_irq(dport->port.irq, mux);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows an RS485 driver to be written in user space.
+ * -------------------------------------------------------------------
+ */
+static unsigned int dz_tx_empty(struct uart_port *uport)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned short tmp, mask = 1 << dport->port.line;
+
+       tmp = dz_in(dport, DZ_TCR);
+       tmp &= mask;
+
+       return tmp ? 0 : TIOCSER_TEMT;
+}
+
+static void dz_break_ctl(struct uart_port *uport, int break_state)
+{
+       /*
+        * FIXME: Can't access BREAK bits in TDR easily;
+        * reuse the code for polled TX. --macro
+        */
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned short tmp, mask = 1 << dport->port.line;
+
+       spin_lock_irqsave(&uport->lock, flags);
+       tmp = dz_in(dport, DZ_TCR);
+       if (break_state)
+               tmp |= mask;
+       else
+               tmp &= ~mask;
+       dz_out(dport, DZ_TCR, tmp);
+       spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int dz_encode_baud_rate(unsigned int baud)
+{
+       switch (baud) {
+       case 50:
+               return DZ_B50;
+       case 75:
+               return DZ_B75;
+       case 110:
+               return DZ_B110;
+       case 134:
+               return DZ_B134;
+       case 150:
+               return DZ_B150;
+       case 300:
+               return DZ_B300;
+       case 600:
+               return DZ_B600;
+       case 1200:
+               return DZ_B1200;
+       case 1800:
+               return DZ_B1800;
+       case 2000:
+               return DZ_B2000;
+       case 2400:
+               return DZ_B2400;
+       case 3600:
+               return DZ_B3600;
+       case 4800:
+               return DZ_B4800;
+       case 7200:
+               return DZ_B7200;
+       case 9600:
+               return DZ_B9600;
+       default:
+               return -1;
+       }
+}
+
+
+static void dz_reset(struct dz_port *dport)
+{
+       struct dz_mux *mux = dport->mux;
+
+       if (mux->initialised)
+               return;
+
+       dz_out(dport, DZ_CSR, DZ_CLR);
+       while (dz_in(dport, DZ_CSR) & DZ_CLR);
+       iob();
+
+       /* Enable scanning.  */
+       dz_out(dport, DZ_CSR, DZ_MSE);
+
+       mux->initialised = 1;
+}
+
+static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+                          struct ktermios *old_termios)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned int cflag, baud;
+       int bflag;
+
+       cflag = dport->port.line;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cflag |= DZ_CS5;
+               break;
+       case CS6:
+               cflag |= DZ_CS6;
+               break;
+       case CS7:
+               cflag |= DZ_CS7;
+               break;
+       case CS8:
+       default:
+               cflag |= DZ_CS8;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cflag |= DZ_CSTOPB;
+       if (termios->c_cflag & PARENB)
+               cflag |= DZ_PARENB;
+       if (termios->c_cflag & PARODD)
+               cflag |= DZ_PARODD;
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
+       bflag = dz_encode_baud_rate(baud);
+       if (bflag < 0)  {                       /* Try to keep unchanged.  */
+               baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600);
+               bflag = dz_encode_baud_rate(baud);
+               if (bflag < 0)  {               /* Resort to 9600.  */
+                       baud = 9600;
+                       bflag = DZ_B9600;
+               }
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+       cflag |= bflag;
+
+       if (termios->c_cflag & CREAD)
+               cflag |= DZ_RXENAB;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       dz_out(dport, DZ_LPR, cflag);
+       dport->cflag = cflag;
+
+       /* setup accept flag */
+       dport->port.read_status_mask = DZ_OERR;
+       if (termios->c_iflag & INPCK)
+               dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               dport->port.read_status_mask |= DZ_BREAK;
+
+       /* characters to ignore */
+       uport->ignore_status_mask = 0;
+       if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
+               dport->port.ignore_status_mask |= DZ_OERR;
+       if (termios->c_iflag & IGNPAR)
+               dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
+       if (termios->c_iflag & IGNBRK)
+               dport->port.ignore_status_mask |= DZ_BREAK;
+
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+/*
+ * Hack alert!
+ * Required solely so that the initial PROM-based console
+ * works undisturbed in parallel with this one.
+ */
+static void dz_pm(struct uart_port *uport, unsigned int state,
+                 unsigned int oldstate)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       if (state < 3)
+               dz_start_tx(&dport->port);
+       else
+               dz_stop_tx(&dport->port);
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+
+static const char *dz_type(struct uart_port *uport)
+{
+       return "DZ";
+}
+
+static void dz_release_port(struct uart_port *uport)
+{
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+
+       iounmap(uport->membase);
+       uport->membase = NULL;
+
+       map_guard = atomic_add_return(-1, &mux->map_guard);
+       if (!map_guard)
+               release_mem_region(uport->mapbase, dec_kn_slot_size);
+}
+
+static int dz_map_port(struct uart_port *uport)
+{
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                dec_kn_slot_size);
+       if (!uport->membase) {
+               printk(KERN_ERR "dz: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int dz_request_port(struct uart_port *uport)
+{
+       struct dz_mux *mux = to_dport(uport)->mux;
+       int map_guard;
+       int ret;
+
+       map_guard = atomic_add_return(1, &mux->map_guard);
+       if (map_guard == 1) {
+               if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
+                                       "dz")) {
+                       atomic_add(-1, &mux->map_guard);
+                       printk(KERN_ERR
+                              "dz: Unable to reserve MMIO resource\n");
+                       return -EBUSY;
+               }
+       }
+       ret = dz_map_port(uport);
+       if (ret) {
+               map_guard = atomic_add_return(-1, &mux->map_guard);
+               if (!map_guard)
+                       release_mem_region(uport->mapbase, dec_kn_slot_size);
+               return ret;
+       }
+       return 0;
+}
+
+static void dz_config_port(struct uart_port *uport, int flags)
+{
+       struct dz_port *dport = to_dport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (dz_request_port(uport))
+                       return;
+
+               uport->type = PORT_DZ;
+
+               dz_reset(dport);
+       }
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops dz_ops = {
+       .tx_empty       = dz_tx_empty,
+       .get_mctrl      = dz_get_mctrl,
+       .set_mctrl      = dz_set_mctrl,
+       .stop_tx        = dz_stop_tx,
+       .start_tx       = dz_start_tx,
+       .stop_rx        = dz_stop_rx,
+       .enable_ms      = dz_enable_ms,
+       .break_ctl      = dz_break_ctl,
+       .startup        = dz_startup,
+       .shutdown       = dz_shutdown,
+       .set_termios    = dz_set_termios,
+       .pm             = dz_pm,
+       .type           = dz_type,
+       .release_port   = dz_release_port,
+       .request_port   = dz_request_port,
+       .config_port    = dz_config_port,
+       .verify_port    = dz_verify_port,
+};
+
+static void __init dz_init_ports(void)
+{
+       static int first = 1;
+       unsigned long base;
+       int line;
+
+       if (!first)
+               return;
+       first = 0;
+
+       if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
+               base = dec_kn_slot_base + KN01_DZ11;
+       else
+               base = dec_kn_slot_base + KN02_DZ11;
+
+       for (line = 0; line < DZ_NB_PORT; line++) {
+               struct dz_port *dport = &dz_mux.dport[line];
+               struct uart_port *uport = &dport->port;
+
+               dport->mux      = &dz_mux;
+
+               uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
+               uport->fifosize = 1;
+               uport->iotype   = UPIO_MEM;
+               uport->flags    = UPF_BOOT_AUTOCONF;
+               uport->ops      = &dz_ops;
+               uport->line     = line;
+               uport->mapbase  = base;
+       }
+}
+
+#ifdef CONFIG_SERIAL_DZ_CONSOLE
+/*
+ * -------------------------------------------------------------------
+ * dz_console_putchar() -- transmit a character
+ *
+ * Polled transmission.  This is tricky.  We need to mask transmit
+ * interrupts so that they do not interfere, enable the transmitter
+ * for the line requested and then wait till the transmit scanner
+ * requests data for this line.  But it may request data for another
+ * line first, in which case we have to disable its transmitter and
+ * repeat waiting till our line pops up.  Only then the character may
+ * be transmitted.  Finally, the state of the transmitter mask is
+ * restored.  Welcome to the world of PDP-11!
+ * -------------------------------------------------------------------
+ */
+static void dz_console_putchar(struct uart_port *uport, int ch)
+{
+       struct dz_port *dport = to_dport(uport);
+       unsigned long flags;
+       unsigned short csr, tcr, trdy, mask;
+       int loops = 10000;
+
+       spin_lock_irqsave(&dport->port.lock, flags);
+       csr = dz_in(dport, DZ_CSR);
+       dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
+       tcr = dz_in(dport, DZ_TCR);
+       tcr |= 1 << dport->port.line;
+       mask = tcr;
+       dz_out(dport, DZ_TCR, mask);
+       iob();
+       spin_unlock_irqrestore(&dport->port.lock, flags);
+
+       do {
+               trdy = dz_in(dport, DZ_CSR);
+               if (!(trdy & DZ_TRDY))
+                       continue;
+               trdy = (trdy & DZ_TLINE) >> 8;
+               if (trdy == dport->port.line)
+                       break;
+               mask &= ~(1 << trdy);
+               dz_out(dport, DZ_TCR, mask);
+               iob();
+               udelay(2);
+       } while (--loops);
+
+       if (loops)                              /* Cannot send otherwise. */
+               dz_out(dport, DZ_TDR, ch);
+
+       dz_out(dport, DZ_TCR, tcr);
+       dz_out(dport, DZ_CSR, csr);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+ *
+ * dz_console_print is registered for printk.
+ * The console must be locked when we get here.
+ * -------------------------------------------------------------------
+ */
+static void dz_console_print(struct console *co,
+                            const char *str,
+                            unsigned int count)
+{
+       struct dz_port *dport = &dz_mux.dport[co->index];
+#ifdef DEBUG_DZ
+       prom_printf((char *) str);
+#endif
+       uart_console_write(&dport->port, str, count, dz_console_putchar);
+}
+
+static int __init dz_console_setup(struct console *co, char *options)
+{
+       struct dz_port *dport = &dz_mux.dport[co->index];
+       struct uart_port *uport = &dport->port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       ret = dz_map_port(uport);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
+
+       dz_reset(dport);
+       dz_pm(uport, 0, -1);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&dport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver dz_reg;
+static struct console dz_console = {
+       .name   = "ttyS",
+       .write  = dz_console_print,
+       .device = uart_console_device,
+       .setup  = dz_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &dz_reg,
+};
+
+static int __init dz_serial_console_init(void)
+{
+       if (!IOASIC) {
+               dz_init_ports();
+               register_console(&dz_console);
+               return 0;
+       } else
+               return -ENXIO;
+}
+
+console_initcall(dz_serial_console_init);
+
+#define SERIAL_DZ_CONSOLE      &dz_console
+#else
+#define SERIAL_DZ_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_DZ_CONSOLE */
+
+static struct uart_driver dz_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = DZ_NB_PORT,
+       .cons                   = SERIAL_DZ_CONSOLE,
+};
+
+static int __init dz_init(void)
+{
+       int ret, i;
+
+       if (IOASIC)
+               return -ENXIO;
+
+       printk("%s%s\n", dz_name, dz_version);
+
+       dz_init_ports();
+
+       ret = uart_register_driver(&dz_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < DZ_NB_PORT; i++)
+               uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
+
+       return 0;
+}
+
+module_init(dz_init);
diff --git a/drivers/tty/serial/dz.h b/drivers/tty/serial/dz.h
new file mode 100644 (file)
index 0000000..faf169e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * dz.h: Serial port driver for DECstations equipped
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * Copyright (C) 2004, 2006  Maciej W. Rozycki
+ */
+#ifndef DZ_SERIAL_H
+#define DZ_SERIAL_H
+
+/*
+ * Definitions for the Control and Status Register.
+ */
+#define DZ_TRDY        0x8000                 /* Transmitter empty */
+#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enbl */
+#define DZ_TLINE       0x0300                 /* Transmitter Line Number */
+#define DZ_RDONE       0x0080                 /* Receiver data ready */
+#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
+#define DZ_MSE         0x0020                 /* Master Scan Enable */
+#define DZ_CLR         0x0010                 /* Master reset */
+#define DZ_MAINT       0x0008                 /* Loop Back Mode */
+
+/*
+ * Definitions for the Receiver Buffer Register.
+ */
+#define DZ_RBUF_MASK   0x00FF                 /* Data Mask */
+#define DZ_LINE_MASK   0x0300                 /* Line Mask */
+#define DZ_DVAL        0x8000                 /* Valid Data indicator */
+#define DZ_OERR        0x4000                 /* Overrun error indicator */
+#define DZ_FERR        0x2000                 /* Frame error indicator */
+#define DZ_PERR        0x1000                 /* Parity error indicator */
+
+#define DZ_BREAK       0x0800                 /* BREAK event software flag */
+
+#define LINE(x) ((x & DZ_LINE_MASK) >> 8)     /* Get the line number
+                                                 from the input buffer */
+#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
+
+/*
+ * Definitions for the Transmit Control Register.
+ */
+#define DZ_LINE_KEYBOARD 0x0001
+#define DZ_LINE_MOUSE    0x0002
+#define DZ_LINE_MODEM    0x0004
+#define DZ_LINE_PRINTER  0x0008
+
+#define DZ_MODEM_RTS     0x0800               /* RTS for the modem line (2) */
+#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
+#define DZ_PRINT_RTS     0x0200               /* RTS for the prntr line (3) */
+#define DZ_PRINT_DTR     0x0100               /* DTR for the prntr line (3) */
+#define DZ_LNENB         0x000f               /* Transmitter Line Enable */
+
+/*
+ * Definitions for the Modem Status Register.
+ */
+#define DZ_MODEM_RI      0x0800               /* RI for the modem line (2) */
+#define DZ_MODEM_CD      0x0400               /* CD for the modem line (2) */
+#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
+#define DZ_MODEM_CTS     0x0100               /* CTS for the modem line (2) */
+#define DZ_PRINT_RI      0x0008               /* RI for the printer line (3) */
+#define DZ_PRINT_CD      0x0004               /* CD for the printer line (3) */
+#define DZ_PRINT_DSR     0x0002               /* DSR for the prntr line (3) */
+#define DZ_PRINT_CTS     0x0001               /* CTS for the prntr line (3) */
+
+/*
+ * Definitions for the Transmit Data Register.
+ */
+#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
+#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
+#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
+#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
+
+/*
+ * Definitions for the Line Parameter Register.
+ */
+#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
+#define DZ_MOUSE         0x0001               /* line 1 = mouse */
+#define DZ_MODEM         0x0002               /* line 2 = modem */
+#define DZ_PRINTER       0x0003               /* line 3 = printer */
+
+#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
+#define DZ_CS5           0x0000               /* 5 bits per byte */
+#define DZ_CS6           0x0008               /* 6 bits per byte */
+#define DZ_CS7           0x0010               /* 7 bits per byte */
+#define DZ_CS8           0x0018               /* 8 bits per byte */
+
+#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
+
+#define DZ_PARENB        0x0040               /* Parity enable */
+#define DZ_PARODD        0x0080               /* Odd parity instead of even */
+
+#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
+#define DZ_B50           0x0000
+#define DZ_B75           0x0100
+#define DZ_B110          0x0200
+#define DZ_B134          0x0300
+#define DZ_B150          0x0400
+#define DZ_B300          0x0500
+#define DZ_B600          0x0600
+#define DZ_B1200         0x0700 
+#define DZ_B1800         0x0800
+#define DZ_B2000         0x0900
+#define DZ_B2400         0x0A00
+#define DZ_B3600         0x0B00
+#define DZ_B4800         0x0C00
+#define DZ_B7200         0x0D00
+#define DZ_B9600         0x0E00
+
+#define DZ_RXENAB        0x1000               /* Receiver Enable */
+
+/*
+ * Addresses for the DZ registers
+ */
+#define DZ_CSR       0x00            /* Control and Status Register */
+#define DZ_RBUF      0x08            /* Receive Buffer */
+#define DZ_LPR       0x08            /* Line Parameters Register */
+#define DZ_TCR       0x10            /* Transmitter Control Register */
+#define DZ_MSR       0x18            /* Modem Status Register */
+#define DZ_TDR       0x18            /* Transmit Data Register */
+
+#define DZ_NB_PORT 4
+
+#define DZ_XMIT_SIZE   4096                 /* buffer size */
+#define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
+
+#endif /* DZ_SERIAL_H */
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
new file mode 100644 (file)
index 0000000..53a4682
--- /dev/null
@@ -0,0 +1,1658 @@
+/*
+  * icom.c
+  *
+  * Copyright (C) 2001 IBM Corporation. All rights reserved.
+  *
+  * Serial device driver.
+  *
+  * Based on code from serial.c
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+  *
+  */
+#define SERIAL_DO_RESTART
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/termios.h>
+#include <linux/fs.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/firmware.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "icom.h"
+
+/*#define ICOM_TRACE            enable port trace capabilities */
+
+#define ICOM_DRIVER_NAME "icom"
+#define ICOM_VERSION_STR "1.3.1"
+#define NR_PORTS              128
+#define ICOM_PORT ((struct icom_port *)port)
+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
+
+static const struct pci_device_id icom_pci_table[] = {
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = ADAPTER_V1,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
+               .driver_data = ADAPTER_V2,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_IBM,
+               .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+               .subvendor = PCI_VENDOR_ID_IBM,
+               .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
+               .driver_data = ADAPTER_V2,
+       },
+       {}
+};
+
+struct lookup_proc_table start_proc[4] = {
+       {NULL, ICOM_CONTROL_START_A},
+       {NULL, ICOM_CONTROL_START_B},
+       {NULL, ICOM_CONTROL_START_C},
+       {NULL, ICOM_CONTROL_START_D}
+};
+
+
+struct lookup_proc_table stop_proc[4] = {
+       {NULL, ICOM_CONTROL_STOP_A},
+       {NULL, ICOM_CONTROL_STOP_B},
+       {NULL, ICOM_CONTROL_STOP_C},
+       {NULL, ICOM_CONTROL_STOP_D}
+};
+
+struct lookup_int_table int_mask_tbl[4] = {
+       {NULL, ICOM_INT_MASK_PRC_A},
+       {NULL, ICOM_INT_MASK_PRC_B},
+       {NULL, ICOM_INT_MASK_PRC_C},
+       {NULL, ICOM_INT_MASK_PRC_D},
+};
+
+
+MODULE_DEVICE_TABLE(pci, icom_pci_table);
+
+static LIST_HEAD(icom_adapter_head);
+
+/* spinlock for adapter initialization and changing adapter operations */
+static spinlock_t icom_lock;
+
+#ifdef ICOM_TRACE
+static inline void trace(struct icom_port *icom_port, char *trace_pt,
+                       unsigned long trace_data)
+{
+       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
+       icom_port->port, trace_pt, trace_data);
+}
+#else
+static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
+#endif
+static void icom_kref_release(struct kref *kref);
+
+static void free_port_memory(struct icom_port *icom_port)
+{
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       trace(icom_port, "RET_PORT_MEM", 0);
+       if (icom_port->recv_buf) {
+               pci_free_consistent(dev, 4096, icom_port->recv_buf,
+                                   icom_port->recv_buf_pci);
+               icom_port->recv_buf = NULL;
+       }
+       if (icom_port->xmit_buf) {
+               pci_free_consistent(dev, 4096, icom_port->xmit_buf,
+                                   icom_port->xmit_buf_pci);
+               icom_port->xmit_buf = NULL;
+       }
+       if (icom_port->statStg) {
+               pci_free_consistent(dev, 4096, icom_port->statStg,
+                                   icom_port->statStg_pci);
+               icom_port->statStg = NULL;
+       }
+
+       if (icom_port->xmitRestart) {
+               pci_free_consistent(dev, 4096, icom_port->xmitRestart,
+                                   icom_port->xmitRestart_pci);
+               icom_port->xmitRestart = NULL;
+       }
+}
+
+static int __devinit get_port_memory(struct icom_port *icom_port)
+{
+       int index;
+       unsigned long stgAddr;
+       unsigned long startStgAddr;
+       unsigned long offset;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       icom_port->xmit_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
+       if (!icom_port->xmit_buf) {
+               dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
+               return -ENOMEM;
+       }
+
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->xmit_buf);
+
+       icom_port->recv_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
+       if (!icom_port->recv_buf) {
+               dev_err(&dev->dev, "Can not allocate Receive buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->recv_buf);
+
+       icom_port->statStg =
+           pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
+       if (!icom_port->statStg) {
+               dev_err(&dev->dev, "Can not allocate Status buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->statStg);
+
+       icom_port->xmitRestart =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
+       if (!icom_port->xmitRestart) {
+               dev_err(&dev->dev,
+                       "Can not allocate xmit Restart buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+
+       memset(icom_port->statStg, 0, 4096);
+
+       /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
+           indicates that frames are to be transmitted
+       */
+
+       stgAddr = (unsigned long) icom_port->statStg;
+       for (index = 0; index < NUM_XBUFFS; index++) {
+               trace(icom_port, "FOD_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
+               if (index < (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_ADDR", stgAddr);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else if (index == (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+               }
+       }
+       /* FIDs */
+       startStgAddr = stgAddr;
+
+       /* fill in every entry, even if no buffer */
+       for (index = 0; index <  NUM_RBUFFS; index++) {
+               trace(icom_port, "FID_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
+               icom_port->statStg->rcv[index].leLength = 0;
+               icom_port->statStg->rcv[index].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+               if (index < (NUM_RBUFFS - 1) ) {
+                       offset = stgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                             cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci);
+               } else if (index == (NUM_RBUFFS -1) ) {
+                       offset = startStgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                           cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf + 2048);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci + 2048);
+               } else {
+                       icom_port->statStg->rcv[index].leNext = 0;
+                       icom_port->statStg->rcv[index].leBuffer = 0;
+               }
+       }
+
+       return 0;
+}
+
+static void stop_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+
+
+       if (port < 4) {
+               temp = readl(stop_proc[port].global_control_reg);
+               temp =
+                       (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
+               writel(temp, stop_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(stop_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void start_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               start_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+       if (port < 4) {
+               temp = readl(start_proc[port].global_control_reg);
+               temp =
+                       (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
+               writel(temp, start_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(start_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void load_code(struct icom_port *icom_port)
+{
+       const struct firmware *fw;
+       char __iomem *iram_ptr;
+       int index;
+       int status = 0;
+       void __iomem *dram_ptr = icom_port->dram;
+       dma_addr_t temp_pci;
+       unsigned char *new_page = NULL;
+       unsigned char cable_id = NO_CABLE;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       /* Clear out any pending interrupts */
+       writew(0x3FFF, icom_port->int_reg);
+
+       trace(icom_port, "CLEAR_INTERRUPTS", 0);
+
+       /* Stop processor */
+       stop_processor(icom_port);
+
+       /* Zero out DRAM */
+       memset_io(dram_ptr, 0, 512);
+
+       /* Load Call Setup into Adapter */
+       if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = 0; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Load Resident DCE portion of Adapter */
+       if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_IRAM_SIZE) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Set Hardware level */
+       if (icom_port->adapter->version == ADAPTER_V2)
+               writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
+
+       /* Start the processor in Adapter */
+       start_processor(icom_port);
+
+       writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
+              &(icom_port->dram->HDLCConfigReg));
+       writeb(0x04, &(icom_port->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0x00, &(icom_port->dram->CmdReg));
+       writeb(0x10, &(icom_port->dram->async_config3));
+       writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
+               ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
+
+       /*Set up data in icom DRAM to indicate where personality
+        *code is located and its length.
+        */
+       new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
+
+       if (!new_page) {
+               dev_err(&dev->dev, "Can not allocate DMA buffer\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       for (index = 0; index < fw->size; index++)
+               new_page[index] = fw->data[index];
+
+       release_firmware(fw);
+
+       writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
+       writel(temp_pci, &icom_port->dram->mac_load_addr);
+
+       /*Setting the syncReg to 0x80 causes adapter to start downloading
+          the personality code into adapter instruction RAM.
+          Once code is loaded, it will begin executing and, based on
+          information provided above, will start DMAing data from
+          shared memory to adapter DRAM.
+        */
+       /* the wait loop below verifies this write operation has been done
+          and processed
+       */
+       writeb(START_DOWNLOAD, &icom_port->dram->sync);
+
+       /* Wait max 1 Sec for data download and processor to start */
+       for (index = 0; index < 10; index++) {
+               msleep(100);
+               if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
+                       break;
+       }
+
+       if (index == 10)
+               status = -1;
+
+       /*
+        * check Cable ID
+        */
+       cable_id = readb(&icom_port->dram->cable_id);
+
+       if (cable_id & ICOM_CABLE_ID_VALID) {
+               /* Get cable ID into the lower 4 bits (standard form) */
+               cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               icom_port->cable_id = cable_id;
+       } else {
+               dev_err(&dev->dev,"Invalid or no cable attached\n");
+               icom_port->cable_id = NO_CABLE;
+       }
+
+      load_code_exit:
+
+       if (status != 0) {
+               /* Clear out any pending interrupts */
+               writew(0x3FFF, icom_port->int_reg);
+
+               /* Turn off port */
+               writeb(ICOM_DISABLE, &(icom_port->dram->disable));
+
+               /* Stop processor */
+               stop_processor(icom_port);
+
+               dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
+       }
+
+       if (new_page != NULL)
+               pci_free_consistent(dev, 4096, new_page, temp_pci);
+}
+
+static int startup(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cable_id, raw_cable_id;
+       unsigned long flags;
+       int port;
+
+       trace(icom_port, "STARTUP", 0);
+
+       if (!icom_port->dram) {
+               /* should NEVER be NULL */
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                       "Unusable Port, port configuration missing\n");
+               return -ENODEV;
+       }
+
+       /*
+        * check Cable ID
+        */
+       raw_cable_id = readb(&icom_port->dram->cable_id);
+       trace(icom_port, "CABLE_ID", raw_cable_id);
+
+       /* Get cable ID into the lower 4 bits (standard form) */
+       cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+
+       /* Check for valid Cable ID */
+       if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+           (cable_id != icom_port->cable_id)) {
+
+               /* reload adapter code, pick up any potential changes in cable id */
+               load_code(icom_port);
+
+               /* still no sign of cable, error out */
+               raw_cable_id = readb(&icom_port->dram->cable_id);
+               cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+                   (icom_port->cable_id == NO_CABLE))
+                       return -EIO;
+       }
+
+       /*
+        * Finally, clear and  enable interrupts
+        */
+       spin_lock_irqsave(&icom_lock, flags);
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port == 0 || port == 2)
+               writew(0x00FF, icom_port->int_reg);
+       else
+               writew(0x3F00, icom_port->int_reg);
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+       return 0;
+}
+
+static void shutdown(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cmdReg;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+       trace(icom_port, "SHUTDOWN", 0);
+
+       /*
+        * disable all interrupts
+        */
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+       spin_unlock_irqrestore(&icom_lock, flags);
+
+       /*
+        * disable break condition
+        */
+       cmdReg = readb(&icom_port->dram->CmdReg);
+       if (cmdReg & CMD_SND_BREAK) {
+               writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
+       }
+}
+
+static int icom_write(struct uart_port *port)
+{
+       unsigned long data_count;
+       unsigned char cmdReg;
+       unsigned long offset;
+       int temp_tail = port->state->xmit.tail;
+
+       trace(ICOM_PORT, "WRITE", 0);
+
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT) {
+               trace(ICOM_PORT, "WRITE_FULL", 0);
+               return 0;
+       }
+
+       data_count = 0;
+       while ((port->state->xmit.head != temp_tail) &&
+              (data_count <= XMIT_BUFF_SZ)) {
+
+               ICOM_PORT->xmit_buf[data_count++] =
+                   port->state->xmit.buf[temp_tail];
+
+               temp_tail++;
+               temp_tail &= (UART_XMIT_SIZE - 1);
+       }
+
+       if (data_count) {
+               ICOM_PORT->statStg->xmit[0].flags =
+                   cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
+               ICOM_PORT->statStg->xmit[0].leLength =
+                   cpu_to_le16(data_count);
+               offset =
+                   (unsigned long) &ICOM_PORT->statStg->xmit[0] -
+                   (unsigned long) ICOM_PORT->statStg;
+               *ICOM_PORT->xmitRestart =
+                   cpu_to_le32(ICOM_PORT->statStg_pci + offset);
+               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+               writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
+                      &ICOM_PORT->dram->CmdReg);
+               writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
+               trace(ICOM_PORT, "WRITE_START", data_count);
+               /* write flush */
+               readb(&ICOM_PORT->dram->StartXmitCmd);
+       }
+
+       return data_count;
+}
+
+static inline void check_modem_status(struct icom_port *icom_port)
+{
+       static char old_status = 0;
+       char delta_status;
+       unsigned char status;
+
+       spin_lock(&icom_port->uart_port.lock);
+
+       /*modem input register */
+       status = readb(&icom_port->dram->isr);
+       trace(icom_port, "CHECK_MODEM", status);
+       delta_status = status ^ old_status;
+       if (delta_status) {
+               if (delta_status & ICOM_RI)
+                       icom_port->uart_port.icount.rng++;
+               if (delta_status & ICOM_DSR)
+                       icom_port->uart_port.icount.dsr++;
+               if (delta_status & ICOM_DCD)
+                       uart_handle_dcd_change(&icom_port->uart_port,
+                                              delta_status & ICOM_DCD);
+               if (delta_status & ICOM_CTS)
+                       uart_handle_cts_change(&icom_port->uart_port,
+                                              delta_status & ICOM_CTS);
+
+               wake_up_interruptible(&icom_port->uart_port.state->
+                                     port.delta_msr_wait);
+               old_status = status;
+       }
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       unsigned short int count;
+       int i;
+
+       if (port_int_reg & (INT_XMIT_COMPLETED)) {
+               trace(icom_port, "XMIT_COMPLETE", 0);
+
+               /* clear buffer in use bit */
+               icom_port->statStg->xmit[0].flags &=
+                       cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
+
+               count = (unsigned short int)
+                       cpu_to_le16(icom_port->statStg->xmit[0].leLength);
+               icom_port->uart_port.icount.tx += count;
+
+               for (i=0; i<count &&
+                       !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
+
+                       icom_port->uart_port.state->xmit.tail++;
+                       icom_port->uart_port.state->xmit.tail &=
+                               (UART_XMIT_SIZE - 1);
+               }
+
+               if (!icom_write(&icom_port->uart_port))
+                       /* activate write queue */
+                       uart_write_wakeup(&icom_port->uart_port);
+       } else
+               trace(icom_port, "XMIT_DISABLED", 0);
+}
+
+static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       short int count, rcv_buff;
+       struct tty_struct *tty = icom_port->uart_port.state->port.tty;
+       unsigned short int status;
+       struct uart_icount *icount;
+       unsigned long offset;
+       unsigned char flag;
+
+       trace(icom_port, "RCV_COMPLETE", 0);
+       rcv_buff = icom_port->next_rcv;
+
+       status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       while (status & SA_FL_RCV_DONE) {
+               int first = -1;
+
+               trace(icom_port, "FID_STATUS", status);
+               count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
+
+               trace(icom_port, "RCV_COUNT", count);
+
+               trace(icom_port, "REAL_COUNT", count);
+
+               offset =
+                       cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
+                       icom_port->recv_buf_pci;
+
+               /* Block copy all but the last byte as this may have status */
+               if (count > 0) {
+                       first = icom_port->recv_buf[offset];
+                       tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
+               }
+
+               icount = &icom_port->uart_port.icount;
+               icount->rx += count;
+
+               /* Break detect logic */
+               if ((status & SA_FLAGS_FRAME_ERROR)
+                   && first == 0) {
+                       status &= ~SA_FLAGS_FRAME_ERROR;
+                       status |= SA_FLAGS_BREAK_DET;
+                       trace(icom_port, "BREAK_DET", 0);
+               }
+
+               flag = TTY_NORMAL;
+
+               if (status &
+                   (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
+                    SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
+
+                       if (status & SA_FLAGS_BREAK_DET)
+                               icount->brk++;
+                       if (status & SA_FLAGS_PARITY_ERROR)
+                               icount->parity++;
+                       if (status & SA_FLAGS_FRAME_ERROR)
+                               icount->frame++;
+                       if (status & SA_FLAGS_OVERRUN)
+                               icount->overrun++;
+
+                       /*
+                        * Now check to see if character should be
+                        * ignored, and mask off conditions which
+                        * should be ignored.
+                        */
+                       if (status & icom_port->ignore_status_mask) {
+                               trace(icom_port, "IGNORE_CHAR", 0);
+                               goto ignore_char;
+                       }
+
+                       status &= icom_port->read_status_mask;
+
+                       if (status & SA_FLAGS_BREAK_DET) {
+                               flag = TTY_BREAK;
+                       } else if (status & SA_FLAGS_PARITY_ERROR) {
+                               trace(icom_port, "PARITY_ERROR", 0);
+                               flag = TTY_PARITY;
+                       } else if (status & SA_FLAGS_FRAME_ERROR)
+                               flag = TTY_FRAME;
+
+               }
+
+               tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
+
+               if (status & SA_FLAGS_OVERRUN)
+                       /*
+                        * Overrun is special, since it's
+                        * reported immediately, and doesn't
+                        * affect the current character
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ignore_char:
+               icom_port->statStg->rcv[rcv_buff].flags = 0;
+               icom_port->statStg->rcv[rcv_buff].leLength = 0;
+               icom_port->statStg->rcv[rcv_buff].WorkingLength =
+                       (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+
+               rcv_buff++;
+               if (rcv_buff == NUM_RBUFFS)
+                       rcv_buff = 0;
+
+               status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       }
+       icom_port->next_rcv = rcv_buff;
+       tty_flip_buffer_push(tty);
+}
+
+static void process_interrupt(u16 port_int_reg,
+                             struct icom_port *icom_port)
+{
+
+       spin_lock(&icom_port->uart_port.lock);
+       trace(icom_port, "INTERRUPT", port_int_reg);
+
+       if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
+               xmit_interrupt(port_int_reg, icom_port);
+
+       if (port_int_reg & INT_RCV_COMPLETED)
+               recv_interrupt(port_int_reg, icom_port);
+
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static irqreturn_t icom_interrupt(int irq, void *dev_id)
+{
+       void __iomem * int_reg;
+       u32 adapter_interrupts;
+       u16 port_int_reg;
+       struct icom_adapter *icom_adapter;
+       struct icom_port *icom_port;
+
+       /* find icom_port for this interrupt */
+       icom_adapter = (struct icom_adapter *) dev_id;
+
+       if (icom_adapter->version == ADAPTER_V2) {
+               int_reg = icom_adapter->base_addr + 0x8024;
+
+               adapter_interrupts = readl(int_reg);
+
+               if (adapter_interrupts & 0x00003FFF) {
+                       /* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */
+                       icom_port = &icom_adapter->port_info[2];
+                       port_int_reg = (u16) adapter_interrupts;
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+               if (adapter_interrupts & 0x3FFF0000) {
+                       /* port 3 interrupt */
+                       icom_port = &icom_adapter->port_info[3];
+                       if (icom_port->status == ICOM_PORT_ACTIVE) {
+                               port_int_reg =
+                                   (u16) (adapter_interrupts >> 16);
+                               process_interrupt(port_int_reg, icom_port);
+                               check_modem_status(icom_port);
+                       }
+               }
+
+               /* Clear out any pending interrupts */
+               writel(adapter_interrupts, int_reg);
+
+               int_reg = icom_adapter->base_addr + 0x8004;
+       } else {
+               int_reg = icom_adapter->base_addr + 0x4004;
+       }
+
+       adapter_interrupts = readl(int_reg);
+
+       if (adapter_interrupts & 0x00003FFF) {
+               /* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */
+               icom_port = &icom_adapter->port_info[0];
+               port_int_reg = (u16) adapter_interrupts;
+               process_interrupt(port_int_reg, icom_port);
+               check_modem_status(icom_port);
+       }
+       if (adapter_interrupts & 0x3FFF0000) {
+               /* port 1 interrupt */
+               icom_port = &icom_adapter->port_info[1];
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       port_int_reg = (u16) (adapter_interrupts >> 16);
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+       }
+
+       /* Clear out any pending interrupts */
+       writel(adapter_interrupts, int_reg);
+
+       /* flush the write */
+       adapter_interrupts = readl(int_reg);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ------------------------------------------------------------------
+ * Begin serial-core API
+ * ------------------------------------------------------------------
+ */
+static unsigned int icom_tx_empty(struct uart_port *port)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
+static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned char local_osr;
+
+       trace(ICOM_PORT, "SET_MODEM", 0);
+       local_osr = readb(&ICOM_PORT->dram->osr);
+
+       if (mctrl & TIOCM_RTS) {
+               trace(ICOM_PORT, "RAISE_RTS", 0);
+               local_osr |= ICOM_RTS;
+       } else {
+               trace(ICOM_PORT, "LOWER_RTS", 0);
+               local_osr &= ~ICOM_RTS;
+       }
+
+       if (mctrl & TIOCM_DTR) {
+               trace(ICOM_PORT, "RAISE_DTR", 0);
+               local_osr |= ICOM_DTR;
+       } else {
+               trace(ICOM_PORT, "LOWER_DTR", 0);
+               local_osr &= ~ICOM_DTR;
+       }
+
+       writeb(local_osr, &ICOM_PORT->dram->osr);
+}
+
+static unsigned int icom_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int result;
+
+       trace(ICOM_PORT, "GET_MODEM", 0);
+
+       status = readb(&ICOM_PORT->dram->isr);
+
+       result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
+           | ((status & ICOM_RI) ? TIOCM_RNG : 0)
+           | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
+           | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
+       return result;
+}
+
+static void icom_stop_tx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "STOP", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
+}
+
+static void icom_start_tx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "START", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
+               writeb(cmdReg & ~CMD_HOLD_XMIT,
+                      &ICOM_PORT->dram->CmdReg);
+
+       icom_write(port);
+}
+
+static void icom_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned char xdata;
+       int index;
+       unsigned long flags;
+
+       trace(ICOM_PORT, "SEND_XCHAR", ch);
+
+       /* wait .1 sec to send char */
+       for (index = 0; index < 10; index++) {
+               spin_lock_irqsave(&port->lock, flags);
+               xdata = readb(&ICOM_PORT->dram->xchar);
+               if (xdata == 0x00) {
+                       trace(ICOM_PORT, "QUICK_WRITE", 0);
+                       writeb(ch, &ICOM_PORT->dram->xchar);
+
+                       /* flush write operation */
+                       xdata = readb(&ICOM_PORT->dram->xchar);
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               msleep(10);
+       }
+}
+
+static void icom_stop_rx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+}
+
+static void icom_enable_ms(struct uart_port *port)
+{
+       /* no-op */
+}
+
+static void icom_break(struct uart_port *port, int break_state)
+{
+       unsigned char cmdReg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "BREAK", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if (break_state == -1) {
+               writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       } else {
+               writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int icom_open(struct uart_port *port)
+{
+       int retval;
+
+       kref_get(&ICOM_PORT->adapter->kref);
+       retval = startup(ICOM_PORT);
+
+       if (retval) {
+               kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+               trace(ICOM_PORT, "STARTUP_ERROR", 0);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void icom_close(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "CLOSE", 0);
+
+       /* stop receiver */
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
+              &ICOM_PORT->dram->CmdReg);
+
+       shutdown(ICOM_PORT);
+
+       kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+}
+
+static void icom_set_termios(struct uart_port *port,
+                            struct ktermios *termios,
+                            struct ktermios *old_termios)
+{
+       int baud;
+       unsigned cflag, iflag;
+       char new_config2;
+       char new_config3 = 0;
+       char tmp_byte;
+       int index;
+       int rcv_buff, xmit_buff;
+       unsigned long offset;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "CHANGE_SPEED", 0);
+
+       cflag = termios->c_cflag;
+       iflag = termios->c_iflag;
+
+       new_config2 = ICOM_ACFG_DRIVE1;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:               /* 5 bits/char */
+               new_config2 |= ICOM_ACFG_5BPC;
+               break;
+       case CS6:               /* 6 bits/char */
+               new_config2 |= ICOM_ACFG_6BPC;
+               break;
+       case CS7:               /* 7 bits/char */
+               new_config2 |= ICOM_ACFG_7BPC;
+               break;
+       case CS8:               /* 8 bits/char */
+               new_config2 |= ICOM_ACFG_8BPC;
+               break;
+       default:
+               break;
+       }
+       if (cflag & CSTOPB) {
+               /* 2 stop bits */
+               new_config2 |= ICOM_ACFG_2STOP_BIT;
+       }
+       if (cflag & PARENB) {
+               /* parity bit enabled */
+               new_config2 |= ICOM_ACFG_PARITY_ENAB;
+               trace(ICOM_PORT, "PARENB", 0);
+       }
+       if (cflag & PARODD) {
+               /* odd parity */
+               new_config2 |= ICOM_ACFG_PARITY_ODD;
+               trace(ICOM_PORT, "PARODD", 0);
+       }
+
+       /* Determine divisor based on baud rate */
+       baud = uart_get_baud_rate(port, termios, old_termios,
+                                 icom_acfg_baud[0],
+                                 icom_acfg_baud[BAUD_TABLE_LIMIT]);
+       if (!baud)
+               baud = 9600;    /* B0 transition handled in rs_set_termios */
+
+       for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
+               if (icom_acfg_baud[index] == baud) {
+                       new_config3 = index;
+                       break;
+               }
+       }
+
+       uart_update_timeout(port, cflag, baud);
+
+       /* CTS flow control flag and modem status interrupts */
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       if (cflag & CRTSCTS)
+               tmp_byte |= HDLC_HDW_FLOW;
+       else
+               tmp_byte &= ~HDLC_HDW_FLOW;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+
+       /*
+        * Set up parity check flag
+        */
+       ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
+       if (iflag & INPCK)
+               ICOM_PORT->read_status_mask |=
+                   SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
+
+       if ((iflag & BRKINT) || (iflag & PARMRK))
+               ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
+
+       /*
+        * Characters to ignore
+        */
+       ICOM_PORT->ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               ICOM_PORT->ignore_status_mask |=
+                   SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
+       if (iflag & IGNBRK) {
+               ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (iflag & IGNPAR)
+                       ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
+       }
+
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
+
+       /* Turn off Receiver to prepare for reset */
+       writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* clear all current buffers of data */
+       for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
+               ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+       }
+
+       for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
+               ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
+       }
+
+       /* activate changes and start xmit and receiver here */
+       /* Enable the receiver */
+       writeb(new_config3, &(ICOM_PORT->dram->async_config3));
+       writeb(new_config2, &(ICOM_PORT->dram->async_config2));
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+       writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0xFF, &(ICOM_PORT->dram->ier));  /* enable modem signal interrupts */
+
+       /* reset processor */
+       writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* Enable Transmitter and Reciever */
+       offset =
+           (unsigned long) &ICOM_PORT->statStg->rcv[0] -
+           (unsigned long) ICOM_PORT->statStg;
+       writel(ICOM_PORT->statStg_pci + offset,
+              &ICOM_PORT->dram->RcvStatusAddr);
+       ICOM_PORT->next_rcv = 0;
+       ICOM_PORT->put_length = 0;
+       *ICOM_PORT->xmitRestart = 0;
+       writel(ICOM_PORT->xmitRestart_pci,
+              &ICOM_PORT->dram->XmitStatusAddr);
+       trace(ICOM_PORT, "XR_ENAB", 0);
+       writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *icom_type(struct uart_port *port)
+{
+       return "icom";
+}
+
+static void icom_release_port(struct uart_port *port)
+{
+}
+
+static int icom_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void icom_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ICOM;
+}
+
+static struct uart_ops icom_ops = {
+       .tx_empty = icom_tx_empty,
+       .set_mctrl = icom_set_mctrl,
+       .get_mctrl = icom_get_mctrl,
+       .stop_tx = icom_stop_tx,
+       .start_tx = icom_start_tx,
+       .send_xchar = icom_send_xchar,
+       .stop_rx = icom_stop_rx,
+       .enable_ms = icom_enable_ms,
+       .break_ctl = icom_break,
+       .startup = icom_open,
+       .shutdown = icom_close,
+       .set_termios = icom_set_termios,
+       .type = icom_type,
+       .release_port = icom_release_port,
+       .request_port = icom_request_port,
+       .config_port = icom_config_port,
+};
+
+#define ICOM_CONSOLE NULL
+
+static struct uart_driver icom_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = ICOM_DRIVER_NAME,
+       .dev_name = "ttyA",
+       .major = ICOM_MAJOR,
+       .minor = ICOM_MINOR_START,
+       .nr = NR_PORTS,
+       .cons = ICOM_CONSOLE,
+};
+
+static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
+{
+       u32 subsystem_id = icom_adapter->subsystem_id;
+       int i;
+       struct icom_port *icom_port;
+
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_adapter->numb_ports = 2;
+
+               for (i = 0; i < 2; i++) {
+                       icom_port = &icom_adapter->port_info[i];
+                       icom_port->port = i;
+                       icom_port->status = ICOM_PORT_ACTIVE;
+                       icom_port->imbed_modem = ICOM_UNKNOWN;
+               }
+       } else {
+               if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
+                       icom_adapter->numb_ports = 4;
+
+                       for (i = 0; i < 4; i++) {
+                               icom_port = &icom_adapter->port_info[i];
+
+                               icom_port->port = i;
+                               icom_port->status = ICOM_PORT_ACTIVE;
+                               icom_port->imbed_modem = ICOM_IMBED_MODEM;
+                       }
+               } else {
+                       icom_adapter->numb_ports = 4;
+
+                       icom_adapter->port_info[0].port = 0;
+                       icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
+
+                       if (subsystem_id ==
+                           PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
+                       } else {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
+                       }
+
+                       icom_adapter->port_info[1].status = ICOM_PORT_OFF;
+
+                       icom_adapter->port_info[2].port = 2;
+                       icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
+                       icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
+                       icom_adapter->port_info[3].status = ICOM_PORT_OFF;
+               }
+       }
+
+       return 0;
+}
+
+static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
+{
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_port->global_reg = icom_adapter->base_addr + 0x4000;
+               icom_port->int_reg = icom_adapter->base_addr +
+                   0x4004 + 2 - 2 * port_num;
+       } else {
+               icom_port->global_reg = icom_adapter->base_addr + 0x8000;
+               if (icom_port->port < 2)
+                       icom_port->int_reg = icom_adapter->base_addr +
+                           0x8004 + 2 - 2 * icom_port->port;
+               else
+                       icom_port->int_reg = icom_adapter->base_addr +
+                           0x8024 + 2 - 2 * (icom_port->port - 2);
+       }
+}
+static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int port_num;
+
+       for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
+
+               icom_port = &icom_adapter->port_info[port_num];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port_active(icom_port, icom_adapter, port_num);
+                       icom_port->dram = icom_adapter->base_addr +
+                                       0x2000 * icom_port->port;
+
+                       icom_port->adapter = icom_adapter;
+
+                       /* get port memory */
+                       if (get_port_memory(icom_port) != 0) {
+                               dev_err(&icom_port->adapter->pci_dev->dev,
+                                       "Memory allocation for port FAILED\n");
+                       }
+               }
+       }
+       return 0;
+}
+
+static int __devinit icom_alloc_adapter(struct icom_adapter
+                                       **icom_adapter_ref)
+{
+       int adapter_count = 0;
+       struct icom_adapter *icom_adapter;
+       struct icom_adapter *cur_adapter_entry;
+       struct list_head *tmp;
+
+       icom_adapter = (struct icom_adapter *)
+           kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
+
+       if (!icom_adapter) {
+               return -ENOMEM;
+       }
+
+       list_for_each(tmp, &icom_adapter_head) {
+               cur_adapter_entry =
+                   list_entry(tmp, struct icom_adapter,
+                              icom_adapter_entry);
+               if (cur_adapter_entry->index != adapter_count) {
+                       break;
+               }
+               adapter_count++;
+       }
+
+       icom_adapter->index = adapter_count;
+       list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
+
+       *icom_adapter_ref = icom_adapter;
+       return 0;
+}
+
+static void icom_free_adapter(struct icom_adapter *icom_adapter)
+{
+       list_del(&icom_adapter->icom_adapter_entry);
+       kfree(icom_adapter);
+}
+
+static void icom_remove_adapter(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int index;
+
+       for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       dev_info(&icom_adapter->pci_dev->dev,
+                                "Device removed\n");
+
+                       uart_remove_one_port(&icom_uart_driver,
+                                            &icom_port->uart_port);
+
+                       /* be sure that DTR and RTS are dropped */
+                       writeb(0x00, &icom_port->dram->osr);
+
+                       /* Wait 0.1 Sec for simple Init to complete */
+                       msleep(100);
+
+                       /* Stop proccessor */
+                       stop_processor(icom_port);
+
+                       free_port_memory(icom_port);
+               }
+       }
+
+       free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
+       iounmap(icom_adapter->base_addr);
+       pci_release_regions(icom_adapter->pci_dev);
+       icom_free_adapter(icom_adapter);
+}
+
+static void icom_kref_release(struct kref *kref)
+{
+       struct icom_adapter *icom_adapter;
+
+       icom_adapter = to_icom_adapter(kref);
+       icom_remove_adapter(icom_adapter);
+}
+
+static int __devinit icom_probe(struct pci_dev *dev,
+                               const struct pci_device_id *ent)
+{
+       int index;
+       unsigned int command_reg;
+       int retval;
+       struct icom_adapter *icom_adapter;
+       struct icom_port *icom_port;
+
+       retval = pci_enable_device(dev);
+       if (retval) {
+               dev_err(&dev->dev, "Device enable FAILED\n");
+               return retval;
+       }
+
+       if ( (retval = pci_request_regions(dev, "icom"))) {
+                dev_err(&dev->dev, "pci_request_regions FAILED\n");
+                pci_disable_device(dev);
+                return retval;
+        }
+
+       pci_set_master(dev);
+
+       if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
+               dev_err(&dev->dev, "PCI Config read FAILED\n");
+               return retval;
+       }
+
+       pci_write_config_dword(dev, PCI_COMMAND,
+               command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
+               | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+       if (ent->driver_data == ADAPTER_V1) {
+               pci_write_config_dword(dev, 0x44, 0x8300830A);
+       } else {
+               pci_write_config_dword(dev, 0x44, 0x42004200);
+               pci_write_config_dword(dev, 0x48, 0x42004200);
+       }
+
+
+       retval = icom_alloc_adapter(&icom_adapter);
+       if (retval) {
+                dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
+                retval = -EIO;
+                goto probe_exit0;
+       }
+
+       icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
+       icom_adapter->pci_dev = dev;
+       icom_adapter->version = ent->driver_data;
+       icom_adapter->subsystem_id = ent->subdevice;
+
+
+       retval = icom_init_ports(icom_adapter);
+       if (retval) {
+               dev_err(&dev->dev, "Port configuration failed\n");
+               goto probe_exit1;
+       }
+
+       icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
+
+       if (!icom_adapter->base_addr)
+               goto probe_exit1;
+
+        /* save off irq and request irq line */
+        if ( (retval = request_irq(dev->irq, icom_interrupt,
+                                  IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
+                                  (void *) icom_adapter))) {
+                 goto probe_exit2;
+        }
+
+       retval = icom_load_ports(icom_adapter);
+
+       for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
+                       icom_port->uart_port.type = PORT_ICOM;
+                       icom_port->uart_port.iotype = UPIO_MEM;
+                       icom_port->uart_port.membase =
+                                              (char *) icom_adapter->base_addr_pci;
+                       icom_port->uart_port.fifosize = 16;
+                       icom_port->uart_port.ops = &icom_ops;
+                       icom_port->uart_port.line =
+                       icom_port->port + icom_adapter->index * 4;
+                       if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
+                               icom_port->status = ICOM_PORT_OFF;
+                               dev_err(&dev->dev, "Device add failed\n");
+                        } else
+                               dev_info(&dev->dev, "Device added\n");
+               }
+       }
+
+       kref_init(&icom_adapter->kref);
+       return 0;
+
+probe_exit2:
+       iounmap(icom_adapter->base_addr);
+probe_exit1:
+       icom_free_adapter(icom_adapter);
+
+probe_exit0:
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+
+       return retval;
+}
+
+static void __devexit icom_remove(struct pci_dev *dev)
+{
+       struct icom_adapter *icom_adapter;
+       struct list_head *tmp;
+
+       list_for_each(tmp, &icom_adapter_head) {
+               icom_adapter = list_entry(tmp, struct icom_adapter,
+                                         icom_adapter_entry);
+               if (icom_adapter->pci_dev == dev) {
+                       kref_put(&icom_adapter->kref, icom_kref_release);
+                       return;
+               }
+       }
+
+       dev_err(&dev->dev, "Unable to find device to remove\n");
+}
+
+static struct pci_driver icom_pci_driver = {
+       .name = ICOM_DRIVER_NAME,
+       .id_table = icom_pci_table,
+       .probe = icom_probe,
+       .remove = __devexit_p(icom_remove),
+};
+
+static int __init icom_init(void)
+{
+       int ret;
+
+       spin_lock_init(&icom_lock);
+
+       ret = uart_register_driver(&icom_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = pci_register_driver(&icom_pci_driver);
+
+       if (ret < 0)
+               uart_unregister_driver(&icom_uart_driver);
+
+       return ret;
+}
+
+static void __exit icom_exit(void)
+{
+       pci_unregister_driver(&icom_pci_driver);
+       uart_unregister_driver(&icom_uart_driver);
+}
+
+module_init(icom_init);
+module_exit(icom_exit);
+
+MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
+MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
+MODULE_SUPPORTED_DEVICE
+    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("icom_call_setup.bin");
+MODULE_FIRMWARE("icom_res_dce.bin");
+MODULE_FIRMWARE("icom_asc.bin");
diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h
new file mode 100644 (file)
index 0000000..c8029e0
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * icom.h
+ *
+ * Copyright (C) 2001 Michael Anderson, IBM Corporation
+ *
+ * Serial device driver include file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/serial_core.h>
+
+#define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
+static int icom_acfg_baud[] = {
+       300,
+       600,
+       900,
+       1200,
+       1800,
+       2400,
+       3600,
+       4800,
+       7200,
+       9600,
+       14400,
+       19200,
+       28800,
+       38400,
+       57600,
+       76800,
+       115200,
+       153600,
+       230400,
+       307200,
+       460800,
+};
+
+struct icom_regs {
+       u32 control;            /* Adapter Control Register     */
+       u32 interrupt;          /* Adapter Interrupt Register   */
+       u32 int_mask;           /* Adapter Interrupt Mask Reg   */
+       u32 int_pri;            /* Adapter Interrupt Priority r */
+       u32 int_reg_b;          /* Adapter non-masked Interrupt */
+       u32 resvd01;
+       u32 resvd02;
+       u32 resvd03;
+       u32 control_2;          /* Adapter Control Register 2   */
+       u32 interrupt_2;        /* Adapter Interrupt Register 2 */
+       u32 int_mask_2;         /* Adapter Interrupt Mask 2     */
+       u32 int_pri_2;          /* Adapter Interrupt Prior 2    */
+       u32 int_reg_2b;         /* Adapter non-masked 2         */
+};
+
+struct func_dram {
+       u32 reserved[108];      /* 0-1B0   reserved by personality code */
+       u32 RcvStatusAddr;      /* 1B0-1B3 Status Address for Next rcv */
+       u8 RcvStnAddr;          /* 1B4     Receive Station Addr */
+       u8 IdleState;           /* 1B5     Idle State */
+       u8 IdleMonitor;         /* 1B6     Idle Monitor */
+       u8 FlagFillIdleTimer;   /* 1B7     Flag Fill Idle Timer */
+       u32 XmitStatusAddr;     /* 1B8-1BB Transmit Status Address */
+       u8 StartXmitCmd;        /* 1BC     Start Xmit Command */
+       u8 HDLCConfigReg;       /* 1BD     Reserved */
+       u8 CauseCode;           /* 1BE     Cause code for fatal error */
+       u8 xchar;               /* 1BF     High priority send */
+       u32 reserved3;          /* 1C0-1C3 Reserved */
+       u8 PrevCmdReg;          /* 1C4     Reserved */
+       u8 CmdReg;              /* 1C5     Command Register */
+       u8 async_config2;       /* 1C6     Async Config Byte 2 */
+       u8 async_config3;       /* 1C7     Async Config Byte 3 */
+       u8 dce_resvd[20];       /* 1C8-1DB DCE Rsvd           */
+       u8 dce_resvd21;         /* 1DC     DCE Rsvd (21st byte */
+       u8 misc_flags;          /* 1DD     misc flags         */
+#define V2_HARDWARE     0x40
+#define ICOM_HDW_ACTIVE 0x01
+       u8 call_length;         /* 1DE     Phone #/CFI buff ln */
+       u8 call_length2;        /* 1DF     Upper byte (unused) */
+       u32 call_addr;          /* 1E0-1E3 Phn #/CFI buff addr */
+       u16 timer_value;        /* 1E4-1E5 general timer value */
+       u8 timer_command;       /* 1E6     general timer cmd  */
+       u8 dce_command;         /* 1E7     dce command reg    */
+       u8 dce_cmd_status;      /* 1E8     dce command stat   */
+       u8 x21_r1_ioff;         /* 1E9     dce ready counter  */
+       u8 x21_r0_ioff;         /* 1EA     dce not ready ctr  */
+       u8 x21_ralt_ioff;       /* 1EB     dce CNR counter    */
+       u8 x21_r1_ion;          /* 1EC     dce ready I on ctr */
+       u8 rsvd_ier;            /* 1ED     Rsvd for IER (if ne */
+       u8 ier;                 /* 1EE     Interrupt Enable   */
+       u8 isr;                 /* 1EF     Input Signal Reg   */
+       u8 osr;                 /* 1F0     Output Signal Reg  */
+       u8 reset;               /* 1F1     Reset/Reload Reg   */
+       u8 disable;             /* 1F2     Disable Reg        */
+       u8 sync;                /* 1F3     Sync Reg           */
+       u8 error_stat;          /* 1F4     Error Status       */
+       u8 cable_id;            /* 1F5     Cable ID           */
+       u8 cs_length;           /* 1F6     CS Load Length     */
+       u8 mac_length;          /* 1F7     Mac Load Length    */
+       u32 cs_load_addr;       /* 1F8-1FB Call Load PCI Addr */
+       u32 mac_load_addr;      /* 1FC-1FF Mac Load PCI Addr  */
+};
+
+/*
+ * adapter defines and structures
+ */
+#define ICOM_CONTROL_START_A         0x00000008
+#define ICOM_CONTROL_STOP_A          0x00000004
+#define ICOM_CONTROL_START_B         0x00000002
+#define ICOM_CONTROL_STOP_B          0x00000001
+#define ICOM_CONTROL_START_C         0x00000008
+#define ICOM_CONTROL_STOP_C          0x00000004
+#define ICOM_CONTROL_START_D         0x00000002
+#define ICOM_CONTROL_STOP_D          0x00000001
+#define ICOM_IRAM_OFFSET             0x1000
+#define ICOM_IRAM_SIZE               0x0C00
+#define ICOM_DCE_IRAM_OFFSET         0x0A00
+#define ICOM_CABLE_ID_VALID          0x01
+#define ICOM_CABLE_ID_MASK           0xF0
+#define ICOM_DISABLE                 0x80
+#define CMD_XMIT_RCV_ENABLE          0xC0
+#define CMD_XMIT_ENABLE              0x40
+#define CMD_RCV_DISABLE              0x00
+#define CMD_RCV_ENABLE               0x80
+#define CMD_RESTART                  0x01
+#define CMD_HOLD_XMIT                0x02
+#define CMD_SND_BREAK                0x04
+#define RS232_CABLE                  0x06
+#define V24_CABLE                    0x0E
+#define V35_CABLE                    0x0C
+#define V36_CABLE                    0x02
+#define NO_CABLE                     0x00
+#define START_DOWNLOAD               0x80
+#define ICOM_INT_MASK_PRC_A          0x00003FFF
+#define ICOM_INT_MASK_PRC_B          0x3FFF0000
+#define ICOM_INT_MASK_PRC_C          0x00003FFF
+#define ICOM_INT_MASK_PRC_D          0x3FFF0000
+#define INT_RCV_COMPLETED            0x1000
+#define INT_XMIT_COMPLETED           0x2000
+#define INT_IDLE_DETECT              0x0800
+#define INT_RCV_DISABLED             0x0400
+#define INT_XMIT_DISABLED            0x0200
+#define INT_RCV_XMIT_SHUTDOWN        0x0100
+#define INT_FATAL_ERROR              0x0080
+#define INT_CABLE_PULL               0x0020
+#define INT_SIGNAL_CHANGE            0x0010
+#define HDLC_PPP_PURE_ASYNC          0x02
+#define HDLC_FF_FILL                 0x00
+#define HDLC_HDW_FLOW                0x01
+#define START_XMIT                   0x80
+#define ICOM_ACFG_DRIVE1             0x20
+#define ICOM_ACFG_NO_PARITY          0x00
+#define ICOM_ACFG_PARITY_ENAB        0x02
+#define ICOM_ACFG_PARITY_ODD         0x01
+#define ICOM_ACFG_8BPC               0x00
+#define ICOM_ACFG_7BPC               0x04
+#define ICOM_ACFG_6BPC               0x08
+#define ICOM_ACFG_5BPC               0x0C
+#define ICOM_ACFG_1STOP_BIT          0x00
+#define ICOM_ACFG_2STOP_BIT          0x10
+#define ICOM_DTR                     0x80
+#define ICOM_RTS                     0x40
+#define ICOM_RI                      0x08
+#define ICOM_DSR                     0x80
+#define ICOM_DCD                     0x20
+#define ICOM_CTS                     0x40
+
+#define NUM_XBUFFS 1
+#define NUM_RBUFFS 2
+#define RCV_BUFF_SZ 0x0200
+#define XMIT_BUFF_SZ 0x1000
+struct statusArea {
+    /**********************************************/
+       /* Transmit Status Area                       */
+    /**********************************************/
+       struct xmit_status_area{
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 leLengthASD;
+               u16 leOffsetASD;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FLAGS_DONE           0x0080 /* Done with Segment */
+#define SA_FLAGS_CONTINUED      0x8000 /* More Segments */
+#define SA_FLAGS_IDLE           0x4000 /* Mark IDLE after frm */
+#define SA_FLAGS_READY_TO_XMIT  0x0800
+#define SA_FLAGS_STAT_MASK      0x007F
+       } xmit[NUM_XBUFFS];
+
+    /**********************************************/
+       /* Receive Status Area                        */
+    /**********************************************/
+       struct {
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 WorkingLength;      /* size of segment */
+               u16 reserv01;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FL_RCV_DONE           0x0010        /* Data ready */
+#define SA_FLAGS_OVERRUN         0x0040
+#define SA_FLAGS_PARITY_ERROR    0x0080
+#define SA_FLAGS_FRAME_ERROR     0x0001
+#define SA_FLAGS_FRAME_TRUNC     0x0002
+#define SA_FLAGS_BREAK_DET       0x0004        /* set conditionally by device driver, not hardware */
+#define SA_FLAGS_RCV_MASK        0xFFE6
+       } rcv[NUM_RBUFFS];
+};
+
+struct icom_adapter;
+
+
+#define ICOM_MAJOR       243
+#define ICOM_MINOR_START 0
+
+struct icom_port {
+       struct uart_port uart_port;
+       u8 imbed_modem;
+#define ICOM_UNKNOWN           1
+#define ICOM_RVX               2
+#define ICOM_IMBED_MODEM       3
+       unsigned char cable_id;
+       unsigned char read_status_mask;
+       unsigned char ignore_status_mask;
+       void __iomem * int_reg;
+       struct icom_regs __iomem *global_reg;
+       struct func_dram __iomem *dram;
+       int port;
+       struct statusArea *statStg;
+       dma_addr_t statStg_pci;
+       u32 *xmitRestart;
+       dma_addr_t xmitRestart_pci;
+       unsigned char *xmit_buf;
+       dma_addr_t xmit_buf_pci;
+       unsigned char *recv_buf;
+       dma_addr_t recv_buf_pci;
+       int next_rcv;
+       int put_length;
+       int status;
+#define ICOM_PORT_ACTIVE       1       /* Port exists. */
+#define ICOM_PORT_OFF          0       /* Port does not exist. */
+       int load_in_progress;
+       struct icom_adapter *adapter;
+};
+
+struct icom_adapter {
+       void __iomem * base_addr;
+       unsigned long base_addr_pci;
+       struct pci_dev *pci_dev;
+       struct icom_port port_info[4];
+       int index;
+       int version;
+#define ADAPTER_V1     0x0001
+#define ADAPTER_V2     0x0002
+       u32 subsystem_id;
+#define FOUR_PORT_MODEL                                0x0252
+#define V2_TWO_PORTS_RVX                       0x021A
+#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
+       int numb_ports;
+       struct list_head icom_adapter_entry;
+       struct kref kref;
+};
+
+/* prototype */
+extern void iCom_sercons_init(void);
+
+struct lookup_proc_table {
+       u32     __iomem *global_control_reg;
+       unsigned long   processor_id;
+};
+
+struct lookup_int_table {
+       u32     __iomem *global_int_mask;
+       unsigned long   processor_id;
+};
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
new file mode 100644 (file)
index 0000000..ab93763
--- /dev/null
@@ -0,0 +1,1406 @@
+/****************************************************************************
+ *
+ * Driver for the IFX 6x60 spi modem.
+ *
+ * Copyright (C) 2008 Option International
+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
+ *                   Denis Joseph Barrow <d.barow@option.com>
+ *                   Jan Dumon <j.dumon@option.com>
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Russ Gorby <richardx.r.gorby@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ * Driver modified by Intel from Option gtm501l_spi.c
+ *
+ * Notes
+ * o   The driver currently assumes a single device only. If you need to
+ *     change this then look for saved_ifx_dev and add a device lookup
+ * o   The driver is intended to be big-endian safe but has never been
+ *     tested that way (no suitable hardware). There are a couple of FIXME
+ *     notes by areas that may need addressing
+ * o   Some of the GPIO naming/setup assumptions may need revisiting if
+ *     you need to use this driver for another platform.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/tty.h>
+#include <linux/kfifo.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rfkill.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/dmapool.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/ifx_modem.h>
+#include <linux/delay.h>
+
+#include "ifx6x60.h"
+
+#define IFX_SPI_MORE_MASK              0x10
+#define IFX_SPI_MORE_BIT               12      /* bit position in u16 */
+#define IFX_SPI_CTS_BIT                        13      /* bit position in u16 */
+#define IFX_SPI_TTY_ID                 0
+#define IFX_SPI_TIMEOUT_SEC            2
+#define IFX_SPI_HEADER_0               (-1)
+#define IFX_SPI_HEADER_F               (-2)
+
+/* forward reference */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+
+/* local variables */
+static int spi_b16 = 1;                        /* 8 or 16 bit word length */
+static struct tty_driver *tty_drv;
+static struct ifx_spi_device *saved_ifx_dev;
+static struct lock_class_key ifx_spi_key;
+
+/* GPIO/GPE settings */
+
+/**
+ *     mrdy_set_high           -       set MRDY GPIO
+ *     @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_high(struct ifx_spi_device *ifx)
+{
+       gpio_set_value(ifx->gpio.mrdy, 1);
+}
+
+/**
+ *     mrdy_set_low            -       clear MRDY GPIO
+ *     @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_low(struct ifx_spi_device *ifx)
+{
+       gpio_set_value(ifx->gpio.mrdy, 0);
+}
+
+/**
+ *     ifx_spi_power_state_set
+ *     @ifx_dev: our SPI device
+ *     @val: bits to set
+ *
+ *     Set bit in power status and signal power system if status becomes non-0
+ */
+static void
+ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+       /*
+        * if power status is already non-0, just update, else
+        * tell power system
+        */
+       if (!ifx_dev->power_status)
+               pm_runtime_get(&ifx_dev->spi_dev->dev);
+       ifx_dev->power_status |= val;
+
+       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *     ifx_spi_power_state_clear       -       clear power bit
+ *     @ifx_dev: our SPI device
+ *     @val: bits to clear
+ *
+ *     clear bit in power status and signal power system if status becomes 0
+ */
+static void
+ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+       if (ifx_dev->power_status) {
+               ifx_dev->power_status &= ~val;
+               if (!ifx_dev->power_status)
+                       pm_runtime_put(&ifx_dev->spi_dev->dev);
+       }
+
+       spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *     swap_buf
+ *     @buf: our buffer
+ *     @len : number of bytes (not words) in the buffer
+ *     @end: end of buffer
+ *
+ *     Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf(u16 *buf, int len, void *end)
+{
+       int n;
+
+       len = ((len + 1) >> 1);
+       if ((void *)&buf[len] > end) {
+               pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
+                      &buf[len], end);
+               return;
+       }
+       for (n = 0; n < len; n++) {
+               *buf = cpu_to_be16(*buf);
+               buf++;
+       }
+}
+
+/**
+ *     mrdy_assert             -       assert MRDY line
+ *     @ifx_dev: our SPI device
+ *
+ *     Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
+ *     now.
+ *
+ *     FIXME: Can SRDY even go high as we are running this code ?
+ */
+static void mrdy_assert(struct ifx_spi_device *ifx_dev)
+{
+       int val = gpio_get_value(ifx_dev->gpio.srdy);
+       if (!val) {
+               if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
+                                     &ifx_dev->flags)) {
+                       ifx_dev->spi_timer.expires =
+                               jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
+                       add_timer(&ifx_dev->spi_timer);
+
+               }
+       }
+       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
+       mrdy_set_high(ifx_dev);
+}
+
+/**
+ *     ifx_spi_hangup          -       hang up an IFX device
+ *     @ifx_dev: our SPI device
+ *
+ *     Hang up the tty attached to the IFX device if one is currently
+ *     open. If not take no action
+ */
+static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
+{
+       struct tty_port *pport = &ifx_dev->tty_port;
+       struct tty_struct *tty = tty_port_tty_get(pport);
+       if (tty) {
+               tty_hangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     ifx_spi_timeout         -       SPI timeout
+ *     @arg: our SPI device
+ *
+ *     The SPI has timed out: hang up the tty. Users will then see a hangup
+ *     and error events.
+ */
+static void ifx_spi_timeout(unsigned long arg)
+{
+       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
+
+       dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
+       ifx_spi_ttyhangup(ifx_dev);
+       mrdy_set_low(ifx_dev);
+       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+}
+
+/* char/tty operations */
+
+/**
+ *     ifx_spi_tiocmget        -       get modem lines
+ *     @tty: our tty device
+ *     @filp: file handle issuing the request
+ *
+ *     Map the signal state into Linux modem flags and report the value
+ *     in Linux terms
+ */
+static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+       unsigned int value;
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+       value =
+       (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
+       (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
+       (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
+       (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
+       (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
+       (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
+       return value;
+}
+
+/**
+ *     ifx_spi_tiocmset        -       set modem bits
+ *     @tty: the tty structure
+ *     @filp: file handle issuing the request
+ *     @set: bits to set
+ *     @clear: bits to clear
+ *
+ *     The IFX6x60 only supports DTR and RTS. Set them accordingly
+ *     and flag that an update to the modem is needed.
+ *
+ *     FIXME: do we need to kick the tranfers when we do this ?
+ */
+static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
+                           unsigned int set, unsigned int clear)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+       if (set & TIOCM_RTS)
+               set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+       if (set & TIOCM_DTR)
+               set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+       if (clear & TIOCM_RTS)
+               clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+       if (clear & TIOCM_DTR)
+               clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+
+       set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
+       return 0;
+}
+
+/**
+ *     ifx_spi_open    -       called on tty open
+ *     @tty: our tty device
+ *     @filp: file handle being associated with the tty
+ *
+ *     Open the tty interface. We let the tty_port layer do all the work
+ *     for us.
+ *
+ *     FIXME: Remove single device assumption and saved_ifx_dev
+ */
+static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
+{
+       return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
+}
+
+/**
+ *     ifx_spi_close   -       called when our tty closes
+ *     @tty: the tty being closed
+ *     @filp: the file handle being closed
+ *
+ *     Perform the close of the tty. We use the tty_port layer to do all
+ *     our hard work.
+ */
+static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       tty_port_close(&ifx_dev->tty_port, tty, filp);
+       /* FIXME: should we do an ifx_spi_reset here ? */
+}
+
+/**
+ *     ifx_decode_spi_header   -       decode received header
+ *     @buffer: the received data
+ *     @length: decoded length
+ *     @more: decoded more flag
+ *     @received_cts: status of cts we received
+ *
+ *     Note how received_cts is handled -- if header is all F it is left
+ *     the same as it was, if header is all 0 it is set to 0 otherwise it is
+ *     taken from the incoming header.
+ *
+ *     FIXME: endianness
+ */
+static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
+                       unsigned char *more, unsigned char *received_cts)
+{
+       u16 h1;
+       u16 h2;
+       u16 *in_buffer = (u16 *)buffer;
+
+       h1 = *in_buffer;
+       h2 = *(in_buffer+1);
+
+       if (h1 == 0 && h2 == 0) {
+               *received_cts = 0;
+               return IFX_SPI_HEADER_0;
+       } else if (h1 == 0xffff && h2 == 0xffff) {
+               /* spi_slave_cts remains as it was */
+               return IFX_SPI_HEADER_F;
+       }
+
+       *length = h1 & 0xfff;   /* upper bits of byte are flags */
+       *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
+       *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
+       return 0;
+}
+
+/**
+ *     ifx_setup_spi_header    -       set header fields
+ *     @txbuffer: pointer to start of SPI buffer
+ *     @tx_count: bytes
+ *     @more: indicate if more to follow
+ *
+ *     Format up an SPI header for a transfer
+ *
+ *     FIXME: endianness?
+ */
+static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
+                                       unsigned char more)
+{
+       *(u16 *)(txbuffer) = tx_count;
+       *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
+       txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
+}
+
+/**
+ *     ifx_spi_wakeup_serial   -       SPI space made
+ *     @port_data: our SPI device
+ *
+ *     We have emptied the FIFO enough that we want to get more data
+ *     queued into it. Poke the line discipline via tty_wakeup so that
+ *     it will feed us more bits
+ */
+static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
+{
+       struct tty_struct *tty;
+
+       tty = tty_port_tty_get(&ifx_dev->tty_port);
+       if (!tty)
+               return;
+       tty_wakeup(tty);
+       tty_kref_put(tty);
+}
+
+/**
+ *     ifx_spi_prepare_tx_buffer       -       prepare transmit frame
+ *     @ifx_dev: our SPI device
+ *
+ *     The transmit buffr needs a header and various other bits of
+ *     information followed by as much data as we can pull from the FIFO
+ *     and transfer. This function formats up a suitable buffer in the
+ *     ifx_dev->tx_buffer
+ *
+ *     FIXME: performance - should we wake the tty when the queue is half
+ *                          empty ?
+ */
+static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
+{
+       int temp_count;
+       int queue_length;
+       int tx_count;
+       unsigned char *tx_buffer;
+
+       tx_buffer = ifx_dev->tx_buffer;
+       memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
+
+       /* make room for required SPI header */
+       tx_buffer += IFX_SPI_HEADER_OVERHEAD;
+       tx_count = IFX_SPI_HEADER_OVERHEAD;
+
+       /* clear to signal no more data if this turns out to be the
+        * last buffer sent in a sequence */
+       ifx_dev->spi_more = 0;
+
+       /* if modem cts is set, just send empty buffer */
+       if (!ifx_dev->spi_slave_cts) {
+               /* see if there's tx data */
+               queue_length = kfifo_len(&ifx_dev->tx_fifo);
+               if (queue_length != 0) {
+                       /* data to mux -- see if there's room for it */
+                       temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
+                       temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
+                                       tx_buffer, temp_count,
+                                       &ifx_dev->fifo_lock);
+
+                       /* update buffer pointer and data count in message */
+                       tx_buffer += temp_count;
+                       tx_count += temp_count;
+                       if (temp_count == queue_length)
+                               /* poke port to get more data */
+                               ifx_spi_wakeup_serial(ifx_dev);
+                       else /* more data in port, use next SPI message */
+                               ifx_dev->spi_more = 1;
+               }
+       }
+       /* have data and info for header -- set up SPI header in buffer */
+       /* spi header needs payload size, not entire buffer size */
+       ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
+                                       tx_count-IFX_SPI_HEADER_OVERHEAD,
+                                       ifx_dev->spi_more);
+       /* swap actual data in the buffer */
+       swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+               &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
+       return tx_count;
+}
+
+/**
+ *     ifx_spi_write           -       line discipline write
+ *     @tty: our tty device
+ *     @buf: pointer to buffer to write (kernel space)
+ *     @count: size of buffer
+ *
+ *     Write the characters we have been given into the FIFO. If the device
+ *     is not active then activate it, when the SRDY line is asserted back
+ *     this will commence I/O
+ */
+static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
+                        int count)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       unsigned char *tmp_buf = (unsigned char *)buf;
+       int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
+                                  &ifx_dev->fifo_lock);
+       mrdy_assert(ifx_dev);
+       return tx_count;
+}
+
+/**
+ *     ifx_spi_chars_in_buffer -       line discipline helper
+ *     @tty: our tty device
+ *
+ *     Report how much data we can accept before we drop bytes. As we use
+ *     a simple FIFO this is nice and easy.
+ */
+static int ifx_spi_write_room(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_spi_chars_in_buffer -       line discipline helper
+ *     @tty: our tty device
+ *
+ *     Report how many characters we have buffered. In our case this is the
+ *     number of bytes sitting in our transmit FIFO.
+ */
+static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       return kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_port_hangup
+ *     @port: our tty port
+ *
+ *     tty port hang up. Called when tty_hangup processing is invoked either
+ *     by loss of carrier, or by software (eg vhangup). Serialized against
+ *     activate/shutdown by the tty layer.
+ */
+static void ifx_spi_hangup(struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev = tty->driver_data;
+       tty_port_hangup(&ifx_dev->tty_port);
+}
+
+/**
+ *     ifx_port_activate
+ *     @port: our tty port
+ *
+ *     tty port activate method - called for first open. Serialized
+ *     with hangup and shutdown by the tty layer.
+ */
+static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct ifx_spi_device *ifx_dev =
+               container_of(port, struct ifx_spi_device, tty_port);
+
+       /* clear any old data; can't do this in 'close' */
+       kfifo_reset(&ifx_dev->tx_fifo);
+
+       /* put port data into this tty */
+       tty->driver_data = ifx_dev;
+
+       /* allows flip string push from int context */
+       tty->low_latency = 1;
+
+       return 0;
+}
+
+/**
+ *     ifx_port_shutdown
+ *     @port: our tty port
+ *
+ *     tty port shutdown method - called for last port close. Serialized
+ *     with hangup and activate by the tty layer.
+ */
+static void ifx_port_shutdown(struct tty_port *port)
+{
+       struct ifx_spi_device *ifx_dev =
+               container_of(port, struct ifx_spi_device, tty_port);
+
+       mrdy_set_low(ifx_dev);
+       clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+       tasklet_kill(&ifx_dev->io_work_tasklet);
+}
+
+static const struct tty_port_operations ifx_tty_port_ops = {
+       .activate = ifx_port_activate,
+       .shutdown = ifx_port_shutdown,
+};
+
+static const struct tty_operations ifx_spi_serial_ops = {
+       .open = ifx_spi_open,
+       .close = ifx_spi_close,
+       .write = ifx_spi_write,
+       .hangup = ifx_spi_hangup,
+       .write_room = ifx_spi_write_room,
+       .chars_in_buffer = ifx_spi_chars_in_buffer,
+       .tiocmget = ifx_spi_tiocmget,
+       .tiocmset = ifx_spi_tiocmset,
+};
+
+/**
+ *     ifx_spi_insert_fip_string       -       queue received data
+ *     @ifx_ser: our SPI device
+ *     @chars: buffer we have received
+ *     @size: number of chars reeived
+ *
+ *     Queue bytes to the tty assuming the tty side is currently open. If
+ *     not the discard the data.
+ */
+static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
+                                   unsigned char *chars, size_t size)
+{
+       struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
+       if (!tty)
+               return;
+       tty_insert_flip_string(tty, chars, size);
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+}
+
+/**
+ *     ifx_spi_complete        -       SPI transfer completed
+ *     @ctx: our SPI device
+ *
+ *     An SPI transfer has completed. Process any received data and kick off
+ *     any further transmits we can commence.
+ */
+static void ifx_spi_complete(void *ctx)
+{
+       struct ifx_spi_device *ifx_dev = ctx;
+       struct tty_struct *tty;
+       struct tty_ldisc *ldisc = NULL;
+       int length;
+       int actual_length;
+       unsigned char more;
+       unsigned char cts;
+       int local_write_pending = 0;
+       int queue_length;
+       int srdy;
+       int decode_result;
+
+       mrdy_set_low(ifx_dev);
+
+       if (!ifx_dev->spi_msg.status) {
+               /* check header validity, get comm flags */
+               swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+                       &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
+               decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
+                               &length, &more, &cts);
+               if (decode_result == IFX_SPI_HEADER_0) {
+                       dev_dbg(&ifx_dev->spi_dev->dev,
+                               "ignore input: invalid header 0");
+                       ifx_dev->spi_slave_cts = 0;
+                       goto complete_exit;
+               } else if (decode_result == IFX_SPI_HEADER_F) {
+                       dev_dbg(&ifx_dev->spi_dev->dev,
+                               "ignore input: invalid header F");
+                       goto complete_exit;
+               }
+
+               ifx_dev->spi_slave_cts = cts;
+
+               actual_length = min((unsigned int)length,
+                                       ifx_dev->spi_msg.actual_length);
+               swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+                        actual_length,
+                        &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
+               ifx_spi_insert_flip_string(
+                       ifx_dev,
+                       ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
+                       (size_t)actual_length);
+       } else {
+               dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
+                      ifx_dev->spi_msg.status);
+       }
+
+complete_exit:
+       if (ifx_dev->write_pending) {
+               ifx_dev->write_pending = 0;
+               local_write_pending = 1;
+       }
+
+       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
+
+       queue_length = kfifo_len(&ifx_dev->tx_fifo);
+       srdy = gpio_get_value(ifx_dev->gpio.srdy);
+       if (!srdy)
+               ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
+
+       /* schedule output if there is more to do */
+       if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
+               tasklet_schedule(&ifx_dev->io_work_tasklet);
+       else {
+               if (more || ifx_dev->spi_more || queue_length > 0 ||
+                       local_write_pending) {
+                       if (ifx_dev->spi_slave_cts) {
+                               if (more)
+                                       mrdy_assert(ifx_dev);
+                       } else
+                               mrdy_assert(ifx_dev);
+               } else {
+                       /*
+                        * poke line discipline driver if any for more data
+                        * may or may not get more data to write
+                        * for now, say not busy
+                        */
+                       ifx_spi_power_state_clear(ifx_dev,
+                                                 IFX_SPI_POWER_DATA_PENDING);
+                       tty = tty_port_tty_get(&ifx_dev->tty_port);
+                       if (tty) {
+                               ldisc = tty_ldisc_ref(tty);
+                               if (ldisc) {
+                                       ldisc->ops->write_wakeup(tty);
+                                       tty_ldisc_deref(ldisc);
+                               }
+                               tty_kref_put(tty);
+                       }
+               }
+       }
+}
+
+/**
+ *     ifx_spio_io             -       I/O tasklet
+ *     @data: our SPI device
+ *
+ *     Queue data for transmission if possible and then kick off the
+ *     transfer.
+ */
+static void ifx_spi_io(unsigned long data)
+{
+       int retval;
+       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
+
+       if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+               if (ifx_dev->gpio.unack_srdy_int_nb > 0)
+                       ifx_dev->gpio.unack_srdy_int_nb--;
+
+               ifx_spi_prepare_tx_buffer(ifx_dev);
+
+               spi_message_init(&ifx_dev->spi_msg);
+               INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
+
+               ifx_dev->spi_msg.context = ifx_dev;
+               ifx_dev->spi_msg.complete = ifx_spi_complete;
+
+               /* set up our spi transfer */
+               /* note len is BYTES, not transfers */
+               ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
+               ifx_dev->spi_xfer.cs_change = 0;
+               ifx_dev->spi_xfer.speed_hz = 12500000;
+               /* ifx_dev->spi_xfer.speed_hz = 390625; */
+               ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
+
+               ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
+               ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
+
+               /*
+                * setup dma pointers
+                */
+               if (ifx_dev->is_6160) {
+                       ifx_dev->spi_msg.is_dma_mapped = 1;
+                       ifx_dev->tx_dma = ifx_dev->tx_bus;
+                       ifx_dev->rx_dma = ifx_dev->rx_bus;
+                       ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
+                       ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
+               } else {
+                       ifx_dev->spi_msg.is_dma_mapped = 0;
+                       ifx_dev->tx_dma = (dma_addr_t)0;
+                       ifx_dev->rx_dma = (dma_addr_t)0;
+                       ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
+                       ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
+               }
+
+               spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
+
+               /* Assert MRDY. This may have already been done by the write
+                * routine.
+                */
+               mrdy_assert(ifx_dev);
+
+               retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
+               if (retval) {
+                       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
+                                 &ifx_dev->flags);
+                       tasklet_schedule(&ifx_dev->io_work_tasklet);
+                       return;
+               }
+       } else
+               ifx_dev->write_pending = 1;
+}
+
+/**
+ *     ifx_spi_free_port       -       free up the tty side
+ *     @ifx_dev: IFX device going away
+ *
+ *     Unregister and free up a port when the device goes away
+ */
+static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
+{
+       if (ifx_dev->tty_dev)
+               tty_unregister_device(tty_drv, ifx_dev->minor);
+       kfifo_free(&ifx_dev->tx_fifo);
+}
+
+/**
+ *     ifx_spi_create_port     -       create a new port
+ *     @ifx_dev: our spi device
+ *
+ *     Allocate and initialise the tty port that goes with this interface
+ *     and add it to the tty layer so that it can be opened.
+ */
+static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
+{
+       int ret = 0;
+       struct tty_port *pport = &ifx_dev->tty_port;
+
+       spin_lock_init(&ifx_dev->fifo_lock);
+       lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
+               &ifx_spi_key, 0);
+
+       if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       pport->ops = &ifx_tty_port_ops;
+       tty_port_init(pport);
+       ifx_dev->minor = IFX_SPI_TTY_ID;
+       ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
+                                              &ifx_dev->spi_dev->dev);
+       if (IS_ERR(ifx_dev->tty_dev)) {
+               dev_dbg(&ifx_dev->spi_dev->dev,
+                       "%s: registering tty device failed", __func__);
+               ret = PTR_ERR(ifx_dev->tty_dev);
+               goto error_ret;
+       }
+       return 0;
+
+error_ret:
+       ifx_spi_free_port(ifx_dev);
+       return ret;
+}
+
+/**
+ *     ifx_spi_handle_srdy             -       handle SRDY
+ *     @ifx_dev: device asserting SRDY
+ *
+ *     Check our device state and see what we need to kick off when SRDY
+ *     is asserted. This usually means killing the timer and firing off the
+ *     I/O processing.
+ */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
+{
+       if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
+               del_timer_sync(&ifx_dev->spi_timer);
+               clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+       }
+
+       ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
+
+       if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
+               tasklet_schedule(&ifx_dev->io_work_tasklet);
+       else
+               set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+}
+
+/**
+ *     ifx_spi_srdy_interrupt  -       SRDY asserted
+ *     @irq: our IRQ number
+ *     @dev: our ifx device
+ *
+ *     The modem asserted SRDY. Handle the srdy event
+ */
+static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
+{
+       struct ifx_spi_device *ifx_dev = dev;
+       ifx_dev->gpio.unack_srdy_int_nb++;
+       ifx_spi_handle_srdy(ifx_dev);
+       return IRQ_HANDLED;
+}
+
+/**
+ *     ifx_spi_reset_interrupt -       Modem has changed reset state
+ *     @irq: interrupt number
+ *     @dev: our device pointer
+ *
+ *     The modem has either entered or left reset state. Check the GPIO
+ *     line to see which.
+ *
+ *     FIXME: review locking on MR_INPROGRESS versus
+ *     parallel unsolicited reset/solicited reset
+ */
+static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
+{
+       struct ifx_spi_device *ifx_dev = dev;
+       int val = gpio_get_value(ifx_dev->gpio.reset_out);
+       int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
+
+       if (val == 0) {
+               /* entered reset */
+               set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+               if (!solreset) {
+                       /* unsolicited reset  */
+                       ifx_spi_ttyhangup(ifx_dev);
+               }
+       } else {
+               /* exited reset */
+               clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+               if (solreset) {
+                       set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
+                       wake_up(&ifx_dev->mdm_reset_wait);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/**
+ *     ifx_spi_free_device - free device
+ *     @ifx_dev: device to free
+ *
+ *     Free the IFX device
+ */
+static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
+{
+       ifx_spi_free_port(ifx_dev);
+       dma_free_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               ifx_dev->tx_buffer,
+                               ifx_dev->tx_bus);
+       dma_free_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               ifx_dev->rx_buffer,
+                               ifx_dev->rx_bus);
+}
+
+/**
+ *     ifx_spi_reset   -       reset modem
+ *     @ifx_dev: modem to reset
+ *
+ *     Perform a reset on the modem
+ */
+static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
+{
+       int ret;
+       /*
+        * set up modem power, reset
+        *
+        * delays are required on some platforms for the modem
+        * to reset properly
+        */
+       set_bit(MR_START, &ifx_dev->mdm_reset_state);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       gpio_set_value(ifx_dev->gpio.reset, 0);
+       msleep(25);
+       gpio_set_value(ifx_dev->gpio.reset, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 1);
+       msleep(1);
+       gpio_set_value(ifx_dev->gpio.po, 0);
+       ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
+                                test_bit(MR_COMPLETE,
+                                         &ifx_dev->mdm_reset_state),
+                                IFX_RESET_TIMEOUT);
+       if (!ret)
+               dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
+                        ifx_dev->mdm_reset_state);
+
+       ifx_dev->mdm_reset_state = 0;
+       return ret;
+}
+
+/**
+ *     ifx_spi_spi_probe       -       probe callback
+ *     @spi: our possible matching SPI device
+ *
+ *     Probe for a 6x60 modem on SPI bus. Perform any needed device and
+ *     GPIO setup.
+ *
+ *     FIXME:
+ *     -       Support for multiple devices
+ *     -       Split out MID specific GPIO handling eventually
+ */
+
+static int ifx_spi_spi_probe(struct spi_device *spi)
+{
+       int ret;
+       int srdy;
+       struct ifx_modem_platform_data *pl_data = NULL;
+       struct ifx_spi_device *ifx_dev;
+
+       if (saved_ifx_dev) {
+               dev_dbg(&spi->dev, "ignoring subsequent detection");
+               return -ENODEV;
+       }
+
+       /* initialize structure to hold our device variables */
+       ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
+       if (!ifx_dev) {
+               dev_err(&spi->dev, "spi device allocation failed");
+               return -ENOMEM;
+       }
+       saved_ifx_dev = ifx_dev;
+       ifx_dev->spi_dev = spi;
+       clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+       spin_lock_init(&ifx_dev->write_lock);
+       spin_lock_init(&ifx_dev->power_lock);
+       ifx_dev->power_status = 0;
+       init_timer(&ifx_dev->spi_timer);
+       ifx_dev->spi_timer.function = ifx_spi_timeout;
+       ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
+       ifx_dev->is_6160 = pl_data->is_6160;
+
+       /* ensure SPI protocol flags are initialized to enable transfer */
+       ifx_dev->spi_more = 0;
+       ifx_dev->spi_slave_cts = 0;
+
+       /*initialize transfer and dma buffers */
+       ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               &ifx_dev->tx_bus,
+                               GFP_KERNEL);
+       if (!ifx_dev->tx_buffer) {
+               dev_err(&spi->dev, "DMA-TX buffer allocation failed");
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+                               IFX_SPI_TRANSFER_SIZE,
+                               &ifx_dev->rx_bus,
+                               GFP_KERNEL);
+       if (!ifx_dev->rx_buffer) {
+               dev_err(&spi->dev, "DMA-RX buffer allocation failed");
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* initialize waitq for modem reset */
+       init_waitqueue_head(&ifx_dev->mdm_reset_wait);
+
+       spi_set_drvdata(spi, ifx_dev);
+       tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
+                                               (unsigned long)ifx_dev);
+
+       set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
+
+       /* create our tty port */
+       ret = ifx_spi_create_port(ifx_dev);
+       if (ret != 0) {
+               dev_err(&spi->dev, "create default tty port failed");
+               goto error_ret;
+       }
+
+       pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+       if (pl_data) {
+               ifx_dev->gpio.reset = pl_data->rst_pmu;
+               ifx_dev->gpio.po = pl_data->pwr_on;
+               ifx_dev->gpio.mrdy = pl_data->mrdy;
+               ifx_dev->gpio.srdy = pl_data->srdy;
+               ifx_dev->gpio.reset_out = pl_data->rst_out;
+       } else {
+               dev_err(&spi->dev, "missing platform data!");
+               ret = -ENODEV;
+               goto error_ret;
+       }
+
+       dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
+                ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
+                ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
+
+       /* Configure gpios */
+       ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
+                       ifx_dev->gpio.reset);
+               goto error_ret;
+       }
+       ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
+       ret += gpio_export(ifx_dev->gpio.reset, 1);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
+                       ifx_dev->gpio.reset);
+               ret = -EBUSY;
+               goto error_ret2;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
+       ret += gpio_direction_output(ifx_dev->gpio.po, 0);
+       ret += gpio_export(ifx_dev->gpio.po, 1);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
+                       ifx_dev->gpio.po);
+               ret = -EBUSY;
+               goto error_ret3;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
+                       ifx_dev->gpio.mrdy);
+               goto error_ret3;
+       }
+       ret += gpio_export(ifx_dev->gpio.mrdy, 1);
+       ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
+                       ifx_dev->gpio.mrdy);
+               ret = -EBUSY;
+               goto error_ret4;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
+                       ifx_dev->gpio.srdy);
+               ret = -EBUSY;
+               goto error_ret4;
+       }
+       ret += gpio_export(ifx_dev->gpio.srdy, 1);
+       ret += gpio_direction_input(ifx_dev->gpio.srdy);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
+                       ifx_dev->gpio.srdy);
+               ret = -EBUSY;
+               goto error_ret5;
+       }
+
+       ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
+                       ifx_dev->gpio.reset_out);
+               goto error_ret5;
+       }
+       ret += gpio_export(ifx_dev->gpio.reset_out, 1);
+       ret += gpio_direction_input(ifx_dev->gpio.reset_out);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
+                       ifx_dev->gpio.reset_out);
+               ret = -EBUSY;
+               goto error_ret6;
+       }
+
+       ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
+                         ifx_spi_reset_interrupt,
+                         IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
+               (void *)ifx_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to get irq %x\n",
+                       gpio_to_irq(ifx_dev->gpio.reset_out));
+               goto error_ret6;
+       }
+
+       ret = ifx_spi_reset(ifx_dev);
+
+       ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
+                         ifx_spi_srdy_interrupt,
+                         IRQF_TRIGGER_RISING, DRVNAME,
+                         (void *)ifx_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Unable to get irq %x",
+                       gpio_to_irq(ifx_dev->gpio.srdy));
+               goto error_ret7;
+       }
+
+       /* set pm runtime power state and register with power system */
+       pm_runtime_set_active(&spi->dev);
+       pm_runtime_enable(&spi->dev);
+
+       /* handle case that modem is already signaling SRDY */
+       /* no outgoing tty open at this point, this just satisfies the
+        * modem's read and should reset communication properly
+        */
+       srdy = gpio_get_value(ifx_dev->gpio.srdy);
+
+       if (srdy) {
+               mrdy_assert(ifx_dev);
+               ifx_spi_handle_srdy(ifx_dev);
+       } else
+               mrdy_set_low(ifx_dev);
+       return 0;
+
+error_ret7:
+       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+error_ret6:
+       gpio_free(ifx_dev->gpio.srdy);
+error_ret5:
+       gpio_free(ifx_dev->gpio.mrdy);
+error_ret4:
+       gpio_free(ifx_dev->gpio.reset);
+error_ret3:
+       gpio_free(ifx_dev->gpio.po);
+error_ret2:
+       gpio_free(ifx_dev->gpio.reset_out);
+error_ret:
+       ifx_spi_free_device(ifx_dev);
+       saved_ifx_dev = NULL;
+       return ret;
+}
+
+/**
+ *     ifx_spi_spi_remove      -       SPI device was removed
+ *     @spi: SPI device
+ *
+ *     FIXME: We should be shutting the device down here not in
+ *     the module unload path.
+ */
+
+static int ifx_spi_spi_remove(struct spi_device *spi)
+{
+       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+       /* stop activity */
+       tasklet_kill(&ifx_dev->io_work_tasklet);
+       /* free irq */
+       free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+       free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+
+       gpio_free(ifx_dev->gpio.srdy);
+       gpio_free(ifx_dev->gpio.mrdy);
+       gpio_free(ifx_dev->gpio.reset);
+       gpio_free(ifx_dev->gpio.po);
+       gpio_free(ifx_dev->gpio.reset_out);
+
+       /* free allocations */
+       ifx_spi_free_device(ifx_dev);
+
+       saved_ifx_dev = NULL;
+       return 0;
+}
+
+/**
+ *     ifx_spi_spi_shutdown    -       called on SPI shutdown
+ *     @spi: SPI device
+ *
+ *     No action needs to be taken here
+ */
+
+static void ifx_spi_spi_shutdown(struct spi_device *spi)
+{
+}
+
+/*
+ * various suspends and resumes have nothing to do
+ * no hardware to save state for
+ */
+
+/**
+ *     ifx_spi_spi_suspend     -       suspend SPI on system suspend
+ *     @dev: device being suspended
+ *
+ *     Suspend the SPI side. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_spi_resume      -       resume SPI side on system resume
+ *     @dev: device being suspended
+ *
+ *     Suspend the SPI side. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_spi_resume(struct spi_device *spi)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_suspend      -       suspend modem on system suspend
+ *     @dev: device being suspended
+ *
+ *     Suspend the modem. No action needed on Intel MID platforms, may
+ *     need extending for other systems.
+ */
+static int ifx_spi_pm_suspend(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_resume       -       resume modem on system resume
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to resume. No action needed.
+ *
+ *     FIXME: do we need to reset anything here ?
+ */
+static int ifx_spi_pm_resume(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_resume       -       suspend modem
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to resume. No action needed.
+ */
+static int ifx_spi_pm_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_suspend      -       suspend modem
+ *     @dev: device being suspended
+ *
+ *     Allow the modem to suspend and thus suspend to continue up the
+ *     device tree.
+ */
+static int ifx_spi_pm_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+/**
+ *     ifx_spi_pm_runtime_idle         -       check if modem idle
+ *     @dev: our device
+ *
+ *     Check conditions and queue runtime suspend if idle.
+ */
+static int ifx_spi_pm_runtime_idle(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+       if (!ifx_dev->power_status)
+               pm_runtime_suspend(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops ifx_spi_pm = {
+       .resume = ifx_spi_pm_resume,
+       .suspend = ifx_spi_pm_suspend,
+       .runtime_resume = ifx_spi_pm_runtime_resume,
+       .runtime_suspend = ifx_spi_pm_runtime_suspend,
+       .runtime_idle = ifx_spi_pm_runtime_idle
+};
+
+static const struct spi_device_id ifx_id_table[] = {
+       {"ifx6160", 0},
+       {"ifx6260", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ifx_id_table);
+
+/* spi operations */
+static const struct spi_driver ifx_spi_driver_6160 = {
+       .driver = {
+               .name = "ifx6160",
+               .bus = &spi_bus_type,
+               .pm = &ifx_spi_pm,
+               .owner = THIS_MODULE},
+       .probe = ifx_spi_spi_probe,
+       .shutdown = ifx_spi_spi_shutdown,
+       .remove = __devexit_p(ifx_spi_spi_remove),
+       .suspend = ifx_spi_spi_suspend,
+       .resume = ifx_spi_spi_resume,
+       .id_table = ifx_id_table
+};
+
+/**
+ *     ifx_spi_exit    -       module exit
+ *
+ *     Unload the module.
+ */
+
+static void __exit ifx_spi_exit(void)
+{
+       /* unregister */
+       tty_unregister_driver(tty_drv);
+       spi_unregister_driver((void *)&ifx_spi_driver_6160);
+}
+
+/**
+ *     ifx_spi_init            -       module entry point
+ *
+ *     Initialise the SPI and tty interfaces for the IFX SPI driver
+ *     We need to initialize upper-edge spi driver after the tty
+ *     driver because otherwise the spi probe will race
+ */
+
+static int __init ifx_spi_init(void)
+{
+       int result;
+
+       tty_drv = alloc_tty_driver(1);
+       if (!tty_drv) {
+               pr_err("%s: alloc_tty_driver failed", DRVNAME);
+               return -ENOMEM;
+       }
+
+       tty_drv->magic = TTY_DRIVER_MAGIC;
+       tty_drv->owner = THIS_MODULE;
+       tty_drv->driver_name = DRVNAME;
+       tty_drv->name = TTYNAME;
+       tty_drv->minor_start = IFX_SPI_TTY_ID;
+       tty_drv->num = 1;
+       tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+       tty_drv->subtype = SERIAL_TYPE_NORMAL;
+       tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       tty_drv->init_termios = tty_std_termios;
+
+       tty_set_operations(tty_drv, &ifx_spi_serial_ops);
+
+       result = tty_register_driver(tty_drv);
+       if (result) {
+               pr_err("%s: tty_register_driver failed(%d)",
+                       DRVNAME, result);
+               put_tty_driver(tty_drv);
+               return result;
+       }
+
+       result = spi_register_driver((void *)&ifx_spi_driver_6160);
+       if (result) {
+               pr_err("%s: spi_register_driver failed(%d)",
+                       DRVNAME, result);
+               tty_unregister_driver(tty_drv);
+       }
+       return result;
+}
+
+module_init(ifx_spi_init);
+module_exit(ifx_spi_exit);
+
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("IFX6x60 spi driver");
+MODULE_LICENSE("GPL");
+MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h
new file mode 100644 (file)
index 0000000..deb7b8d
--- /dev/null
@@ -0,0 +1,129 @@
+/****************************************************************************
+ *
+ * Driver for the IFX spi modem.
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Jim Stanley <jim.stanley@intel.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ *
+ *
+ *****************************************************************************/
+#ifndef _IFX6X60_H
+#define _IFX6X60_H
+
+#define DRVNAME                                "ifx6x60"
+#define TTYNAME                                "ttyIFX"
+
+/* #define IFX_THROTTLE_CODE */
+
+#define IFX_SPI_MAX_MINORS             1
+#define IFX_SPI_TRANSFER_SIZE          2048
+#define IFX_SPI_FIFO_SIZE              4096
+
+#define IFX_SPI_HEADER_OVERHEAD                4
+#define IFX_RESET_TIMEOUT              msecs_to_jiffies(50)
+
+/* device flags bitfield definitions */
+#define IFX_SPI_STATE_PRESENT          0
+#define IFX_SPI_STATE_IO_IN_PROGRESS   1
+#define IFX_SPI_STATE_IO_READY         2
+#define IFX_SPI_STATE_TIMER_PENDING    3
+
+/* flow control bitfields */
+#define IFX_SPI_DCD                    0
+#define IFX_SPI_CTS                    1
+#define IFX_SPI_DSR                    2
+#define IFX_SPI_RI                     3
+#define IFX_SPI_DTR                    4
+#define IFX_SPI_RTS                    5
+#define IFX_SPI_TX_FC                  6
+#define IFX_SPI_RX_FC                  7
+#define IFX_SPI_UPDATE                 8
+
+#define IFX_SPI_PAYLOAD_SIZE           (IFX_SPI_TRANSFER_SIZE - \
+                                               IFX_SPI_HEADER_OVERHEAD)
+
+#define IFX_SPI_IRQ_TYPE               DETECT_EDGE_RISING
+#define IFX_SPI_GPIO_TARGET            0
+#define IFX_SPI_GPIO0                  0x105
+
+#define IFX_SPI_STATUS_TIMEOUT         (2000*HZ)
+
+/* values for bits in power status byte */
+#define IFX_SPI_POWER_DATA_PENDING     1
+#define IFX_SPI_POWER_SRDY             2
+
+struct ifx_spi_device {
+       /* Our SPI device */
+       struct spi_device *spi_dev;
+
+       /* Port specific data */
+       struct kfifo tx_fifo;
+       spinlock_t fifo_lock;
+       unsigned long signal_state;
+
+       /* TTY Layer logic */
+       struct tty_port tty_port;
+       struct device *tty_dev;
+       int minor;
+
+       /* Low level I/O work */
+       struct tasklet_struct io_work_tasklet;
+       unsigned long flags;
+       dma_addr_t rx_dma;
+       dma_addr_t tx_dma;
+
+       int is_6160;                            /* Modem type */
+
+       spinlock_t write_lock;
+       int write_pending;
+       spinlock_t power_lock;
+       unsigned char power_status;
+
+       unsigned char *rx_buffer;
+       unsigned char *tx_buffer;
+       dma_addr_t rx_bus;
+       dma_addr_t tx_bus;
+       unsigned char spi_more;
+       unsigned char spi_slave_cts;
+
+       struct timer_list spi_timer;
+
+       struct spi_message spi_msg;
+       struct spi_transfer spi_xfer;
+
+       struct {
+               /* gpio lines */
+               unsigned short srdy;            /* slave-ready gpio */
+               unsigned short mrdy;            /* master-ready gpio */
+               unsigned short reset;           /* modem-reset gpio */
+               unsigned short po;              /* modem-on gpio */
+               unsigned short reset_out;       /* modem-in-reset gpio */
+               /* state/stats */
+               int unack_srdy_int_nb;
+       } gpio;
+
+       /* modem reset */
+       unsigned long mdm_reset_state;
+#define MR_START       0
+#define MR_INPROGRESS  1
+#define MR_COMPLETE    2
+       wait_queue_head_t mdm_reset_wait;
+};
+
+#endif /* _IFX6X60_H */
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
new file mode 100644 (file)
index 0000000..dfcf4b1
--- /dev/null
@@ -0,0 +1,1380 @@
+/*
+ *  linux/drivers/serial/imx.c
+ *
+ *  Driver for Motorola IMX serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Author: Sascha Hauer <sascha@saschahauer.de>
+ *  Copyright (C) 2004 Pengutronix
+ *
+ *  Copyright (C) 2009 emlix GmbH
+ *  Author: Fabian Godehardt (added IrDA support for iMX)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * [29-Mar-2005] Mike Lee
+ * Added hardware handshake
+ */
+
+#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/rational.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+
+/* Register definitions */
+#define URXD0 0x0  /* Receiver Register */
+#define URTX0 0x40 /* Transmitter Register */
+#define UCR1  0x80 /* Control Register 1 */
+#define UCR2  0x84 /* Control Register 2 */
+#define UCR3  0x88 /* Control Register 3 */
+#define UCR4  0x8c /* Control Register 4 */
+#define UFCR  0x90 /* FIFO Control Register */
+#define USR1  0x94 /* Status Register 1 */
+#define USR2  0x98 /* Status Register 2 */
+#define UESC  0x9c /* Escape Character Register */
+#define UTIM  0xa0 /* Escape Timer Register */
+#define UBIR  0xa4 /* BRM Incremental Register */
+#define UBMR  0xa8 /* BRM Modulator Register */
+#define UBRC  0xac /* Baud Rate Count Register */
+#define MX2_ONEMS 0xb0 /* One Millisecond register */
+#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+
+/* UART Control Register Bit Fields.*/
+#define  URXD_CHARRDY    (1<<15)
+#define  URXD_ERR        (1<<14)
+#define  URXD_OVRRUN     (1<<13)
+#define  URXD_FRMERR     (1<<12)
+#define  URXD_BRK        (1<<11)
+#define  URXD_PRERR      (1<<10)
+#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
+#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
+#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
+#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
+#define  UCR1_RRDYEN     (1<<9)         /* Recv ready interrupt enable */
+#define  UCR1_RDMAEN     (1<<8)         /* Recv ready DMA enable */
+#define  UCR1_IREN       (1<<7)         /* Infrared interface enable */
+#define  UCR1_TXMPTYEN   (1<<6)         /* Transimitter empty interrupt enable */
+#define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
+#define  UCR1_SNDBRK     (1<<4)         /* Send break */
+#define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
+#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
+#define  UCR1_DOZE       (1<<1)         /* Doze */
+#define  UCR1_UARTEN     (1<<0)         /* UART enabled */
+#define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
+#define  UCR2_IRTS      (1<<14) /* Ignore RTS pin */
+#define  UCR2_CTSC      (1<<13) /* CTS pin control */
+#define  UCR2_CTS        (1<<12) /* Clear to send */
+#define  UCR2_ESCEN      (1<<11) /* Escape enable */
+#define  UCR2_PREN       (1<<8)  /* Parity enable */
+#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
+#define  UCR2_STPB       (1<<6)         /* Stop */
+#define  UCR2_WS         (1<<5)         /* Word size */
+#define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
+#define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
+#define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
+#define  UCR2_SRST      (1<<0)  /* SW reset */
+#define  UCR3_DTREN     (1<<13) /* DTR interrupt enable */
+#define  UCR3_PARERREN   (1<<12) /* Parity enable */
+#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
+#define  UCR3_DSR        (1<<10) /* Data set ready */
+#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
+#define  UCR3_RI         (1<<8)  /* Ring indicator */
+#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
+#define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
+#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+#define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
+#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
+#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
+#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
+#define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
+#define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
+#define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
+#define  UCR4_CTSTL_MASK 0x3F    /* CTS trigger is 6 bits wide */
+#define  UCR4_INVR      (1<<9)  /* Inverted infrared reception */
+#define  UCR4_ENIRI     (1<<8)  /* Serial infrared interrupt enable */
+#define  UCR4_WKEN      (1<<7)  /* Wake interrupt enable */
+#define  UCR4_REF16     (1<<6)  /* Ref freq 16 MHz */
+#define  UCR4_IRSC      (1<<5)  /* IR special case */
+#define  UCR4_TCEN      (1<<3)  /* Transmit complete interrupt enable */
+#define  UCR4_BKEN      (1<<2)  /* Break condition interrupt enable */
+#define  UCR4_OREN      (1<<1)  /* Receiver overrun interrupt enable */
+#define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
+#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
+#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+#define  UFCR_RFDIV_REG(x)     (((x) < 7 ? 6 - (x) : 6) << 7)
+#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
+#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
+#define  USR1_RTSS      (1<<14) /* RTS pin status */
+#define  USR1_TRDY      (1<<13) /* Transmitter ready interrupt/dma flag */
+#define  USR1_RTSD      (1<<12) /* RTS delta */
+#define  USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
+#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
+#define  USR1_RRDY       (1<<9)         /* Receiver ready interrupt/dma flag */
+#define  USR1_TIMEOUT    (1<<7)         /* Receive timeout interrupt status */
+#define  USR1_RXDS      (1<<6)  /* Receiver idle interrupt flag */
+#define  USR1_AIRINT    (1<<5)  /* Async IR wake interrupt flag */
+#define  USR1_AWAKE     (1<<4)  /* Aysnc wake interrupt flag */
+#define  USR2_ADET      (1<<15) /* Auto baud rate detect complete */
+#define  USR2_TXFE      (1<<14) /* Transmit buffer FIFO empty */
+#define  USR2_DTRF      (1<<13) /* DTR edge interrupt flag */
+#define  USR2_IDLE      (1<<12) /* Idle condition */
+#define  USR2_IRINT     (1<<8)  /* Serial infrared interrupt flag */
+#define  USR2_WAKE      (1<<7)  /* Wake */
+#define  USR2_RTSF      (1<<4)  /* RTS edge interrupt flag */
+#define  USR2_TXDC      (1<<3)  /* Transmitter complete */
+#define  USR2_BRCD      (1<<2)  /* Break condition */
+#define  USR2_ORE        (1<<1)         /* Overrun error */
+#define  USR2_RDR        (1<<0)         /* Recv data ready */
+#define  UTS_FRCPERR    (1<<13) /* Force parity error */
+#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
+#define  UTS_TXEMPTY    (1<<6)  /* TxFIFO empty */
+#define  UTS_RXEMPTY    (1<<5)  /* RxFIFO empty */
+#define  UTS_TXFULL     (1<<4)  /* TxFIFO full */
+#define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
+#define  UTS_SOFTRST    (1<<0)  /* Software reset */
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_IMX_MAJOR        207
+#define MINOR_START            16
+#define DEV_NAME               "ttymxc"
+#define MAX_INTERNAL_IRQ       MXC_INTERNAL_IRQS
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+#define DRIVER_NAME "IMX-uart"
+
+#define UART_NR 8
+
+struct imx_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+       int                     txirq,rxirq,rtsirq;
+       unsigned int            have_rtscts:1;
+       unsigned int            use_irda:1;
+       unsigned int            irda_inv_rx:1;
+       unsigned int            irda_inv_tx:1;
+       unsigned short          trcv_delay; /* transceiver delay */
+       struct clk              *clk;
+};
+
+#ifdef CONFIG_IRDA
+#define USE_IRDA(sport)        ((sport)->use_irda)
+#else
+#define USE_IRDA(sport)        (0)
+#endif
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void imx_timeout(unsigned long data)
+{
+       struct imx_port *sport = (struct imx_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               imx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_tx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       if (USE_IRDA(sport)) {
+               /* half duplex - wait for end of transmission */
+               int n = 256;
+               while ((--n > 0) &&
+                     !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
+                       udelay(5);
+                       barrier();
+               }
+               /*
+                * irda transceiver - wait a bit more to avoid
+                * cutoff, hardware dependent
+                */
+               udelay(sport->trcv_delay);
+
+               /*
+                * half duplex - reactivate receive mode,
+                * flush receive pipe echo crap
+                */
+               if (readl(sport->port.membase + USR2) & USR2_TXDC) {
+                       temp = readl(sport->port.membase + UCR1);
+                       temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp &= ~(UCR4_TCEN);
+                       writel(temp, sport->port.membase + UCR4);
+
+                       while (readl(sport->port.membase + URXD0) &
+                              URXD_CHARRDY)
+                               barrier();
+
+                       temp = readl(sport->port.membase + UCR1);
+                       temp |= UCR1_RRDYEN;
+                       writel(temp, sport->port.membase + UCR1);
+
+                       temp = readl(sport->port.membase + UCR4);
+                       temp |= UCR4_DREN;
+                       writel(temp, sport->port.membase + UCR4);
+               }
+               return;
+       }
+
+       temp = readl(sport->port.membase + UCR1);
+       writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_rx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2);
+       writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void imx_enable_ms(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static inline void imx_transmit_buffer(struct imx_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       while (!uart_circ_empty(xmit) &&
+                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+               writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               imx_stop_tx(&sport->port);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_start_tx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       if (USE_IRDA(sport)) {
+               /* half duplex in IrDA mode; have to disable receive mode */
+               temp = readl(sport->port.membase + UCR4);
+               temp &= ~(UCR4_DREN);
+               writel(temp, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~(UCR1_RRDYEN);
+               writel(temp, sport->port.membase + UCR1);
+       }
+
+       temp = readl(sport->port.membase + UCR1);
+       writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR1);
+               temp |= UCR1_TRDYEN;
+               writel(temp, sport->port.membase + UCR1);
+
+               temp = readl(sport->port.membase + UCR4);
+               temp |= UCR4_TCEN;
+               writel(temp, sport->port.membase + UCR4);
+       }
+
+       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+               imx_transmit_buffer(sport);
+}
+
+static irqreturn_t imx_rtsint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       writel(USR1_RTSD, sport->port.membase + USR1);
+       uart_handle_cts_change(&sport->port, !!val);
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_txint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock,flags);
+       if (sport->port.x_char)
+       {
+               /* Send next char */
+               writel(sport->port.x_char, sport->port.membase + URTX0);
+               goto out;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               imx_stop_tx(&sport->port);
+               goto out;
+       }
+
+       imx_transmit_buffer(sport);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_rxint(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int rx,flg,ignored = 0;
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned long flags, temp;
+
+       spin_lock_irqsave(&sport->port.lock,flags);
+
+       while (readl(sport->port.membase + USR2) & USR2_RDR) {
+               flg = TTY_NORMAL;
+               sport->port.icount.rx++;
+
+               rx = readl(sport->port.membase + URXD0);
+
+               temp = readl(sport->port.membase + USR2);
+               if (temp & USR2_BRCD) {
+                       writel(USR2_BRCD, sport->port.membase + USR2);
+                       if (uart_handle_break(&sport->port))
+                               continue;
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+                       continue;
+
+               if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
+                       if (rx & URXD_PRERR)
+                               sport->port.icount.parity++;
+                       else if (rx & URXD_FRMERR)
+                               sport->port.icount.frame++;
+                       if (rx & URXD_OVRRUN)
+                               sport->port.icount.overrun++;
+
+                       if (rx & sport->port.ignore_status_mask) {
+                               if (++ignored > 100)
+                                       goto out;
+                               continue;
+                       }
+
+                       rx &= sport->port.read_status_mask;
+
+                       if (rx & URXD_PRERR)
+                               flg = TTY_PARITY;
+                       else if (rx & URXD_FRMERR)
+                               flg = TTY_FRAME;
+                       if (rx & URXD_OVRRUN)
+                               flg = TTY_OVERRUN;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               tty_insert_flip_char(tty, rx, flg);
+       }
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_int(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int sts;
+
+       sts = readl(sport->port.membase + USR1);
+
+       if (sts & USR1_RRDY)
+               imx_rxint(irq, dev_id);
+
+       if (sts & USR1_TRDY &&
+                       readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+               imx_txint(irq, dev_id);
+
+       if (sts & USR1_RTSD)
+               imx_rtsint(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int imx_tx_empty(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
+}
+
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+
+       if (readl(sport->port.membase + USR1) & USR1_RTSS)
+               tmp |= TIOCM_CTS;
+
+       if (readl(sport->port.membase + UCR2) & UCR2_CTS)
+               tmp |= TIOCM_RTS;
+
+       return tmp;
+}
+
+static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
+
+       if (mctrl & TIOCM_RTS)
+               temp |= UCR2_CTS;
+
+       writel(temp, sport->port.membase + UCR2);
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void imx_break_ctl(struct uart_port *port, int break_state)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags, temp;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+
+       if ( break_state != 0 )
+               temp |= UCR1_SNDBRK;
+
+       writel(temp, sport->port.membase + UCR1);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+#define TXTL 2 /* reset default */
+#define RXTL 1 /* reset default */
+
+static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+{
+       unsigned int val;
+       unsigned int ufcr_rfdiv;
+
+       /* set receiver / transmitter trigger level.
+        * RFDIV is set such way to satisfy requested uartclk value
+        */
+       val = TXTL << 10 | RXTL;
+       ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
+                       / sport->port.uartclk;
+
+       if(!ufcr_rfdiv)
+               ufcr_rfdiv = 1;
+
+       val |= UFCR_RFDIV_REG(ufcr_rfdiv);
+
+       writel(val, sport->port.membase + UFCR);
+
+       return 0;
+}
+
+/* half the RX buffer size */
+#define CTSTL 16
+
+static int imx_startup(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int retval;
+       unsigned long flags, temp;
+
+       imx_setup_ufcr(sport, 0);
+
+       /* disable the DREN bit (Data Ready interrupt enable) before
+        * requesting IRQs
+        */
+       temp = readl(sport->port.membase + UCR4);
+
+       if (USE_IRDA(sport))
+               temp |= UCR4_IRSC;
+
+       /* set the trigger level for CTS */
+       temp &= ~(UCR4_CTSTL_MASK<<  UCR4_CTSTL_SHF);
+       temp |= CTSTL<<  UCR4_CTSTL_SHF;
+
+       writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+
+       if (USE_IRDA(sport)) {
+               /* reset fifo's and state machines */
+               int i = 100;
+               temp = readl(sport->port.membase + UCR2);
+               temp &= ~UCR2_SRST;
+               writel(temp, sport->port.membase + UCR2);
+               while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
+                   (--i > 0)) {
+                       udelay(1);
+               }
+       }
+
+       /*
+        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
+        * chips only have one interrupt.
+        */
+       if (sport->txirq > 0) {
+               retval = request_irq(sport->rxirq, imx_rxint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out1;
+
+               retval = request_irq(sport->txirq, imx_txint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out2;
+
+               /* do not use RTS IRQ on IrDA */
+               if (!USE_IRDA(sport)) {
+                       retval = request_irq(sport->rtsirq, imx_rtsint,
+                                    (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
+                                      IRQF_TRIGGER_FALLING |
+                                      IRQF_TRIGGER_RISING,
+                                       DRIVER_NAME, sport);
+                       if (retval)
+                               goto error_out3;
+               }
+       } else {
+               retval = request_irq(sport->port.irq, imx_int, 0,
+                               DRIVER_NAME, sport);
+               if (retval) {
+                       free_irq(sport->port.irq, sport);
+                       goto error_out1;
+               }
+       }
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+       writel(USR1_RTSD, sport->port.membase + USR1);
+
+       temp = readl(sport->port.membase + UCR1);
+       temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
+
+       if (USE_IRDA(sport)) {
+               temp |= UCR1_IREN;
+               temp &= ~(UCR1_RTSDEN);
+       }
+
+       writel(temp, sport->port.membase + UCR1);
+
+       temp = readl(sport->port.membase + UCR2);
+       temp |= (UCR2_RXEN | UCR2_TXEN);
+       writel(temp, sport->port.membase + UCR2);
+
+       if (USE_IRDA(sport)) {
+               /* clear RX-FIFO */
+               int i = 64;
+               while ((--i > 0) &&
+                       (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
+                       barrier();
+               }
+       }
+
+       if (!cpu_is_mx1()) {
+               temp = readl(sport->port.membase + UCR3);
+               temp |= MX2_UCR3_RXDMUXSEL;
+               writel(temp, sport->port.membase + UCR3);
+       }
+
+       if (USE_IRDA(sport)) {
+               temp = readl(sport->port.membase + UCR4);
+               if (sport->irda_inv_rx)
+                       temp |= UCR4_INVR;
+               else
+                       temp &= ~(UCR4_INVR);
+               writel(temp | UCR4_DREN, sport->port.membase + UCR4);
+
+               temp = readl(sport->port.membase + UCR3);
+               if (sport->irda_inv_tx)
+                       temp |= UCR3_INVT;
+               else
+                       temp &= ~(UCR3_INVT);
+               writel(temp, sport->port.membase + UCR3);
+       }
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irqsave(&sport->port.lock,flags);
+       imx_enable_ms(&sport->port);
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               sport->irda_inv_rx = pdata->irda_inv_rx;
+               sport->irda_inv_tx = pdata->irda_inv_tx;
+               sport->trcv_delay = pdata->transceiver_delay;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(1);
+       }
+
+       return 0;
+
+error_out3:
+       if (sport->txirq)
+               free_irq(sport->txirq, sport);
+error_out2:
+       if (sport->rxirq)
+               free_irq(sport->rxirq, sport);
+error_out1:
+       return retval;
+}
+
+static void imx_shutdown(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+
+       temp = readl(sport->port.membase + UCR2);
+       temp &= ~(UCR2_TXEN);
+       writel(temp, sport->port.membase + UCR2);
+
+       if (USE_IRDA(sport)) {
+               struct imxuart_platform_data *pdata;
+               pdata = sport->port.dev->platform_data;
+               if (pdata->irda_enable)
+                       pdata->irda_enable(0);
+       }
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Free the interrupts
+        */
+       if (sport->txirq > 0) {
+               if (!USE_IRDA(sport))
+                       free_irq(sport->rtsirq, sport);
+               free_irq(sport->txirq, sport);
+               free_irq(sport->rxirq, sport);
+       } else
+               free_irq(sport->port.irq, sport);
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+
+       temp = readl(sport->port.membase + UCR1);
+       temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+       if (USE_IRDA(sport))
+               temp &= ~(UCR1_IREN);
+
+       writel(temp, sport->port.membase + UCR1);
+}
+
+static void
+imx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags;
+       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+       unsigned int div, ufcr;
+       unsigned long num, denom;
+       uint64_t tdiv64;
+
+       /*
+        * If we don't support modem control lines, don't allow
+        * these to be set.
+        */
+       if (0) {
+               termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+               termios->c_cflag |= CLOCAL;
+       }
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
+       else
+               ucr2 = UCR2_SRST | UCR2_IRTS;
+
+       if (termios->c_cflag & CRTSCTS) {
+               if( sport->have_rtscts ) {
+                       ucr2 &= ~UCR2_IRTS;
+                       ucr2 |= UCR2_CTSC;
+               } else {
+                       termios->c_cflag &= ~CRTSCTS;
+               }
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               ucr2 |= UCR2_STPB;
+       if (termios->c_cflag & PARENB) {
+               ucr2 |= UCR2_PREN;
+               if (termios->c_cflag & PARODD)
+                       ucr2 |= UCR2_PROE;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask = 0;
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |= URXD_BRK;
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |= URXD_PRERR;
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |= URXD_BRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |= URXD_OVRRUN;
+       }
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_ucr1 = readl(sport->port.membase + UCR1);
+       writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+                       sport->port.membase + UCR1);
+
+       while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
+               barrier();
+
+       /* then, disable everything */
+       old_txrxen = readl(sport->port.membase + UCR2);
+       writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
+                       sport->port.membase + UCR2);
+       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+
+       if (USE_IRDA(sport)) {
+               /*
+                * use maximum available submodule frequency to
+                * avoid missing short pulses due to low sampling rate
+                */
+               div = 1;
+       } else {
+               div = sport->port.uartclk / (baud * 16);
+               if (div > 7)
+                       div = 7;
+               if (!div)
+                       div = 1;
+       }
+
+       rational_best_approximation(16 * div * baud, sport->port.uartclk,
+               1 << 16, 1 << 16, &num, &denom);
+
+       tdiv64 = sport->port.uartclk;
+       tdiv64 *= num;
+       do_div(tdiv64, denom * 16 * div);
+       tty_termios_encode_baud_rate(termios,
+                               (speed_t)tdiv64, (speed_t)tdiv64);
+
+       num -= 1;
+       denom -= 1;
+
+       ufcr = readl(sport->port.membase + UFCR);
+       ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
+       writel(ufcr, sport->port.membase + UFCR);
+
+       writel(num, sport->port.membase + UBIR);
+       writel(denom, sport->port.membase + UBMR);
+
+       if (!cpu_is_mx1())
+               writel(sport->port.uartclk / div / 1000,
+                               sport->port.membase + MX2_ONEMS);
+
+       writel(old_ucr1, sport->port.membase + UCR1);
+
+       /* set the parity, stop bits and data size */
+       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               imx_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *imx_type(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return sport->port.type == PORT_IMX ? "IMX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void imx_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *mmres;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mmres->start, mmres->end - mmres->start + 1);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int imx_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *mmres;
+       void *ret;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mmres)
+               return -ENODEV;
+
+       ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
+                       "imx-uart");
+
+       return  ret ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void imx_config_port(struct uart_port *port, int flags)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           imx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_IMX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_IMX and PORT_UNKNOWN
+ */
+static int
+imx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != UPIO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops imx_pops = {
+       .tx_empty       = imx_tx_empty,
+       .set_mctrl      = imx_set_mctrl,
+       .get_mctrl      = imx_get_mctrl,
+       .stop_tx        = imx_stop_tx,
+       .start_tx       = imx_start_tx,
+       .stop_rx        = imx_stop_rx,
+       .enable_ms      = imx_enable_ms,
+       .break_ctl      = imx_break_ctl,
+       .startup        = imx_startup,
+       .shutdown       = imx_shutdown,
+       .set_termios    = imx_set_termios,
+       .type           = imx_type,
+       .release_port   = imx_release_port,
+       .request_port   = imx_request_port,
+       .config_port    = imx_config_port,
+       .verify_port    = imx_verify_port,
+};
+
+static struct imx_port *imx_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_IMX_CONSOLE
+static void imx_console_putchar(struct uart_port *port, int ch)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
+               barrier();
+
+       writel(ch, sport->port.membase + URTX0);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+imx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct imx_port *sport = imx_ports[co->index];
+       unsigned int old_ucr1, old_ucr2, ucr1;
+
+       /*
+        *      First, save UCR1/2 and then disable interrupts
+        */
+       ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
+       old_ucr2 = readl(sport->port.membase + UCR2);
+
+       if (cpu_is_mx1())
+               ucr1 |= MX1_UCR1_UARTCLKEN;
+       ucr1 |= UCR1_UARTEN;
+       ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
+
+       writel(ucr1, sport->port.membase + UCR1);
+
+       writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
+
+       uart_console_write(&sport->port, s, count, imx_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore UCR1/2
+        */
+       while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
+
+       writel(old_ucr1, sport->port.membase + UCR1);
+       writel(old_ucr2, sport->port.membase + UCR2);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+imx_console_get_options(struct imx_port *sport, int *baud,
+                          int *parity, int *bits)
+{
+
+       if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
+               /* ok, the port was enabled */
+               unsigned int ucr2, ubir,ubmr, uartclk;
+               unsigned int baud_raw;
+               unsigned int ucfr_rfdiv;
+
+               ucr2 = readl(sport->port.membase + UCR2);
+
+               *parity = 'n';
+               if (ucr2 & UCR2_PREN) {
+                       if (ucr2 & UCR2_PROE)
+                               *parity = 'o';
+                       else
+                               *parity = 'e';
+               }
+
+               if (ucr2 & UCR2_WS)
+                       *bits = 8;
+               else
+                       *bits = 7;
+
+               ubir = readl(sport->port.membase + UBIR) & 0xffff;
+               ubmr = readl(sport->port.membase + UBMR) & 0xffff;
+
+               ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
+               if (ucfr_rfdiv == 6)
+                       ucfr_rfdiv = 7;
+               else
+                       ucfr_rfdiv = 6 - ucfr_rfdiv;
+
+               uartclk = clk_get_rate(sport->clk);
+               uartclk /= ucfr_rfdiv;
+
+               {       /*
+                        * The next code provides exact computation of
+                        *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
+                        * without need of float support or long long division,
+                        * which would be required to prevent 32bit arithmetic overflow
+                        */
+                       unsigned int mul = ubir + 1;
+                       unsigned int div = 16 * (ubmr + 1);
+                       unsigned int rem = uartclk % div;
+
+                       baud_raw = (uartclk / div) * mul;
+                       baud_raw += (rem * mul + div / 2) / div;
+                       *baud = (baud_raw + 50) / 100 * 100;
+               }
+
+               if(*baud != baud_raw)
+                       printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
+                               baud_raw, *baud);
+       }
+}
+
+static int __init
+imx_console_setup(struct console *co, char *options)
+{
+       struct imx_port *sport;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
+               co->index = 0;
+       sport = imx_ports[co->index];
+       if(sport == NULL)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               imx_console_get_options(sport, &baud, &parity, &bits);
+
+       imx_setup_ufcr(sport, 0);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver imx_reg;
+static struct console imx_console = {
+       .name           = DEV_NAME,
+       .write          = imx_console_write,
+       .device         = uart_console_device,
+       .setup          = imx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &imx_reg,
+};
+
+#define IMX_CONSOLE    &imx_console
+#else
+#define IMX_CONSOLE    NULL
+#endif
+
+static struct uart_driver imx_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = DEV_NAME,
+       .major          = SERIAL_IMX_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ARRAY_SIZE(imx_ports),
+       .cons           = IMX_CONSOLE,
+};
+
+static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct imx_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_suspend_port(&imx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_imx_resume(struct platform_device *dev)
+{
+       struct imx_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_resume_port(&imx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_imx_probe(struct platform_device *pdev)
+{
+       struct imx_port *sport;
+       struct imxuart_platform_data *pdata;
+       void __iomem *base;
+       int ret = 0;
+       struct resource *res;
+
+       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+       if (!sport)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto free;
+       }
+
+       base = ioremap(res->start, PAGE_SIZE);
+       if (!base) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       sport->port.dev = &pdev->dev;
+       sport->port.mapbase = res->start;
+       sport->port.membase = base;
+       sport->port.type = PORT_IMX,
+       sport->port.iotype = UPIO_MEM;
+       sport->port.irq = platform_get_irq(pdev, 0);
+       sport->rxirq = platform_get_irq(pdev, 0);
+       sport->txirq = platform_get_irq(pdev, 1);
+       sport->rtsirq = platform_get_irq(pdev, 2);
+       sport->port.fifosize = 32;
+       sport->port.ops = &imx_pops;
+       sport->port.flags = UPF_BOOT_AUTOCONF;
+       sport->port.line = pdev->id;
+       init_timer(&sport->timer);
+       sport->timer.function = imx_timeout;
+       sport->timer.data     = (unsigned long)sport;
+
+       sport->clk = clk_get(&pdev->dev, "uart");
+       if (IS_ERR(sport->clk)) {
+               ret = PTR_ERR(sport->clk);
+               goto unmap;
+       }
+       clk_enable(sport->clk);
+
+       sport->port.uartclk = clk_get_rate(sport->clk);
+
+       imx_ports[pdev->id] = sport;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+               sport->have_rtscts = 1;
+
+#ifdef CONFIG_IRDA
+       if (pdata && (pdata->flags & IMXUART_IRDA))
+               sport->use_irda = 1;
+#endif
+
+       if (pdata && pdata->init) {
+               ret = pdata->init(pdev);
+               if (ret)
+                       goto clkput;
+       }
+
+       ret = uart_add_one_port(&imx_reg, &sport->port);
+       if (ret)
+               goto deinit;
+       platform_set_drvdata(pdev, &sport->port);
+
+       return 0;
+deinit:
+       if (pdata && pdata->exit)
+               pdata->exit(pdev);
+clkput:
+       clk_put(sport->clk);
+       clk_disable(sport->clk);
+unmap:
+       iounmap(sport->port.membase);
+free:
+       kfree(sport);
+
+       return ret;
+}
+
+static int serial_imx_remove(struct platform_device *pdev)
+{
+       struct imxuart_platform_data *pdata;
+       struct imx_port *sport = platform_get_drvdata(pdev);
+
+       pdata = pdev->dev.platform_data;
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport) {
+               uart_remove_one_port(&imx_reg, &sport->port);
+               clk_put(sport->clk);
+       }
+
+       clk_disable(sport->clk);
+
+       if (pdata && pdata->exit)
+               pdata->exit(pdev);
+
+       iounmap(sport->port.membase);
+       kfree(sport);
+
+       return 0;
+}
+
+static struct platform_driver serial_imx_driver = {
+       .probe          = serial_imx_probe,
+       .remove         = serial_imx_remove,
+
+       .suspend        = serial_imx_suspend,
+       .resume         = serial_imx_resume,
+       .driver         = {
+               .name   = "imx-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init imx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: IMX driver\n");
+
+       ret = uart_register_driver(&imx_reg);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&serial_imx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&imx_reg);
+
+       return 0;
+}
+
+static void __exit imx_serial_exit(void)
+{
+       platform_driver_unregister(&serial_imx_driver);
+       uart_unregister_driver(&imx_reg);
+}
+
+module_init(imx_serial_init);
+module_exit(imx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("IMX generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-uart");
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
new file mode 100644 (file)
index 0000000..ee43efc
--- /dev/null
@@ -0,0 +1,2199 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * This file contains a module version of the ioc3 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/ioc3.h>
+#include <linux/slab.h>
+
+/*
+ * Interesting things about the ioc3
+ */
+
+#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
+#define PORTS_PER_CARD         2
+#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
+#define MAX_CARDS              8
+#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
+
+/* determine given the sio_ir what port it applies to */
+#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
+
+
+/*
+ * we have 2 logical ports (rs232, rs422) for each physical port
+ * evens are rs232, odds are rs422
+ */
+#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
+#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
+#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
+#define IS_RS232(_x)           !((_x) & 1)
+
+static unsigned int Num_of_ioc3_cards;
+static unsigned int Submodule_slot;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)   ;
+//#define DPRINT_CONFIG(_x...)  printk _x
+#define NOT_PROGRESS() ;
+//#define NOT_PROGRESS()       printk("%s : fails %d\n", __func__, __LINE__)
+
+/* number of characters we want to transmit to the lower level at a time */
+#define MAX_CHARS              256
+#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
+
+/* Device name we're using */
+#define DEVICE_NAME            "ttySIOC"
+#define DEVICE_MAJOR           204
+#define DEVICE_MINOR           116
+
+/* flags for next_char_state */
+#define NCS_BREAK              0x1
+#define NCS_PARITY             0x2
+#define NCS_FRAMING            0x4
+#define NCS_OVERRUN            0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED     1200
+#define MAX_BAUD_SUPPORTED     115200
+
+/* protocol types supported */
+#define PROTO_RS232            0
+#define PROTO_RS422            1
+
+/* Notification types */
+#define N_DATA_READY           0x01
+#define N_OUTPUT_LOWAT         0x02
+#define N_BREAK                        0x04
+#define N_PARITY_ERROR         0x08
+#define N_FRAMING_ERROR                0x10
+#define N_OVERRUN_ERROR                0x20
+#define N_DDCD                 0x40
+#define N_DCTS                 0x80
+
+#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
+                                               | N_OVERRUN_ERROR)
+
+#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
+#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
+#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
+
+#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
+
+#define RING_BUF_SIZE          4096
+#define BUF_SIZE_BIT           SBBR_L_SIZE
+#define PROD_CONS_MASK         PROD_CONS_PTR_4K
+
+#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
+
+/* driver specific - one per card */
+struct ioc3_card {
+       struct {
+               /* uart ports are allocated here */
+               struct uart_port icp_uart_port[LOGICAL_PORTS];
+               /* the ioc3_port used for this port */
+               struct ioc3_port *icp_port;
+       } ic_port[PORTS_PER_CARD];
+       /* currently enabled interrupts */
+       uint32_t ic_enable;
+};
+
+/* Local port info for each IOC3 serial port */
+struct ioc3_port {
+       /* handy reference material */
+       struct uart_port *ip_port;
+       struct ioc3_card *ip_card;
+       struct ioc3_driver_data *ip_idd;
+       struct ioc3_submodule *ip_is;
+
+       /* pci mem addresses for this port */
+       struct ioc3_serialregs __iomem *ip_serial_regs;
+       struct ioc3_uartregs __iomem *ip_uart_regs;
+
+       /* Ring buffer page for this port */
+       dma_addr_t ip_dma_ringbuf;
+       /* vaddr of ring buffer */
+       struct ring_buffer *ip_cpu_ringbuf;
+
+       /* Rings for this port */
+       struct ring *ip_inring;
+       struct ring *ip_outring;
+
+       /* Hook to port specific values */
+       struct port_hooks *ip_hooks;
+
+       spinlock_t ip_lock;
+
+       /* Various rx/tx parameters */
+       int ip_baud;
+       int ip_tx_lowat;
+       int ip_rx_timeout;
+
+       /* Copy of notification bits */
+       int ip_notify;
+
+       /* Shadow copies of various registers so we don't need to PIO
+        * read them constantly
+        */
+       uint32_t ip_sscr;
+       uint32_t ip_tx_prod;
+       uint32_t ip_rx_cons;
+       unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH             0x01
+       /* used to signify that we have turned off the rx_high
+        * temporarily - we need to drain the fifo and don't
+        * want to get blasted with interrupts.
+        */
+#define DCD_ON                 0x02
+       /* DCD state is on */
+#define LOWAT_WRITTEN          0x04
+#define READ_ABORTED           0x08
+       /* the read was aborted - used to avaoid infinate looping
+        * in the interrupt handler
+        */
+#define INPUT_ENABLE           0x10
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct port_hooks {
+       uint32_t intr_delta_dcd;
+       uint32_t intr_delta_cts;
+       uint32_t intr_tx_mt;
+       uint32_t intr_rx_timer;
+       uint32_t intr_rx_high;
+       uint32_t intr_tx_explicit;
+       uint32_t intr_clear;
+       uint32_t intr_all;
+       char rs422_select_pin;
+};
+
+static struct port_hooks hooks_array[PORTS_PER_CARD] = {
+       /* values for port A */
+       {
+       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SA_TX_MT,
+       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
+       .intr_rx_high = SIO_IR_SA_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
+                               | SIO_IR_SA_RX_HIGH
+                               | SIO_IR_SA_RX_TIMER
+                               | SIO_IR_SA_DELTA_DCD
+                               | SIO_IR_SA_DELTA_CTS
+                               | SIO_IR_SA_INT
+                               | SIO_IR_SA_TX_EXPLICIT
+                               | SIO_IR_SA_MEMERR),
+       .intr_all =  SIO_IR_SA,
+       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
+        },
+
+       /* values for port B */
+       {
+       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SB_TX_MT,
+       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
+       .intr_rx_high = SIO_IR_SB_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
+                               | SIO_IR_SB_RX_HIGH
+                               | SIO_IR_SB_RX_TIMER
+                               | SIO_IR_SB_DELTA_DCD
+                               | SIO_IR_SB_DELTA_CTS
+                               | SIO_IR_SB_INT
+                               | SIO_IR_SB_TX_EXPLICIT
+                               | SIO_IR_SB_MEMERR),
+       .intr_all = SIO_IR_SB,
+       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
+        }
+};
+
+struct ring_entry {
+       union {
+               struct {
+                       uint32_t alldata;
+                       uint32_t allsc;
+               } all;
+               struct {
+                       char data[4];   /* data bytes */
+                       char sc[4];     /* status/control */
+               } s;
+       } u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc                u.s.sc
+#define ring_data      u.s.data
+#define ring_allsc     u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+       struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+       struct ring TX_A;
+       struct ring RX_A;
+       struct ring TX_B;
+       struct ring RX_B;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* for Infinite loop detection  */
+#define MAXITER                10000000
+
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc3_port *port, int baud)
+{
+       int divisor;
+       int actual_baud;
+       int diff;
+       int lcr, prediv;
+       struct ioc3_uartregs __iomem *uart;
+
+       for (prediv = 6; prediv < 64; prediv++) {
+               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
+               if (!divisor)
+                       continue;       /* invalid divisor */
+               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
+
+               diff = actual_baud - baud;
+               if (diff < 0)
+                       diff = -diff;
+
+               /* if we're within 1% we've found a match */
+               if (diff * 100 <= actual_baud)
+                       break;
+       }
+
+       /* if the above loop completed, we didn't match
+        * the baud rate.  give up.
+        */
+       if (prediv == 64) {
+               NOT_PROGRESS();
+               return 1;
+       }
+
+       uart = port->ip_uart_regs;
+       lcr = readb(&uart->iu_lcr);
+
+       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
+       writeb((unsigned char)divisor, &uart->iu_dll);
+       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
+       writeb((unsigned char)prediv, &uart->iu_scr);
+       writeb((unsigned char)lcr, &uart->iu_lcr);
+
+       return 0;
+}
+
+/**
+ * get_ioc3_port - given a uart port, return the control structure
+ * @the_port: uart port to find
+ */
+static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
+{
+       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
+       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
+       int ii, jj;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return NULL;
+       }
+       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
+               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
+                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
+                               return card_ptr->ic_port[ii].icp_port;
+               }
+       }
+       NOT_PROGRESS();
+       return NULL;
+}
+
+/**
+ * port_init - Initialize the sio and ioc3 hardware for a given port
+ *                     called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc3_port *port)
+{
+       uint32_t sio_cr;
+       struct port_hooks *hooks = port->ip_hooks;
+       struct ioc3_uartregs __iomem *uart;
+       int reset_loop_counter = 0xfffff;
+       struct ioc3_driver_data *idd = port->ip_idd;
+
+       /* Idle the IOC3 serial interface */
+       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
+
+       /* Wait until any pending bus activity for this port has ceased */
+       do {
+               sio_cr = readl(&idd->vma->sio_cr);
+               if (reset_loop_counter-- <= 0) {
+                       printk(KERN_WARNING
+                              "IOC3 unable to come out of reset"
+                               " scr 0x%x\n", sio_cr);
+                       return -1;
+               }
+       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
+              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
+               || sio_cr == SIO_CR_ARB_DIAG_TXB
+               || sio_cr == SIO_CR_ARB_DIAG_RXA
+               || sio_cr == SIO_CR_ARB_DIAG_RXB));
+
+       /* Finish reset sequence */
+       writel(0, &port->ip_serial_regs->sscr);
+
+       /* Once RESET is done, reload cached tx_prod and rx_cons values
+        * and set rings to empty by making prod == cons
+        */
+       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       /* Disable interrupts for this 16550 */
+       uart = port->ip_uart_regs;
+       writeb(0, &uart->iu_lcr);
+       writeb(0, &uart->iu_ier);
+
+       /* Set the default baud */
+       set_baud(port, port->ip_baud);
+
+       /* Set line control to 8 bits no parity */
+       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Enable the FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
+       /* then reset 16550 FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+              &uart->iu_fcr);
+
+       /* Clear modem control register */
+       writeb(0, &uart->iu_mcr);
+
+       /* Clear deltas in modem status register */
+       writel(0, &port->ip_serial_regs->shadow);
+
+       /* Only do this once per port pair */
+       if (port->ip_hooks == &hooks_array[0]) {
+               unsigned long ring_pci_addr;
+               uint32_t __iomem *sbbr_l, *sbbr_h;
+
+               sbbr_l = &idd->vma->sbbr_l;
+               sbbr_h = &idd->vma->sbbr_h;
+               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
+                              __func__, (void *)ring_pci_addr));
+
+               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
+               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
+       }
+
+       /* Set the receive timeout value to 10 msec */
+       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+       /* Set rx threshold, enable DMA */
+       /* Set high water mark at 3/4 of full ring */
+       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+
+       /* uart experiences pauses at high baud rate reducing actual
+        * throughput by 10% or so unless we enable high speed polling
+        * XXX when this hardware bug is resolved we should revert to
+        * normal polling speed
+        */
+       port->ip_sscr |= SSCR_HIGH_SPD;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Disable and clear all serial related interrupt bits */
+       port->ip_card->ic_enable &= ~hooks->intr_clear;
+       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
+       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
+       return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if ((port->ip_card->ic_enable & mask) != mask) {
+               port->ip_card->ic_enable |= mask;
+               ioc3_enable(port->ip_is, port->ip_idd, mask);
+       }
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc3_port *port)
+{
+       int spiniter = 0;
+
+       port->ip_flags = INPUT_ENABLE;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER) {
+                               NOT_PROGRESS();
+                               return -1;
+                       }
+               }
+       }
+
+       /* Reset the input fifo.  If the uart received chars while the port
+        * was closed and DMA is not enabled, the uart may have a bunch of
+        * chars hanging around in its rx fifo which will not be discarded
+        * by rclr in the upper layer. We must get rid of them here.
+        */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+              &port->ip_uart_regs->iu_fcr);
+
+       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Re-enable DMA, set default threshold to intr whenever there is
+        * data available.
+        */
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= 1;     /* default threshold */
+
+       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+        * flag if it was set above
+        */
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       port->ip_tx_lowat = 1;
+       return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
+{
+       int threshold;
+
+       port->ip_rx_timeout = timeout;
+
+       /* Timeout is in ticks.  Let's figure out how many chars we
+        * can receive at the current baud rate in that interval
+        * and set the rx threshold to that amount.  There are 4 chars
+        * per ring entry, so we'll divide the number of chars that will
+        * arrive in timeout by 4.
+        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+        */
+       threshold = timeout * port->ip_baud / 4000;
+       if (threshold == 0)
+               threshold = 1;  /* otherwise we'll intr all the time! */
+
+       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
+               return 1;
+
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= threshold;
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Now set the rx timeout to the given value
+        * again timeout * SRTR_HZ / HZ
+        */
+       timeout = timeout * SRTR_HZ / 100;
+       if (timeout > SRTR_CNT)
+               timeout = SRTR_CNT;
+       writel(timeout, &port->ip_serial_regs->srtr);
+       return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc3_port *port,
+           int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+       char lcr, sizebits;
+       int spiniter = 0;
+
+       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
+                       "parodd %d\n",
+                      __func__, ((struct uart_port *)port->ip_port)->line,
+                       baud, byte_size, stop_bits, parenb, parodd));
+
+       if (set_baud(port, baud))
+               return 1;
+
+       switch (byte_size) {
+       case 5:
+               sizebits = UART_LCR_WLEN5;
+               break;
+       case 6:
+               sizebits = UART_LCR_WLEN6;
+               break;
+       case 7:
+               sizebits = UART_LCR_WLEN7;
+               break;
+       case 8:
+               sizebits = UART_LCR_WLEN8;
+               break;
+       default:
+               return 1;
+       }
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+
+       /* Clear relevant fields in lcr */
+       lcr = readb(&port->ip_uart_regs->iu_lcr);
+       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+       /* Set byte size in lcr */
+       lcr |= sizebits;
+
+       /* Set parity */
+       if (parenb) {
+               lcr |= UART_LCR_PARITY;
+               if (!parodd)
+                       lcr |= UART_LCR_EPAR;
+       }
+
+       /* Set stop bits */
+       if (stop_bits)
+               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+       writeb(lcr, &port->ip_uart_regs->iu_lcr);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       port->ip_baud = baud;
+
+       /* When we get within this number of ring entries of filling the
+        * entire ring on tx, place an EXPLICIT intr to generate a lowat
+        * notification when output has drained.
+        */
+       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+       if (port->ip_tx_lowat == 0)
+               port->ip_tx_lowat = 1;
+
+       set_rx_timeout(port, 2);
+       return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *                     actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc3_port *port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total = 0;
+       struct ring *outring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+
+       BUG_ON(!(len >= 0));
+
+       prod_ptr = port->ip_tx_prod;
+       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       outring = port->ip_outring;
+
+       /* Maintain a 1-entry red-zone.  The ring buffer is full when
+        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+        * in the body of the loop, I'll do it now.
+        */
+       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+       /* Stuff the bytes into the output */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               int xx;
+
+               /* Get 4 bytes (one ring entry) at a time */
+               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+               /* Invalidate all entries */
+               entry->ring_allsc = 0;
+
+               /* Copy in some bytes */
+               for (xx = 0; (xx < 4) && (len > 0); xx++) {
+                       entry->ring_data[xx] = *buf++;
+                       entry->ring_sc[xx] = TXCB_VALID;
+                       len--;
+                       total++;
+               }
+
+               /* If we are within some small threshold of filling up the
+                * entire ring buffer, we must place an EXPLICIT intr here
+                * to generate a lowat interrupt in case we subsequently
+                * really do fill up the ring and the caller goes to sleep.
+                * No need to place more than one though.
+                */
+               if (!(port->ip_flags & LOWAT_WRITTEN) &&
+                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
+                       port->ip_flags |= LOWAT_WRITTEN;
+                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
+               }
+
+               /* Go on to next entry */
+               prod_ptr += sizeof(struct ring_entry);
+               prod_ptr &= PROD_CONS_MASK;
+       }
+
+       /* If we sent something, start DMA if necessary */
+       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
+               port->ip_sscr |= SSCR_DMA_EN;
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+
+       /* Store the new producer pointer.  If tx is disabled, we stuff the
+        * data into the ring buffer, but we don't actually start tx.
+        */
+       if (!uart_tx_stopped(port->ip_port)) {
+               writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+               /* If we are now transmitting, enable tx_mt interrupt so we
+                * can disable DMA if necessary when the tx finishes.
+                */
+               if (total > 0)
+                       enable_intrs(port, hooks->intr_tx_mt);
+       }
+       port->ip_tx_prod = prod_ptr;
+
+       return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if (port->ip_card->ic_enable & mask) {
+               ioc3_disable(port->ip_is, port->ip_idd, mask);
+               port->ip_card->ic_enable &= ~mask;
+       }
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc3_port *port, int mask, int set_on)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+       uint32_t intrbits, sscrbits;
+
+       BUG_ON(!mask);
+
+       intrbits = sscrbits = 0;
+
+       if (mask & N_DATA_READY)
+               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+       if (mask & N_OUTPUT_LOWAT)
+               intrbits |= hooks->intr_tx_explicit;
+       if (mask & N_DDCD) {
+               intrbits |= hooks->intr_delta_dcd;
+               sscrbits |= SSCR_RX_RING_DCD;
+       }
+       if (mask & N_DCTS)
+               intrbits |= hooks->intr_delta_cts;
+
+       if (set_on) {
+               enable_intrs(port, intrbits);
+               port->ip_notify |= mask;
+               port->ip_sscr |= sscrbits;
+       } else {
+               disable_intrs(port, intrbits);
+               port->ip_notify &= ~mask;
+               port->ip_sscr &= ~sscrbits;
+       }
+
+       /* We require DMA if either DATA_READY or DDCD notification is
+        * currently requested. If neither of these is requested and
+        * there is currently no tx in progress, DMA may be disabled.
+        */
+       if (port->ip_notify & (N_DATA_READY | N_DDCD))
+               port->ip_sscr |= SSCR_DMA_EN;
+       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
+               port->ip_sscr &= ~SSCR_DMA_EN;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+                         int mask1, int mask2)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       int spiniter = 0;
+       char mcr;
+
+       if (!port)
+               return -1;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+       shadow = readl(&port->ip_serial_regs->shadow);
+       mcr = (shadow & 0xff000000) >> 24;
+
+       /* Set new value */
+       mcr |= mask1;
+       shadow |= mask2;
+       writeb(mcr, &port->ip_uart_regs->iu_mcr);
+       writel(shadow, &port->ip_serial_regs->shadow);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       return 0;
+}
+
+/**
+ * ioc3_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc3_set_proto(struct ioc3_port *port, int proto)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+
+       switch (proto) {
+       default:
+       case PROTO_RS232:
+               /* Clear the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs232\n", __func__));
+               writel(0, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+
+       case PROTO_RS422:
+               /* Set the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs422\n", __func__));
+               writel(1, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+       }
+       return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with the_port->lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+       int xmit_count, tail, head;
+       int result;
+       char *start;
+       struct tty_struct *tty;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct uart_state *state;
+
+       if (!the_port)
+               return;
+       if (!port)
+               return;
+
+       state = the_port->state;
+       tty = state->port.tty;
+
+       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
+               /* Nothing to do or hw stopped */
+               set_notification(port, N_ALL_OUTPUT, 0);
+               return;
+       }
+
+       head = state->xmit.head;
+       tail = state->xmit.tail;
+       start = (char *)&state->xmit.buf[tail];
+
+       /* write out all the data or until the end of the buffer */
+       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+       if (xmit_count > 0) {
+               result = do_write(port, start, xmit_count);
+               if (result > 0) {
+                       /* booking */
+                       xmit_count -= result;
+                       the_port->icount.tx += result;
+                       /* advance the pointers */
+                       tail += result;
+                       tail &= UART_XMIT_SIZE - 1;
+                       state->xmit.tail = tail;
+                       start = (char *)&state->xmit.buf[tail];
+               }
+       }
+       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(the_port);
+
+       if (uart_circ_empty(&state->xmit)) {
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+       } else {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+       }
+}
+
+/**
+ * ioc3_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc3_change_speed(struct uart_port *the_port,
+                 struct ktermios *new_termios, struct ktermios *old_termios)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned int cflag, iflag;
+       int baud;
+       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+       struct uart_state *state = the_port->state;
+
+       cflag = new_termios->c_cflag;
+       iflag = new_termios->c_iflag;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               new_data = 5;
+               break;
+       case CS6:
+               new_data = 6;
+               break;
+       case CS7:
+               new_data = 7;
+               break;
+       case CS8:
+               new_data = 8;
+               break;
+       default:
+               /* cuz we always need a default ... */
+               new_data = 5;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               new_stop = 1;
+       }
+       if (cflag & PARENB) {
+               new_parity_enable = 1;
+               if (cflag & PARODD)
+                       new_parity = 1;
+       }
+       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
+                               the_port->line));
+
+       if (!the_port->fifosize)
+               the_port->fifosize = FIFO_SIZE;
+       uart_update_timeout(the_port, cflag, baud);
+
+       the_port->ignore_status_mask = N_ALL_INPUT;
+
+       state->port.tty->low_latency = 1;
+
+       if (iflag & IGNPAR)
+               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+                                                 | N_FRAMING_ERROR);
+       if (iflag & IGNBRK) {
+               the_port->ignore_status_mask &= ~N_BREAK;
+               if (iflag & IGNPAR)
+                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+       }
+       if (!(cflag & CREAD)) {
+               /* ignore everything */
+               the_port->ignore_status_mask &= ~N_DATA_READY;
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable hardware flow control */
+               port->ip_sscr |= SSCR_HFC_EN;
+       }
+       else {
+               /* disable hardware flow control */
+               port->ip_sscr &= ~SSCR_HFC_EN;
+       }
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Set the configuration and proper notification call */
+       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
+                      "config_port(baud %d data %d stop %d penable %d "
+                       " parity %d), notification 0x%x\n",
+                      __func__, (void *)port, the_port->line, cflag, baud,
+                      new_data, new_stop, new_parity_enable, new_parity,
+                      the_port->ignore_status_mask));
+
+       if ((config_port(port, baud,    /* baud */
+                        new_data,      /* byte size */
+                        new_stop,      /* stop bits */
+                        new_parity_enable,     /* set parity */
+                        new_parity)) >= 0) {   /* parity 1==odd */
+               set_notification(port, the_port->ignore_status_mask, 1);
+       }
+}
+
+/**
+ * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic3_startup_local(struct uart_port *the_port)
+{
+       struct ioc3_port *port;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       local_open(port);
+
+       /* set the protocol */
+       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
+                                                       PROTO_RS422);
+       return 0;
+}
+
+/*
+ * ioc3_cb_output_lowat - called when the output low water mark is hit
+ * @port: port to output
+ */
+static void ioc3_cb_output_lowat(struct ioc3_port *port)
+{
+       unsigned long pflags;
+
+       /* the_port->lock is set on the call here */
+       if (port->ip_port) {
+               spin_lock_irqsave(&port->ip_port->lock, pflags);
+               transmit_chars(port->ip_port);
+               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
+       }
+}
+
+/*
+ * ioc3_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+       struct uart_icount *icount;
+
+       icount = &the_port->icount;
+
+       if (ncs & NCS_BREAK)
+               icount->brk++;
+       if (ncs & NCS_FRAMING)
+               icount->frame++;
+       if (ncs & NCS_OVERRUN)
+               icount->overrun++;
+       if (ncs & NCS_PARITY)
+               icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *                     actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct ring *inring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+       int byte_num;
+       char *sc;
+       int loop_counter;
+
+       BUG_ON(!(len >= 0));
+       BUG_ON(!port);
+
+       /* There is a nasty timing issue in the IOC3. When the rx_timer
+        * expires or the rx_high condition arises, we take an interrupt.
+        * At some point while servicing the interrupt, we read bytes from
+        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+        * not started until the first byte is received *after* it is armed,
+        * and any bytes pending in the rx construction buffers are not drained
+        * to memory until either there are 4 bytes available or the rx_timer
+        * expires.  This leads to a potential situation where data is left
+        * in the construction buffers forever - 1 to 3 bytes were received
+        * after the interrupt was generated but before the rx_timer was
+        * re-armed. At that point as long as no subsequent bytes are received
+        * the timer will never be started and the bytes will remain in the
+        * construction buffer forever.  The solution is to execute a DRAIN
+        * command after rearming the timer.  This way any bytes received before
+        * the DRAIN will be drained to memory, and any bytes received after
+        * the DRAIN will start the TIMER and be drained when it expires.
+        * Luckily, this only needs to be done when the DMA buffer is empty
+        * since there is no requirement that this function return all
+        * available data as long as it returns some.
+        */
+       /* Re-arm the timer */
+
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       cons_ptr = port->ip_rx_cons;
+
+       if (prod_ptr == cons_ptr) {
+               int reset_dma = 0;
+
+               /* Input buffer appears empty, do a flush. */
+
+               /* DMA must be enabled for this to work. */
+               if (!(port->ip_sscr & SSCR_DMA_EN)) {
+                       port->ip_sscr |= SSCR_DMA_EN;
+                       reset_dma = 1;
+               }
+
+               /* Potential race condition: we must reload the srpir after
+                * issuing the drain command, otherwise we could think the rx
+                * buffer is empty, then take a very long interrupt, and when
+                * we come back it's full and we wait forever for the drain to
+                * complete.
+                */
+               writel(port->ip_sscr | SSCR_RX_DRAIN,
+                      &port->ip_serial_regs->sscr);
+               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+
+               /* We must not wait for the DRAIN to complete unless there are
+                * at least 8 bytes (2 ring entries) available to receive the
+                * data otherwise the DRAIN will never complete and we'll
+                * deadlock here.
+                * In fact, to make things easier, I'll just ignore the flush if
+                * there is any data at all now available.
+                */
+               if (prod_ptr == cons_ptr) {
+                       loop_counter = 0;
+                       while (readl(&port->ip_serial_regs->sscr) &
+                              SSCR_RX_DRAIN) {
+                               loop_counter++;
+                               if (loop_counter > MAXITER)
+                                       return -1;
+                       }
+
+                       /* SIGH. We have to reload the prod_ptr *again* since
+                        * the drain may have caused it to change
+                        */
+                       prod_ptr = readl(&port->ip_serial_regs->srpir)
+                           & PROD_CONS_MASK;
+               }
+               if (reset_dma) {
+                       port->ip_sscr &= ~SSCR_DMA_EN;
+                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+               }
+       }
+       inring = port->ip_inring;
+       port->ip_flags &= ~READ_ABORTED;
+
+       total = 0;
+       loop_counter = 0xfffff; /* to avoid hangs */
+
+       /* Grab bytes from the hardware */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on read (line %d).\n",
+                               the_port->line);
+                       break;
+               }
+
+               /* According to the producer pointer, this ring entry
+                * must contain some data.  But if the PIO happened faster
+                * than the DMA, the data may not be available yet, so let's
+                * wait until it arrives.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       /* Indicate the read is aborted so we don't disable
+                        * the interrupt thinking that the consumer is
+                        * congested.
+                        */
+                       port->ip_flags |= READ_ABORTED;
+                       len = 0;
+                       break;
+               }
+
+               /* Load the bytes/status out of the ring entry */
+               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+                       sc = &(entry->ring_sc[byte_num]);
+
+                       /* Check for change in modem state or overrun */
+                       if ((*sc & RXSB_MODEM_VALID)
+                           && (port->ip_notify & N_DDCD)) {
+                               /* Notify upper layer if DCD dropped */
+                               if ((port->ip_flags & DCD_ON)
+                                   && !(*sc & RXSB_DCD)) {
+                                       /* If we have already copied some data,
+                                        * return it.  We'll pick up the carrier
+                                        * drop on the next pass.  That way we
+                                        * don't throw away the data that has
+                                        * already been copied back to
+                                        * the caller's buffer.
+                                        */
+                                       if (total > 0) {
+                                               len = 0;
+                                               break;
+                                       }
+                                       port->ip_flags &= ~DCD_ON;
+
+                                       /* Turn off this notification so the
+                                        * carrier drop protocol won't see it
+                                        * again when it does a read.
+                                        */
+                                       *sc &= ~RXSB_MODEM_VALID;
+
+                                       /* To keep things consistent, we need
+                                        * to update the consumer pointer so
+                                        * the next reader won't come in and
+                                        * try to read the same ring entries
+                                        * again. This must be done here before
+                                        * the dcd change.
+                                        */
+
+                                       if ((entry->ring_allsc & RING_ANY_VALID)
+                                           == 0) {
+                                               cons_ptr += (int)sizeof
+                                                   (struct ring_entry);
+                                               cons_ptr &= PROD_CONS_MASK;
+                                       }
+                                       writel(cons_ptr,
+                                              &port->ip_serial_regs->srcir);
+                                       port->ip_rx_cons = cons_ptr;
+
+                                       /* Notify upper layer of carrier drop */
+                                       if ((port->ip_notify & N_DDCD)
+                                           && port->ip_port) {
+                                               uart_handle_dcd_change
+                                                       (port->ip_port, 0);
+                                               wake_up_interruptible
+                                                   (&the_port->state->
+                                                    port.delta_msr_wait);
+                                       }
+
+                                       /* If we had any data to return, we
+                                        * would have returned it above.
+                                        */
+                                       return 0;
+                               }
+                       }
+                       if (*sc & RXSB_MODEM_VALID) {
+                               /* Notify that an input overrun occurred */
+                               if ((*sc & RXSB_OVERRUN)
+                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
+                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
+                               }
+                               /* Don't look at this byte again */
+                               *sc &= ~RXSB_MODEM_VALID;
+                       }
+
+                       /* Check for valid data or RX errors */
+                       if ((*sc & RXSB_DATA_VALID) &&
+                           ((*sc & (RXSB_PAR_ERR
+                                    | RXSB_FRAME_ERR | RXSB_BREAK))
+                            && (port->ip_notify & (N_PARITY_ERROR
+                                                   | N_FRAMING_ERROR
+                                                   | N_BREAK)))) {
+                               /* There is an error condition on the next byte.
+                                * If we have already transferred some bytes,
+                                * we'll stop here. Otherwise if this is the
+                                * first byte to be read, we'll just transfer
+                                * it alone after notifying the
+                                * upper layer of its status.
+                                */
+                               if (total > 0) {
+                                       len = 0;
+                                       break;
+                               } else {
+                                       if ((*sc & RXSB_PAR_ERR) &&
+                                           (port->
+                                            ip_notify & N_PARITY_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_PARITY);
+                                       }
+                                       if ((*sc & RXSB_FRAME_ERR) &&
+                                           (port->
+                                            ip_notify & N_FRAMING_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_FRAMING);
+                                       }
+                                       if ((*sc & RXSB_BREAK)
+                                           && (port->ip_notify & N_BREAK)) {
+                                               ioc3_cb_post_ncs
+                                                   (the_port, NCS_BREAK);
+                                       }
+                                       len = 1;
+                               }
+                       }
+                       if (*sc & RXSB_DATA_VALID) {
+                               *sc &= ~RXSB_DATA_VALID;
+                               *buf = entry->ring_data[byte_num];
+                               buf++;
+                               len--;
+                               total++;
+                       }
+               }
+
+               /* If we used up this entry entirely, go on to the next one,
+                * otherwise we must have run out of buffer space, so
+                * leave the consumer pointer here for the next read in case
+                * there are still unread bytes in this entry.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       cons_ptr += (int)sizeof(struct ring_entry);
+                       cons_ptr &= PROD_CONS_MASK;
+               }
+       }
+
+       /* Update consumer pointer and re-arm rx timer interrupt */
+       writel(cons_ptr, &port->ip_serial_regs->srcir);
+       port->ip_rx_cons = cons_ptr;
+
+       /* If we have now dipped below the rx high water mark and we have
+        * rx_high interrupt turned off, we can now turn it back on again.
+        */
+       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+                                              & PROD_CONS_MASK) <
+                                             ((port->
+                                               ip_sscr &
+                                               SSCR_RX_THRESHOLD)
+                                              << PROD_CONS_PTR_OFF))) {
+               port->ip_flags &= ~INPUT_HIGH;
+               enable_intrs(port, hooks->intr_rx_high);
+       }
+       return total;
+}
+
+/**
+ * receive_chars - upper level read.
+ * @the_port: port to read from
+ */
+static int receive_chars(struct uart_port *the_port)
+{
+       struct tty_struct *tty;
+       unsigned char ch[MAX_CHARS];
+       int read_count = 0, read_room, flip = 0;
+       struct uart_state *state = the_port->state;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned long pflags;
+
+       /* Make sure all the pointers are "good" ones */
+       if (!state)
+               return 0;
+       if (!state->port.tty)
+               return 0;
+
+       if (!(port->ip_flags & INPUT_ENABLE))
+               return 0;
+
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = state->port.tty;
+
+       read_count = do_read(the_port, ch, MAX_CHARS);
+       if (read_count > 0) {
+               flip = 1;
+               read_room = tty_insert_flip_string(tty, ch, read_count);
+               the_port->icount.rx += read_count;
+       }
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
+       if (flip)
+               tty_flip_buffer_push(tty);
+
+       return read_count;
+}
+
+/**
+ * ioc3uart_intr_one - lowest level (per port) interrupt handler.
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ */
+
+static int inline
+ioc3uart_intr_one(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending)
+{
+       int port_num = GET_PORT_FROM_SIO_IR(pending);
+       struct port_hooks *hooks;
+       unsigned int rx_high_rd_aborted = 0;
+       unsigned long flags;
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int loop_counter;
+       struct ioc3_card *card_ptr;
+       unsigned int sio_ir;
+
+       card_ptr = idd->data[is->id];
+       port = card_ptr->ic_port[port_num].icp_port;
+       hooks = port->ip_hooks;
+
+       /* Possible race condition here: The tx_mt interrupt bit may be
+        * cleared without the intervention of the interrupt handler,
+        * e.g. by a write.  If the top level interrupt handler reads a
+        * tx_mt, then some other processor does a write, starting up
+        * output, then we come in here, see the tx_mt and stop DMA, the
+        * output started by the other processor will hang.  Thus we can
+        * only rely on tx_mt being legitimate if it is read while the
+        * port lock is held.  Therefore this bit must be ignored in the
+        * passed in interrupt mask which was read by the top level
+        * interrupt handler since the port lock was not held at the time
+        * it was read.  We can only rely on this bit being accurate if it
+        * is read while the port lock is held.  So we'll clear it for now,
+        * and reload it later once we have the port lock.
+        */
+
+       sio_ir = pending & ~(hooks->intr_tx_mt);
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       loop_counter = MAXITER; /* to avoid hangs */
+
+       do {
+               uint32_t shadow;
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on interrupt (line %d).\n",
+                               ((struct uart_port *)port->ip_port)->line);
+                       break;
+               }
+               /* Handle a DCD change */
+               if (sio_ir & hooks->intr_delta_dcd) {
+                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DDCD)
+                           && (shadow & SHADOW_DCD)
+                           && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_dcd_change(the_port,
+                                               shadow & SHADOW_DCD);
+                               wake_up_interruptible
+                                   (&the_port->state->port.delta_msr_wait);
+                       } else if ((port->ip_notify & N_DDCD)
+                                  && !(shadow & SHADOW_DCD)) {
+                               /* Flag delta DCD/no DCD */
+                               uart_handle_dcd_change(port->ip_port,
+                                               shadow & SHADOW_DCD);
+                               port->ip_flags |= DCD_ON;
+                       }
+               }
+
+               /* Handle a CTS change */
+               if (sio_ir & hooks->intr_delta_cts) {
+                       ioc3_ack(is, idd, hooks->intr_delta_cts);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_cts_change(the_port, shadow
+                                               & SHADOW_CTS);
+                               wake_up_interruptible
+                                   (&the_port->state->port.delta_msr_wait);
+                       }
+               }
+
+               /* rx timeout interrupt.  Must be some data available.  Put this
+                * before the check for rx_high since servicing this condition
+                * may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_rx_timer) {
+                       ioc3_ack(is, idd, hooks->intr_rx_timer);
+                       if ((port->ip_notify & N_DATA_READY)
+                                               && (port->ip_port)) {
+                               receive_chars(port->ip_port);
+                       }
+               }
+
+               /* rx high interrupt. Must be after rx_timer.  */
+               else if (sio_ir & hooks->intr_rx_high) {
+                       /* Data available, notify upper layer */
+                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
+                               receive_chars(port->ip_port);
+                       }
+
+                       /* We can't ACK this interrupt.  If receive_chars didn't
+                        * cause the condition to clear, we'll have to disable
+                        * the interrupt until the data is drained.
+                        * If the read was aborted, don't disable the interrupt
+                        * as this may cause us to hang indefinitely.  An
+                        * aborted read generally means that this interrupt
+                        * hasn't been delivered to the cpu yet anyway, even
+                        * though we see it as asserted when we read the sio_ir.
+                        */
+                       if ((sio_ir = PENDING(card_ptr, idd))
+                                       & hooks->intr_rx_high) {
+                               if (port->ip_flags & READ_ABORTED) {
+                                       rx_high_rd_aborted++;
+                               }
+                               else {
+                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
+                                       port->ip_flags |= INPUT_HIGH;
+                               }
+                       }
+               }
+
+               /* We got a low water interrupt: notify upper layer to
+                * send more data.  Must come before tx_mt since servicing
+                * this condition may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_tx_explicit) {
+                       port->ip_flags &= ~LOWAT_WRITTEN;
+                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
+                       if (port->ip_notify & N_OUTPUT_LOWAT)
+                               ioc3_cb_output_lowat(port);
+               }
+
+               /* Handle tx_mt.  Must come after tx_explicit.  */
+               else if (sio_ir & hooks->intr_tx_mt) {
+                       /* If we are expecting a lowat notification
+                        * and we get to this point it probably means that for
+                        * some reason the tx_explicit didn't work as expected
+                        * (that can legitimately happen if the output buffer is
+                        * filled up in just the right way).
+                        * So send the notification now.
+                        */
+                       if (port->ip_notify & N_OUTPUT_LOWAT) {
+                               ioc3_cb_output_lowat(port);
+
+                               /* We need to reload the sio_ir since the lowat
+                                * call may have caused another write to occur,
+                                * clearing the tx_mt condition.
+                                */
+                               sio_ir = PENDING(card_ptr, idd);
+                       }
+
+                       /* If the tx_mt condition still persists even after the
+                        * lowat call, we've got some work to do.
+                        */
+                       if (sio_ir & hooks->intr_tx_mt) {
+                               /* If we are not currently expecting DMA input,
+                                * and the transmitter has just gone idle,
+                                * there is no longer any reason for DMA, so
+                                * disable it.
+                                */
+                               if (!(port->ip_notify
+                                     & (N_DATA_READY | N_DDCD))) {
+                                       BUG_ON(!(port->ip_sscr
+                                                & SSCR_DMA_EN));
+                                       port->ip_sscr &= ~SSCR_DMA_EN;
+                                       writel(port->ip_sscr,
+                                              &port->ip_serial_regs->sscr);
+                               }
+                               /* Prevent infinite tx_mt interrupt */
+                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
+                       }
+               }
+               sio_ir = PENDING(card_ptr, idd);
+
+               /* if the read was aborted and only hooks->intr_rx_high,
+                * clear hooks->intr_rx_high, so we do not loop forever.
+                */
+
+               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+                       sio_ir &= ~hooks->intr_rx_high;
+               }
+       } while (sio_ir & hooks->intr_all);
+
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+       ioc3_enable(is, idd, card_ptr->ic_enable);
+       return 0;
+}
+
+/**
+ * ioc3uart_intr - field all serial interrupts
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ *
+ */
+
+static int ioc3uart_intr(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending)
+{
+       int ret = 0;
+
+       /*
+        * The upper level interrupt handler sends interrupts for both ports
+        * here. So we need to call for each port with its interrupts.
+        */
+
+       if (pending & SIO_IR_SA)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
+       if (pending & SIO_IR_SB)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
+
+       return ret;
+}
+
+/**
+ * ic3_type
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic3_type(struct uart_port *the_port)
+{
+       if (IS_RS232(the_port->line))
+               return "SGI IOC3 Serial [rs232]";
+       else
+               return "SGI IOC3 Serial [rs422]";
+}
+
+/**
+ * ic3_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic3_tx_empty(struct uart_port *the_port)
+{
+       unsigned int ret = 0;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
+               ret = TIOCSER_TEMT;
+       return ret;
+}
+
+/**
+ * ic3_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * ic3_stop_rx - stop the receiver
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_rx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               port->ip_flags &= ~INPUT_ENABLE;
+}
+
+/**
+ * null_void_function
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic3_shutdown - shut down the port - free irq and disable
+ * @port: port to shut down
+ *
+ */
+static void ic3_shutdown(struct uart_port *the_port)
+{
+       unsigned long port_flags;
+       struct ioc3_port *port;
+       struct uart_state *state;
+
+       port = get_ioc3_port(the_port);
+       if (!port)
+               return;
+
+       state = the_port->state;
+       wake_up_interruptible(&state->port.delta_msr_wait);
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       set_notification(port, N_ALL, 0);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       set_mcr(the_port, mcr, SHADOW_DTR);
+}
+
+/**
+ * ic3_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic3_get_mctrl(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       unsigned int ret = 0;
+
+       if (!port)
+               return 0;
+
+       shadow = readl(&port->ip_serial_regs->shadow);
+       if (shadow & SHADOW_DCD)
+               ret |= TIOCM_CD;
+       if (shadow & SHADOW_DR)
+               ret |= TIOCM_DSR;
+       if (shadow & SHADOW_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+/**
+ * ic3_start_tx - Start transmitter. Called with the_port->lock
+ * @port: Port to operate on
+ *
+ */
+static void ic3_start_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
+       }
+}
+
+/**
+ * ic3_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic3_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic3_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int ic3_startup(struct uart_port *the_port)
+{
+       int retval;
+       struct ioc3_port *port;
+       struct ioc3_card *card_ptr;
+       unsigned long port_flags;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       card_ptr = port->ip_card;
+       port->ip_port = the_port;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+
+       /* Start up the serial port */
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       retval = ic3_startup_local(the_port);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+       return retval;
+}
+
+/**
+ * ic3_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic3_set_termios(struct uart_port *the_port,
+               struct ktermios *termios, struct ktermios *old_termios)
+{
+       unsigned long port_flags;
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       ioc3_change_speed(the_port, termios, old_termios);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic3_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+static struct uart_ops ioc3_ops = {
+       .tx_empty = ic3_tx_empty,
+       .set_mctrl = ic3_set_mctrl,
+       .get_mctrl = ic3_get_mctrl,
+       .stop_tx = ic3_stop_tx,
+       .start_tx = ic3_start_tx,
+       .stop_rx = ic3_stop_rx,
+       .enable_ms = null_void_function,
+       .break_ctl = ic3_break_ctl,
+       .startup = ic3_startup,
+       .shutdown = ic3_shutdown,
+       .set_termios = ic3_set_termios,
+       .type = ic3_type,
+       .release_port = null_void_function,
+       .request_port = ic3_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc3_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "ioc3_serial",
+       .dev_name = DEVICE_NAME,
+       .major = DEVICE_MAJOR,
+       .minor = DEVICE_MINOR,
+       .nr = MAX_LOGICAL_PORTS
+};
+
+/**
+ * ioc3_serial_core_attach - register with serial core
+ *             This is done during pci probing
+ * @is: submodule struct for this
+ * @idd: handle for this card
+ */
+static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
+                               struct ioc3_driver_data *idd)
+{
+       struct ioc3_port *port;
+       struct uart_port *the_port;
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       int ii, phys_port;
+       struct pci_dev *pdev = idd->pdev;
+
+       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
+                      __func__, pdev, (void *)card_ptr));
+
+       if (!card_ptr)
+               return -ENODEV;
+
+       /* once around for each logical port on this card */
+       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+               phys_port = GET_PHYSICAL_PORT(ii);
+               the_port = &card_ptr->ic_port[phys_port].
+                               icp_uart_port[GET_LOGICAL_PORT(ii)];
+               port = card_ptr->ic_port[phys_port].icp_port;
+               port->ip_port = the_port;
+
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
+                       __func__, (void *)the_port, (void *)port,
+                               phys_port, ii));
+
+               /* membase, iobase and mapbase just need to be non-0 */
+               the_port->membase = (unsigned char __iomem *)1;
+               the_port->iobase = (pdev->bus->number << 16) |  ii;
+               the_port->line = (Num_of_ioc3_cards << 2) | ii;
+               the_port->mapbase = 1;
+               the_port->type = PORT_16550A;
+               the_port->fifosize = FIFO_SIZE;
+               the_port->ops = &ioc3_ops;
+               the_port->irq = idd->irq_io;
+               the_port->dev = &pdev->dev;
+
+               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
+                       printk(KERN_WARNING
+                         "%s: unable to add port %d bus %d\n",
+                              __func__, the_port->line, pdev->bus->number);
+               } else {
+                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
+                         the_port->line, the_port->irq, pdev->bus->number));
+               }
+
+               /* all ports are rs232 for now */
+               if (IS_PHYSICAL_PORT(ii))
+                       ioc3_set_proto(port, PROTO_RS232);
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_remove - register detach function
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this submodule
+ */
+
+static int ioc3uart_remove(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd)
+{
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int ii;
+
+       if (card_ptr) {
+               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
+                       if (the_port)
+                               uart_remove_one_port(&ioc3_uart, the_port);
+                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
+                       if (port && IS_PHYSICAL_PORT(ii)
+                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
+                               pci_free_consistent(port->ip_idd->pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       (void *)port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                               kfree(port);
+                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                                       icp_port = NULL;
+                       }
+               }
+               kfree(card_ptr);
+               idd->data[is->id] = NULL;
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_probe - card probe function called from shim driver
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this card
+ */
+
+static int __devinit
+ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+       struct pci_dev *pdev = idd->pdev;
+       struct ioc3_card *card_ptr;
+       int ret = 0;
+       struct ioc3_port *port;
+       struct ioc3_port *ports[PORTS_PER_CARD];
+       int phys_port;
+       int cnt;
+
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
+
+       card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
+       if (!card_ptr) {
+               printk(KERN_WARNING "ioc3_attach_one"
+                      ": unable to get memory for the IOC3\n");
+               return -ENOMEM;
+       }
+       idd->data[is->id] = card_ptr;
+       Submodule_slot = is->id;
+
+       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
+               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
+               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
+
+       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
+
+       /* Enable serial port mode select generic PIO pins as outputs */
+       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
+
+       /* Create port structures for each port */
+       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
+               port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
+               if (!port) {
+                       printk(KERN_WARNING
+                              "IOC3 serial memory not available for port\n");
+                       ret = -ENOMEM;
+                       goto out4;
+               }
+               spin_lock_init(&port->ip_lock);
+
+               /* we need to remember the previous ones, to point back to
+                * them farther down - setting up the ring buffers.
+                */
+               ports[phys_port] = port;
+
+               /* init to something useful */
+               card_ptr->ic_port[phys_port].icp_port = port;
+               port->ip_is = is;
+               port->ip_idd = idd;
+               port->ip_baud = 9600;
+               port->ip_card = card_ptr;
+               port->ip_hooks = &hooks_array[phys_port];
+
+               /* Setup each port */
+               if (phys_port == 0) {
+                       port->ip_serial_regs = &idd->vma->port_a;
+                       port->ip_uart_regs = &idd->vma->sregs.uarta;
+
+                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* setup ring buffers */
+                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
+                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
+
+                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
+                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
+                       port->ip_inring = RING(port, RX_A);
+                       port->ip_outring = RING(port, TX_A);
+                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+               else {
+                       port->ip_serial_regs = &idd->vma->port_b;
+                       port->ip_uart_regs = &idd->vma->sregs.uartb;
+
+                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* share the ring buffers */
+                       port->ip_dma_ringbuf =
+                           ports[phys_port - 1]->ip_dma_ringbuf;
+                       port->ip_cpu_ringbuf =
+                           ports[phys_port - 1]->ip_cpu_ringbuf;
+                       port->ip_inring = RING(port, RX_B);
+                       port->ip_outring = RING(port, TX_B);
+                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __func__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+
+               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
+                              __func__,
+                              phys_port, (void *)port, (void *)card_ptr));
+               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+                              (void *)port->ip_serial_regs,
+                              (void *)port->ip_uart_regs));
+
+               /* Initialize the hardware for IOC3 */
+               port_init(port);
+
+               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
+                              "outring 0x%p\n",
+                              __func__,
+                              phys_port, (void *)port,
+                              (void *)port->ip_inring,
+                              (void *)port->ip_outring));
+
+       }
+
+       /* register port with the serial core */
+
+       if ((ret = ioc3_serial_core_attach(is, idd)))
+               goto out4;
+
+       Num_of_ioc3_cards++;
+
+       return ret;
+
+       /* error exits that give back resources */
+out4:
+       for (cnt = 0; cnt < phys_port; cnt++)
+               kfree(ports[cnt]);
+
+       kfree(card_ptr);
+       return ret;
+}
+
+static struct ioc3_submodule ioc3uart_ops = {
+       .name = "IOC3uart",
+       .probe = ioc3uart_probe,
+       .remove = ioc3uart_remove,
+       /* call .intr for both ports initially */
+       .irq_mask = SIO_IR_SA | SIO_IR_SB,
+       .intr = ioc3uart_intr,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * ioc3_detect - module init called,
+ */
+static int __init ioc3uart_init(void)
+{
+       int ret;
+
+       /* register with serial core */
+       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
+               printk(KERN_WARNING
+                      "%s: Couldn't register IOC3 uart serial driver\n",
+                      __func__);
+               return ret;
+       }
+       ret = ioc3_register_submodule(&ioc3uart_ops);
+       if (ret)
+               uart_unregister_driver(&ioc3_uart);
+       return ret;
+}
+
+static void __exit ioc3uart_exit(void)
+{
+       ioc3_unregister_submodule(&ioc3uart_ops);
+       uart_unregister_driver(&ioc3_uart);
+}
+
+module_init(ioc3uart_init);
+module_exit(ioc3uart_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
new file mode 100644 (file)
index 0000000..fcfe826
--- /dev/null
@@ -0,0 +1,2953 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * This file contains a module version of the ioc4 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioc4.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+
+/*
+ * interesting things about the ioc4
+ */
+
+#define IOC4_NUM_SERIAL_PORTS  4       /* max ports per card */
+#define IOC4_NUM_CARDS         8       /* max cards per partition */
+
+#define        GET_SIO_IR(_n)  (_n == 0) ? (IOC4_SIO_IR_S0) : \
+                               (_n == 1) ? (IOC4_SIO_IR_S1) : \
+                               (_n == 2) ? (IOC4_SIO_IR_S2) : \
+                               (IOC4_SIO_IR_S3)
+
+#define        GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
+                               (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
+                               (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
+                               (IOC4_OTHER_IR_S3_MEMERR)
+
+
+/*
+ * All IOC4 registers are 32 bits wide.
+ */
+
+/*
+ * PCI Memory Space Map
+ */
+#define IOC4_PCI_ERR_ADDR_L     0x000  /* Low Error Address */
+#define IOC4_PCI_ERR_ADDR_VLD          (0x1 << 0)
+#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
+#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
+#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
+#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
+#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
+
+/* Interrupt types */
+#define        IOC4_SIO_INTR_TYPE      0
+#define        IOC4_OTHER_INTR_TYPE    1
+#define        IOC4_NUM_INTR_TYPES     2
+
+/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
+#define IOC4_SIO_IR_S0_TX_MT      0x00000001   /* Serial port 0 TX empty */
+#define IOC4_SIO_IR_S0_RX_FULL    0x00000002   /* Port 0 RX buf full */
+#define IOC4_SIO_IR_S0_RX_HIGH    0x00000004   /* Port 0 RX hiwat */
+#define IOC4_SIO_IR_S0_RX_TIMER           0x00000008   /* Port 0 RX timeout */
+#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010  /* Port 0 delta DCD */
+#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020  /* Port 0 delta CTS */
+#define IOC4_SIO_IR_S0_INT        0x00000040   /* Port 0 pass-thru intr */
+#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080  /* Port 0 explicit TX thru */
+#define IOC4_SIO_IR_S1_TX_MT      0x00000100   /* Serial port 1 */
+#define IOC4_SIO_IR_S1_RX_FULL    0x00000200   /* */
+#define IOC4_SIO_IR_S1_RX_HIGH    0x00000400   /* */
+#define IOC4_SIO_IR_S1_RX_TIMER           0x00000800   /* */
+#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000  /* */
+#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000  /* */
+#define IOC4_SIO_IR_S1_INT        0x00004000   /* */
+#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000  /* */
+#define IOC4_SIO_IR_S2_TX_MT      0x00010000   /* Serial port 2 */
+#define IOC4_SIO_IR_S2_RX_FULL    0x00020000   /* */
+#define IOC4_SIO_IR_S2_RX_HIGH    0x00040000   /* */
+#define IOC4_SIO_IR_S2_RX_TIMER           0x00080000   /* */
+#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000  /* */
+#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000  /* */
+#define IOC4_SIO_IR_S2_INT        0x00400000   /* */
+#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000  /* */
+#define IOC4_SIO_IR_S3_TX_MT      0x01000000   /* Serial port 3 */
+#define IOC4_SIO_IR_S3_RX_FULL    0x02000000   /* */
+#define IOC4_SIO_IR_S3_RX_HIGH    0x04000000   /* */
+#define IOC4_SIO_IR_S3_RX_TIMER           0x08000000   /* */
+#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000  /* */
+#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000  /* */
+#define IOC4_SIO_IR_S3_INT        0x40000000   /* */
+#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000  /* */
+
+/* Per device interrupt masks */
+#define IOC4_SIO_IR_S0         (IOC4_SIO_IR_S0_TX_MT | \
+                                IOC4_SIO_IR_S0_RX_FULL | \
+                                IOC4_SIO_IR_S0_RX_HIGH | \
+                                IOC4_SIO_IR_S0_RX_TIMER | \
+                                IOC4_SIO_IR_S0_DELTA_DCD | \
+                                IOC4_SIO_IR_S0_DELTA_CTS | \
+                                IOC4_SIO_IR_S0_INT | \
+                                IOC4_SIO_IR_S0_TX_EXPLICIT)
+#define IOC4_SIO_IR_S1         (IOC4_SIO_IR_S1_TX_MT | \
+                                IOC4_SIO_IR_S1_RX_FULL | \
+                                IOC4_SIO_IR_S1_RX_HIGH | \
+                                IOC4_SIO_IR_S1_RX_TIMER | \
+                                IOC4_SIO_IR_S1_DELTA_DCD | \
+                                IOC4_SIO_IR_S1_DELTA_CTS | \
+                                IOC4_SIO_IR_S1_INT | \
+                                IOC4_SIO_IR_S1_TX_EXPLICIT)
+#define IOC4_SIO_IR_S2         (IOC4_SIO_IR_S2_TX_MT | \
+                                IOC4_SIO_IR_S2_RX_FULL | \
+                                IOC4_SIO_IR_S2_RX_HIGH | \
+                                IOC4_SIO_IR_S2_RX_TIMER | \
+                                IOC4_SIO_IR_S2_DELTA_DCD | \
+                                IOC4_SIO_IR_S2_DELTA_CTS | \
+                                IOC4_SIO_IR_S2_INT | \
+                                IOC4_SIO_IR_S2_TX_EXPLICIT)
+#define IOC4_SIO_IR_S3         (IOC4_SIO_IR_S3_TX_MT | \
+                                IOC4_SIO_IR_S3_RX_FULL | \
+                                IOC4_SIO_IR_S3_RX_HIGH | \
+                                IOC4_SIO_IR_S3_RX_TIMER | \
+                                IOC4_SIO_IR_S3_DELTA_DCD | \
+                                IOC4_SIO_IR_S3_DELTA_CTS | \
+                                IOC4_SIO_IR_S3_INT | \
+                                IOC4_SIO_IR_S3_TX_EXPLICIT)
+
+/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
+#define IOC4_OTHER_IR_ATA_INT          0x00000001  /* ATAPI intr pass-thru */
+#define IOC4_OTHER_IR_ATA_MEMERR       0x00000002  /* ATAPI DMA PCI error */
+#define IOC4_OTHER_IR_S0_MEMERR                0x00000004  /* Port 0 PCI error */
+#define IOC4_OTHER_IR_S1_MEMERR                0x00000008  /* Port 1 PCI error */
+#define IOC4_OTHER_IR_S2_MEMERR                0x00000010  /* Port 2 PCI error */
+#define IOC4_OTHER_IR_S3_MEMERR                0x00000020  /* Port 3 PCI error */
+#define IOC4_OTHER_IR_KBD_INT          0x00000040  /* Keyboard/mouse */
+#define IOC4_OTHER_IR_RESERVED         0x007fff80  /* Reserved */
+#define IOC4_OTHER_IR_RT_INT           0x00800000  /* INT_OUT section output */
+#define IOC4_OTHER_IR_GEN_INT          0xff000000  /* Generic pins */
+
+#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
+                                 IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
+
+/* Bitmasks for IOC4_SIO_CR */
+#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
+#define IOC4_SIO_CR_ARB_DIAG_TX0       0x00000000
+#define IOC4_SIO_CR_ARB_DIAG_RX0       0x00000010
+#define IOC4_SIO_CR_ARB_DIAG_TX1       0x00000020
+#define IOC4_SIO_CR_ARB_DIAG_RX1       0x00000030
+#define IOC4_SIO_CR_ARB_DIAG_TX2       0x00000040
+#define IOC4_SIO_CR_ARB_DIAG_RX2       0x00000050
+#define IOC4_SIO_CR_ARB_DIAG_TX3       0x00000060
+#define IOC4_SIO_CR_ARB_DIAG_RX3       0x00000070
+#define IOC4_SIO_CR_SIO_DIAG_IDLE      0x00000080  /* 0 -> active request among
+                                                          serial ports (ro) */
+/* Defs for some of the generic I/O pins */
+#define IOC4_GPCR_UART0_MODESEL           0x10 /* Pin is output to port 0
+                                                  mode sel */
+#define IOC4_GPCR_UART1_MODESEL           0x20 /* Pin is output to port 1
+                                                  mode sel */
+#define IOC4_GPCR_UART2_MODESEL           0x40 /* Pin is output to port 2
+                                                  mode sel */
+#define IOC4_GPCR_UART3_MODESEL           0x80 /* Pin is output to port 3
+                                                  mode sel */
+
+#define IOC4_GPPR_UART0_MODESEL_PIN   4        /* GIO pin controlling
+                                          uart 0 mode select */
+#define IOC4_GPPR_UART1_MODESEL_PIN   5        /* GIO pin controlling
+                                          uart 1 mode select */
+#define IOC4_GPPR_UART2_MODESEL_PIN   6        /* GIO pin controlling
+                                          uart 2 mode select */
+#define IOC4_GPPR_UART3_MODESEL_PIN   7        /* GIO pin controlling
+                                          uart 3 mode select */
+
+/* Bitmasks for serial RX status byte */
+#define IOC4_RXSB_OVERRUN       0x01   /* Char(s) lost */
+#define IOC4_RXSB_PAR_ERR      0x02    /* Parity error */
+#define IOC4_RXSB_FRAME_ERR    0x04    /* Framing error */
+#define IOC4_RXSB_BREAK                0x08    /* Break character */
+#define IOC4_RXSB_CTS          0x10    /* State of CTS */
+#define IOC4_RXSB_DCD          0x20    /* State of DCD */
+#define IOC4_RXSB_MODEM_VALID   0x40   /* DCD, CTS, and OVERRUN are valid */
+#define IOC4_RXSB_DATA_VALID    0x80   /* Data byte, FRAME_ERR PAR_ERR
+                                        * & BREAK valid */
+
+/* Bitmasks for serial TX control byte */
+#define IOC4_TXCB_INT_WHEN_DONE 0x20   /* Interrupt after this byte is sent */
+#define IOC4_TXCB_INVALID      0x00    /* Byte is invalid */
+#define IOC4_TXCB_VALID                0x40    /* Byte is valid */
+#define IOC4_TXCB_MCR          0x80    /* Data<7:0> to modem control reg */
+#define IOC4_TXCB_DELAY                0xc0    /* Delay data<7:0> mSec */
+
+/* Bitmasks for IOC4_SBBR_L */
+#define IOC4_SBBR_L_SIZE       0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
+
+/* Bitmasks for IOC4_SSCR_<3:0> */
+#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
+#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
+#define IOC4_SSCR_HFC_EN       0x00020000  /* Hardware flow control enabled */
+#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
+#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
+#define IOC4_SSCR_DIAG         0x00200000  /* Bypass clock divider for sim */
+#define IOC4_SSCR_RX_DRAIN     0x08000000  /* Drain RX buffer to memory */
+#define IOC4_SSCR_DMA_EN       0x10000000  /* Enable ring buffer DMA */
+#define IOC4_SSCR_DMA_PAUSE    0x20000000  /* Pause DMA */
+#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
+#define IOC4_SSCR_RESET                0x80000000  /* Reset DMA channels */
+
+/* All producer/comsumer pointers are the same bitfield */
+#define IOC4_PROD_CONS_PTR_4K   0x00000ff8     /* For 4K buffers */
+#define IOC4_PROD_CONS_PTR_1K   0x000003f8     /* For 1K buffers */
+#define IOC4_PROD_CONS_PTR_OFF           3
+
+/* Bitmasks for IOC4_SRCIR_<3:0> */
+#define IOC4_SRCIR_ARM         0x80000000      /* Arm RX timer */
+
+/* Bitmasks for IOC4_SHADOW_<3:0> */
+#define IOC4_SHADOW_DR  0x00000001     /* Data ready */
+#define IOC4_SHADOW_OE  0x00000002     /* Overrun error */
+#define IOC4_SHADOW_PE  0x00000004     /* Parity error */
+#define IOC4_SHADOW_FE  0x00000008     /* Framing error */
+#define IOC4_SHADOW_BI  0x00000010     /* Break interrupt */
+#define IOC4_SHADOW_THRE 0x00000020    /* Xmit holding register empty */
+#define IOC4_SHADOW_TEMT 0x00000040    /* Xmit shift register empty */
+#define IOC4_SHADOW_RFCE 0x00000080    /* Char in RX fifo has an error */
+#define IOC4_SHADOW_DCTS 0x00010000    /* Delta clear to send */
+#define IOC4_SHADOW_DDCD 0x00080000    /* Delta data carrier detect */
+#define IOC4_SHADOW_CTS         0x00100000     /* Clear to send */
+#define IOC4_SHADOW_DCD         0x00800000     /* Data carrier detect */
+#define IOC4_SHADOW_DTR         0x01000000     /* Data terminal ready */
+#define IOC4_SHADOW_RTS         0x02000000     /* Request to send */
+#define IOC4_SHADOW_OUT1 0x04000000    /* 16550 OUT1 bit */
+#define IOC4_SHADOW_OUT2 0x08000000    /* 16550 OUT2 bit */
+#define IOC4_SHADOW_LOOP 0x10000000    /* Loopback enabled */
+
+/* Bitmasks for IOC4_SRTR_<3:0> */
+#define IOC4_SRTR_CNT          0x00000fff      /* Reload value for RX timer */
+#define IOC4_SRTR_CNT_VAL      0x0fff0000      /* Current value of RX timer */
+#define IOC4_SRTR_CNT_VAL_SHIFT         16
+#define IOC4_SRTR_HZ                 16000     /* SRTR clock frequency */
+
+/* Serial port register map used for DMA and PIO serial I/O */
+struct ioc4_serialregs {
+       uint32_t sscr;
+       uint32_t stpir;
+       uint32_t stcir;
+       uint32_t srpir;
+       uint32_t srcir;
+       uint32_t srtr;
+       uint32_t shadow;
+};
+
+/* IOC4 UART register map */
+struct ioc4_uartregs {
+       char i4u_lcr;
+       union {
+               char iir;       /* read only */
+               char fcr;       /* write only */
+       } u3;
+       union {
+               char ier;       /* DLAB == 0 */
+               char dlm;       /* DLAB == 1 */
+       } u2;
+       union {
+               char rbr;       /* read only, DLAB == 0 */
+               char thr;       /* write only, DLAB == 0 */
+               char dll;       /* DLAB == 1 */
+       } u1;
+       char i4u_scr;
+       char i4u_msr;
+       char i4u_lsr;
+       char i4u_mcr;
+};
+
+/* short names */
+#define i4u_dll u1.dll
+#define i4u_ier u2.ier
+#define i4u_dlm u2.dlm
+#define i4u_fcr u3.fcr
+
+/* Serial port registers used for DMA serial I/O */
+struct ioc4_serial {
+       uint32_t sbbr01_l;
+       uint32_t sbbr01_h;
+       uint32_t sbbr23_l;
+       uint32_t sbbr23_h;
+
+       struct ioc4_serialregs port_0;
+       struct ioc4_serialregs port_1;
+       struct ioc4_serialregs port_2;
+       struct ioc4_serialregs port_3;
+       struct ioc4_uartregs uart_0;
+       struct ioc4_uartregs uart_1;
+       struct ioc4_uartregs uart_2;
+       struct ioc4_uartregs uart_3;
+} ioc4_serial;
+
+/* UART clock speed */
+#define IOC4_SER_XIN_CLK_66     66666667
+#define IOC4_SER_XIN_CLK_33     33333333
+
+#define IOC4_W_IES             0
+#define IOC4_W_IEC             1
+
+typedef void ioc4_intr_func_f(void *, uint32_t);
+typedef ioc4_intr_func_f *ioc4_intr_func_t;
+
+static unsigned int Num_of_ioc4_cards;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)   ;
+//#define DPRINT_CONFIG(_x...) printk _x
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS   256
+
+/* number of characters we want to transmit to the lower level at a time */
+#define IOC4_MAX_CHARS 256
+#define IOC4_FIFO_CHARS        255
+
+/* Device name we're using */
+#define DEVICE_NAME_RS232  "ttyIOC"
+#define DEVICE_NAME_RS422  "ttyAIOC"
+#define DEVICE_MAJOR      204
+#define DEVICE_MINOR_RS232 50
+#define DEVICE_MINOR_RS422 84
+
+
+/* register offsets */
+#define IOC4_SERIAL_OFFSET     0x300
+
+/* flags for next_char_state */
+#define NCS_BREAK      0x1
+#define NCS_PARITY     0x2
+#define NCS_FRAMING    0x4
+#define NCS_OVERRUN    0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED     1200
+#define MAX_BAUD_SUPPORTED     115200
+
+/* protocol types supported */
+#define PROTO_RS232    3
+#define PROTO_RS422    7
+
+/* Notification types */
+#define N_DATA_READY   0x01
+#define N_OUTPUT_LOWAT 0x02
+#define N_BREAK                0x04
+#define N_PARITY_ERROR 0x08
+#define N_FRAMING_ERROR        0x10
+#define N_OVERRUN_ERROR        0x20
+#define N_DDCD         0x40
+#define N_DCTS         0x80
+
+#define N_ALL_INPUT    (N_DATA_READY | N_BREAK |                       \
+                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
+                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT   N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS   (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
+
+#define N_ALL          (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |      \
+                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
+                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_DIVISOR(_x, clk)           (((clk) + (_x) * 8) / ((_x) * 16))
+#define DIVISOR_TO_BAUD(div, clk)      ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
+
+#define PENDING(_p)    (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
+#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
+
+/* Default to 4k buffers */
+#ifdef IOC4_1K_BUFFERS
+#define RING_BUF_SIZE 1024
+#define IOC4_BUF_SIZE_BIT 0
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
+#else
+#define RING_BUF_SIZE 4096
+#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
+#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
+#endif
+
+#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
+
+/*
+ * This is the entry saved by the driver - one per card
+ */
+
+#define UART_PORT_MIN          0
+#define UART_PORT_RS232                UART_PORT_MIN
+#define UART_PORT_RS422                1
+#define UART_PORT_COUNT                2       /* one for each mode */
+
+struct ioc4_control {
+       int ic_irq;
+       struct {
+               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
+               struct uart_port icp_uart_port[UART_PORT_COUNT];
+               /* Handy reference material */
+               struct ioc4_port *icp_port;
+       } ic_port[IOC4_NUM_SERIAL_PORTS];
+       struct ioc4_soft *ic_soft;
+};
+
+/*
+ * per-IOC4 data structure
+ */
+#define MAX_IOC4_INTR_ENTS     (8 * sizeof(uint32_t))
+struct ioc4_soft {
+       struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
+       struct ioc4_serial __iomem *is_ioc4_serial_addr;
+
+       /* Each interrupt type has an entry in the array */
+       struct ioc4_intr_type {
+
+               /*
+                * Each in-use entry in this array contains at least
+                * one nonzero bit in sd_bits; no two entries in this
+                * array have overlapping sd_bits values.
+                */
+               struct ioc4_intr_info {
+                       uint32_t sd_bits;
+                       ioc4_intr_func_f *sd_intr;
+                       void *sd_info;
+               } is_intr_info[MAX_IOC4_INTR_ENTS];
+
+               /* Number of entries active in the above array */
+               atomic_t is_num_intrs;
+       } is_intr_type[IOC4_NUM_INTR_TYPES];
+
+       /* is_ir_lock must be held while
+        * modifying sio_ie values, so
+        * we can be sure that sio_ie is
+        * not changing when we read it
+        * along with sio_ir.
+        */
+       spinlock_t is_ir_lock;  /* SIO_IE[SC] mod lock */
+};
+
+/* Local port info for each IOC4 serial ports */
+struct ioc4_port {
+       struct uart_port *ip_port;      /* current active port ptr */
+       /* Ptrs for all ports */
+       struct uart_port *ip_all_ports[UART_PORT_COUNT];
+       /* Back ptrs for this port */
+       struct ioc4_control *ip_control;
+       struct pci_dev *ip_pdev;
+       struct ioc4_soft *ip_ioc4_soft;
+
+       /* pci mem addresses */
+       struct ioc4_misc_regs __iomem *ip_mem;
+       struct ioc4_serial __iomem *ip_serial;
+       struct ioc4_serialregs __iomem *ip_serial_regs;
+       struct ioc4_uartregs __iomem *ip_uart_regs;
+
+       /* Ring buffer page for this port */
+       dma_addr_t ip_dma_ringbuf;
+       /* vaddr of ring buffer */
+       struct ring_buffer *ip_cpu_ringbuf;
+
+       /* Rings for this port */
+       struct ring *ip_inring;
+       struct ring *ip_outring;
+
+       /* Hook to port specific values */
+       struct hooks *ip_hooks;
+
+       spinlock_t ip_lock;
+
+       /* Various rx/tx parameters */
+       int ip_baud;
+       int ip_tx_lowat;
+       int ip_rx_timeout;
+
+       /* Copy of notification bits */
+       int ip_notify;
+
+       /* Shadow copies of various registers so we don't need to PIO
+        * read them constantly
+        */
+       uint32_t ip_ienb;       /* Enabled interrupts */
+       uint32_t ip_sscr;
+       uint32_t ip_tx_prod;
+       uint32_t ip_rx_cons;
+       int ip_pci_bus_speed;
+       unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH     0x01
+#define DCD_ON         0x02
+#define LOWAT_WRITTEN  0x04
+#define READ_ABORTED   0x08
+#define PORT_ACTIVE    0x10
+#define PORT_INACTIVE  0       /* This is the value when "off" */
+
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct hooks {
+       uint32_t intr_delta_dcd;
+       uint32_t intr_delta_cts;
+       uint32_t intr_tx_mt;
+       uint32_t intr_rx_timer;
+       uint32_t intr_rx_high;
+       uint32_t intr_tx_explicit;
+       uint32_t intr_dma_error;
+       uint32_t intr_clear;
+       uint32_t intr_all;
+       int rs422_select_pin;
+};
+
+static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
+       /* Values for port 0 */
+       {
+        IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
+        IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
+        IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
+        IOC4_OTHER_IR_S0_MEMERR,
+        (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
+         IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
+         IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
+         IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
+        IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
+        },
+
+       /* Values for port 1 */
+       {
+        IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
+        IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
+        IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
+        IOC4_OTHER_IR_S1_MEMERR,
+        (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
+         IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
+         IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
+         IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
+        IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
+        },
+
+       /* Values for port 2 */
+       {
+        IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
+        IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
+        IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
+        IOC4_OTHER_IR_S2_MEMERR,
+        (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
+         IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
+         IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
+         IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
+        IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
+        },
+
+       /* Values for port 3 */
+       {
+        IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
+        IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
+        IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
+        IOC4_OTHER_IR_S3_MEMERR,
+        (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
+         IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
+         IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
+         IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
+        IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
+        }
+};
+
+/* A ring buffer entry */
+struct ring_entry {
+       union {
+               struct {
+                       uint32_t alldata;
+                       uint32_t allsc;
+               } all;
+               struct {
+                       char data[4];   /* data bytes */
+                       char sc[4];     /* status/control */
+               } s;
+       } u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+       ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc     u.s.sc
+#define ring_data   u.s.data
+#define ring_allsc  u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+       struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+       struct ring TX_0_OR_2;
+       struct ring RX_0_OR_2;
+       struct ring TX_1_OR_3;
+       struct ring RX_1_OR_3;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* Infinite loop detection.
+ */
+#define MAXITER 10000000
+
+/* Prototypes */
+static void receive_chars(struct uart_port *);
+static void handle_intr(void *arg, uint32_t sio_ir);
+
+/*
+ * port_is_active - determines if this port is currently active
+ * @port: ptr to soft struct for this port
+ * @uart_port: uart port to test for
+ */
+static inline int port_is_active(struct ioc4_port *port,
+               struct uart_port *uart_port)
+{
+       if (port) {
+               if ((port->ip_flags & PORT_ACTIVE)
+                                       && (port->ip_port == uart_port))
+                       return 1;
+       }
+       return 0;
+}
+
+
+/**
+ * write_ireg - write the interrupt regs
+ * @ioc4_soft: ptr to soft struct for this port
+ * @val: value to write
+ * @which: which register
+ * @type: which ireg set
+ */
+static inline void
+write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
+{
+       struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
+
+       switch (type) {
+       case IOC4_SIO_INTR_TYPE:
+               switch (which) {
+               case IOC4_W_IES:
+                       writel(val, &mem->sio_ies.raw);
+                       break;
+
+               case IOC4_W_IEC:
+                       writel(val, &mem->sio_iec.raw);
+                       break;
+               }
+               break;
+
+       case IOC4_OTHER_INTR_TYPE:
+               switch (which) {
+               case IOC4_W_IES:
+                       writel(val, &mem->other_ies.raw);
+                       break;
+
+               case IOC4_W_IEC:
+                       writel(val, &mem->other_iec.raw);
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
+}
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc4_port *port, int baud)
+{
+       int actual_baud;
+       int diff;
+       int lcr;
+       unsigned short divisor;
+       struct ioc4_uartregs __iomem *uart;
+
+       divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
+       if (!divisor)
+               return 1;
+       actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
+
+       diff = actual_baud - baud;
+       if (diff < 0)
+               diff = -diff;
+
+       /* If we're within 1%, we've found a match */
+       if (diff * 100 > actual_baud)
+               return 1;
+
+       uart = port->ip_uart_regs;
+       lcr = readb(&uart->i4u_lcr);
+       writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
+       writeb((unsigned char)divisor, &uart->i4u_dll);
+       writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
+       writeb(lcr, &uart->i4u_lcr);
+       return 0;
+}
+
+
+/**
+ * get_ioc4_port - given a uart port, return the control structure
+ * @port: uart port
+ * @set: set this port as current
+ */
+static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
+{
+       struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
+       struct ioc4_control *control = idd->idd_serial_data;
+       struct ioc4_port *port;
+       int port_num, port_type;
+
+       if (control) {
+               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
+                                                       port_num++ ) {
+                       port = control->ic_port[port_num].icp_port;
+                       if (!port)
+                               continue;
+                       for (port_type = UART_PORT_MIN;
+                                               port_type < UART_PORT_COUNT;
+                                               port_type++) {
+                               if (the_port == port->ip_all_ports
+                                                       [port_type]) {
+                                       /* set local copy */
+                                       if (set) {
+                                               port->ip_port = the_port;
+                                       }
+                                       return port;
+                               }
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* The IOC4 hardware provides no atomic way to determine if interrupts
+ * are pending since two reads are required to do so.  The handler must
+ * read the SIO_IR and the SIO_IES, and take the logical and of the
+ * two.  When this value is zero, all interrupts have been serviced and
+ * the handler may return.
+ *
+ * This has the unfortunate "hole" that, if some other CPU or
+ * some other thread or some higher level interrupt manages to
+ * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
+ * think we have observed SIO_IR&SIO_IE==0 when in fact this
+ * condition never really occurred.
+ *
+ * To solve this, we use a simple spinlock that must be held
+ * whenever modifying SIO_IE; holding this lock while observing
+ * both SIO_IR and SIO_IE guarantees that we do not falsely
+ * conclude that no enabled interrupts are pending.
+ */
+
+static inline uint32_t
+pending_intrs(struct ioc4_soft *soft, int type)
+{
+       struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
+       unsigned long flag;
+       uint32_t intrs = 0;
+
+       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+              || (type == IOC4_OTHER_INTR_TYPE)));
+
+       spin_lock_irqsave(&soft->is_ir_lock, flag);
+
+       switch (type) {
+       case IOC4_SIO_INTR_TYPE:
+               intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
+               break;
+
+       case IOC4_OTHER_INTR_TYPE:
+               intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
+
+               /* Don't process any ATA interrupte */
+               intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+               break;
+
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+       return intrs;
+}
+
+/**
+ * port_init - Initialize the sio and ioc4 hardware for a given port
+ *                     called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc4_port *port)
+{
+       uint32_t sio_cr;
+       struct hooks *hooks = port->ip_hooks;
+       struct ioc4_uartregs __iomem *uart;
+
+       /* Idle the IOC4 serial interface */
+       writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
+
+       /* Wait until any pending bus activity for this port has ceased */
+       do
+               sio_cr = readl(&port->ip_mem->sio_cr.raw);
+       while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
+
+       /* Finish reset sequence */
+       writel(0, &port->ip_serial_regs->sscr);
+
+       /* Once RESET is done, reload cached tx_prod and rx_cons values
+        * and set rings to empty by making prod == cons
+        */
+       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       /* Disable interrupts for this 16550 */
+       uart = port->ip_uart_regs;
+       writeb(0, &uart->i4u_lcr);
+       writeb(0, &uart->i4u_ier);
+
+       /* Set the default baud */
+       set_baud(port, port->ip_baud);
+
+       /* Set line control to 8 bits no parity */
+       writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
+                                       /* UART_LCR_STOP == 1 stop */
+
+       /* Enable the FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
+       /* then reset 16550 FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+                       &uart->i4u_fcr);
+
+       /* Clear modem control register */
+       writeb(0, &uart->i4u_mcr);
+
+       /* Clear deltas in modem status register */
+       readb(&uart->i4u_msr);
+
+       /* Only do this once per port pair */
+       if (port->ip_hooks == &hooks_array[0]
+                           || port->ip_hooks == &hooks_array[2]) {
+               unsigned long ring_pci_addr;
+               uint32_t __iomem *sbbr_l;
+               uint32_t __iomem *sbbr_h;
+
+               if (port->ip_hooks == &hooks_array[0]) {
+                       sbbr_l = &port->ip_serial->sbbr01_l;
+                       sbbr_h = &port->ip_serial->sbbr01_h;
+               } else {
+                       sbbr_l = &port->ip_serial->sbbr23_l;
+                       sbbr_h = &port->ip_serial->sbbr23_h;
+               }
+
+               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+               DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
+                                       __func__, ring_pci_addr));
+
+               writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
+               writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
+       }
+
+       /* Set the receive timeout value to 10 msec */
+       writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+       /* Set rx threshold, enable DMA */
+       /* Set high water mark at 3/4 of full ring */
+       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Disable and clear all serial related interrupt bits */
+       write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
+                      IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+       port->ip_ienb &= ~hooks->intr_clear;
+       writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
+       return 0;
+}
+
+/**
+ * handle_dma_error_intr - service any pending DMA error interrupts for the
+ *                     given port - 2nd level called via sd_intr
+ * @arg: handler arg
+ * @other_ir: ioc4regs
+ */
+static void handle_dma_error_intr(void *arg, uint32_t other_ir)
+{
+       struct ioc4_port *port = (struct ioc4_port *)arg;
+       struct hooks *hooks = port->ip_hooks;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       /* ACK the interrupt */
+       writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
+
+       if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
+               printk(KERN_ERR
+                       "PCI error address is 0x%llx, "
+                               "master is serial port %c %s\n",
+                    (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
+                                                        << 32)
+                               | readl(&port->ip_mem->pci_err_addr_l.raw))
+                                       & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
+                    ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
+                            IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
+                    (readl(&port->ip_mem->pci_err_addr_l.raw)
+                               & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
+                               ? "RX" : "TX");
+
+               if (readl(&port->ip_mem->pci_err_addr_l.raw)
+                                               & IOC4_PCI_ERR_ADDR_MUL_ERR) {
+                       printk(KERN_ERR
+                               "Multiple errors occurred\n");
+               }
+       }
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+
+       /* Re-enable DMA error interrupts */
+       write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
+                                               IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * intr_connect - interrupt connect function
+ * @soft: soft struct for this card
+ * @type: interrupt type
+ * @intrbits: bit pattern to set
+ * @intr: handler function
+ * @info: handler arg
+ */
+static void
+intr_connect(struct ioc4_soft *soft, int type,
+                 uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
+{
+       int i;
+       struct ioc4_intr_info *intr_ptr;
+
+       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
+              || (type == IOC4_OTHER_INTR_TYPE)));
+
+       i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
+       BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
+
+       /* Save off the lower level interrupt handler */
+       intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
+       intr_ptr->sd_bits = intrbits;
+       intr_ptr->sd_intr = intr;
+       intr_ptr->sd_info = info;
+}
+
+/**
+ * ioc4_intr - Top level IOC4 interrupt handler.
+ * @irq: irq value
+ * @arg: handler arg
+ */
+
+static irqreturn_t ioc4_intr(int irq, void *arg)
+{
+       struct ioc4_soft *soft;
+       uint32_t this_ir, this_mir;
+       int xx, num_intrs = 0;
+       int intr_type;
+       int handled = 0;
+       struct ioc4_intr_info *intr_info;
+
+       soft = arg;
+       for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
+               num_intrs = (int)atomic_read(
+                               &soft->is_intr_type[intr_type].is_num_intrs);
+
+               this_mir = this_ir = pending_intrs(soft, intr_type);
+
+               /* Farm out the interrupt to the various drivers depending on
+                * which interrupt bits are set.
+                */
+               for (xx = 0; xx < num_intrs; xx++) {
+                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
+                       if ((this_mir = this_ir & intr_info->sd_bits)) {
+                               /* Disable owned interrupts, call handler */
+                               handled++;
+                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
+                                                               intr_type);
+                               intr_info->sd_intr(intr_info->sd_info, this_mir);
+                               this_ir &= ~this_mir;
+                       }
+               }
+       }
+#ifdef DEBUG_INTERRUPTS
+       {
+               struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
+               unsigned long flag;
+
+               spin_lock_irqsave(&soft->is_ir_lock, flag);
+               printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
+                               "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
+                    __func__, __LINE__,
+                    (void *)mem, readl(&mem->sio_ir.raw),
+                    readl(&mem->sio_ies.raw),
+                    readl(&mem->other_ir.raw),
+                    readl(&mem->other_ies.raw),
+                    IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
+               spin_unlock_irqrestore(&soft->is_ir_lock, flag);
+       }
+#endif
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * ioc4_attach_local - Device initialization.
+ *                     Called at *_attach() time for each
+ *                     IOC4 with serial ports in the system.
+ * @idd: Master module data for this IOC4
+ */
+static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
+{
+       struct ioc4_port *port;
+       struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
+       int port_number;
+       uint16_t ioc4_revid_min = 62;
+       uint16_t ioc4_revid;
+       struct pci_dev *pdev = idd->idd_pdev;
+       struct ioc4_control* control = idd->idd_serial_data;
+       struct ioc4_soft *soft = control->ic_soft;
+       void __iomem *ioc4_misc = idd->idd_misc_regs;
+       void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
+
+       /* IOC4 firmware must be at least rev 62 */
+       pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
+
+       printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
+       if (ioc4_revid < ioc4_revid_min) {
+               printk(KERN_WARNING
+                   "IOC4 serial not supported on firmware rev %d, "
+                               "please upgrade to rev %d or higher\n",
+                               ioc4_revid, ioc4_revid_min);
+               return -EPERM;
+       }
+       BUG_ON(ioc4_misc == NULL);
+       BUG_ON(ioc4_serial == NULL);
+
+       /* Create port structures for each port */
+       for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
+                                                       port_number++) {
+               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
+               if (!port) {
+                       printk(KERN_WARNING
+                               "IOC4 serial memory not available for port\n");
+                       return -ENOMEM;
+               }
+               spin_lock_init(&port->ip_lock);
+
+               /* we need to remember the previous ones, to point back to
+                * them farther down - setting up the ring buffers.
+                */
+               ports[port_number] = port;
+
+               /* Allocate buffers and jumpstart the hardware.  */
+               control->ic_port[port_number].icp_port = port;
+               port->ip_ioc4_soft = soft;
+               port->ip_pdev = pdev;
+               port->ip_ienb = 0;
+               /* Use baud rate calculations based on detected PCI
+                * bus speed.  Simply test whether the PCI clock is
+                * running closer to 66MHz or 33MHz.
+                */
+               if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
+                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
+               } else {
+                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
+               }
+               port->ip_baud = 9600;
+               port->ip_control = control;
+               port->ip_mem = ioc4_misc;
+               port->ip_serial = ioc4_serial;
+
+               /* point to the right hook */
+               port->ip_hooks = &hooks_array[port_number];
+
+               /* Get direct hooks to the serial regs and uart regs
+                * for this port
+                */
+               switch (port_number) {
+               case 0:
+                       port->ip_serial_regs = &(port->ip_serial->port_0);
+                       port->ip_uart_regs = &(port->ip_serial->uart_0);
+                       break;
+               case 1:
+                       port->ip_serial_regs = &(port->ip_serial->port_1);
+                       port->ip_uart_regs = &(port->ip_serial->uart_1);
+                       break;
+               case 2:
+                       port->ip_serial_regs = &(port->ip_serial->port_2);
+                       port->ip_uart_regs = &(port->ip_serial->uart_2);
+                       break;
+               default:
+               case 3:
+                       port->ip_serial_regs = &(port->ip_serial->port_3);
+                       port->ip_uart_regs = &(port->ip_serial->uart_3);
+                       break;
+               }
+
+               /* ring buffers are 1 to a pair of ports */
+               if (port_number && (port_number & 1)) {
+                       /* odd use the evens buffer */
+                       port->ip_dma_ringbuf =
+                                       ports[port_number - 1]->ip_dma_ringbuf;
+                       port->ip_cpu_ringbuf =
+                                       ports[port_number - 1]->ip_cpu_ringbuf;
+                       port->ip_inring = RING(port, RX_1_OR_3);
+                       port->ip_outring = RING(port, TX_1_OR_3);
+
+               } else {
+                       if (port->ip_dma_ringbuf == 0) {
+                               port->ip_cpu_ringbuf = pci_alloc_consistent
+                                       (pdev, TOTAL_RING_BUF_SIZE,
+                                       &port->ip_dma_ringbuf);
+
+                       }
+                       BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
+                               (TOTAL_RING_BUF_SIZE - 1)) == 0));
+                       DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
+                                               "ip_dma_ringbuf 0x%p\n",
+                                       __func__,
+                                       (void *)port->ip_cpu_ringbuf,
+                                       (void *)port->ip_dma_ringbuf));
+                       port->ip_inring = RING(port, RX_0_OR_2);
+                       port->ip_outring = RING(port, TX_0_OR_2);
+               }
+               DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
+                               __func__,
+                               port_number, (void *)port, (void *)control));
+               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+                               (void *)port->ip_serial_regs,
+                               (void *)port->ip_uart_regs));
+
+               /* Initialize the hardware for IOC4 */
+               port_init(port);
+
+               DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
+                                               "outring 0x%p\n",
+                               __func__,
+                               port_number, (void *)port,
+                               (void *)port->ip_inring,
+                               (void *)port->ip_outring));
+
+               /* Attach interrupt handlers */
+               intr_connect(soft, IOC4_SIO_INTR_TYPE,
+                               GET_SIO_IR(port_number),
+                               handle_intr, port);
+
+               intr_connect(soft, IOC4_OTHER_INTR_TYPE,
+                               GET_OTHER_IR(port_number),
+                               handle_dma_error_intr, port);
+       }
+       return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       if ((port->ip_ienb & mask) != mask) {
+               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
+                                               IOC4_SIO_INTR_TYPE);
+               port->ip_ienb |= mask;
+       }
+
+       if (port->ip_ienb)
+               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+                               IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc4_port *port)
+{
+       int spiniter = 0;
+
+       port->ip_flags = PORT_ACTIVE;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while((readl(&port->ip_serial_regs-> sscr)
+                               & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER) {
+                               port->ip_flags = PORT_INACTIVE;
+                               return -1;
+                       }
+               }
+       }
+
+       /* Reset the input fifo.  If the uart received chars while the port
+        * was closed and DMA is not enabled, the uart may have a bunch of
+        * chars hanging around in its rx fifo which will not be discarded
+        * by rclr in the upper layer. We must get rid of them here.
+        */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+                               &port->ip_uart_regs->i4u_fcr);
+
+       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
+                                       /* UART_LCR_STOP == 1 stop */
+
+       /* Re-enable DMA, set default threshold to intr whenever there is
+        * data available.
+        */
+       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+       port->ip_sscr |= 1;     /* default threshold */
+
+       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+        * flag if it was set above
+        */
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       port->ip_tx_lowat = 1;
+       return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
+{
+       int threshold;
+
+       port->ip_rx_timeout = timeout;
+
+       /* Timeout is in ticks.  Let's figure out how many chars we
+        * can receive at the current baud rate in that interval
+        * and set the rx threshold to that amount.  There are 4 chars
+        * per ring entry, so we'll divide the number of chars that will
+        * arrive in timeout by 4.
+        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+        */
+       threshold = timeout * port->ip_baud / 4000;
+       if (threshold == 0)
+               threshold = 1;  /* otherwise we'll intr all the time! */
+
+       if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
+               return 1;
+
+       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
+       port->ip_sscr |= threshold;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Now set the rx timeout to the given value
+        * again timeout * IOC4_SRTR_HZ / HZ
+        */
+       timeout = timeout * IOC4_SRTR_HZ / 100;
+       if (timeout > IOC4_SRTR_CNT)
+               timeout = IOC4_SRTR_CNT;
+
+       writel(timeout, &port->ip_serial_regs->srtr);
+       return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc4_port *port,
+           int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+       char lcr, sizebits;
+       int spiniter = 0;
+
+       DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
+               __func__, baud, byte_size, stop_bits, parenb, parodd));
+
+       if (set_baud(port, baud))
+               return 1;
+
+       switch (byte_size) {
+       case 5:
+               sizebits = UART_LCR_WLEN5;
+               break;
+       case 6:
+               sizebits = UART_LCR_WLEN6;
+               break;
+       case 7:
+               sizebits = UART_LCR_WLEN7;
+               break;
+       case 8:
+               sizebits = UART_LCR_WLEN8;
+               break;
+       default:
+               return 1;
+       }
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while((readl(&port->ip_serial_regs->sscr)
+                                               & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+
+       /* Clear relevant fields in lcr */
+       lcr = readb(&port->ip_uart_regs->i4u_lcr);
+       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+       /* Set byte size in lcr */
+       lcr |= sizebits;
+
+       /* Set parity */
+       if (parenb) {
+               lcr |= UART_LCR_PARITY;
+               if (!parodd)
+                       lcr |= UART_LCR_EPAR;
+       }
+
+       /* Set stop bits */
+       if (stop_bits)
+               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+       writeb(lcr, &port->ip_uart_regs->i4u_lcr);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       port->ip_baud = baud;
+
+       /* When we get within this number of ring entries of filling the
+        * entire ring on tx, place an EXPLICIT intr to generate a lowat
+        * notification when output has drained.
+        */
+       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+       if (port->ip_tx_lowat == 0)
+               port->ip_tx_lowat = 1;
+
+       set_rx_timeout(port, 2);
+
+       return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *                     actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc4_port *port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total = 0;
+       struct ring *outring;
+       struct ring_entry *entry;
+       struct hooks *hooks = port->ip_hooks;
+
+       BUG_ON(!(len >= 0));
+
+       prod_ptr = port->ip_tx_prod;
+       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       outring = port->ip_outring;
+
+       /* Maintain a 1-entry red-zone.  The ring buffer is full when
+        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+        * in the body of the loop, I'll do it now.
+        */
+       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+       /* Stuff the bytes into the output */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               int xx;
+
+               /* Get 4 bytes (one ring entry) at a time */
+               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+               /* Invalidate all entries */
+               entry->ring_allsc = 0;
+
+               /* Copy in some bytes */
+               for (xx = 0; (xx < 4) && (len > 0); xx++) {
+                       entry->ring_data[xx] = *buf++;
+                       entry->ring_sc[xx] = IOC4_TXCB_VALID;
+                       len--;
+                       total++;
+               }
+
+               /* If we are within some small threshold of filling up the
+                * entire ring buffer, we must place an EXPLICIT intr here
+                * to generate a lowat interrupt in case we subsequently
+                * really do fill up the ring and the caller goes to sleep.
+                * No need to place more than one though.
+                */
+               if (!(port->ip_flags & LOWAT_WRITTEN) &&
+                       ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+                               <= port->ip_tx_lowat
+                                       * (int)sizeof(struct ring_entry)) {
+                       port->ip_flags |= LOWAT_WRITTEN;
+                       entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
+               }
+
+               /* Go on to next entry */
+               prod_ptr += sizeof(struct ring_entry);
+               prod_ptr &= PROD_CONS_MASK;
+       }
+
+       /* If we sent something, start DMA if necessary */
+       if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+               port->ip_sscr |= IOC4_SSCR_DMA_EN;
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+
+       /* Store the new producer pointer.  If tx is disabled, we stuff the
+        * data into the ring buffer, but we don't actually start tx.
+        */
+       if (!uart_tx_stopped(port->ip_port)) {
+               writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+               /* If we are now transmitting, enable tx_mt interrupt so we
+                * can disable DMA if necessary when the tx finishes.
+                */
+               if (total > 0)
+                       enable_intrs(port, hooks->intr_tx_mt);
+       }
+       port->ip_tx_prod = prod_ptr;
+       return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void disable_intrs(struct ioc4_port *port, uint32_t mask)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       if (port->ip_ienb & mask) {
+               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
+                                       IOC4_SIO_INTR_TYPE);
+               port->ip_ienb &= ~mask;
+       }
+
+       if (!port->ip_ienb)
+               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
+                               IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc4_port *port, int mask, int set_on)
+{
+       struct hooks *hooks = port->ip_hooks;
+       uint32_t intrbits, sscrbits;
+
+       BUG_ON(!mask);
+
+       intrbits = sscrbits = 0;
+
+       if (mask & N_DATA_READY)
+               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+       if (mask & N_OUTPUT_LOWAT)
+               intrbits |= hooks->intr_tx_explicit;
+       if (mask & N_DDCD) {
+               intrbits |= hooks->intr_delta_dcd;
+               sscrbits |= IOC4_SSCR_RX_RING_DCD;
+       }
+       if (mask & N_DCTS)
+               intrbits |= hooks->intr_delta_cts;
+
+       if (set_on) {
+               enable_intrs(port, intrbits);
+               port->ip_notify |= mask;
+               port->ip_sscr |= sscrbits;
+       } else {
+               disable_intrs(port, intrbits);
+               port->ip_notify &= ~mask;
+               port->ip_sscr &= ~sscrbits;
+       }
+
+       /* We require DMA if either DATA_READY or DDCD notification is
+        * currently requested. If neither of these is requested and
+        * there is currently no tx in progress, DMA may be disabled.
+        */
+       if (port->ip_notify & (N_DATA_READY | N_DDCD))
+               port->ip_sscr |= IOC4_SSCR_DMA_EN;
+       else if (!(port->ip_ienb & hooks->intr_tx_mt))
+               port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+               int mask1, int mask2)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       uint32_t shadow;
+       int spiniter = 0;
+       char mcr;
+
+       if (!port)
+               return -1;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
+                       &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                                       & IOC4_SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+       shadow = readl(&port->ip_serial_regs->shadow);
+       mcr = (shadow & 0xff000000) >> 24;
+
+       /* Set new value */
+       mcr |= mask1;
+       shadow |= mask2;
+
+       writeb(mcr, &port->ip_uart_regs->i4u_mcr);
+       writel(shadow, &port->ip_serial_regs->shadow);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       return 0;
+}
+
+/**
+ * ioc4_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc4_set_proto(struct ioc4_port *port, int proto)
+{
+       struct hooks *hooks = port->ip_hooks;
+
+       switch (proto) {
+       case PROTO_RS232:
+               /* Clear the appropriate GIO pin */
+               writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
+               break;
+
+       case PROTO_RS422:
+               /* Set the appropriate GIO pin */
+               writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
+               break;
+
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with ip_lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+       int xmit_count, tail, head;
+       int result;
+       char *start;
+       struct tty_struct *tty;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       struct uart_state *state;
+
+       if (!the_port)
+               return;
+       if (!port)
+               return;
+
+       state = the_port->state;
+       tty = state->port.tty;
+
+       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
+               /* Nothing to do or hw stopped */
+               set_notification(port, N_ALL_OUTPUT, 0);
+               return;
+       }
+
+       head = state->xmit.head;
+       tail = state->xmit.tail;
+       start = (char *)&state->xmit.buf[tail];
+
+       /* write out all the data or until the end of the buffer */
+       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+       if (xmit_count > 0) {
+               result = do_write(port, start, xmit_count);
+               if (result > 0) {
+                       /* booking */
+                       xmit_count -= result;
+                       the_port->icount.tx += result;
+                       /* advance the pointers */
+                       tail += result;
+                       tail &= UART_XMIT_SIZE - 1;
+                       state->xmit.tail = tail;
+                       start = (char *)&state->xmit.buf[tail];
+               }
+       }
+       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(the_port);
+
+       if (uart_circ_empty(&state->xmit)) {
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+       } else {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+       }
+}
+
+/**
+ * ioc4_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc4_change_speed(struct uart_port *the_port,
+                 struct ktermios *new_termios, struct ktermios *old_termios)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       int baud, bits;
+       unsigned cflag, iflag;
+       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+       struct uart_state *state = the_port->state;
+
+       cflag = new_termios->c_cflag;
+       iflag = new_termios->c_iflag;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               new_data = 5;
+               bits = 7;
+               break;
+       case CS6:
+               new_data = 6;
+               bits = 8;
+               break;
+       case CS7:
+               new_data = 7;
+               bits = 9;
+               break;
+       case CS8:
+               new_data = 8;
+               bits = 10;
+               break;
+       default:
+               /* cuz we always need a default ... */
+               new_data = 5;
+               bits = 7;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               bits++;
+               new_stop = 1;
+       }
+       if (cflag & PARENB) {
+               bits++;
+               new_parity_enable = 1;
+               if (cflag & PARODD)
+                       new_parity = 1;
+       }
+       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+                               MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
+
+       /* default is 9600 */
+       if (!baud)
+               baud = 9600;
+
+       if (!the_port->fifosize)
+               the_port->fifosize = IOC4_FIFO_CHARS;
+       the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
+       the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
+
+       the_port->ignore_status_mask = N_ALL_INPUT;
+
+       state->port.tty->low_latency = 1;
+
+       if (iflag & IGNPAR)
+               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+                                               | N_FRAMING_ERROR);
+       if (iflag & IGNBRK) {
+               the_port->ignore_status_mask &= ~N_BREAK;
+               if (iflag & IGNPAR)
+                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+       }
+       if (!(cflag & CREAD)) {
+               /* ignore everything */
+               the_port->ignore_status_mask &= ~N_DATA_READY;
+       }
+
+       if (cflag & CRTSCTS) {
+               port->ip_sscr |= IOC4_SSCR_HFC_EN;
+       }
+       else {
+               port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
+       }
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Set the configuration and proper notification call */
+       DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
+               "config_port(baud %d data %d stop %d p enable %d parity %d),"
+               " notification 0x%x\n",
+            __func__, (void *)port, cflag, baud, new_data, new_stop,
+            new_parity_enable, new_parity, the_port->ignore_status_mask));
+
+       if ((config_port(port, baud,            /* baud */
+                        new_data,              /* byte size */
+                        new_stop,              /* stop bits */
+                        new_parity_enable,     /* set parity */
+                        new_parity)) >= 0) {   /* parity 1==odd */
+               set_notification(port, the_port->ignore_status_mask, 1);
+       }
+}
+
+/**
+ * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic4_startup_local(struct uart_port *the_port)
+{
+       struct ioc4_port *port;
+       struct uart_state *state;
+
+       if (!the_port)
+               return -1;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port)
+               return -1;
+
+       state = the_port->state;
+
+       local_open(port);
+
+       /* set the protocol - mapbase has the port type */
+       ioc4_set_proto(port, the_port->mapbase);
+
+       /* set the speed of the serial port */
+       ioc4_change_speed(the_port, state->port.tty->termios,
+                         (struct ktermios *)0);
+
+       return 0;
+}
+
+/*
+ * ioc4_cb_output_lowat - called when the output low water mark is hit
+ * @the_port: port to output
+ */
+static void ioc4_cb_output_lowat(struct uart_port *the_port)
+{
+       unsigned long pflags;
+
+       /* ip_lock is set on the call here */
+       if (the_port) {
+               spin_lock_irqsave(&the_port->lock, pflags);
+               transmit_chars(the_port);
+               spin_unlock_irqrestore(&the_port->lock, pflags);
+       }
+}
+
+/**
+ * handle_intr - service any interrupts for the given port - 2nd level
+ *                     called via sd_intr
+ * @arg: handler arg
+ * @sio_ir: ioc4regs
+ */
+static void handle_intr(void *arg, uint32_t sio_ir)
+{
+       struct ioc4_port *port = (struct ioc4_port *)arg;
+       struct hooks *hooks = port->ip_hooks;
+       unsigned int rx_high_rd_aborted = 0;
+       unsigned long flags;
+       struct uart_port *the_port;
+       int loop_counter;
+
+       /* Possible race condition here: The tx_mt interrupt bit may be
+        * cleared without the intervention of the interrupt handler,
+        * e.g. by a write.  If the top level interrupt handler reads a
+        * tx_mt, then some other processor does a write, starting up
+        * output, then we come in here, see the tx_mt and stop DMA, the
+        * output started by the other processor will hang.  Thus we can
+        * only rely on tx_mt being legitimate if it is read while the
+        * port lock is held.  Therefore this bit must be ignored in the
+        * passed in interrupt mask which was read by the top level
+        * interrupt handler since the port lock was not held at the time
+        * it was read.  We can only rely on this bit being accurate if it
+        * is read while the port lock is held.  So we'll clear it for now,
+        * and reload it later once we have the port lock.
+        */
+       sio_ir &= ~(hooks->intr_tx_mt);
+
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       loop_counter = MAXITER; /* to avoid hangs */
+
+       do {
+               uint32_t shadow;
+
+               if ( loop_counter-- <= 0 ) {
+                       printk(KERN_WARNING "IOC4 serial: "
+                                       "possible hang condition/"
+                                       "port stuck on interrupt.\n");
+                       break;
+               }
+
+               /* Handle a DCD change */
+               if (sio_ir & hooks->intr_delta_dcd) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_delta_dcd,
+                               &port->ip_mem->sio_ir.raw);
+
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DDCD)
+                                       && (shadow & IOC4_SHADOW_DCD)
+                                       && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               the_port->icount.dcd = 1;
+                               wake_up_interruptible
+                                           (&the_port->state->port.delta_msr_wait);
+                       } else if ((port->ip_notify & N_DDCD)
+                                       && !(shadow & IOC4_SHADOW_DCD)) {
+                               /* Flag delta DCD/no DCD */
+                               port->ip_flags |= DCD_ON;
+                       }
+               }
+
+               /* Handle a CTS change */
+               if (sio_ir & hooks->intr_delta_cts) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_delta_cts,
+                                       &port->ip_mem->sio_ir.raw);
+
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DCTS)
+                                       && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               the_port->icount.cts =
+                                       (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
+                               wake_up_interruptible
+                                       (&the_port->state->port.delta_msr_wait);
+                       }
+               }
+
+               /* rx timeout interrupt.  Must be some data available.  Put this
+                * before the check for rx_high since servicing this condition
+                * may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_rx_timer) {
+                       /* ACK the interrupt */
+                       writel(hooks->intr_rx_timer,
+                               &port->ip_mem->sio_ir.raw);
+
+                       if ((port->ip_notify & N_DATA_READY)
+                                       && (port->ip_port)) {
+                               /* ip_lock is set on call here */
+                               receive_chars(port->ip_port);
+                       }
+               }
+
+               /* rx high interrupt. Must be after rx_timer.  */
+               else if (sio_ir & hooks->intr_rx_high) {
+                       /* Data available, notify upper layer */
+                       if ((port->ip_notify & N_DATA_READY)
+                                               && port->ip_port) {
+                               /* ip_lock is set on call here */
+                               receive_chars(port->ip_port);
+                       }
+
+                       /* We can't ACK this interrupt.  If receive_chars didn't
+                        * cause the condition to clear, we'll have to disable
+                        * the interrupt until the data is drained.
+                        * If the read was aborted, don't disable the interrupt
+                        * as this may cause us to hang indefinitely.  An
+                        * aborted read generally means that this interrupt
+                        * hasn't been delivered to the cpu yet anyway, even
+                        * though we see it as asserted when we read the sio_ir.
+                        */
+                       if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
+                               if ((port->ip_flags & READ_ABORTED) == 0) {
+                                       port->ip_ienb &= ~hooks->intr_rx_high;
+                                       port->ip_flags |= INPUT_HIGH;
+                               } else {
+                                       rx_high_rd_aborted++;
+                               }
+                       }
+               }
+
+               /* We got a low water interrupt: notify upper layer to
+                * send more data.  Must come before tx_mt since servicing
+                * this condition may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_tx_explicit) {
+                       port->ip_flags &= ~LOWAT_WRITTEN;
+
+                       /* ACK the interrupt */
+                       writel(hooks->intr_tx_explicit,
+                                       &port->ip_mem->sio_ir.raw);
+
+                       if (port->ip_notify & N_OUTPUT_LOWAT)
+                               ioc4_cb_output_lowat(port->ip_port);
+               }
+
+               /* Handle tx_mt.  Must come after tx_explicit.  */
+               else if (sio_ir & hooks->intr_tx_mt) {
+                       /* If we are expecting a lowat notification
+                        * and we get to this point it probably means that for
+                        * some reason the tx_explicit didn't work as expected
+                        * (that can legitimately happen if the output buffer is
+                        * filled up in just the right way).
+                        * So send the notification now.
+                        */
+                       if (port->ip_notify & N_OUTPUT_LOWAT) {
+                               ioc4_cb_output_lowat(port->ip_port);
+
+                               /* We need to reload the sio_ir since the lowat
+                                * call may have caused another write to occur,
+                                * clearing the tx_mt condition.
+                                */
+                               sio_ir = PENDING(port);
+                       }
+
+                       /* If the tx_mt condition still persists even after the
+                        * lowat call, we've got some work to do.
+                        */
+                       if (sio_ir & hooks->intr_tx_mt) {
+
+                               /* If we are not currently expecting DMA input,
+                                * and the transmitter has just gone idle,
+                                * there is no longer any reason for DMA, so
+                                * disable it.
+                                */
+                               if (!(port->ip_notify
+                                               & (N_DATA_READY | N_DDCD))) {
+                                       BUG_ON(!(port->ip_sscr
+                                                       & IOC4_SSCR_DMA_EN));
+                                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+                                       writel(port->ip_sscr,
+                                          &port->ip_serial_regs->sscr);
+                               }
+
+                               /* Prevent infinite tx_mt interrupt */
+                               port->ip_ienb &= ~hooks->intr_tx_mt;
+                       }
+               }
+               sio_ir = PENDING(port);
+
+               /* if the read was aborted and only hooks->intr_rx_high,
+                * clear hooks->intr_rx_high, so we do not loop forever.
+                */
+
+               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+                       sio_ir &= ~hooks->intr_rx_high;
+               }
+       } while (sio_ir & hooks->intr_all);
+
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+
+       /* Re-enable interrupts before returning from interrupt handler.
+        * Getting interrupted here is okay.  It'll just v() our semaphore, and
+        * we'll come through the loop again.
+        */
+
+       write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
+                                                       IOC4_SIO_INTR_TYPE);
+}
+
+/*
+ * ioc4_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+       struct uart_icount *icount;
+
+       icount = &the_port->icount;
+
+       if (ncs & NCS_BREAK)
+               icount->brk++;
+       if (ncs & NCS_FRAMING)
+               icount->frame++;
+       if (ncs & NCS_OVERRUN)
+               icount->overrun++;
+       if (ncs & NCS_PARITY)
+               icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *                     actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, unsigned char *buf,
+                               int len)
+{
+       int prod_ptr, cons_ptr, total;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       struct ring *inring;
+       struct ring_entry *entry;
+       struct hooks *hooks = port->ip_hooks;
+       int byte_num;
+       char *sc;
+       int loop_counter;
+
+       BUG_ON(!(len >= 0));
+       BUG_ON(!port);
+
+       /* There is a nasty timing issue in the IOC4. When the rx_timer
+        * expires or the rx_high condition arises, we take an interrupt.
+        * At some point while servicing the interrupt, we read bytes from
+        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+        * not started until the first byte is received *after* it is armed,
+        * and any bytes pending in the rx construction buffers are not drained
+        * to memory until either there are 4 bytes available or the rx_timer
+        * expires.  This leads to a potential situation where data is left
+        * in the construction buffers forever - 1 to 3 bytes were received
+        * after the interrupt was generated but before the rx_timer was
+        * re-armed. At that point as long as no subsequent bytes are received
+        * the timer will never be started and the bytes will remain in the
+        * construction buffer forever.  The solution is to execute a DRAIN
+        * command after rearming the timer.  This way any bytes received before
+        * the DRAIN will be drained to memory, and any bytes received after
+        * the DRAIN will start the TIMER and be drained when it expires.
+        * Luckily, this only needs to be done when the DMA buffer is empty
+        * since there is no requirement that this function return all
+        * available data as long as it returns some.
+        */
+       /* Re-arm the timer */
+       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       cons_ptr = port->ip_rx_cons;
+
+       if (prod_ptr == cons_ptr) {
+               int reset_dma = 0;
+
+               /* Input buffer appears empty, do a flush. */
+
+               /* DMA must be enabled for this to work. */
+               if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
+                       port->ip_sscr |= IOC4_SSCR_DMA_EN;
+                       reset_dma = 1;
+               }
+
+               /* Potential race condition: we must reload the srpir after
+                * issuing the drain command, otherwise we could think the rx
+                * buffer is empty, then take a very long interrupt, and when
+                * we come back it's full and we wait forever for the drain to
+                * complete.
+                */
+               writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
+                               &port->ip_serial_regs->sscr);
+               prod_ptr = readl(&port->ip_serial_regs->srpir)
+                               & PROD_CONS_MASK;
+
+               /* We must not wait for the DRAIN to complete unless there are
+                * at least 8 bytes (2 ring entries) available to receive the
+                * data otherwise the DRAIN will never complete and we'll
+                * deadlock here.
+                * In fact, to make things easier, I'll just ignore the flush if
+                * there is any data at all now available.
+                */
+               if (prod_ptr == cons_ptr) {
+                       loop_counter = 0;
+                       while (readl(&port->ip_serial_regs->sscr) &
+                                               IOC4_SSCR_RX_DRAIN) {
+                               loop_counter++;
+                               if (loop_counter > MAXITER)
+                                       return -1;
+                       }
+
+                       /* SIGH. We have to reload the prod_ptr *again* since
+                        * the drain may have caused it to change
+                        */
+                       prod_ptr = readl(&port->ip_serial_regs->srpir)
+                                                       & PROD_CONS_MASK;
+               }
+               if (reset_dma) {
+                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
+                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+               }
+       }
+       inring = port->ip_inring;
+       port->ip_flags &= ~READ_ABORTED;
+
+       total = 0;
+       loop_counter = 0xfffff; /* to avoid hangs */
+
+       /* Grab bytes from the hardware */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
+
+               if ( loop_counter-- <= 0 ) {
+                       printk(KERN_WARNING "IOC4 serial: "
+                                       "possible hang condition/"
+                                       "port stuck on read.\n");
+                       break;
+               }
+
+               /* According to the producer pointer, this ring entry
+                * must contain some data.  But if the PIO happened faster
+                * than the DMA, the data may not be available yet, so let's
+                * wait until it arrives.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       /* Indicate the read is aborted so we don't disable
+                        * the interrupt thinking that the consumer is
+                        * congested.
+                        */
+                       port->ip_flags |= READ_ABORTED;
+                       len = 0;
+                       break;
+               }
+
+               /* Load the bytes/status out of the ring entry */
+               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+                       sc = &(entry->ring_sc[byte_num]);
+
+                       /* Check for change in modem state or overrun */
+                       if ((*sc & IOC4_RXSB_MODEM_VALID)
+                                               && (port->ip_notify & N_DDCD)) {
+                               /* Notify upper layer if DCD dropped */
+
+                               if ((port->ip_flags & DCD_ON)
+                                               && !(*sc & IOC4_RXSB_DCD)) {
+
+                                       /* If we have already copied some data,
+                                        * return it.  We'll pick up the carrier
+                                        * drop on the next pass.  That way we
+                                        * don't throw away the data that has
+                                        * already been copied back to
+                                        * the caller's buffer.
+                                        */
+                                       if (total > 0) {
+                                               len = 0;
+                                               break;
+                                       }
+                                       port->ip_flags &= ~DCD_ON;
+
+                                       /* Turn off this notification so the
+                                        * carrier drop protocol won't see it
+                                        * again when it does a read.
+                                        */
+                                       *sc &= ~IOC4_RXSB_MODEM_VALID;
+
+                                       /* To keep things consistent, we need
+                                        * to update the consumer pointer so
+                                        * the next reader won't come in and
+                                        * try to read the same ring entries
+                                        * again. This must be done here before
+                                        * the dcd change.
+                                        */
+
+                                       if ((entry->ring_allsc & RING_ANY_VALID)
+                                                                       == 0) {
+                                               cons_ptr += (int)sizeof
+                                                       (struct ring_entry);
+                                               cons_ptr &= PROD_CONS_MASK;
+                                       }
+                                       writel(cons_ptr,
+                                               &port->ip_serial_regs->srcir);
+                                       port->ip_rx_cons = cons_ptr;
+
+                                       /* Notify upper layer of carrier drop */
+                                       if ((port->ip_notify & N_DDCD)
+                                                  && port->ip_port) {
+                                               the_port->icount.dcd = 0;
+                                               wake_up_interruptible
+                                                   (&the_port->state->
+                                                       port.delta_msr_wait);
+                                       }
+
+                                       /* If we had any data to return, we
+                                        * would have returned it above.
+                                        */
+                                       return 0;
+                               }
+                       }
+                       if (*sc & IOC4_RXSB_MODEM_VALID) {
+                               /* Notify that an input overrun occurred */
+                               if ((*sc & IOC4_RXSB_OVERRUN)
+                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
+                                       ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
+                               }
+                               /* Don't look at this byte again */
+                               *sc &= ~IOC4_RXSB_MODEM_VALID;
+                       }
+
+                       /* Check for valid data or RX errors */
+                       if ((*sc & IOC4_RXSB_DATA_VALID) &&
+                                       ((*sc & (IOC4_RXSB_PAR_ERR
+                                                       | IOC4_RXSB_FRAME_ERR
+                                                       | IOC4_RXSB_BREAK))
+                                       && (port->ip_notify & (N_PARITY_ERROR
+                                                       | N_FRAMING_ERROR
+                                                       | N_BREAK)))) {
+                               /* There is an error condition on the next byte.
+                                * If we have already transferred some bytes,
+                                * we'll stop here. Otherwise if this is the
+                                * first byte to be read, we'll just transfer
+                                * it alone after notifying the
+                                * upper layer of its status.
+                                */
+                               if (total > 0) {
+                                       len = 0;
+                                       break;
+                               } else {
+                                       if ((*sc & IOC4_RXSB_PAR_ERR) &&
+                                          (port->ip_notify & N_PARITY_ERROR)) {
+                                               ioc4_cb_post_ncs(the_port,
+                                                               NCS_PARITY);
+                                       }
+                                       if ((*sc & IOC4_RXSB_FRAME_ERR) &&
+                                          (port->ip_notify & N_FRAMING_ERROR)){
+                                               ioc4_cb_post_ncs(the_port,
+                                                               NCS_FRAMING);
+                                       }
+                                       if ((*sc & IOC4_RXSB_BREAK)
+                                           && (port->ip_notify & N_BREAK)) {
+                                                       ioc4_cb_post_ncs
+                                                                   (the_port,
+                                                                    NCS_BREAK);
+                                       }
+                                       len = 1;
+                               }
+                       }
+                       if (*sc & IOC4_RXSB_DATA_VALID) {
+                               *sc &= ~IOC4_RXSB_DATA_VALID;
+                               *buf = entry->ring_data[byte_num];
+                               buf++;
+                               len--;
+                               total++;
+                       }
+               }
+
+               /* If we used up this entry entirely, go on to the next one,
+                * otherwise we must have run out of buffer space, so
+                * leave the consumer pointer here for the next read in case
+                * there are still unread bytes in this entry.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       cons_ptr += (int)sizeof(struct ring_entry);
+                       cons_ptr &= PROD_CONS_MASK;
+               }
+       }
+
+       /* Update consumer pointer and re-arm rx timer interrupt */
+       writel(cons_ptr, &port->ip_serial_regs->srcir);
+       port->ip_rx_cons = cons_ptr;
+
+       /* If we have now dipped below the rx high water mark and we have
+        * rx_high interrupt turned off, we can now turn it back on again.
+        */
+       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+                       & PROD_CONS_MASK) < ((port->ip_sscr &
+                               IOC4_SSCR_RX_THRESHOLD)
+                                       << IOC4_PROD_CONS_PTR_OFF))) {
+               port->ip_flags &= ~INPUT_HIGH;
+               enable_intrs(port, hooks->intr_rx_high);
+       }
+       return total;
+}
+
+/**
+ * receive_chars - upper level read. Called with ip_lock.
+ * @the_port: port to read from
+ */
+static void receive_chars(struct uart_port *the_port)
+{
+       struct tty_struct *tty;
+       unsigned char ch[IOC4_MAX_CHARS];
+       int read_count, request_count = IOC4_MAX_CHARS;
+       struct uart_icount *icount;
+       struct uart_state *state = the_port->state;
+       unsigned long pflags;
+
+       /* Make sure all the pointers are "good" ones */
+       if (!state)
+               return;
+       if (!state->port.tty)
+               return;
+
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = state->port.tty;
+
+       request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
+
+       if (request_count > 0) {
+               icount = &the_port->icount;
+               read_count = do_read(the_port, ch, request_count);
+               if (read_count > 0) {
+                       tty_insert_flip_string(tty, ch, read_count);
+                       icount->rx += read_count;
+               }
+       }
+
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
+       tty_flip_buffer_push(tty);
+}
+
+/**
+ * ic4_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic4_type(struct uart_port *the_port)
+{
+       if (the_port->mapbase == PROTO_RS232)
+               return "SGI IOC4 Serial [rs232]";
+       else
+               return "SGI IOC4 Serial [rs422]";
+}
+
+/**
+ * ic4_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic4_tx_empty(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       unsigned int ret = 0;
+
+       if (port_is_active(port, the_port)) {
+               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
+                       ret = TIOCSER_TEMT;
+       }
+       return ret;
+}
+
+/**
+ * ic4_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic4_stop_tx(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port))
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * null_void_function -
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic4_shutdown - shut down the port - free irq and disable
+ * @port: Port to shut down
+ *
+ */
+static void ic4_shutdown(struct uart_port *the_port)
+{
+       unsigned long port_flags;
+       struct ioc4_port *port;
+       struct uart_state *state;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port)
+               return;
+
+       state = the_port->state;
+       port->ip_port = NULL;
+
+       wake_up_interruptible(&state->port.delta_msr_wait);
+
+       if (state->port.tty)
+               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       set_notification(port, N_ALL, 0);
+       port->ip_flags = PORT_INACTIVE;
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic4_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+       unsigned char mcr = 0;
+       struct ioc4_port *port;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port_is_active(port, the_port))
+               return;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
+}
+
+/**
+ * ic4_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic4_get_mctrl(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       uint32_t shadow;
+       unsigned int ret = 0;
+
+       if (!port_is_active(port, the_port))
+               return 0;
+
+       shadow = readl(&port->ip_serial_regs->shadow);
+       if (shadow & IOC4_SHADOW_DCD)
+               ret |= TIOCM_CAR;
+       if (shadow & IOC4_SHADOW_DR)
+               ret |= TIOCM_DSR;
+       if (shadow & IOC4_SHADOW_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+/**
+ * ic4_start_tx - Start transmitter, flush any output
+ * @port: Port to operate on
+ *
+ */
+static void ic4_start_tx(struct uart_port *the_port)
+{
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port)) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
+       }
+}
+
+/**
+ * ic4_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic4_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic4_startup - Start up the serial port
+ * @port: Port to operate on
+ *
+ */
+static int ic4_startup(struct uart_port *the_port)
+{
+       int retval;
+       struct ioc4_port *port;
+       struct ioc4_control *control;
+       struct uart_state *state;
+       unsigned long port_flags;
+
+       if (!the_port)
+               return -ENODEV;
+       port = get_ioc4_port(the_port, 1);
+       if (!port)
+               return -ENODEV;
+       state = the_port->state;
+
+       control = port->ip_control;
+       if (!control) {
+               port->ip_port = NULL;
+               return -ENODEV;
+       }
+
+       /* Start up the serial port */
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       retval = ic4_startup_local(the_port);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+       return retval;
+}
+
+/**
+ * ic4_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic4_set_termios(struct uart_port *the_port,
+               struct ktermios *termios, struct ktermios *old_termios)
+{
+       unsigned long port_flags;
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       ioc4_change_speed(the_port, termios, old_termios);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic4_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic4_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops ioc4_ops = {
+       .tx_empty       = ic4_tx_empty,
+       .set_mctrl      = ic4_set_mctrl,
+       .get_mctrl      = ic4_get_mctrl,
+       .stop_tx        = ic4_stop_tx,
+       .start_tx       = ic4_start_tx,
+       .stop_rx        = null_void_function,
+       .enable_ms      = null_void_function,
+       .break_ctl      = ic4_break_ctl,
+       .startup        = ic4_startup,
+       .shutdown       = ic4_shutdown,
+       .set_termios    = ic4_set_termios,
+       .type           = ic4_type,
+       .release_port   = null_void_function,
+       .request_port   = ic4_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc4_uart_rs232 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs232",
+       .dev_name       = DEVICE_NAME_RS232,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS232,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+static struct uart_driver ioc4_uart_rs422 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs422",
+       .dev_name       = DEVICE_NAME_RS422,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS422,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+
+/**
+ * ioc4_serial_remove_one - detach function
+ *
+ * @idd: IOC4 master module data for this IOC4
+ */
+
+static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
+{
+       int port_num, port_type;
+       struct ioc4_control *control;
+       struct uart_port *the_port;
+       struct ioc4_port *port;
+       struct ioc4_soft *soft;
+
+       /* If serial driver did not attach, don't try to detach */
+       control = idd->idd_serial_data;
+       if (!control)
+               return 0;
+
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               for (port_type = UART_PORT_MIN;
+                                       port_type < UART_PORT_COUNT;
+                                       port_type++) {
+                       the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type];
+                       if (the_port) {
+                               switch (port_type) {
+                               case UART_PORT_RS422:
+                                       uart_remove_one_port(&ioc4_uart_rs422,
+                                                       the_port);
+                                       break;
+                               default:
+                               case UART_PORT_RS232:
+                                       uart_remove_one_port(&ioc4_uart_rs232,
+                                                       the_port);
+                                       break;
+                               }
+                       }
+               }
+               port = control->ic_port[port_num].icp_port;
+               /* we allocate in pairs */
+               if (!(port_num & 1) && port) {
+                       pci_free_consistent(port->ip_pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                       kfree(port);
+               }
+       }
+       soft = control->ic_soft;
+       if (soft) {
+               free_irq(control->ic_irq, soft);
+               if (soft->is_ioc4_serial_addr) {
+                       iounmap(soft->is_ioc4_serial_addr);
+                       release_mem_region((unsigned long)
+                            soft->is_ioc4_serial_addr,
+                               sizeof(struct ioc4_serial));
+               }
+               kfree(soft);
+       }
+       kfree(control);
+       idd->idd_serial_data = NULL;
+
+       return 0;
+}
+
+
+/**
+ * ioc4_serial_core_attach_rs232 - register with serial core
+ *             This is done during pci probing
+ * @pdev: handle for this card
+ */
+static inline int
+ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
+{
+       struct ioc4_port *port;
+       struct uart_port *the_port;
+       struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
+       struct ioc4_control *control = idd->idd_serial_data;
+       int port_num;
+       int port_type_idx;
+       struct uart_driver *u_driver;
+
+
+       DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
+                       __func__, pdev, (void *)control));
+
+       if (!control)
+               return -ENODEV;
+
+       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
+                                               : UART_PORT_RS422;
+
+       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
+                                               : &ioc4_uart_rs422;
+
+       /* once around for each port on this card */
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type_idx];
+               port = control->ic_port[port_num].icp_port;
+               port->ip_all_ports[port_type_idx] = the_port;
+
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
+                               __func__, (void *)the_port,
+                               (void *)port,
+                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
+
+               /* membase, iobase and mapbase just need to be non-0 */
+               the_port->membase = (unsigned char __iomem *)1;
+               the_port->iobase = (pdev->bus->number << 16) |  port_num;
+               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
+               the_port->mapbase = port_type;
+               the_port->type = PORT_16550A;
+               the_port->fifosize = IOC4_FIFO_CHARS;
+               the_port->ops = &ioc4_ops;
+               the_port->irq = control->ic_irq;
+               the_port->dev = &pdev->dev;
+               spin_lock_init(&the_port->lock);
+               if (uart_add_one_port(u_driver, the_port) < 0) {
+                       printk(KERN_WARNING
+                          "%s: unable to add port %d bus %d\n",
+                              __func__, the_port->line, pdev->bus->number);
+               } else {
+                       DPRINT_CONFIG(
+                           ("IOC4 serial port %d irq = %d, bus %d\n",
+                              the_port->line, the_port->irq, pdev->bus->number));
+               }
+       }
+       return 0;
+}
+
+/**
+ * ioc4_serial_attach_one - register attach function
+ *             called per card found from IOC4 master module.
+ * @idd: Master module data for this IOC4
+ */
+int
+ioc4_serial_attach_one(struct ioc4_driver_data *idd)
+{
+       unsigned long tmp_addr1;
+       struct ioc4_serial __iomem *serial;
+       struct ioc4_soft *soft;
+       struct ioc4_control *control;
+       int ret = 0;
+
+
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
+                                                       idd->idd_pci_id));
+
+       /* PCI-RT does not bring out serial connections.
+        * Do not attach to this particular IOC4.
+        */
+       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+               return 0;
+
+       /* request serial registers */
+       tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
+
+       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
+                                       "sioc4_uart")) {
+               printk(KERN_WARNING
+                       "ioc4 (%p): unable to get request region for "
+                               "uart space\n", (void *)idd->idd_pdev);
+               ret = -ENODEV;
+               goto out1;
+       }
+       serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
+       if (!serial) {
+               printk(KERN_WARNING
+                        "ioc4 (%p) : unable to remap ioc4 serial register\n",
+                               (void *)idd->idd_pdev);
+               ret = -ENODEV;
+               goto out2;
+       }
+       DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
+                               __func__, (void *)idd->idd_misc_regs,
+                               (void *)serial));
+
+       /* Get memory for the new card */
+       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
+
+       if (!control) {
+               printk(KERN_WARNING "ioc4_attach_one"
+                      ": unable to get memory for the IOC4\n");
+               ret = -ENOMEM;
+               goto out2;
+       }
+       idd->idd_serial_data = control;
+
+       /* Allocate the soft structure */
+       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
+       if (!soft) {
+               printk(KERN_WARNING
+                      "ioc4 (%p): unable to get memory for the soft struct\n",
+                      (void *)idd->idd_pdev);
+               ret = -ENOMEM;
+               goto out3;
+       }
+
+       spin_lock_init(&soft->is_ir_lock);
+       soft->is_ioc4_misc_addr = idd->idd_misc_regs;
+       soft->is_ioc4_serial_addr = serial;
+
+       /* Init the IOC4 */
+       writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
+              &idd->idd_misc_regs->sio_cr.raw);
+
+       /* Enable serial port mode select generic PIO pins as outputs */
+       writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
+               | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
+               &idd->idd_misc_regs->gpcr_s.raw);
+
+       /* Clear and disable all serial interrupts */
+       write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
+       writel(~0, &idd->idd_misc_regs->sio_ir.raw);
+       write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
+                  IOC4_OTHER_INTR_TYPE);
+       writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
+       control->ic_soft = soft;
+
+       /* Hook up interrupt handler */
+       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
+                               "sgi-ioc4serial", soft)) {
+               control->ic_irq = idd->idd_pdev->irq;
+       } else {
+               printk(KERN_WARNING
+                   "%s : request_irq fails for IRQ 0x%x\n ",
+                       __func__, idd->idd_pdev->irq);
+       }
+       ret = ioc4_attach_local(idd);
+       if (ret)
+               goto out4;
+
+       /* register port with the serial core - 1 rs232, 1 rs422 */
+
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
+               goto out4;
+
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+               goto out5;
+
+       Num_of_ioc4_cards++;
+
+       return ret;
+
+       /* error exits that give back resources */
+out5:
+       ioc4_serial_remove_one(idd);
+out4:
+       kfree(soft);
+out3:
+       kfree(control);
+out2:
+       if (serial)
+               iounmap(serial);
+       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
+out1:
+
+       return ret;
+}
+
+
+static struct ioc4_submodule ioc4_serial_submodule = {
+       .is_name = "IOC4_serial",
+       .is_owner = THIS_MODULE,
+       .is_probe = ioc4_serial_attach_one,
+       .is_remove = ioc4_serial_remove_one,
+};
+
+/**
+ * ioc4_serial_init - module init
+ */
+static int __init ioc4_serial_init(void)
+{
+       int ret;
+
+       /* register with serial core */
+       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs232 IOC4 serial driver\n",
+                       __func__);
+               goto out;
+       }
+       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs422 IOC4 serial driver\n",
+                       __func__);
+               goto out_uart_rs232;
+       }
+
+       /* register with IOC4 main module */
+       ret = ioc4_register_submodule(&ioc4_serial_submodule);
+       if (ret)
+               goto out_uart_rs422;
+       return 0;
+
+out_uart_rs422:
+       uart_unregister_driver(&ioc4_uart_rs422);
+out_uart_rs232:
+       uart_unregister_driver(&ioc4_uart_rs232);
+out:
+       return ret;
+}
+
+static void __exit ioc4_serial_exit(void)
+{
+       ioc4_unregister_submodule(&ioc4_serial_submodule);
+       uart_unregister_driver(&ioc4_uart_rs232);
+       uart_unregister_driver(&ioc4_uart_rs422);
+}
+
+late_initcall(ioc4_serial_init); /* Call only after tty init is done */
+module_exit(ioc4_serial_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
new file mode 100644 (file)
index 0000000..ebff4a1
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+ * Driver for Zilog serial chips found on SGI workstations and
+ * servers.  This driver could actually be made more generic.
+ *
+ * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the
+ * old drivers/sgi/char/sgiserial.c code which itself is based of the original
+ * drivers/sbus/char/zs.c code.  A lot of code has been simply moved over
+ * directly from there but much has been rewritten.  Credits therefore go out
+ * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell
+ * for their work there.
+ *
+ *  Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
+ *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sgialib.h>
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
+
+#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "ip22zilog.h"
+
+/*
+ * On IP22 we need to delay after register accesses but we do not need to
+ * flush writes.
+ */
+#define ZSDELAY()              udelay(5)
+#define ZSDELAY_LONG()         udelay(20)
+#define ZS_WSYNC(channel)      do { } while (0)
+
+#define NUM_IP22ZILOG          1
+#define NUM_CHANNELS           (NUM_IP22ZILOG * 2)
+
+#define ZS_CLOCK               3672000 /* Zilog input clock rate. */
+#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_ip22zilog_port {
+       struct uart_port                port;
+
+       /* IRQ servicing chain.  */
+       struct uart_ip22zilog_port      *next;
+
+       /* Current values of Zilog write registers.  */
+       unsigned char                   curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define IP22ZILOG_FLAG_IS_CONS         0x00000004
+#define IP22ZILOG_FLAG_IS_KGDB         0x00000008
+#define IP22ZILOG_FLAG_MODEM_STATUS    0x00000010
+#define IP22ZILOG_FLAG_IS_CHANNEL_A    0x00000020
+#define IP22ZILOG_FLAG_REGS_HELD       0x00000040
+#define IP22ZILOG_FLAG_TX_STOPPED      0x00000080
+#define IP22ZILOG_FLAG_TX_ACTIVE       0x00000100
+#define IP22ZILOG_FLAG_RESET_DONE      0x00000200
+
+       unsigned int                    tty_break;
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+};
+
+#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel *)((PORT)->membase))
+#define UART_ZILOG(PORT)               ((struct uart_ip22zilog_port *)(PORT))
+#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM)           \
+       (UART_ZILOG(PORT)->curregs[REGNUM])
+#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL)   \
+       ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL))
+#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)       ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)      ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)       ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the IP22 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ *
+ * The port lock must be held and local IRQs must be disabled
+ * when {read,write}_zsreg is invoked.
+ */
+static unsigned char read_zsreg(struct zilog_channel *channel,
+                               unsigned char reg)
+{
+       unsigned char retval;
+
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       retval = readb(&channel->control);
+       ZSDELAY();
+
+       return retval;
+}
+
+static void write_zsreg(struct zilog_channel *channel,
+                       unsigned char reg, unsigned char value)
+{
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       writeb(value, &channel->control);
+       ZSDELAY();
+}
+
+static void ip22zilog_clear_fifo(struct zilog_channel *channel)
+{
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               unsigned char regval;
+
+               regval = readb(&channel->control);
+               ZSDELAY();
+               if (regval & Rx_CH_AV)
+                       break;
+
+               regval = read_zsreg(channel, R1);
+               readb(&channel->data);
+               ZSDELAY();
+
+               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+       }
+}
+
+/* This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
+{
+       int i;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       writeb(ERR_RES, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       ip22zilog_clear_fifo(channel);
+
+       /* Disable all interrupts.  */
+       write_zsreg(channel, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(channel, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(channel, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+
+       /* Synchronous mode config.  */
+       write_zsreg(channel, R6, regs[R6]);
+       write_zsreg(channel, R7, regs[R7]);
+
+       /* Don't mess with the interrupt vector (R2, unused by us) and
+        * master interrupt control (R9).  We make sure this is setup
+        * properly at probe time then never touch it again.
+        */
+
+       /* Disable baud generator.  */
+       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(channel, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(channel, R14, regs[R14]);
+
+       /* External status interrupt control.  */
+       write_zsreg(channel, R15, regs[R15]);
+
+       /* Reset external status interrupts.  */
+       write_zsreg(channel, R0, RES_EXT_INT);
+       write_zsreg(channel, R0, RES_EXT_INT);
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(channel, R1, regs[R1]);
+}
+
+/* Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
+                                      struct zilog_channel *channel)
+{
+       if (!ZS_REGS_HELD(up)) {
+               if (ZS_TX_ACTIVE(up)) {
+                       up->flags |= IP22ZILOG_FLAG_REGS_HELD;
+               } else {
+                       __load_zsregs(channel, up->curregs);
+               }
+       }
+}
+
+#define Rx_BRK 0x0100                   /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                   /* SysRq event software flag.  */
+
+static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+                                                 struct zilog_channel *channel)
+{
+       struct tty_struct *tty;
+       unsigned char ch, flag;
+       unsigned int r1;
+
+       tty = NULL;
+       if (up->port.state != NULL &&
+           up->port.state->port.tty != NULL)
+               tty = up->port.state->port.tty;
+
+       for (;;) {
+               ch = readb(&channel->control);
+               ZSDELAY();
+               if (!(ch & Rx_CH_AV))
+                       break;
+
+               r1 = read_zsreg(channel, R1);
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+
+               ch = readb(&channel->data);
+               ZSDELAY();
+
+               ch &= up->parity_mask;
+
+               /* Handle the null char got when BREAK is removed.  */
+               if (!ch)
+                       r1 |= up->tty_break;
+
+               /* A real serial line, record the character and status.  */
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
+                       up->tty_break = 0;
+
+                       if (r1 & (Rx_SYS | Rx_BRK)) {
+                               up->port.icount.brk++;
+                               if (r1 & Rx_SYS)
+                                       continue;
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                       }
+                       else if (r1 & PAR_ERR)
+                               up->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               up->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               up->port.icount.overrun++;
+                       r1 &= up->port.read_status_mask;
+                       if (r1 & Rx_BRK)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if (tty)
+                       uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
+       }
+       return tty;
+}
+
+static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
+                                  struct zilog_channel *channel)
+{
+       unsigned char status;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       writeb(RES_EXT_INT, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       if (up->curregs[R15] & BRKIE) {
+               if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
+                       if (uart_handle_break(&up->port))
+                               up->tty_break = Rx_SYS;
+                       else
+                               up->tty_break = Rx_BRK;
+               }
+       }
+
+       if (ZS_WANTS_MODEM_STATUS(up)) {
+               if (status & SYNC)
+                       up->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                */
+               if ((status ^ up->prev_status) ^ DCD)
+                       uart_handle_dcd_change(&up->port,
+                                              (status & DCD));
+               if ((status ^ up->prev_status) ^ CTS)
+                       uart_handle_cts_change(&up->port,
+                                              (status & CTS));
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       up->prev_status = status;
+}
+
+static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
+                                   struct zilog_channel *channel)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_CONS(up)) {
+               unsigned char status = readb(&channel->control);
+               ZSDELAY();
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(up)) {
+               __load_zsregs(channel, up->curregs);
+               up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(up)) {
+               up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       if (up->port.x_char) {
+               up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+               writeb(up->port.x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+
+       if (up->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &up->port.state->xmit;
+       if (uart_circ_empty(xmit))
+               goto ack_tx_int;
+       if (uart_tx_stopped(&up->port))
+               goto ack_tx_int;
+
+       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+       writeb(xmit->buf[xmit->tail], &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       up->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return;
+
+ack_tx_int:
+       writeb(RES_Tx_P, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
+{
+       struct uart_ip22zilog_port *up = dev_id;
+
+       while (up) {
+               struct zilog_channel *channel
+                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct tty_struct *tty;
+               unsigned char r3;
+
+               spin_lock(&up->port.lock);
+               r3 = read_zsreg(channel, R3);
+
+               /* Channel A */
+               tty = NULL;
+               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHARxIP)
+                               tty = ip22zilog_receive_chars(up, channel);
+                       if (r3 & CHAEXT)
+                               ip22zilog_status_handle(up, channel);
+                       if (r3 & CHATxIP)
+                               ip22zilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               /* Channel B */
+               up = up->next;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+               spin_lock(&up->port.lock);
+               tty = NULL;
+               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHBRxIP)
+                               tty = ip22zilog_receive_chars(up, channel);
+                       if (r3 & CHBEXT)
+                               ip22zilog_status_handle(up, channel);
+                       if (r3 & CHBTxIP)
+                               ip22zilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               up = up->next;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
+ * port lock, it is acquired here.
+ */
+static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
+{
+       struct zilog_channel *channel;
+       unsigned char status;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       return status;
+}
+
+/* The port lock is not held.  */
+static unsigned int ip22zilog_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned char status;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       status = ip22zilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (status & Tx_BUF_EMP)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int ret;
+
+       status = ip22zilog_read_channel_status(port);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC)
+               ret |= TIOCM_DSR;
+       if (status & CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits;
+
+       set_bits = clear_bits = 0;
+
+       if (mctrl & TIOCM_RTS)
+               set_bits |= RTS;
+       else
+               clear_bits |= RTS;
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */
+       up->curregs[R5] |= set_bits;
+       up->curregs[R5] &= ~clear_bits;
+       write_zsreg(channel, R5, up->curregs[R5]);
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_stop_tx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+
+       up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_start_tx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char status;
+
+       up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+       up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               writeb(port->x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               writeb(xmit->buf[xmit->tail], &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&up->port);
+       }
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_stop_rx(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       struct zilog_channel *channel;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable all RX interrupts.  */
+       up->curregs[R1] &= ~RxINT_MASK;
+       ip22zilog_maybe_update_regs(up, channel);
+}
+
+/* The port lock is held.  */
+static void ip22zilog_enable_ms(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char new_reg;
+
+       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != up->curregs[R15]) {
+               up->curregs[R15] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */
+               write_zsreg(channel, R15, up->curregs[R15]);
+       }
+}
+
+/* The port lock is not held.  */
+static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != up->curregs[R5]) {
+               up->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */
+               write_zsreg(channel, R5, up->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
+{
+       struct zilog_channel *channel;
+       int i;
+
+       if (up->flags & IP22ZILOG_FLAG_RESET_DONE)
+               return;
+
+       /* Let pending transmits finish.  */
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       if (!ZS_IS_CHANNEL_A(up)) {
+               up++;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       }
+       write_zsreg(channel, R9, FHWRES);
+       ZSDELAY_LONG();
+       (void) read_zsreg(channel, R0);
+
+       up->flags |= IP22ZILOG_FLAG_RESET_DONE;
+       up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
+}
+
+static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
+{
+       struct zilog_channel *channel;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+       __ip22zilog_reset(up);
+
+       __load_zsregs(channel, up->curregs);
+       /* set master interrupt enable */
+       write_zsreg(channel, R9, up->curregs[R9]);
+       up->prev_status = readb(&channel->control);
+
+       /* Enable receiver and transmitter.  */
+       up->curregs[R3] |= RxENAB;
+       up->curregs[R5] |= TxENAB;
+
+       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+       ip22zilog_maybe_update_regs(up, channel);
+}
+
+static int ip22zilog_startup(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __ip22zilog_startup(up);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return 0;
+}
+
+/*
+ * The test for ZS_IS_CONS is explained by the following e-mail:
+ *****
+ * From: Russell King <rmk@arm.linux.org.uk>
+ * Date: Sun, 8 Dec 2002 10:18:38 +0000
+ *
+ * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
+ * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
+ * > and I noticed that something is not right with reference
+ * > counting in this case. It seems that when the console
+ * > is open by kernel initially, this is not accounted
+ * > as an open, and uart_startup is not called.
+ *
+ * That is correct.  We are unable to call uart_startup when the serial
+ * console is initialised because it may need to allocate memory (as
+ * request_irq does) and the memory allocators may not have been
+ * initialised.
+ *
+ * 1. initialise the port into a state where it can send characters in the
+ *    console write method.
+ *
+ * 2. don't do the actual hardware shutdown in your shutdown() method (but
+ *    do the normal software shutdown - ie, free irqs etc)
+ *****
+ */
+static void ip22zilog_shutdown(struct uart_port *port)
+{
+       struct uart_ip22zilog_port *up = UART_ZILOG(port);
+       struct zilog_channel *channel;
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable receiver and transmitter.  */
+       up->curregs[R3] &= ~RxENAB;
+       up->curregs[R5] &= ~TxENAB;
+
+       /* Disable all interrupts and BRK assertion.  */
+       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       up->curregs[R5] &= ~SND_BRK;
+       ip22zilog_maybe_update_regs(up, channel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void
+ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
+                      unsigned int iflag, int brg)
+{
+
+       up->curregs[R10] = NRZ;
+       up->curregs[R11] = TCBR | RCBR;
+
+       /* Program BAUD and clock source. */
+       up->curregs[R4] &= ~XCLK_MASK;
+       up->curregs[R4] |= X16CLK;
+       up->curregs[R12] = brg & 0xff;
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       up->curregs[R14] = BRENAB;
+
+       /* Character size, stop bits, and parity. */
+       up->curregs[3] &= ~RxN_MASK;
+       up->curregs[5] &= ~TxN_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               up->curregs[3] |= Rx5;
+               up->curregs[5] |= Tx5;
+               up->parity_mask = 0x1f;
+               break;
+       case CS6:
+               up->curregs[3] |= Rx6;
+               up->curregs[5] |= Tx6;
+               up->parity_mask = 0x3f;
+               break;
+       case CS7:
+               up->curregs[3] |= Rx7;
+               up->curregs[5] |= Tx7;
+               up->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               up->curregs[3] |= Rx8;
+               up->curregs[5] |= Tx8;
+               up->parity_mask = 0xff;
+               break;
+       };
+       up->curregs[4] &= ~0x0c;
+       if (cflag & CSTOPB)
+               up->curregs[4] |= SB2;
+       else
+               up->curregs[4] |= SB1;
+       if (cflag & PARENB)
+               up->curregs[4] |= PAR_ENAB;
+       else
+               up->curregs[4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               up->curregs[4] |= PAR_EVEN;
+       else
+               up->curregs[4] &= ~PAR_EVEN;
+
+       up->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= BRK_ABRT;
+
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask = 0xff;
+}
+
+/* The port lock is not held.  */
+static void
+ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
+                     struct ktermios *old)
+{
+       struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+       unsigned long flags;
+       int baud, brg;
+
+       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
+
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->flags |= IP22ZILOG_FLAG_MODEM_STATUS;
+       else
+               up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
+
+       ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *ip22zilog_type(struct uart_port *port)
+{
+       return "IP22-Zilog";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void ip22zilog_release_port(struct uart_port *port)
+{
+}
+
+static int ip22zilog_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void ip22zilog_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops ip22zilog_pops = {
+       .tx_empty       =       ip22zilog_tx_empty,
+       .set_mctrl      =       ip22zilog_set_mctrl,
+       .get_mctrl      =       ip22zilog_get_mctrl,
+       .stop_tx        =       ip22zilog_stop_tx,
+       .start_tx       =       ip22zilog_start_tx,
+       .stop_rx        =       ip22zilog_stop_rx,
+       .enable_ms      =       ip22zilog_enable_ms,
+       .break_ctl      =       ip22zilog_break_ctl,
+       .startup        =       ip22zilog_startup,
+       .shutdown       =       ip22zilog_shutdown,
+       .set_termios    =       ip22zilog_set_termios,
+       .type           =       ip22zilog_type,
+       .release_port   =       ip22zilog_release_port,
+       .request_port   =       ip22zilog_request_port,
+       .config_port    =       ip22zilog_config_port,
+       .verify_port    =       ip22zilog_verify_port,
+};
+
+static struct uart_ip22zilog_port *ip22zilog_port_table;
+static struct zilog_layout **ip22zilog_chip_regs;
+
+static struct uart_ip22zilog_port *ip22zilog_irq_chain;
+static int zilog_irq = -1;
+
+static void * __init alloc_one_table(unsigned long size)
+{
+       return kzalloc(size, GFP_KERNEL);
+}
+
+static void __init ip22zilog_alloc_tables(void)
+{
+       ip22zilog_port_table = (struct uart_ip22zilog_port *)
+               alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
+       ip22zilog_chip_regs = (struct zilog_layout **)
+               alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
+
+       if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
+               panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
+       }
+}
+
+/* Get the address of the registers for IP22-Zilog instance CHIP.  */
+static struct zilog_layout * __init get_zs(int chip)
+{
+       unsigned long base;
+
+       if (chip < 0 || chip >= NUM_IP22ZILOG) {
+               panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
+       }
+
+       /* Not probe-able, hard code it. */
+       base = (unsigned long) &sgioc->uart;
+
+       zilog_irq = SGI_SERIAL_IRQ;
+       request_mem_region(base, 8, "IP22-Zilog");
+
+       return (struct zilog_layout *) base;
+}
+
+#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
+
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+static void ip22zilog_put_char(struct uart_port *port, int ch)
+{
+       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+       /* This is a timed polling loop so do not switch the explicit
+        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
+        */
+       do {
+               unsigned char val = readb(&channel->control);
+               if (val & Tx_BUF_EMP) {
+                       ZSDELAY();
+                       break;
+               }
+               udelay(5);
+       } while (--loops);
+
+       writeb(ch, &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static void
+ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       uart_console_write(&up->port, s, count, ip22zilog_put_char);
+       udelay(2);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int __init ip22zilog_console_setup(struct console *con, char *options)
+{
+       struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+       unsigned long flags;
+       int baud = 9600, bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       up->flags |= IP22ZILOG_FLAG_IS_CONS;
+
+       printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->curregs[R15] |= BRKIE;
+
+       __ip22zilog_startup(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(&up->port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver ip22zilog_reg;
+
+static struct console ip22zilog_console = {
+       .name   =       "ttyS",
+       .write  =       ip22zilog_console_write,
+       .device =       uart_console_device,
+       .setup  =       ip22zilog_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &ip22zilog_reg,
+};
+#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
+
+static struct uart_driver ip22zilog_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = NUM_CHANNELS,
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+       .cons           = &ip22zilog_console,
+#endif
+};
+
+static void __init ip22zilog_prepare(void)
+{
+       struct uart_ip22zilog_port *up;
+       struct zilog_layout *rp;
+       int channel, chip;
+
+       /*
+        * Temporary fix.
+        */
+       for (channel = 0; channel < NUM_CHANNELS; channel++)
+               spin_lock_init(&ip22zilog_port_table[channel].port.lock);
+
+       ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
+        up = &ip22zilog_port_table[0];
+       for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
+               up[channel].next = &up[channel - 1];
+       up[channel].next = NULL;
+
+       for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
+               if (!ip22zilog_chip_regs[chip]) {
+                       ip22zilog_chip_regs[chip] = rp = get_zs(chip);
+
+                       up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
+                       up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
+
+                       /* In theory mapbase is the physical address ...  */
+                       up[(chip * 2) + 0].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
+                       up[(chip * 2) + 1].port.mapbase =
+                               (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
+               }
+
+               /* Channel A */
+               up[(chip * 2) + 0].port.iotype = UPIO_MEM;
+               up[(chip * 2) + 0].port.irq = zilog_irq;
+               up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
+               up[(chip * 2) + 0].port.fifosize = 1;
+               up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
+               up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
+               up[(chip * 2) + 0].port.flags = 0;
+               up[(chip * 2) + 0].port.line = (chip * 2) + 0;
+               up[(chip * 2) + 0].flags = 0;
+
+               /* Channel B */
+               up[(chip * 2) + 1].port.iotype = UPIO_MEM;
+               up[(chip * 2) + 1].port.irq = zilog_irq;
+               up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
+               up[(chip * 2) + 1].port.fifosize = 1;
+               up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
+               up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
+               up[(chip * 2) + 1].port.line = (chip * 2) + 1;
+               up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
+       }
+
+       for (channel = 0; channel < NUM_CHANNELS; channel++) {
+               struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
+               int brg;
+
+               /* Normal serial TTY. */
+               up->parity_mask = 0xff;
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R9] = NV | MIE;
+               up->curregs[R10] = NRZ;
+               up->curregs[R11] = TCBR | RCBR;
+               brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+               up->curregs[R12] = (brg & 0xff);
+               up->curregs[R13] = (brg >> 8) & 0xff;
+               up->curregs[R14] = BRENAB;
+       }
+}
+
+static int __init ip22zilog_ports_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
+
+       ip22zilog_prepare();
+
+       if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
+                       "IP22-Zilog", ip22zilog_irq_chain)) {
+               panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
+       }
+
+       ret = uart_register_driver(&ip22zilog_reg);
+       if (ret == 0) {
+               int i;
+
+               for (i = 0; i < NUM_CHANNELS; i++) {
+                       struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+
+                       uart_add_one_port(&ip22zilog_reg, &up->port);
+               }
+       }
+
+       return ret;
+}
+
+static int __init ip22zilog_init(void)
+{
+       /* IP22 Zilog setup is hard coded, no probing to do.  */
+       ip22zilog_alloc_tables();
+       ip22zilog_ports_init();
+
+       return 0;
+}
+
+static void __exit ip22zilog_exit(void)
+{
+       int i;
+       struct uart_ip22zilog_port *up;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               up = &ip22zilog_port_table[i];
+
+               uart_remove_one_port(&ip22zilog_reg, &up->port);
+       }
+
+       /* Free IO mem */
+       up = &ip22zilog_port_table[0];
+       for (i = 0; i < NUM_IP22ZILOG; i++) {
+               if (up[(i * 2) + 0].port.mapbase) {
+                  iounmap((void*)up[(i * 2) + 0].port.mapbase);
+                  up[(i * 2) + 0].port.mapbase = 0;
+               }
+               if (up[(i * 2) + 1].port.mapbase) {
+                       iounmap((void*)up[(i * 2) + 1].port.mapbase);
+                       up[(i * 2) + 1].port.mapbase = 0;
+               }
+       }
+
+       uart_unregister_driver(&ip22zilog_reg);
+}
+
+module_init(ip22zilog_init);
+module_exit(ip22zilog_exit);
+
+/* David wrote it but I'm to blame for the bugs ...  */
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_DESCRIPTION("SGI Zilog serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ip22zilog.h b/drivers/tty/serial/ip22zilog.h
new file mode 100644 (file)
index 0000000..a59a9a8
--- /dev/null
@@ -0,0 +1,281 @@
+#ifndef _IP22_ZILOG_H
+#define _IP22_ZILOG_H
+
+#include <asm/byteorder.h>
+
+struct zilog_channel {
+#ifdef __BIG_ENDIAN
+       volatile unsigned char unused0[3];
+       volatile unsigned char control;
+       volatile unsigned char unused1[3];
+       volatile unsigned char data;
+#else /* __LITTLE_ENDIAN */
+       volatile unsigned char control;
+       volatile unsigned char unused0[3];
+       volatile unsigned char data;
+       volatile unsigned char unused1[3];
+#endif
+};
+
+struct zilog_layout {
+       struct zilog_channel channelB;
+       struct zilog_channel channelA;
+};
+
+#define NUM_ZSREGS    16
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENAB          0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        ZCIE    2       /* Zero count IE */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC            0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY   0x00
+#define CHB_EXT_STAT   0x02
+#define CHB_Rx_AVAIL   0x04
+#define CHB_SPECIAL    0x06
+#define CHA_Tx_EMPTY   0x08
+#define CHA_EXT_STAT   0x0a
+#define CHA_Rx_AVAIL   0x0c
+#define CHA_SPECIAL    0x0e
+#define STATUS_MASK    0x0e
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    do { writeb(ERR_RES, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { writeb(RES_EXT_INT, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARFIFO(channel)   do { readb(&channel->data); \
+                                    udelay(2); \
+                                    readb(&channel->data); \
+                                    udelay(2); \
+                                    readb(&channel->data); \
+                                    udelay(2); } while(0)
+
+#endif /* _IP22_ZILOG_H */
diff --git a/drivers/tty/serial/jsm/Makefile b/drivers/tty/serial/jsm/Makefile
new file mode 100644 (file)
index 0000000..e46b6e0
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for Jasmine adapter
+#
+
+obj-$(CONFIG_SERIAL_JSM) += jsm.o
+
+jsm-objs :=    jsm_driver.o jsm_neo.o jsm_tty.o
+
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
new file mode 100644 (file)
index 0000000..38a509c
--- /dev/null
@@ -0,0 +1,388 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ ***********************************************************************/
+
+#ifndef __JSM_DRIVER_H
+#define __JSM_DRIVER_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>       /* To pick up the varions Linux types */
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+enum {
+       DBG_INIT        = 0x01,
+       DBG_BASIC       = 0x02,
+       DBG_CORE        = 0x04,
+       DBG_OPEN        = 0x08,
+       DBG_CLOSE       = 0x10,
+       DBG_READ        = 0x20,
+       DBG_WRITE       = 0x40,
+       DBG_IOCTL       = 0x80,
+       DBG_PROC        = 0x100,
+       DBG_PARAM       = 0x200,
+       DBG_PSCAN       = 0x400,
+       DBG_EVENT       = 0x800,
+       DBG_DRAIN       = 0x1000,
+       DBG_MSIGS       = 0x2000,
+       DBG_MGMT        = 0x4000,
+       DBG_INTR        = 0x8000,
+       DBG_CARR        = 0x10000,
+};
+
+#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \
+       if ((DBG_##nlevel & jsm_debug))                 \
+       dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
+
+#define        MAXLINES        256
+#define MAXPORTS       8
+#define MAX_STOPS_SENT 5
+
+/* Board type definitions */
+
+#define T_NEO          0000
+#define T_CLASSIC      0001
+#define T_PCIBUS       0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING     0x0
+#define BD_REASON      0x7f
+#define BD_NOTFOUND    0x1
+#define BD_NOIOPORT    0x2
+#define BD_NOMEM       0x3
+#define BD_NOBIOS      0x4
+#define BD_NOFEP       0x5
+#define BD_FAILED      0x6
+#define BD_ALLOCATED   0x7
+#define BD_TRIBOOT     0x8
+#define BD_BADKME      0x80
+
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN    ((4096) + 4)
+#define MYFLIPLEN      N_TTY_BUF_SIZE
+
+#define JSM_VERSION    "jsm: 1.2-1-INKERNEL"
+#define JSM_PARTNUM    "40002438_A-INKERNEL"
+
+struct jsm_board;
+struct jsm_channel;
+
+/************************************************************************
+ * Per board operations structure                                      *
+ ************************************************************************/
+struct board_ops {
+       irq_handler_t intr;
+       void (*uart_init) (struct jsm_channel *ch);
+       void (*uart_off) (struct jsm_channel *ch);
+       void (*param) (struct jsm_channel *ch);
+       void (*assert_modem_signals) (struct jsm_channel *ch);
+       void (*flush_uart_write) (struct jsm_channel *ch);
+       void (*flush_uart_read) (struct jsm_channel *ch);
+       void (*disable_receiver) (struct jsm_channel *ch);
+       void (*enable_receiver) (struct jsm_channel *ch);
+       void (*send_break) (struct jsm_channel *ch);
+       void (*clear_break) (struct jsm_channel *ch, int);
+       void (*send_start_character) (struct jsm_channel *ch);
+       void (*send_stop_character) (struct jsm_channel *ch);
+       void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
+       u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
+       void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
+};
+
+
+/*
+ *     Per-board information
+ */
+struct jsm_board
+{
+       int             boardnum;       /* Board number: 0-32 */
+
+       int             type;           /* Type of board */
+       u8              rev;            /* PCI revision ID */
+       struct pci_dev  *pci_dev;
+       u32             maxports;       /* MAX ports this board can handle */
+
+       spinlock_t      bd_intr_lock;   /* Used to protect the poller tasklet and
+                                        * the interrupt routine from each other.
+                                        */
+
+       u32             nasync;         /* Number of ports on card */
+
+       u32             irq;            /* Interrupt request number */
+
+       u64             membase;        /* Start of base memory of the card */
+       u64             membase_end;    /* End of base memory of the card */
+
+       u8      __iomem *re_map_membase;/* Remapped memory of the card */
+
+       u64             iobase;         /* Start of io base of the card */
+       u64             iobase_end;     /* End of io base of the card */
+
+       u32             bd_uart_offset; /* Space between each UART */
+
+       struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
+       char            *flipbuf;       /* Our flip buffer, alloced if board is found */
+
+       u32             bd_dividend;    /* Board/UARTs specific dividend */
+
+       struct board_ops *bd_ops;
+
+       struct list_head jsm_board_entry;
+};
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON                0x0001          /* Printer on string            */
+#define CH_STOP                0x0002          /* Output is stopped            */
+#define CH_STOPI       0x0004          /* Input is stopped             */
+#define CH_CD          0x0008          /* Carrier is present           */
+#define CH_FCAR                0x0010          /* Carrier forced on            */
+#define CH_HANGUP      0x0020          /* Hangup received              */
+
+#define CH_RECEIVER_OFF        0x0040          /* Receiver is off              */
+#define CH_OPENING     0x0080          /* Port in fragile open state   */
+#define CH_CLOSING     0x0100          /* Port in fragile close state  */
+#define CH_FIFO_ENABLED 0x0200         /* Port has FIFOs enabled       */
+#define CH_TX_FIFO_EMPTY 0x0400                /* TX Fifo is completely empty  */
+#define CH_TX_FIFO_LWM 0x0800          /* TX Fifo is below Low Water   */
+#define CH_BREAK_SENDING 0x1000                /* Break is being sent          */
+#define CH_LOOPBACK 0x2000             /* Channel is in lookback mode  */
+#define CH_FLIPBUF_IN_USE 0x4000       /* Channel's flipbuf is in use  */
+#define CH_BAUD0       0x08000         /* Used for checking B0 transitions */
+
+/* Our Read/Error/Write queue sizes */
+#define RQUEUEMASK     0x1FFF          /* 8 K - 1 */
+#define EQUEUEMASK     0x1FFF          /* 8 K - 1 */
+#define WQUEUEMASK     0x0FFF          /* 4 K - 1 */
+#define RQUEUESIZE     (RQUEUEMASK + 1)
+#define EQUEUESIZE     RQUEUESIZE
+#define WQUEUESIZE     (WQUEUEMASK + 1)
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct jsm_channel {
+       struct uart_port uart_port;
+       struct jsm_board        *ch_bd;         /* Board structure pointer      */
+
+       spinlock_t      ch_lock;        /* provide for serialization */
+       wait_queue_head_t ch_flags_wait;
+
+       u32             ch_portnum;     /* Port number, 0 offset.       */
+       u32             ch_open_count;  /* open count                   */
+       u32             ch_flags;       /* Channel flags                */
+
+       u64             ch_close_delay; /* How long we should drop RTS/DTR for */
+
+       tcflag_t        ch_c_iflag;     /* channel iflags               */
+       tcflag_t        ch_c_cflag;     /* channel cflags               */
+       tcflag_t        ch_c_oflag;     /* channel oflags               */
+       tcflag_t        ch_c_lflag;     /* channel lflags               */
+       u8              ch_stopc;       /* Stop character               */
+       u8              ch_startc;      /* Start character              */
+
+       u8              ch_mostat;      /* FEP output modem status      */
+       u8              ch_mistat;      /* FEP input modem status       */
+
+       struct neo_uart_struct __iomem *ch_neo_uart;    /* Pointer to the "mapped" UART struct */
+       u8              ch_cached_lsr;  /* Cached value of the LSR register */
+
+       u8              *ch_rqueue;     /* Our read queue buffer - malloc'ed */
+       u16             ch_r_head;      /* Head location of the read queue */
+       u16             ch_r_tail;      /* Tail location of the read queue */
+
+       u8              *ch_equeue;     /* Our error queue buffer - malloc'ed */
+       u16             ch_e_head;      /* Head location of the error queue */
+       u16             ch_e_tail;      /* Tail location of the error queue */
+
+       u8              *ch_wqueue;     /* Our write queue buffer - malloc'ed */
+       u16             ch_w_head;      /* Head location of the write queue */
+       u16             ch_w_tail;      /* Tail location of the write queue */
+
+       u64             ch_rxcount;     /* total of data received so far */
+       u64             ch_txcount;     /* total of data transmitted so far */
+
+       u8              ch_r_tlevel;    /* Receive Trigger level */
+       u8              ch_t_tlevel;    /* Transmit Trigger level */
+
+       u8              ch_r_watermark; /* Receive Watermark */
+
+
+       u32             ch_stops_sent;  /* How many times I have sent a stop character
+                                        * to try to stop the other guy sending.
+                                        */
+       u64             ch_err_parity;  /* Count of parity errors on channel */
+       u64             ch_err_frame;   /* Count of framing errors on channel */
+       u64             ch_err_break;   /* Count of breaks on channel */
+       u64             ch_err_overrun; /* Count of overruns on channel */
+
+       u64             ch_xon_sends;   /* Count of xons transmitted */
+       u64             ch_xoff_sends;  /* Count of xoffs transmitted */
+};
+
+
+/************************************************************************
+ * Per channel/port NEO UART structure                                 *
+ ************************************************************************
+ *             Base Structure Entries Usage Meanings to Host           *
+ *                                                                     *
+ *     W = read write          R = read only                           *
+ *                     U = Unused.                                     *
+ ************************************************************************/
+
+struct neo_uart_struct {
+        u8 txrx;               /* WR   RHR/THR - Holding Reg */
+        u8 ier;                /* WR   IER - Interrupt Enable Reg */
+        u8 isr_fcr;            /* WR   ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+        u8 lcr;                /* WR   LCR - Line Control Reg */
+        u8 mcr;                /* WR   MCR - Modem Control Reg */
+        u8 lsr;                /* WR   LSR - Line Status Reg */
+        u8 msr;                /* WR   MSR - Modem Status Reg */
+        u8 spr;                /* WR   SPR - Scratch Pad Reg */
+        u8 fctr;               /* WR   FCTR - Feature Control Reg */
+        u8 efr;                /* WR   EFR - Enhanced Function Reg */
+        u8 tfifo;              /* WR   TXCNT/TXTRG - Transmit FIFO Reg */
+        u8 rfifo;              /* WR   RXCNT/RXTRG - Recieve FIFO Reg */
+        u8 xoffchar1;  /* WR   XOFF 1 - XOff Character 1 Reg */
+        u8 xoffchar2;  /* WR   XOFF 2 - XOff Character 2 Reg */
+        u8 xonchar1;   /* WR   XON 1 - Xon Character 1 Reg */
+        u8 xonchar2;   /* WR   XON 2 - XOn Character 2 Reg */
+
+        u8 reserved1[0x2ff - 0x200]; /* U      Reserved by Exar */
+        u8 txrxburst[64];      /* RW   64 bytes of RX/TX FIFO Data */
+        u8 reserved2[0x37f - 0x340]; /* U      Reserved by Exar */
+        u8 rxburst_with_errors[64];    /* R    64 bytes of RX FIFO Data + LSR */
+};
+
+/* Where to read the extended interrupt register (32bits instead of 8bits) */
+#define        UART_17158_POLL_ADDR_OFFSET     0x80
+
+/*
+ * These are the redefinitions for the FCTR on the XR17C158, since
+ * Exar made them different than their earlier design. (XR16C854)
+ */
+
+/* These are only applicable when table D is selected */
+#define UART_17158_FCTR_RTS_NODELAY    0x00
+#define UART_17158_FCTR_RTS_4DELAY     0x01
+#define UART_17158_FCTR_RTS_6DELAY     0x02
+#define UART_17158_FCTR_RTS_8DELAY     0x03
+#define UART_17158_FCTR_RTS_12DELAY    0x12
+#define UART_17158_FCTR_RTS_16DELAY    0x05
+#define UART_17158_FCTR_RTS_20DELAY    0x13
+#define UART_17158_FCTR_RTS_24DELAY    0x06
+#define UART_17158_FCTR_RTS_28DELAY    0x14
+#define UART_17158_FCTR_RTS_32DELAY    0x07
+#define UART_17158_FCTR_RTS_36DELAY    0x16
+#define UART_17158_FCTR_RTS_40DELAY    0x08
+#define UART_17158_FCTR_RTS_44DELAY    0x09
+#define UART_17158_FCTR_RTS_48DELAY    0x10
+#define UART_17158_FCTR_RTS_52DELAY    0x11
+
+#define UART_17158_FCTR_RTS_IRDA       0x10
+#define UART_17158_FCTR_RS485          0x20
+#define UART_17158_FCTR_TRGA           0x00
+#define UART_17158_FCTR_TRGB           0x40
+#define UART_17158_FCTR_TRGC           0x80
+#define UART_17158_FCTR_TRGD           0xC0
+
+/* 17158 trigger table selects.. */
+#define UART_17158_FCTR_BIT6           0x40
+#define UART_17158_FCTR_BIT7           0x80
+
+/* 17158 TX/RX memmapped buffer offsets */
+#define UART_17158_RX_FIFOSIZE         64
+#define UART_17158_TX_FIFOSIZE         64
+
+/* 17158 Extended IIR's */
+#define UART_17158_IIR_RDI_TIMEOUT     0x0C    /* Receiver data TIMEOUT */
+#define UART_17158_IIR_XONXOFF         0x10    /* Received an XON/XOFF char */
+#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20        /* CTS/DSR or RTS/DTR state change */
+#define UART_17158_IIR_FIFO_ENABLED    0xC0    /* 16550 FIFOs are Enabled */
+
+/*
+ * These are the extended interrupts that get sent
+ * back to us from the UART's 32bit interrupt register
+ */
+#define UART_17158_RX_LINE_STATUS      0x1     /* RX Ready */
+#define UART_17158_RXRDY_TIMEOUT       0x2     /* RX Ready Timeout */
+#define UART_17158_TXRDY               0x3     /* TX Ready */
+#define UART_17158_MSR                 0x4     /* Modem State Change */
+#define UART_17158_TX_AND_FIFO_CLR     0x40    /* Transmitter Holding Reg Empty */
+#define UART_17158_RX_FIFO_DATA_ERROR  0x80    /* UART detected an RX FIFO Data error */
+
+/*
+ * These are the EXTENDED definitions for the 17C158's Interrupt
+ * Enable Register.
+ */
+#define UART_17158_EFR_ECB     0x10    /* Enhanced control bit */
+#define UART_17158_EFR_IXON    0x2     /* Receiver compares Xon1/Xoff1 */
+#define UART_17158_EFR_IXOFF   0x8     /* Transmit Xon1/Xoff1 */
+#define UART_17158_EFR_RTSDTR  0x40    /* Auto RTS/DTR Flow Control Enable */
+#define UART_17158_EFR_CTSDSR  0x80    /* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_17158_XOFF_DETECT 0x1     /* Indicates whether chip saw an incoming XOFF char */
+#define UART_17158_XON_DETECT  0x2     /* Indicates whether chip saw an incoming XON char */
+
+#define UART_17158_IER_RSVD1   0x10    /* Reserved by Exar */
+#define UART_17158_IER_XOFF    0x20    /* Xoff Interrupt Enable */
+#define UART_17158_IER_RTSDTR  0x40    /* Output Interrupt Enable */
+#define UART_17158_IER_CTSDSR  0x80    /* Input Interrupt Enable */
+
+#define PCI_DEVICE_NEO_2DB9_PCI_NAME           "Neo 2 - DB9 Universal PCI"
+#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME                "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_2RJ45_PCI_NAME          "Neo 2 - RJ45 Universal PCI"
+#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME       "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME           "Neo 4 - PCI Express - IBM"
+
+/*
+ * Our Global Variables.
+ */
+extern struct  uart_driver jsm_uart_driver;
+extern struct  board_ops jsm_neo_ops;
+extern int     jsm_debug;
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+int jsm_tty_write(struct uart_port *port);
+int jsm_tty_init(struct jsm_board *);
+int jsm_uart_port_init(struct jsm_board *);
+int jsm_remove_uart_port(struct jsm_board *);
+void jsm_input(struct jsm_channel *ch);
+void jsm_check_queue_flow_control(struct jsm_channel *ch);
+
+#endif
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
new file mode 100644 (file)
index 0000000..18f5484
--- /dev/null
@@ -0,0 +1,297 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ *
+ ***********************************************************************/
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "jsm.h"
+
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International "
+                  "Neo PCI based product line");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("jsm");
+
+#define JSM_DRIVER_NAME "jsm"
+#define NR_PORTS       32
+#define JSM_MINOR_START        0
+
+struct uart_driver jsm_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = JSM_DRIVER_NAME,
+       .dev_name       = "ttyn",
+       .major          = 0,
+       .minor          = JSM_MINOR_START,
+       .nr             = NR_PORTS,
+};
+
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state);
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
+static void jsm_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers jsm_err_handler = {
+       .error_detected = jsm_io_error_detected,
+       .slot_reset = jsm_io_slot_reset,
+       .resume = jsm_io_resume,
+};
+
+int jsm_debug;
+module_param(jsm_debug, int, 0);
+MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
+
+static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int rc = 0;
+       struct jsm_board *brd;
+       static int adapter_count = 0;
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_err(&pdev->dev, "Device enable FAILED\n");
+               goto out;
+       }
+
+       rc = pci_request_regions(pdev, "jsm");
+       if (rc) {
+               dev_err(&pdev->dev, "pci_request_region FAILED\n");
+               goto out_disable_device;
+       }
+
+       brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
+       if (!brd) {
+               dev_err(&pdev->dev,
+                       "memory allocation for board structure failed\n");
+               rc = -ENOMEM;
+               goto out_release_regions;
+       }
+
+       /* store the info for the board we've found */
+       brd->boardnum = adapter_count++;
+       brd->pci_dev = pdev;
+       if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+               brd->maxports = 4;
+       else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
+               brd->maxports = 8;
+       else
+               brd->maxports = 2;
+
+       spin_lock_init(&brd->bd_intr_lock);
+
+       /* store which revision we have */
+       brd->rev = pdev->revision;
+
+       brd->irq = pdev->irq;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev,
+               "jsm_found_board - NEO adapter\n");
+
+       /* get the PCI Base Address Registers */
+       brd->membase    = pci_resource_start(pdev, 0);
+       brd->membase_end = pci_resource_end(pdev, 0);
+
+       if (brd->membase & 1)
+               brd->membase &= ~3;
+       else
+               brd->membase &= ~15;
+
+       /* Assign the board_ops struct */
+       brd->bd_ops = &jsm_neo_ops;
+
+       brd->bd_uart_offset = 0x200;
+       brd->bd_dividend = 921600;
+
+       brd->re_map_membase = ioremap(brd->membase, 0x1000);
+       if (!brd->re_map_membase) {
+               dev_err(&pdev->dev,
+                       "card has no PCI Memory resources, "
+                       "failing board.\n");
+               rc = -ENOMEM;
+               goto out_kfree_brd;
+       }
+
+       rc = request_irq(brd->irq, brd->bd_ops->intr,
+                       IRQF_SHARED, "JSM", brd);
+       if (rc) {
+               printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
+               goto out_iounmap;
+       }
+
+       rc = jsm_tty_init(brd);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
+               rc = -ENXIO;
+               goto out_free_irq;
+       }
+
+       rc = jsm_uart_port_init(brd);
+       if (rc < 0) {
+               /* XXX: leaking all resources from jsm_tty_init here! */
+               dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
+               rc = -ENXIO;
+               goto out_free_irq;
+       }
+
+       /* Log the information about the board */
+       dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
+                       adapter_count, brd->rev, brd->irq);
+
+       /*
+        * allocate flip buffer for board.
+        *
+        * Okay to malloc with GFP_KERNEL, we are not at interrupt
+        * context, and there are no locks held.
+        */
+       brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+       if (!brd->flipbuf) {
+               /* XXX: leaking all resources from jsm_tty_init and
+                       jsm_uart_port_init here! */
+               dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
+               rc = -ENOMEM;
+               goto out_free_uart;
+       }
+
+       pci_set_drvdata(pdev, brd);
+       pci_save_state(pdev);
+
+       return 0;
+ out_free_uart:
+       jsm_remove_uart_port(brd);
+ out_free_irq:
+       jsm_remove_uart_port(brd);
+       free_irq(brd->irq, brd);
+ out_iounmap:
+       iounmap(brd->re_map_membase);
+ out_kfree_brd:
+       kfree(brd);
+ out_release_regions:
+       pci_release_regions(pdev);
+ out_disable_device:
+       pci_disable_device(pdev);
+ out:
+       return rc;
+}
+
+static void __devexit jsm_remove_one(struct pci_dev *pdev)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+       int i = 0;
+
+       jsm_remove_uart_port(brd);
+
+       free_irq(brd->irq, brd);
+       iounmap(brd->re_map_membase);
+
+       /* Free all allocated channels structs */
+       for (i = 0; i < brd->maxports; i++) {
+               if (brd->channels[i]) {
+                       kfree(brd->channels[i]->ch_rqueue);
+                       kfree(brd->channels[i]->ch_equeue);
+                       kfree(brd->channels[i]->ch_wqueue);
+                       kfree(brd->channels[i]);
+               }
+       }
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       kfree(brd->flipbuf);
+       kfree(brd);
+}
+
+static struct pci_device_id jsm_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
+
+static struct pci_driver jsm_driver = {
+       .name           = "jsm",
+       .id_table       = jsm_pci_tbl,
+       .probe          = jsm_probe_one,
+       .remove         = __devexit_p(jsm_remove_one),
+       .err_handler    = &jsm_err_handler,
+};
+
+static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
+                                       pci_channel_state_t state)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       jsm_remove_uart_port(brd);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
+{
+       int rc;
+
+       rc = pci_enable_device(pdev);
+
+       if (rc)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       pci_set_master(pdev);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void jsm_io_resume(struct pci_dev *pdev)
+{
+       struct jsm_board *brd = pci_get_drvdata(pdev);
+
+       pci_restore_state(pdev);
+
+       jsm_uart_port_init(brd);
+}
+
+static int __init jsm_init_module(void)
+{
+       int rc;
+
+       rc = uart_register_driver(&jsm_uart_driver);
+       if (!rc) {
+               rc = pci_register_driver(&jsm_driver);
+               if (rc)
+                       uart_unregister_driver(&jsm_uart_driver);
+       }
+       return rc;
+}
+
+static void __exit jsm_exit_module(void)
+{
+       pci_unregister_driver(&jsm_driver);
+       uart_unregister_driver(&jsm_uart_driver);
+}
+
+module_init(jsm_init_module);
+module_exit(jsm_exit_module);
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
new file mode 100644 (file)
index 0000000..7960d96
--- /dev/null
@@ -0,0 +1,1412 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ibm.com>
+ *
+ ***********************************************************************/
+#include <linux/delay.h>       /* For udelay */
+#include <linux/serial_reg.h>  /* For the various UART offsets */
+#include <linux/tty.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "jsm.h"               /* Driver main header file */
+
+static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+/*
+ * This function allows calls to ensure that all outstanding
+ * PCI writes have been completed, by doing a PCI read against
+ * a non-destructive, read-only location on the Neo card.
+ *
+ * In this case, we are reading the DVID (Read-only Device Identification)
+ * value of the Neo card.
+ */
+static inline void neo_pci_posting_flush(struct jsm_board *bd)
+{
+      readb(bd->re_map_membase + 0x8D);
+}
+
+static void neo_set_cts_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
+
+       /* Turn on auto CTS flow control */
+       ier |= (UART_17158_IER_CTSDSR);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
+
+       /* Turn off auto Xon flow control */
+       efr &= ~(UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+
+       /* Feed the UART our trigger levels */
+       writeb(8, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 8;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_rts_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
+
+       /* Turn on auto RTS flow control */
+       ier |= (UART_17158_IER_RTSDTR);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
+
+       /* Turn off auto Xoff flow control */
+       ier &= ~(UART_17158_IER_XOFF);
+       efr &= ~(UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+       ch->ch_r_watermark = 4;
+
+       writeb(56, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 56;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+
+       /*
+        * From the Neo UART spec sheet:
+        * The auto RTS/DTR function must be started by asserting
+        * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
+        * it is enabled.
+        */
+       ch->ch_mostat |= (UART_MCR_RTS);
+}
+
+
+static void neo_set_ixon_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
+
+       /* Turn off auto CTS flow control */
+       ier &= ~(UART_17158_IER_CTSDSR);
+       efr &= ~(UART_17158_EFR_CTSDSR);
+
+       /* Turn on auto Xon flow control */
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+       ch->ch_r_watermark = 4;
+
+       writeb(32, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 32;
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
+
+       /* Turn off auto RTS flow control */
+       ier &= ~(UART_17158_IER_RTSDTR);
+       efr &= ~(UART_17158_EFR_RTSDTR);
+
+       /* Turn on auto Xoff flow control */
+       ier |= (UART_17158_IER_XOFF);
+       efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       writeb(8, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 8;
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_input_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
+
+       /* Turn off auto RTS flow control */
+       ier &= ~(UART_17158_IER_RTSDTR);
+       efr &= ~(UART_17158_EFR_RTSDTR);
+
+       /* Turn off auto Xoff flow control */
+       ier &= ~(UART_17158_IER_XOFF);
+       if (ch->ch_c_iflag & IXON)
+               efr &= ~(UART_17158_EFR_IXOFF);
+       else
+               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       ch->ch_r_watermark = 0;
+
+       writeb(16, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 16;
+
+       writeb(16, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 16;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static void neo_set_no_output_flow_control(struct jsm_channel *ch)
+{
+       u8 ier, efr;
+       ier = readb(&ch->ch_neo_uart->ier);
+       efr = readb(&ch->ch_neo_uart->efr);
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
+
+       /* Turn off auto CTS flow control */
+       ier &= ~(UART_17158_IER_CTSDSR);
+       efr &= ~(UART_17158_EFR_CTSDSR);
+
+       /* Turn off auto Xon flow control */
+       if (ch->ch_c_iflag & IXOFF)
+               efr &= ~(UART_17158_EFR_IXON);
+       else
+               efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+       /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Turn on UART enhanced bits */
+       writeb(efr, &ch->ch_neo_uart->efr);
+
+       /* Turn on table D, with 8 char hi/low watermarks */
+       writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+       ch->ch_r_watermark = 0;
+
+       writeb(16, &ch->ch_neo_uart->tfifo);
+       ch->ch_t_tlevel = 16;
+
+       writeb(16, &ch->ch_neo_uart->rfifo);
+       ch->ch_r_tlevel = 16;
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+}
+
+static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
+{
+
+       /* if hardware flow control is set, then skip this whole thing */
+       if (ch->ch_c_cflag & CRTSCTS)
+               return;
+
+       jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       /* Tell UART what start/stop chars it should be looking for */
+       writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+       writeb(0, &ch->ch_neo_uart->xonchar2);
+
+       writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+       writeb(0, &ch->ch_neo_uart->xoffchar2);
+}
+
+static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
+{
+       int qleft = 0;
+       u8 linestatus = 0;
+       u8 error_mask = 0;
+       int n = 0;
+       int total = 0;
+       u16 head;
+       u16 tail;
+
+       if (!ch)
+               return;
+
+       /* cache head and tail of queue */
+       head = ch->ch_r_head & RQUEUEMASK;
+       tail = ch->ch_r_tail & RQUEUEMASK;
+
+       /* Get our cached LSR */
+       linestatus = ch->ch_cached_lsr;
+       ch->ch_cached_lsr = 0;
+
+       /* Store how much space we have left in the queue */
+       if ((qleft = tail - head - 1) < 0)
+               qleft += RQUEUEMASK + 1;
+
+       /*
+        * If the UART is not in FIFO mode, force the FIFO copy to
+        * NOT be run, by setting total to 0.
+        *
+        * On the other hand, if the UART IS in FIFO mode, then ask
+        * the UART to give us an approximation of data it has RX'ed.
+        */
+       if (!(ch->ch_flags & CH_FIFO_ENABLED))
+               total = 0;
+       else {
+               total = readb(&ch->ch_neo_uart->rfifo);
+
+               /*
+                * EXAR chip bug - RX FIFO COUNT - Fudge factor.
+                *
+                * This resolves a problem/bug with the Exar chip that sometimes
+                * returns a bogus value in the rfifo register.
+                * The count can be any where from 0-3 bytes "off".
+                * Bizarre, but true.
+                */
+               total -= 3;
+       }
+
+       /*
+        * Finally, bound the copy to make sure we don't overflow
+        * our own queue...
+        * The byte by byte copy loop below this loop this will
+        * deal with the queue overflow possibility.
+        */
+       total = min(total, qleft);
+
+       while (total > 0) {
+               /*
+                * Grab the linestatus register, we need to check
+                * to see if there are any errors in the FIFO.
+                */
+               linestatus = readb(&ch->ch_neo_uart->lsr);
+
+               /*
+                * Break out if there is a FIFO error somewhere.
+                * This will allow us to go byte by byte down below,
+                * finding the exact location of the error.
+                */
+               if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+                       break;
+
+               /* Make sure we don't go over the end of our queue */
+               n = min(((u32) total), (RQUEUESIZE - (u32) head));
+
+               /*
+                * Cut down n even further if needed, this is to fix
+                * a problem with memcpy_fromio() with the Neo on the
+                * IBM pSeries platform.
+                * 15 bytes max appears to be the magic number.
+                */
+               n = min((u32) n, (u32) 12);
+
+               /*
+                * Since we are grabbing the linestatus register, which
+                * will reset some bits after our read, we need to ensure
+                * we don't miss our TX FIFO emptys.
+                */
+               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+               linestatus = 0;
+
+               /* Copy data from uart to the queue */
+               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
+               /*
+                * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
+                * that all the data currently in the FIFO is free of
+                * breaks and parity/frame/orun errors.
+                */
+               memset(ch->ch_equeue + head, 0, n);
+
+               /* Add to and flip head if needed */
+               head = (head + n) & RQUEUEMASK;
+               total -= n;
+               qleft -= n;
+               ch->ch_rxcount += n;
+       }
+
+       /*
+        * Create a mask to determine whether we should
+        * insert the character (if any) into our queue.
+        */
+       if (ch->ch_c_iflag & IGNBRK)
+               error_mask |= UART_LSR_BI;
+
+       /*
+        * Now cleanup any leftover bytes still in the UART.
+        * Also deal with any possible queue overflow here as well.
+        */
+       while (1) {
+
+               /*
+                * Its possible we have a linestatus from the loop above
+                * this, so we "OR" on any extra bits.
+                */
+               linestatus |= readb(&ch->ch_neo_uart->lsr);
+
+               /*
+                * If the chip tells us there is no more data pending to
+                * be read, we can then leave.
+                * But before we do, cache the linestatus, just in case.
+                */
+               if (!(linestatus & UART_LSR_DR)) {
+                       ch->ch_cached_lsr = linestatus;
+                       break;
+               }
+
+               /* No need to store this bit */
+               linestatus &= ~UART_LSR_DR;
+
+               /*
+                * Since we are grabbing the linestatus register, which
+                * will reset some bits after our read, we need to ensure
+                * we don't miss our TX FIFO emptys.
+                */
+               if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+                       linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               }
+
+               /*
+                * Discard character if we are ignoring the error mask.
+                */
+               if (linestatus & error_mask) {
+                       u8 discard;
+                       linestatus = 0;
+                       memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
+                       continue;
+               }
+
+               /*
+                * If our queue is full, we have no choice but to drop some data.
+                * The assumption is that HWFLOW or SWFLOW should have stopped
+                * things way way before we got to this point.
+                *
+                * I decided that I wanted to ditch the oldest data first,
+                * I hope thats okay with everyone? Yes? Good.
+                */
+               while (qleft < 1) {
+                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                               "Queue full, dropping DATA:%x LSR:%x\n",
+                               ch->ch_rqueue[tail], ch->ch_equeue[tail]);
+
+                       ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+                       ch->ch_err_overrun++;
+                       qleft++;
+               }
+
+               memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
+               ch->ch_equeue[head] = (u8) linestatus;
+
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                               "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
+
+               /* Ditch any remaining linestatus value. */
+               linestatus = 0;
+
+               /* Add to and flip head if needed */
+               head = (head + 1) & RQUEUEMASK;
+
+               qleft--;
+               ch->ch_rxcount++;
+       }
+
+       /*
+        * Write new final heads to channel structure.
+        */
+       ch->ch_r_head = head & RQUEUEMASK;
+       ch->ch_e_head = head & EQUEUEMASK;
+       jsm_input(ch);
+}
+
+static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
+{
+       u16 head;
+       u16 tail;
+       int n;
+       int s;
+       int qlen;
+       u32 len_written = 0;
+
+       if (!ch)
+               return;
+
+       /* No data to write to the UART */
+       if (ch->ch_w_tail == ch->ch_w_head)
+               return;
+
+       /* If port is "stopped", don't send any data to the UART */
+       if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
+               return;
+       /*
+        * If FIFOs are disabled. Send data directly to txrx register
+        */
+       if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
+               u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
+
+               ch->ch_cached_lsr |= lsrbits;
+               if (ch->ch_cached_lsr & UART_LSR_THRE) {
+                       ch->ch_cached_lsr &= ~(UART_LSR_THRE);
+
+                       writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+                       jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
+                                       "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
+                       ch->ch_w_tail++;
+                       ch->ch_w_tail &= WQUEUEMASK;
+                       ch->ch_txcount++;
+               }
+               return;
+       }
+
+       /*
+        * We have to do it this way, because of the EXAR TXFIFO count bug.
+        */
+       if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
+               return;
+
+       n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
+
+       /* cache head and tail of queue */
+       head = ch->ch_w_head & WQUEUEMASK;
+       tail = ch->ch_w_tail & WQUEUEMASK;
+       qlen = (head - tail) & WQUEUEMASK;
+
+       /* Find minimum of the FIFO space, versus queue length */
+       n = min(n, qlen);
+
+       while (n > 0) {
+
+               s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+               s = min(s, n);
+
+               if (s <= 0)
+                       break;
+
+               memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+               /* Add and flip queue if needed */
+               tail = (tail + s) & WQUEUEMASK;
+               n -= s;
+               ch->ch_txcount += s;
+               len_written += s;
+       }
+
+       /* Update the final tail */
+       ch->ch_w_tail = tail & WQUEUEMASK;
+
+       if (len_written >= ch->ch_t_tlevel)
+               ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+       if (!jsm_tty_write(&ch->uart_port))
+               uart_write_wakeup(&ch->uart_port);
+}
+
+static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
+{
+       u8 msignals = signals;
+
+       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+                       "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
+
+       /* Scrub off lower bits. They signify delta's, which I don't care about */
+       /* Keep DDCD and DDSR though */
+       msignals &= 0xf8;
+
+       if (msignals & UART_MSR_DDCD)
+               uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+       if (msignals & UART_MSR_DDSR)
+               uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
+       if (msignals & UART_MSR_DCD)
+               ch->ch_mistat |= UART_MSR_DCD;
+       else
+               ch->ch_mistat &= ~UART_MSR_DCD;
+
+       if (msignals & UART_MSR_DSR)
+               ch->ch_mistat |= UART_MSR_DSR;
+       else
+               ch->ch_mistat &= ~UART_MSR_DSR;
+
+       if (msignals & UART_MSR_RI)
+               ch->ch_mistat |= UART_MSR_RI;
+       else
+               ch->ch_mistat &= ~UART_MSR_RI;
+
+       if (msignals & UART_MSR_CTS)
+               ch->ch_mistat |= UART_MSR_CTS;
+       else
+               ch->ch_mistat &= ~UART_MSR_CTS;
+
+       jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
+                       "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+               ch->ch_portnum,
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+               !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
+}
+
+/* Make the UART raise any of the output signals we want up */
+static void neo_assert_modem_signals(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+/*
+ * Flush the WRITE FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_write(struct jsm_channel *ch)
+{
+       u8 tmp = 0;
+       int i = 0;
+
+       if (!ch)
+               return;
+
+       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+
+       for (i = 0; i < 10; i++) {
+
+               /* Check to see if the UART feels it completely flushed the FIFO. */
+               tmp = readb(&ch->ch_neo_uart->isr_fcr);
+               if (tmp & 4) {
+                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                                       "Still flushing TX UART... i: %d\n", i);
+                       udelay(10);
+               }
+               else
+                       break;
+       }
+
+       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/*
+ * Flush the READ FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_read(struct jsm_channel *ch)
+{
+       u8 tmp = 0;
+       int i = 0;
+
+       if (!ch)
+               return;
+
+       writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
+
+       for (i = 0; i < 10; i++) {
+
+               /* Check to see if the UART feels it completely flushed the FIFO. */
+               tmp = readb(&ch->ch_neo_uart->isr_fcr);
+               if (tmp & 2) {
+                       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                                       "Still flushing RX UART... i: %d\n", i);
+                       udelay(10);
+               }
+               else
+                       break;
+       }
+}
+
+/*
+ * No locks are assumed to be held when calling this function.
+ */
+static void neo_clear_break(struct jsm_channel *ch, int force)
+{
+       unsigned long lock_flags;
+
+       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+       /* Turn break off, and unset some variables */
+       if (ch->ch_flags & CH_BREAK_SENDING) {
+               u8 temp = readb(&ch->ch_neo_uart->lcr);
+               writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+
+               ch->ch_flags &= ~(CH_BREAK_SENDING);
+               jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
+                               "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+}
+
+/*
+ * Parse the ISR register.
+ */
+static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
+{
+       struct jsm_channel *ch;
+       u8 isr;
+       u8 cause;
+       unsigned long lock_flags;
+
+       if (!brd)
+               return;
+
+       if (port > brd->maxports)
+               return;
+
+       ch = brd->channels[port];
+       if (!ch)
+               return;
+
+       /* Here we try to figure out what caused the interrupt to happen */
+       while (1) {
+
+               isr = readb(&ch->ch_neo_uart->isr_fcr);
+
+               /* Bail if no pending interrupt */
+               if (isr & UART_IIR_NO_INT)
+                       break;
+
+               /*
+                * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
+                */
+               isr &= ~(UART_17158_IIR_FIFO_ENABLED);
+
+               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                               "%s:%d isr: %x\n", __FILE__, __LINE__, isr);
+
+               if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
+                       /* Read data from uart -> queue */
+                       neo_copy_data_from_uart_to_queue(ch);
+
+                       /* Call our tty layer to enforce queue flow control if needed. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       jsm_check_queue_flow_control(ch);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               if (isr & UART_IIR_THRI) {
+                       /* Transfer data (if any) from Write Queue -> UART. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+                       neo_copy_data_from_queue_to_uart(ch);
+               }
+
+               if (isr & UART_17158_IIR_XONXOFF) {
+                       cause = readb(&ch->ch_neo_uart->xoffchar1);
+
+                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                       "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
+
+                       /*
+                        * Since the UART detected either an XON or
+                        * XOFF match, we need to figure out which
+                        * one it was, so we can suspend or resume data flow.
+                        */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       if (cause == UART_17158_XON_DETECT) {
+                               /* Is output stopped right now, if so, resume it */
+                               if (brd->channels[port]->ch_flags & CH_STOP) {
+                                       ch->ch_flags &= ~(CH_STOP);
+                               }
+                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                               "Port %d. XON detected in incoming data\n", port);
+                       }
+                       else if (cause == UART_17158_XOFF_DETECT) {
+                               if (!(brd->channels[port]->ch_flags & CH_STOP)) {
+                                       ch->ch_flags |= CH_STOP;
+                                       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                                       "Setting CH_STOP\n");
+                               }
+                               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                                               "Port: %d. XOFF detected in incoming data\n", port);
+                       }
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
+                       /*
+                        * If we get here, this means the hardware is doing auto flow control.
+                        * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
+                        */
+                       cause = readb(&ch->ch_neo_uart->mcr);
+
+                       /* Which pin is doing auto flow? RTS or DTR? */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+                       if ((cause & 0x4) == 0) {
+                               if (cause & UART_MCR_RTS)
+                                       ch->ch_mostat |= UART_MCR_RTS;
+                               else
+                                       ch->ch_mostat &= ~(UART_MCR_RTS);
+                       } else {
+                               if (cause & UART_MCR_DTR)
+                                       ch->ch_mostat |= UART_MCR_DTR;
+                               else
+                                       ch->ch_mostat &= ~(UART_MCR_DTR);
+                       }
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               }
+
+               /* Parse any modem signal changes */
+               jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                               "MOD_STAT: sending to parse_modem_sigs\n");
+               neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+       }
+}
+
+static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
+{
+       struct jsm_channel *ch;
+       int linestatus;
+       unsigned long lock_flags;
+
+       if (!brd)
+               return;
+
+       if (port > brd->maxports)
+               return;
+
+       ch = brd->channels[port];
+       if (!ch)
+               return;
+
+       linestatus = readb(&ch->ch_neo_uart->lsr);
+
+       jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
+                       "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
+
+       ch->ch_cached_lsr |= linestatus;
+
+       if (ch->ch_cached_lsr & UART_LSR_DR) {
+               /* Read data from uart -> queue */
+               neo_copy_data_from_uart_to_queue(ch);
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               jsm_check_queue_flow_control(ch);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+       }
+
+       /*
+        * This is a special flag. It indicates that at least 1
+        * RX error (parity, framing, or break) has happened.
+        * Mark this in our struct, which will tell me that I have
+        *to do the special RX+LSR read for this FIFO load.
+        */
+       if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d Got an RX error, need to parse LSR\n",
+                       __FILE__, __LINE__, port);
+
+       /*
+        * The next 3 tests should *NOT* happen, as the above test
+        * should encapsulate all 3... At least, thats what Exar says.
+        */
+
+       if (linestatus & UART_LSR_PE) {
+               ch->ch_err_parity++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_FE) {
+               ch->ch_err_frame++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_BI) {
+               ch->ch_err_break++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_OE) {
+               /*
+                * Rx Oruns. Exar says that an orun will NOT corrupt
+                * the FIFO. It will just replace the holding register
+                * with this new data byte. So basically just ignore this.
+                * Probably we should eventually have an orun stat in our driver...
+                */
+               ch->ch_err_overrun++;
+               jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+                       "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
+       }
+
+       if (linestatus & UART_LSR_THRE) {
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+               /* Transfer data (if any) from Write Queue -> UART. */
+               neo_copy_data_from_queue_to_uart(ch);
+       }
+       else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
+               spin_lock_irqsave(&ch->ch_lock, lock_flags);
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+               /* Transfer data (if any) from Write Queue -> UART. */
+               neo_copy_data_from_queue_to_uart(ch);
+       }
+}
+
+/*
+ * neo_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void neo_param(struct jsm_channel *ch)
+{
+       u8 lcr = 0;
+       u8 uart_lcr, ier;
+       u32 baud;
+       int quot;
+       struct jsm_board *bd;
+
+       bd = ch->ch_bd;
+       if (!bd)
+               return;
+
+       /*
+        * If baud rate is zero, flush queues, and set mval to drop DTR.
+        */
+       if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+               ch->ch_r_head = ch->ch_r_tail = 0;
+               ch->ch_e_head = ch->ch_e_tail = 0;
+               ch->ch_w_head = ch->ch_w_tail = 0;
+
+               neo_flush_uart_write(ch);
+               neo_flush_uart_read(ch);
+
+               ch->ch_flags |= (CH_BAUD0);
+               ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+               neo_assert_modem_signals(ch);
+               return;
+
+       } else {
+               int i;
+               unsigned int cflag;
+               static struct {
+                       unsigned int rate;
+                       unsigned int cflag;
+               } baud_rates[] = {
+                       { 921600, B921600 },
+                       { 460800, B460800 },
+                       { 230400, B230400 },
+                       { 115200, B115200 },
+                       {  57600, B57600  },
+                       {  38400, B38400  },
+                       {  19200, B19200  },
+                       {   9600, B9600   },
+                       {   4800, B4800   },
+                       {   2400, B2400   },
+                       {   1200, B1200   },
+                       {    600, B600    },
+                       {    300, B300    },
+                       {    200, B200    },
+                       {    150, B150    },
+                       {    134, B134    },
+                       {    110, B110    },
+                       {     75, B75     },
+                       {     50, B50     },
+               };
+
+               cflag = C_BAUD(ch->uart_port.state->port.tty);
+               baud = 9600;
+               for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
+                       if (baud_rates[i].cflag == cflag) {
+                               baud = baud_rates[i].rate;
+                               break;
+                       }
+               }
+
+               if (ch->ch_flags & CH_BAUD0)
+                       ch->ch_flags &= ~(CH_BAUD0);
+       }
+
+       if (ch->ch_c_cflag & PARENB)
+               lcr |= UART_LCR_PARITY;
+
+       if (!(ch->ch_c_cflag & PARODD))
+               lcr |= UART_LCR_EPAR;
+
+       /*
+        * Not all platforms support mark/space parity,
+        * so this will hide behind an ifdef.
+        */
+#ifdef CMSPAR
+       if (ch->ch_c_cflag & CMSPAR)
+               lcr |= UART_LCR_SPAR;
+#endif
+
+       if (ch->ch_c_cflag & CSTOPB)
+               lcr |= UART_LCR_STOP;
+
+       switch (ch->ch_c_cflag & CSIZE) {
+               case CS5:
+                       lcr |= UART_LCR_WLEN5;
+                       break;
+               case CS6:
+                       lcr |= UART_LCR_WLEN6;
+                       break;
+               case CS7:
+                       lcr |= UART_LCR_WLEN7;
+                       break;
+               case CS8:
+               default:
+                       lcr |= UART_LCR_WLEN8;
+               break;
+       }
+
+       ier = readb(&ch->ch_neo_uart->ier);
+       uart_lcr = readb(&ch->ch_neo_uart->lcr);
+
+       if (baud == 0)
+               baud = 9600;
+
+       quot = ch->ch_bd->bd_dividend / baud;
+
+       if (quot != 0) {
+               writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
+               writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
+               writeb((quot >> 8), &ch->ch_neo_uart->ier);
+               writeb(lcr, &ch->ch_neo_uart->lcr);
+       }
+
+       if (uart_lcr != lcr)
+               writeb(lcr, &ch->ch_neo_uart->lcr);
+
+       if (ch->ch_c_cflag & CREAD)
+               ier |= (UART_IER_RDI | UART_IER_RLSI);
+
+       ier |= (UART_IER_THRI | UART_IER_MSI);
+
+       writeb(ier, &ch->ch_neo_uart->ier);
+
+       /* Set new start/stop chars */
+       neo_set_new_start_stop_chars(ch);
+
+       if (ch->ch_c_cflag & CRTSCTS)
+               neo_set_cts_flow_control(ch);
+       else if (ch->ch_c_iflag & IXON) {
+               /* If start/stop is set to disable, then we should disable flow control */
+               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+                       neo_set_no_output_flow_control(ch);
+               else
+                       neo_set_ixon_flow_control(ch);
+       }
+       else
+               neo_set_no_output_flow_control(ch);
+
+       if (ch->ch_c_cflag & CRTSCTS)
+               neo_set_rts_flow_control(ch);
+       else if (ch->ch_c_iflag & IXOFF) {
+               /* If start/stop is set to disable, then we should disable flow control */
+               if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
+                       neo_set_no_input_flow_control(ch);
+               else
+                       neo_set_ixoff_flow_control(ch);
+       }
+       else
+               neo_set_no_input_flow_control(ch);
+       /*
+        * Adjust the RX FIFO Trigger level if baud is less than 9600.
+        * Not exactly elegant, but this is needed because of the Exar chip's
+        * delay on firing off the RX FIFO interrupt on slower baud rates.
+        */
+       if (baud < 9600) {
+               writeb(1, &ch->ch_neo_uart->rfifo);
+               ch->ch_r_tlevel = 1;
+       }
+
+       neo_assert_modem_signals(ch);
+
+       /* Get current status of the modem signals now */
+       neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+       return;
+}
+
+/*
+ * jsm_neo_intr()
+ *
+ * Neo specific interrupt handler.
+ */
+static irqreturn_t neo_intr(int irq, void *voidbrd)
+{
+       struct jsm_board *brd = voidbrd;
+       struct jsm_channel *ch;
+       int port = 0;
+       int type = 0;
+       int current_port;
+       u32 tmp;
+       u32 uart_poll;
+       unsigned long lock_flags;
+       unsigned long lock_flags2;
+       int outofloop_count = 0;
+
+       /* Lock out the slow poller from running on this board. */
+       spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
+
+       /*
+        * Read in "extended" IRQ information from the 32bit Neo register.
+        * Bits 0-7: What port triggered the interrupt.
+        * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
+        */
+       uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
+
+       jsm_printk(INTR, INFO, &brd->pci_dev,
+               "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
+
+       if (!uart_poll) {
+               jsm_printk(INTR, INFO, &brd->pci_dev,
+                       "Kernel interrupted to me, but no pending interrupts...\n");
+               spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+               return IRQ_NONE;
+       }
+
+       /* At this point, we have at least SOMETHING to service, dig further... */
+
+       current_port = 0;
+
+       /* Loop on each port */
+       while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
+
+               tmp = uart_poll;
+               outofloop_count++;
+
+               /* Check current port to see if it has interrupt pending */
+               if ((tmp & jsm_offset_table[current_port]) != 0) {
+                       port = current_port;
+                       type = tmp >> (8 + (port * 3));
+                       type &= 0x7;
+               } else {
+                       current_port++;
+                       continue;
+               }
+
+               jsm_printk(INTR, INFO, &brd->pci_dev,
+               "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
+
+               /* Remove this port + type from uart_poll */
+               uart_poll &= ~(jsm_offset_table[port]);
+
+               if (!type) {
+                       /* If no type, just ignore it, and move onto next port */
+                       jsm_printk(INTR, ERR, &brd->pci_dev,
+                               "Interrupt with no type! port: %d\n", port);
+                       continue;
+               }
+
+               /* Switch on type of interrupt we have */
+               switch (type) {
+
+               case UART_17158_RXRDY_TIMEOUT:
+                       /*
+                        * RXRDY Time-out is cleared by reading data in the
+                       * RX FIFO until it falls below the trigger level.
+                        */
+
+                       /* Verify the port is in range. */
+                       if (port > brd->nasync)
+                               continue;
+
+                       ch = brd->channels[port];
+                       neo_copy_data_from_uart_to_queue(ch);
+
+                       /* Call our tty layer to enforce queue flow control if needed. */
+                       spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+                       jsm_check_queue_flow_control(ch);
+                       spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+
+                       continue;
+
+               case UART_17158_RX_LINE_STATUS:
+                       /*
+                        * RXRDY and RX LINE Status (logic OR of LSR[4:1])
+                        */
+                       neo_parse_lsr(brd, port);
+                       continue;
+
+               case UART_17158_TXRDY:
+                       /*
+                        * TXRDY interrupt clears after reading ISR register for the UART channel.
+                        */
+
+                       /*
+                        * Yes, this is odd...
+                        * Why would I check EVERY possibility of type of
+                        * interrupt, when we know its TXRDY???
+                        * Becuz for some reason, even tho we got triggered for TXRDY,
+                        * it seems to be occassionally wrong. Instead of TX, which
+                        * it should be, I was getting things like RXDY too. Weird.
+                        */
+                       neo_parse_isr(brd, port);
+                       continue;
+
+               case UART_17158_MSR:
+                       /*
+                        * MSR or flow control was seen.
+                        */
+                       neo_parse_isr(brd, port);
+                       continue;
+
+               default:
+                       /*
+                        * The UART triggered us with a bogus interrupt type.
+                        * It appears the Exar chip, when REALLY bogged down, will throw
+                        * these once and awhile.
+                        * Its harmless, just ignore it and move on.
+                        */
+                       jsm_printk(INTR, ERR, &brd->pci_dev,
+                               "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
+                       continue;
+               }
+       }
+
+       spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
+
+       jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
+       return IRQ_HANDLED;
+}
+
+/*
+ * Neo specific way of turning off the receiver.
+ * Used as a way to enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_disable_receiver(struct jsm_channel *ch)
+{
+       u8 tmp = readb(&ch->ch_neo_uart->ier);
+       tmp &= ~(UART_IER_RDI);
+       writeb(tmp, &ch->ch_neo_uart->ier);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Neo specific way of turning on the receiver.
+ * Used as a way to un-enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_enable_receiver(struct jsm_channel *ch)
+{
+       u8 tmp = readb(&ch->ch_neo_uart->ier);
+       tmp |= (UART_IER_RDI);
+       writeb(tmp, &ch->ch_neo_uart->ier);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+static void neo_send_start_character(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       if (ch->ch_startc != __DISABLED_CHAR) {
+               ch->ch_xon_sends++;
+               writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+static void neo_send_stop_character(struct jsm_channel *ch)
+{
+       if (!ch)
+               return;
+
+       if (ch->ch_stopc != __DISABLED_CHAR) {
+               ch->ch_xoff_sends++;
+               writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+/*
+ * neo_uart_init
+ */
+static void neo_uart_init(struct jsm_channel *ch)
+{
+       writeb(0, &ch->ch_neo_uart->ier);
+       writeb(0, &ch->ch_neo_uart->efr);
+       writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
+
+       /* Clear out UART and FIFO */
+       readb(&ch->ch_neo_uart->txrx);
+       writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+       readb(&ch->ch_neo_uart->lsr);
+       readb(&ch->ch_neo_uart->msr);
+
+       ch->ch_flags |= CH_FIFO_ENABLED;
+
+       /* Assert any signals we want up */
+       writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+}
+
+/*
+ * Make the UART completely turn off.
+ */
+static void neo_uart_off(struct jsm_channel *ch)
+{
+       /* Turn off UART enhanced bits */
+       writeb(0, &ch->ch_neo_uart->efr);
+
+       /* Stop all interrupts from occurring. */
+       writeb(0, &ch->ch_neo_uart->ier);
+}
+
+static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
+{
+       u8 left = 0;
+       u8 lsr = readb(&ch->ch_neo_uart->lsr);
+
+       /* We must cache the LSR as some of the bits get reset once read... */
+       ch->ch_cached_lsr |= lsr;
+
+       /* Determine whether the Transmitter is empty or not */
+       if (!(lsr & UART_LSR_TEMT))
+               left = 1;
+       else {
+               ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+               left = 0;
+       }
+
+       return left;
+}
+
+/* Channel lock MUST be held by the calling function! */
+static void neo_send_break(struct jsm_channel *ch)
+{
+       /*
+        * Set the time we should stop sending the break.
+        * If we are already sending a break, toss away the existing
+        * time to stop, and use this new value instead.
+        */
+
+       /* Tell the UART to start sending the break */
+       if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+               u8 temp = readb(&ch->ch_neo_uart->lcr);
+               writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+               ch->ch_flags |= (CH_BREAK_SENDING);
+
+               /* flush write operation */
+               neo_pci_posting_flush(ch->ch_bd);
+       }
+}
+
+/*
+ * neo_send_immediate_char.
+ *
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
+{
+       if (!ch)
+               return;
+
+       writeb(c, &ch->ch_neo_uart->txrx);
+
+       /* flush write operation */
+       neo_pci_posting_flush(ch->ch_bd);
+}
+
+struct board_ops jsm_neo_ops = {
+       .intr                           = neo_intr,
+       .uart_init                      = neo_uart_init,
+       .uart_off                       = neo_uart_off,
+       .param                          = neo_param,
+       .assert_modem_signals           = neo_assert_modem_signals,
+       .flush_uart_write               = neo_flush_uart_write,
+       .flush_uart_read                = neo_flush_uart_read,
+       .disable_receiver               = neo_disable_receiver,
+       .enable_receiver                = neo_enable_receiver,
+       .send_break                     = neo_send_break,
+       .clear_break                    = neo_clear_break,
+       .send_start_character           = neo_send_start_character,
+       .send_stop_character            = neo_send_stop_character,
+       .copy_data_from_queue_to_uart   = neo_copy_data_from_queue_to_uart,
+       .get_uart_bytes_left            = neo_get_uart_bytes_left,
+       .send_immediate_char            = neo_send_immediate_char
+};
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
new file mode 100644 (file)
index 0000000..7a4a914
--- /dev/null
@@ -0,0 +1,910 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06:   changed jsm_input routine to use the dynamically allocated
+ *             tty_buffer changes. Contributors: Scott Kilau and Ananda V.
+ ***********************************************************************/
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>       /* For udelay */
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "jsm.h"
+
+static DECLARE_BITMAP(linemap, MAXLINES);
+
+static void jsm_carrier(struct jsm_channel *ch);
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+       unsigned char mstat;
+       unsigned result;
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       mstat = (ch->ch_mostat | ch->ch_mistat);
+
+       result = 0;
+
+       if (mstat & UART_MCR_DTR)
+               result |= TIOCM_DTR;
+       if (mstat & UART_MCR_RTS)
+               result |= TIOCM_RTS;
+       if (mstat & UART_MSR_CTS)
+               result |= TIOCM_CTS;
+       if (mstat & UART_MSR_DSR)
+               result |= TIOCM_DSR;
+       if (mstat & UART_MSR_RI)
+               result |= TIOCM_RI;
+       if (mstat & UART_MSR_DCD)
+               result |= TIOCM_CD;
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+       return result;
+}
+
+static unsigned int jsm_tty_tx_empty(struct uart_port *port)
+{
+       return TIOCSER_TEMT;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
+{
+       int result;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       result = jsm_get_mstat(channel);
+
+       if (result < 0)
+               return -ENXIO;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+
+       return result;
+}
+
+/*
+ * jsm_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       if (mctrl & TIOCM_RTS)
+               channel->ch_mostat |= UART_MCR_RTS;
+       else
+               channel->ch_mostat &= ~UART_MCR_RTS;
+
+       if (mctrl & TIOCM_DTR)
+               channel->ch_mostat |= UART_MCR_DTR;
+       else
+               channel->ch_mostat &= ~UART_MCR_DTR;
+
+       channel->ch_bd->bd_ops->assert_modem_signals(channel);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+       udelay(10);
+}
+
+static void jsm_tty_start_tx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       channel->ch_flags &= ~(CH_STOP);
+       jsm_tty_write(port);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       channel->ch_flags |= (CH_STOP);
+
+       jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+       struct ktermios *termios;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       termios = port->state->port.tty->termios;
+       if (ch == termios->c_cc[VSTART])
+               channel->ch_bd->bd_ops->send_start_character(channel);
+
+       if (ch == termios->c_cc[VSTOP])
+               channel->ch_bd->bd_ops->send_stop_character(channel);
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static void jsm_tty_stop_rx(struct uart_port *port)
+{
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       channel->ch_bd->bd_ops->disable_receiver(channel);
+}
+
+static void jsm_tty_enable_ms(struct uart_port *port)
+{
+       /* Nothing needed */
+}
+
+static void jsm_tty_break(struct uart_port *port, int break_state)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       if (break_state == -1)
+               channel->ch_bd->bd_ops->send_break(channel);
+       else
+               channel->ch_bd->bd_ops->clear_break(channel, 0);
+
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+       struct jsm_board *brd;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+       struct ktermios *termios;
+
+       /* Get board pointer from our array of majors we have allocated */
+       brd = channel->ch_bd;
+
+       /*
+        * Allocate channel buffers for read/write/error.
+        * Set flag, so we don't get trounced on.
+        */
+       channel->ch_flags |= (CH_OPENING);
+
+       /* Drop locks, as malloc with GFP_KERNEL can sleep */
+
+       if (!channel->ch_rqueue) {
+               channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_rqueue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate read queue buf");
+                       return -ENOMEM;
+               }
+       }
+       if (!channel->ch_equeue) {
+               channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_equeue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate error queue buf");
+                       return -ENOMEM;
+               }
+       }
+       if (!channel->ch_wqueue) {
+               channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
+               if (!channel->ch_wqueue) {
+                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
+                               "unable to allocate write queue buf");
+                       return -ENOMEM;
+               }
+       }
+
+       channel->ch_flags &= ~(CH_OPENING);
+       /*
+        * Initialize if neither terminal is open.
+        */
+       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
+               "jsm_open: initializing channel in open...\n");
+
+       /*
+        * Flush input queues.
+        */
+       channel->ch_r_head = channel->ch_r_tail = 0;
+       channel->ch_e_head = channel->ch_e_tail = 0;
+       channel->ch_w_head = channel->ch_w_tail = 0;
+
+       brd->bd_ops->flush_uart_write(channel);
+       brd->bd_ops->flush_uart_read(channel);
+
+       channel->ch_flags = 0;
+       channel->ch_cached_lsr = 0;
+       channel->ch_stops_sent = 0;
+
+       termios = port->state->port.tty->termios;
+       channel->ch_c_cflag     = termios->c_cflag;
+       channel->ch_c_iflag     = termios->c_iflag;
+       channel->ch_c_oflag     = termios->c_oflag;
+       channel->ch_c_lflag     = termios->c_lflag;
+       channel->ch_startc      = termios->c_cc[VSTART];
+       channel->ch_stopc       = termios->c_cc[VSTOP];
+
+       /* Tell UART to init itself */
+       brd->bd_ops->uart_init(channel);
+
+       /*
+        * Run param in case we changed anything
+        */
+       brd->bd_ops->param(channel);
+
+       jsm_carrier(channel);
+
+       channel->ch_open_count++;
+
+       jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
+       return 0;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+       struct jsm_board *bd;
+       struct ktermios *ts;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
+
+       bd = channel->ch_bd;
+       ts = port->state->port.tty->termios;
+
+       channel->ch_flags &= ~(CH_STOPI);
+
+       channel->ch_open_count--;
+
+       /*
+        * If we have HUPCL set, lower DTR and RTS
+        */
+       if (channel->ch_c_cflag & HUPCL) {
+               jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
+                       "Close. HUPCL set, dropping DTR/RTS\n");
+
+               /* Drop RTS/DTR */
+               channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+               bd->bd_ops->assert_modem_signals(channel);
+       }
+
+       /* Turn off UART interrupts for this port */
+       channel->ch_bd->bd_ops->uart_off(channel);
+
+       jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+                                struct ktermios *termios,
+                                struct ktermios *old_termios)
+{
+       unsigned long lock_flags;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       spin_lock_irqsave(&port->lock, lock_flags);
+       channel->ch_c_cflag     = termios->c_cflag;
+       channel->ch_c_iflag     = termios->c_iflag;
+       channel->ch_c_oflag     = termios->c_oflag;
+       channel->ch_c_lflag     = termios->c_lflag;
+       channel->ch_startc      = termios->c_cc[VSTART];
+       channel->ch_stopc       = termios->c_cc[VSTOP];
+
+       channel->ch_bd->bd_ops->param(channel);
+       jsm_carrier(channel);
+       spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static const char *jsm_tty_type(struct uart_port *port)
+{
+       return "jsm";
+}
+
+static void jsm_tty_release_port(struct uart_port *port)
+{
+}
+
+static int jsm_tty_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void jsm_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_JSM;
+}
+
+static struct uart_ops jsm_ops = {
+       .tx_empty       = jsm_tty_tx_empty,
+       .set_mctrl      = jsm_tty_set_mctrl,
+       .get_mctrl      = jsm_tty_get_mctrl,
+       .stop_tx        = jsm_tty_stop_tx,
+       .start_tx       = jsm_tty_start_tx,
+       .send_xchar     = jsm_tty_send_xchar,
+       .stop_rx        = jsm_tty_stop_rx,
+       .enable_ms      = jsm_tty_enable_ms,
+       .break_ctl      = jsm_tty_break,
+       .startup        = jsm_tty_open,
+       .shutdown       = jsm_tty_close,
+       .set_termios    = jsm_tty_set_termios,
+       .type           = jsm_tty_type,
+       .release_port   = jsm_tty_release_port,
+       .request_port   = jsm_tty_request_port,
+       .config_port    = jsm_config_port,
+};
+
+/*
+ * jsm_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int __devinit jsm_tty_init(struct jsm_board *brd)
+{
+       int i;
+       void __iomem *vaddr;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /*
+        * Allocate channel memory that might not have been allocated
+        * when the driver was first loaded.
+        */
+       for (i = 0; i < brd->nasync; i++) {
+               if (!brd->channels[i]) {
+
+                       /*
+                        * Okay to malloc with GFP_KERNEL, we are not at
+                        * interrupt context, and there are no locks held.
+                        */
+                       brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+                       if (!brd->channels[i]) {
+                               jsm_printk(CORE, ERR, &brd->pci_dev,
+                                       "%s:%d Unable to allocate memory for channel struct\n",
+                                                        __FILE__, __LINE__);
+                       }
+               }
+       }
+
+       ch = brd->channels[0];
+       vaddr = brd->re_map_membase;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               spin_lock_init(&ch->ch_lock);
+
+               if (brd->bd_uart_offset == 0x200)
+                       ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
+
+               ch->ch_bd = brd;
+               ch->ch_portnum = i;
+
+               /* .25 second delay */
+               ch->ch_close_delay = 250;
+
+               init_waitqueue_head(&ch->ch_flags_wait);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+int jsm_uart_port_init(struct jsm_board *brd)
+{
+       int i, rc;
+       unsigned int line;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               brd->channels[i]->uart_port.irq = brd->irq;
+               brd->channels[i]->uart_port.uartclk = 14745600;
+               brd->channels[i]->uart_port.type = PORT_JSM;
+               brd->channels[i]->uart_port.iotype = UPIO_MEM;
+               brd->channels[i]->uart_port.membase = brd->re_map_membase;
+               brd->channels[i]->uart_port.fifosize = 16;
+               brd->channels[i]->uart_port.ops = &jsm_ops;
+               line = find_first_zero_bit(linemap, MAXLINES);
+               if (line >= MAXLINES) {
+                       printk(KERN_INFO "jsm: linemap is full, added device failed\n");
+                       continue;
+               } else
+                       set_bit(line, linemap);
+               brd->channels[i]->uart_port.line = line;
+               rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port);
+               if (rc){
+                       printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
+                       return rc;
+               }
+               else
+                       printk(KERN_INFO "jsm: Port %d added\n", i);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+int jsm_remove_uart_port(struct jsm_board *brd)
+{
+       int i;
+       struct jsm_channel *ch;
+
+       if (!brd)
+               return -ENXIO;
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+
+       /*
+        * Initialize board structure elements.
+        */
+
+       brd->nasync = brd->maxports;
+
+       /* Set up channel variables */
+       for (i = 0; i < brd->nasync; i++) {
+
+               if (!brd->channels[i])
+                       continue;
+
+               ch = brd->channels[i];
+
+               clear_bit(ch->uart_port.line, linemap);
+               uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
+       }
+
+       jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+       return 0;
+}
+
+void jsm_input(struct jsm_channel *ch)
+{
+       struct jsm_board *bd;
+       struct tty_struct *tp;
+       u32 rmask;
+       u16 head;
+       u16 tail;
+       int data_len;
+       unsigned long lock_flags;
+       int len = 0;
+       int n = 0;
+       int s = 0;
+       int i = 0;
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       if (!ch)
+               return;
+
+       tp = ch->uart_port.state->port.tty;
+
+       bd = ch->ch_bd;
+       if(!bd)
+               return;
+
+       spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+       /*
+        *Figure the number of characters in the buffer.
+        *Exit immediately if none.
+        */
+
+       rmask = RQUEUEMASK;
+
+       head = ch->ch_r_head & rmask;
+       tail = ch->ch_r_tail & rmask;
+
+       data_len = (head - tail) & rmask;
+       if (data_len == 0) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               return;
+       }
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+
+       /*
+        *If the device is not open, or CREAD is off, flush
+        *input data and return immediately.
+        */
+       if (!tp ||
+               !(tp->termios->c_cflag & CREAD) ) {
+
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                       "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
+               ch->ch_r_head = tail;
+
+               /* Force queue flow control to be released, if needed */
+               jsm_check_queue_flow_control(ch);
+
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               return;
+       }
+
+       /*
+        * If we are throttled, simply don't read any data.
+        */
+       if (ch->ch_flags & CH_STOPI) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                       "Port %d throttled, not reading any data. head: %x tail: %x\n",
+                       ch->ch_portnum, head, tail);
+               return;
+       }
+
+       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
+
+       if (data_len <= 0) {
+               spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+               return;
+       }
+
+       len = tty_buffer_request_room(tp, data_len);
+       n = len;
+
+       /*
+        * n now contains the most amount of data we can copy,
+        * bounded either by the flip buffer size or the amount
+        * of data the card actually has pending...
+        */
+       while (n) {
+               s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+               s = min(s, n);
+
+               if (s <= 0)
+                       break;
+
+                       /*
+                        * If conditions are such that ld needs to see all
+                        * UART errors, we will have to walk each character
+                        * and error byte and send them to the buffer one at
+                        * a time.
+                        */
+
+               if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+                       for (i = 0; i < s; i++) {
+                               /*
+                                * Give the Linux ld the flags in the
+                                * format it likes.
+                                */
+                               if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+                               else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
+                               else
+                                       tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
+                       }
+               } else {
+                       tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
+               }
+               tail += s;
+               n -= s;
+               /* Flip queue if needed */
+               tail &= rmask;
+       }
+
+       ch->ch_r_tail = tail & rmask;
+       ch->ch_e_tail = tail & rmask;
+       jsm_check_queue_flow_control(ch);
+       spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+       /* Tell the tty layer its okay to "eat" the data now */
+       tty_flip_buffer_push(tp);
+
+       jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_carrier(struct jsm_channel *ch)
+{
+       struct jsm_board *bd;
+
+       int virt_carrier = 0;
+       int phys_carrier = 0;
+
+       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
+       if (!ch)
+               return;
+
+       bd = ch->ch_bd;
+
+       if (!bd)
+               return;
+
+       if (ch->ch_mistat & UART_MSR_DCD) {
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
+               phys_carrier = 1;
+       }
+
+       if (ch->ch_c_cflag & CLOCAL)
+               virt_carrier = 1;
+
+       jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+               "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
+
+       /*
+        * Test for a VIRTUAL carrier transition to HIGH.
+        */
+       if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+               /*
+                * When carrier rises, wake any threads waiting
+                * for carrier in the open routine.
+                */
+
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "carrier: virt DCD rose\n");
+
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        * Test for a PHYSICAL carrier transition to HIGH.
+        */
+       if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+               /*
+                * When carrier rises, wake any threads waiting
+                * for carrier in the open routine.
+                */
+
+               jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+                       "carrier: physical DCD rose\n");
+
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        *  Test for a PHYSICAL transition to low, so long as we aren't
+        *  currently ignoring physical transitions (which is what "virtual
+        *  carrier" indicates).
+        *
+        *  The transition of the virtual carrier to low really doesn't
+        *  matter... it really only means "ignore carrier state", not
+        *  "make pretend that carrier is there".
+        */
+       if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
+                       && (phys_carrier == 0)) {
+               /*
+                *      When carrier drops:
+                *
+                *      Drop carrier on all open units.
+                *
+                *      Flush queues, waking up any task waiting in the
+                *      line discipline.
+                *
+                *      Send a hangup to the control terminal.
+                *
+                *      Enable all select calls.
+                */
+               if (waitqueue_active(&(ch->ch_flags_wait)))
+                       wake_up_interruptible(&ch->ch_flags_wait);
+       }
+
+       /*
+        *  Make sure that our cached values reflect the current reality.
+        */
+       if (virt_carrier == 1)
+               ch->ch_flags |= CH_FCAR;
+       else
+               ch->ch_flags &= ~CH_FCAR;
+
+       if (phys_carrier == 1)
+               ch->ch_flags |= CH_CD;
+       else
+               ch->ch_flags &= ~CH_CD;
+}
+
+
+void jsm_check_queue_flow_control(struct jsm_channel *ch)
+{
+       struct board_ops *bd_ops = ch->ch_bd->bd_ops;
+       int qleft;
+
+       /* Store how much space we have left in the queue */
+       if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+               qleft += RQUEUEMASK + 1;
+
+       /*
+        * Check to see if we should enforce flow control on our queue because
+        * the ld (or user) isn't reading data out of our queue fast enuf.
+        *
+        * NOTE: This is done based on what the current flow control of the
+        * port is set for.
+        *
+        * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+        *      This will cause the UART's FIFO to back up, and force
+        *      the RTS signal to be dropped.
+        * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+        *      the other side, in hopes it will stop sending data to us.
+        * 3) NONE - Nothing we can do.  We will simply drop any extra data
+        *      that gets sent into us when the queue fills up.
+        */
+       if (qleft < 256) {
+               /* HWFLOW */
+               if (ch->ch_c_cflag & CRTSCTS) {
+                       if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
+                               bd_ops->disable_receiver(ch);
+                               ch->ch_flags |= (CH_RECEIVER_OFF);
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+                                       qleft);
+                       }
+               }
+               /* SWFLOW */
+               else if (ch->ch_c_iflag & IXOFF) {
+                       if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+                               bd_ops->send_stop_character(ch);
+                               ch->ch_stops_sent++;
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
+                       }
+               }
+       }
+
+       /*
+        * Check to see if we should unenforce flow control because
+        * ld (or user) finally read enuf data out of our queue.
+        *
+        * NOTE: This is done based on what the current flow control of the
+        * port is set for.
+        *
+        * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+        *      This will cause the UART's FIFO to raise RTS back up,
+        *      which will allow the other side to start sending data again.
+        * 2) SWFLOW (IXOFF) - Send a start character to
+        *      the other side, so it will start sending data to us again.
+        * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+        *      other side, we don't need to do anything now.
+        */
+       if (qleft > (RQUEUESIZE / 2)) {
+               /* HWFLOW */
+               if (ch->ch_c_cflag & CRTSCTS) {
+                       if (ch->ch_flags & CH_RECEIVER_OFF) {
+                               bd_ops->enable_receiver(ch);
+                               ch->ch_flags &= ~(CH_RECEIVER_OFF);
+                               jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+                                       "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+                                       qleft);
+                       }
+               }
+               /* SWFLOW */
+               else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+                       ch->ch_stops_sent = 0;
+                       bd_ops->send_start_character(ch);
+                       jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
+               }
+       }
+}
+
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+int jsm_tty_write(struct uart_port *port)
+{
+       int bufcount;
+       int data_count = 0,data_count1 =0;
+       u16 head;
+       u16 tail;
+       u16 tmask;
+       u32 remain;
+       int temp_tail = port->state->xmit.tail;
+       struct jsm_channel *channel = (struct jsm_channel *)port;
+
+       tmask = WQUEUEMASK;
+       head = (channel->ch_w_head) & tmask;
+       tail = (channel->ch_w_tail) & tmask;
+
+       if ((bufcount = tail - head - 1) < 0)
+               bufcount += WQUEUESIZE;
+
+       bufcount = min(bufcount, 56);
+       remain = WQUEUESIZE - head;
+
+       data_count = 0;
+       if (bufcount >= remain) {
+               bufcount -= remain;
+               while ((port->state->xmit.head != temp_tail) &&
+               (data_count < remain)) {
+                       channel->ch_wqueue[head++] =
+                       port->state->xmit.buf[temp_tail];
+
+                       temp_tail++;
+                       temp_tail &= (UART_XMIT_SIZE - 1);
+                       data_count++;
+               }
+               if (data_count == remain) head = 0;
+       }
+
+       data_count1 = 0;
+       if (bufcount > 0) {
+               remain = bufcount;
+               while ((port->state->xmit.head != temp_tail) &&
+                       (data_count1 < remain)) {
+                       channel->ch_wqueue[head++] =
+                               port->state->xmit.buf[temp_tail];
+
+                       temp_tail++;
+                       temp_tail &= (UART_XMIT_SIZE - 1);
+                       data_count1++;
+
+               }
+       }
+
+       port->state->xmit.tail = temp_tail;
+
+       data_count += data_count1;
+       if (data_count) {
+               head &= tmask;
+               channel->ch_w_head = head;
+       }
+
+       if (data_count) {
+               channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+       }
+
+       return data_count;
+}
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
new file mode 100644 (file)
index 0000000..25a8bc5
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Based on the same principle as kgdboe using the NETPOLL api, this
+ * driver uses a console polling api to implement a gdb serial inteface
+ * which is multiplexed on a console port.
+ *
+ * Maintainer: Jason Wessel <jason.wessel@windriver.com>
+ *
+ * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+
+#define MAX_CONFIG_LEN         40
+
+static struct kgdb_io          kgdboc_io_ops;
+
+/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
+static int configured          = -1;
+
+static char config[MAX_CONFIG_LEN];
+static struct kparam_string kps = {
+       .string                 = config,
+       .maxlen                 = MAX_CONFIG_LEN,
+};
+
+static int kgdboc_use_kms;  /* 1 if we use kernel mode switching */
+static struct tty_driver       *kgdb_tty_driver;
+static int                     kgdb_tty_line;
+
+#ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+                               const struct input_device_id *id)
+{
+       input_reset_device(dev);
+
+       /* Retrun an error - we do not want to bind, just to reset */
+       return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+       /* We do not expect anyone to actually bind to us */
+       BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+       .connect        = kgdboc_reset_connect,
+       .disconnect     = kgdboc_reset_disconnect,
+       .name           = "kgdboc_reset",
+       .id_table       = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+       /*
+        * We need to take a mutex to prevent several instances of
+        * this work running on different CPUs so they don't try
+        * to register again already registered handler.
+        */
+       mutex_lock(&kgdboc_reset_mutex);
+
+       if (input_register_handler(&kgdboc_reset_handler) == 0)
+               input_unregister_handler(&kgdboc_reset_handler);
+
+       mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+       if (likely(system_state == SYSTEM_RUNNING))
+               schedule_work(&kgdboc_restore_input_work);
+}
+
+static int kgdboc_register_kbd(char **cptr)
+{
+       if (strncmp(*cptr, "kbd", 3) == 0) {
+               if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
+                       kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
+                       kdb_poll_idx++;
+                       if (cptr[0][3] == ',')
+                               *cptr += 4;
+                       else
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+static void kgdboc_unregister_kbd(void)
+{
+       int i;
+
+       for (i = 0; i < kdb_poll_idx; i++) {
+               if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
+                       kdb_poll_idx--;
+                       kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
+                       kdb_poll_funcs[kdb_poll_idx] = NULL;
+                       i--;
+               }
+       }
+       flush_work_sync(&kgdboc_restore_input_work);
+}
+#else /* ! CONFIG_KDB_KEYBOARD */
+#define kgdboc_register_kbd(x) 0
+#define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
+#endif /* ! CONFIG_KDB_KEYBOARD */
+
+static int kgdboc_option_setup(char *opt)
+{
+       if (strlen(opt) > MAX_CONFIG_LEN) {
+               printk(KERN_ERR "kgdboc: config string too long\n");
+               return -ENOSPC;
+       }
+       strcpy(config, opt);
+
+       return 0;
+}
+
+__setup("kgdboc=", kgdboc_option_setup);
+
+static void cleanup_kgdboc(void)
+{
+       kgdboc_unregister_kbd();
+       if (configured == 1)
+               kgdb_unregister_io_module(&kgdboc_io_ops);
+}
+
+static int configure_kgdboc(void)
+{
+       struct tty_driver *p;
+       int tty_line = 0;
+       int err;
+       char *cptr = config;
+       struct console *cons;
+
+       err = kgdboc_option_setup(config);
+       if (err || !strlen(config) || isspace(config[0]))
+               goto noconfig;
+
+       err = -ENODEV;
+       kgdboc_io_ops.is_console = 0;
+       kgdb_tty_driver = NULL;
+
+       kgdboc_use_kms = 0;
+       if (strncmp(cptr, "kms,", 4) == 0) {
+               cptr += 4;
+               kgdboc_use_kms = 1;
+       }
+
+       if (kgdboc_register_kbd(&cptr))
+               goto do_register;
+
+       p = tty_find_polling_driver(cptr, &tty_line);
+       if (!p)
+               goto noconfig;
+
+       cons = console_drivers;
+       while (cons) {
+               int idx;
+               if (cons->device && cons->device(cons, &idx) == p &&
+                   idx == tty_line) {
+                       kgdboc_io_ops.is_console = 1;
+                       break;
+               }
+               cons = cons->next;
+       }
+
+       kgdb_tty_driver = p;
+       kgdb_tty_line = tty_line;
+
+do_register:
+       err = kgdb_register_io_module(&kgdboc_io_ops);
+       if (err)
+               goto noconfig;
+
+       configured = 1;
+
+       return 0;
+
+noconfig:
+       config[0] = 0;
+       configured = 0;
+       cleanup_kgdboc();
+
+       return err;
+}
+
+static int __init init_kgdboc(void)
+{
+       /* Already configured? */
+       if (configured == 1)
+               return 0;
+
+       return configure_kgdboc();
+}
+
+static int kgdboc_get_char(void)
+{
+       if (!kgdb_tty_driver)
+               return -1;
+       return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
+                                               kgdb_tty_line);
+}
+
+static void kgdboc_put_char(u8 chr)
+{
+       if (!kgdb_tty_driver)
+               return;
+       kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
+                                       kgdb_tty_line, chr);
+}
+
+static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
+{
+       int len = strlen(kmessage);
+
+       if (len >= MAX_CONFIG_LEN) {
+               printk(KERN_ERR "kgdboc: config string too long\n");
+               return -ENOSPC;
+       }
+
+       /* Only copy in the string if the init function has not run yet */
+       if (configured < 0) {
+               strcpy(config, kmessage);
+               return 0;
+       }
+
+       if (kgdb_connected) {
+               printk(KERN_ERR
+                      "kgdboc: Cannot reconfigure while KGDB is connected.\n");
+
+               return -EBUSY;
+       }
+
+       strcpy(config, kmessage);
+       /* Chop out \n char as a result of echo */
+       if (config[len - 1] == '\n')
+               config[len - 1] = '\0';
+
+       if (configured == 1)
+               cleanup_kgdboc();
+
+       /* Go and configure with the new params. */
+       return configure_kgdboc();
+}
+
+static int dbg_restore_graphics;
+
+static void kgdboc_pre_exp_handler(void)
+{
+       if (!dbg_restore_graphics && kgdboc_use_kms) {
+               dbg_restore_graphics = 1;
+               con_debug_enter(vc_cons[fg_console].d);
+       }
+       /* Increment the module count when the debugger is active */
+       if (!kgdb_connected)
+               try_module_get(THIS_MODULE);
+}
+
+static void kgdboc_post_exp_handler(void)
+{
+       /* decrement the module count when the debugger detaches */
+       if (!kgdb_connected)
+               module_put(THIS_MODULE);
+       if (kgdboc_use_kms && dbg_restore_graphics) {
+               dbg_restore_graphics = 0;
+               con_debug_leave();
+       }
+       kgdboc_restore_input();
+}
+
+static struct kgdb_io kgdboc_io_ops = {
+       .name                   = "kgdboc",
+       .read_char              = kgdboc_get_char,
+       .write_char             = kgdboc_put_char,
+       .pre_exception          = kgdboc_pre_exp_handler,
+       .post_exception         = kgdboc_post_exp_handler,
+};
+
+#ifdef CONFIG_KGDB_SERIAL_CONSOLE
+/* This is only available if kgdboc is a built in for early debugging */
+static int __init kgdboc_early_init(char *opt)
+{
+       /* save the first character of the config string because the
+        * init routine can destroy it.
+        */
+       char save_ch;
+
+       kgdboc_option_setup(opt);
+       save_ch = config[0];
+       init_kgdboc();
+       config[0] = save_ch;
+       return 0;
+}
+
+early_param("ekgdboc", kgdboc_early_init);
+#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
+
+module_init(init_kgdboc);
+module_exit(cleanup_kgdboc);
+module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
+MODULE_DESCRIPTION("KGDB Console TTY Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
new file mode 100644 (file)
index 0000000..bea5c21
--- /dev/null
@@ -0,0 +1,1192 @@
+/*
+ *  m32r_sio.c
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.c.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.  Currently, we don't
+ *  support this very well, and it may well be dropped from this driver
+ *  in future.  As such, mapbase should be NULL.
+ *
+ *  membase is an 'ioremapped' cookie.  This is compatible with the old
+ *  serial.c driver, and is currently the preferred form.
+ */
+
+#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/delay.h>
+
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define PORT_M32R_BASE PORT_M32R_SIO
+#define PORT_INDEX(x)  (x - PORT_M32R_BASE + 1)
+#define BAUD_RATE      115200
+
+#include <linux/serial_core.h>
+#include "m32r_sio.h"
+#include "m32r_sio_reg.h"
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)     printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)     do { } while (0)
+#endif
+
+#define PASS_LIMIT     256
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq) ((irq) != 0)
+
+#define BASE_BAUD      115200
+
+/* Standard COM flags */
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+
+/*
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism.   Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+#if defined(CONFIG_PLAT_USRV)
+
+#define SERIAL_PORT_DFNS                                               \
+       /* UART  CLK     PORT   IRQ            FLAGS */                 \
+       { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
+       { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
+
+#else /* !CONFIG_PLAT_USRV */
+
+#if defined(CONFIG_SERIAL_M32R_PLDSIO)
+#define SERIAL_PORT_DFNS                                               \
+       { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
+         STD_COM_FLAGS }, /* ttyS0 */
+#else
+#define SERIAL_PORT_DFNS                                               \
+       { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R,               \
+         STD_COM_FLAGS }, /* ttyS0 */
+#endif
+
+#endif /* !CONFIG_PLAT_USRV */
+
+static struct old_serial_port old_serial_port[] = {
+       SERIAL_PORT_DFNS
+};
+
+#define UART_NR        ARRAY_SIZE(old_serial_port)
+
+struct uart_sio_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          rev;
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           lsr_break_flag;
+
+       /*
+        * We provide a per-port pm hook.
+        */
+       void                    (*pm)(struct uart_port *port,
+                                     unsigned int state, unsigned int old);
+};
+
+struct irq_info {
+       spinlock_t              lock;
+       struct list_head        *head;
+};
+
+static struct irq_info irq_lists[NR_IRQS];
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[] = {
+       [PORT_UNKNOWN] = {
+               .name                   = "unknown",
+               .dfl_xmit_fifo_size     = 1,
+               .flags                  = 0,
+       },
+       [PORT_INDEX(PORT_M32R_SIO)] = {
+               .name                   = "M32RSIO",
+               .dfl_xmit_fifo_size     = 1,
+               .flags                  = 0,
+       },
+};
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define __sio_in(x) inw((unsigned long)(x))
+#define __sio_out(v,x) outw((v),(unsigned long)(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned short sbaud;
+       sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1;
+       __sio_out(sbaud, PLD_ESIO0BAUR);
+}
+
+static void sio_reset(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_init(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(PLD_ESIO0CR)) != 3);
+}
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define __sio_in(x) inl(x)
+#define __sio_out(v,x) outl((v),(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned long i, j;
+
+       i = boot_cpu_data.bus_clock / (baud * 16);
+       j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud;
+       i -= 1;
+       j = (j + 1) >> 1;
+
+       __sio_out(i, M32R_SIO0_BAUR_PORTL);
+       __sio_out(j, M32R_SIO0_RBAUR_PORTL);
+}
+
+static void sio_reset(void)
+{
+       __sio_out(0x00000300, M32R_SIO0_CR_PORTL);      /* init status */
+       __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL);    /* 8bit        */
+       __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL);    /* 1stop non   */
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);      /* RXCEN */
+}
+
+static void sio_init(void)
+{
+       unsigned int tmp;
+
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_STS_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3);
+}
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+static unsigned int sio_in(struct uart_sio_port *up, int offset)
+{
+       return __sio_in(up->port.iobase + offset);
+}
+
+static void sio_out(struct uart_sio_port *up, int offset, int value)
+{
+       __sio_out(value, up->port.iobase + offset);
+}
+
+static unsigned int serial_in(struct uart_sio_port *up, int offset)
+{
+       if (!offset)
+               return 0;
+
+       return __sio_in(offset);
+}
+
+static void serial_out(struct uart_sio_port *up, int offset, int value)
+{
+       if (!offset)
+               return;
+
+       __sio_out(value, offset);
+}
+
+static void m32r_sio_stop_tx(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void m32r_sio_start_tx(struct uart_port *port)
+{
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+       }
+       while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
+#else
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+#endif
+}
+
+static void m32r_sio_stop_rx(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void m32r_sio_enable_ms(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void receive_chars(struct uart_sio_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch;
+       unsigned char flag;
+       int max_count = 256;
+
+       do {
+               ch = sio_in(up, SIORXB);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+
+                       if (*status & UART_LSR_BI) {
+                               DEBUG_INTR("handling break....");
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               if ((*status & up->port.ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+
+               if (*status & UART_LSR_OE) {
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character.
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               }
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_sio_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+#ifndef CONFIG_SERIAL_M32R_PLDSIO      /* XXX */
+               serial_out(up, UART_TX, up->port.x_char);
+#endif
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               m32r_sio_stop_tx(&up->port);
+               return;
+       }
+
+       count = up->port.fifosize;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+               while (!(serial_in(up, UART_LSR) & UART_LSR_THRE));
+
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       DEBUG_INTR("THRE...");
+
+       if (uart_circ_empty(xmit))
+               m32r_sio_stop_tx(&up->port);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline void m32r_sio_handle_port(struct uart_sio_port *up,
+       unsigned int status)
+{
+       DEBUG_INTR("status = %x...", status);
+
+       if (status & 0x04)
+               receive_chars(up, &status);
+       if (status & 0x01)
+               transmit_chars(up);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
+{
+       struct irq_info *i = dev_id;
+       struct list_head *l, *end = NULL;
+       int pass_counter = 0;
+
+       DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+//     if (irq == PLD_IRQ_SIO0_SND)
+//             irq = PLD_IRQ_SIO0_RCV;
+#else
+       if (irq == M32R_IRQ_SIO0_S)
+               irq = M32R_IRQ_SIO0_R;
+#endif
+
+       spin_lock(&i->lock);
+
+       l = i->head;
+       do {
+               struct uart_sio_port *up;
+               unsigned int sts;
+
+               up = list_entry(l, struct uart_sio_port, list);
+
+               sts = sio_in(up, SIOSTS);
+               if (sts & 0x5) {
+                       spin_lock(&up->port.lock);
+                       m32r_sio_handle_port(up, sts);
+                       spin_unlock(&up->port.lock);
+
+                       end = NULL;
+               } else if (end == NULL)
+                       end = l;
+
+               l = l->next;
+
+               if (l == i->head && pass_counter++ > PASS_LIMIT) {
+                       if (sts & 0xe0)
+                               sio_error(&sts);
+                       break;
+               }
+       } while (l != end);
+
+       spin_unlock(&i->lock);
+
+       DEBUG_INTR("end.\n");
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
+{
+       spin_lock_irq(&i->lock);
+
+       if (!list_empty(i->head)) {
+               if (i->head == &up->list)
+                       i->head = i->head->next;
+               list_del(&up->list);
+       } else {
+               BUG_ON(i->head != &up->list);
+               i->head = NULL;
+       }
+
+       spin_unlock_irq(&i->lock);
+}
+
+static int serial_link_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+       int ret, irq_flags = 0;
+
+       spin_lock_irq(&i->lock);
+
+       if (i->head) {
+               list_add(&up->list, i->head);
+               spin_unlock_irq(&i->lock);
+
+               ret = 0;
+       } else {
+               INIT_LIST_HEAD(&up->list);
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+
+               ret = request_irq(up->port.irq, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-RX", i);
+               ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-TX", i);
+               if (ret < 0)
+                       serial_do_unlink(i, up);
+       }
+
+       return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+
+       BUG_ON(i->head == NULL);
+
+       if (list_empty(i->head)) {
+               free_irq(up->port.irq, i);
+               free_irq(up->port.irq + 1, i);
+       }
+
+       serial_do_unlink(i, up);
+}
+
+/*
+ * This function is used to handle ports that do not have an interrupt.
+ */
+static void m32r_sio_timeout(unsigned long data)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)data;
+       unsigned int timeout;
+       unsigned int sts;
+
+       sts = sio_in(up, SIOSTS);
+       if (sts & 0x5) {
+               spin_lock(&up->port.lock);
+               m32r_sio_handle_port(up, sts);
+               spin_unlock(&up->port.lock);
+       }
+
+       timeout = up->port.timeout;
+       timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+       mod_timer(&up->timer, jiffies + timeout);
+}
+
+static unsigned int m32r_sio_tx_empty(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int m32r_sio_get_mctrl(struct uart_port *port)
+{
+       return 0;
+}
+
+static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+
+}
+
+static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
+{
+
+}
+
+static int m32r_sio_startup(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       int retval;
+
+       sio_init();
+
+       /*
+        * If the "interrupt" for this port doesn't correspond with any
+        * hardware interrupt, we use a timer-based system.  The original
+        * driver used to do this with IRQ0.
+        */
+       if (!is_real_interrupt(up->port.irq)) {
+               unsigned int timeout = up->port.timeout;
+
+               timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies + timeout);
+       } else {
+               retval = serial_link_irq_chain(up);
+               if (retval)
+                       return retval;
+       }
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        * - M32R_SIO: 0x0c
+        * - M32R_PLDSIO: 0x04
+        */
+       up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       sio_out(up, SIOTRCR, up->ier);
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       sio_reset();
+
+       return 0;
+}
+
+static void m32r_sio_shutdown(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       sio_out(up, SIOTRCR, 0);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+
+       sio_init();
+
+       if (!is_real_interrupt(up->port.irq))
+               del_timer_sync(&up->timer);
+       else
+               serial_unlink_irq_chain(up);
+}
+
+static unsigned int m32r_sio_get_divisor(struct uart_port *port,
+       unsigned int baud)
+{
+       return uart_get_divisor(port, baud);
+}
+
+static void m32r_sio_set_termios(struct uart_port *port,
+       struct ktermios *termios, struct ktermios *old)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned char cval = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (termios->c_cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
+#else
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+#endif
+       quot = m32r_sio_get_divisor(port, baud);
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       sio_set_baud_rate(baud);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       up->lcr = cval;                                 /* Save LCR */
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void m32r_sio_pm(struct uart_port *port, unsigned int state,
+       unsigned int oldstate)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->pm)
+               up->pm(port, state, oldstate);
+}
+
+/*
+ * Resource handling.  This is complicated by the fact that resources
+ * depend on the port type.  Maybe we should be claiming the standard
+ * 8250 ports, and then trying to get other resources as necessary?
+ */
+static int
+m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
+{
+       unsigned int size = 8 << up->port.regshift;
+#ifndef CONFIG_SERIAL_M32R_PLDSIO
+       unsigned long start;
+#endif
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case UPIO_MEM:
+               if (up->port.mapbase) {
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+                       *res = request_mem_region(up->port.mapbase, size, "serial");
+#else
+                       start = up->port.mapbase;
+                       *res = request_mem_region(start, size, "serial");
+#endif
+                       if (!*res)
+                               ret = -EBUSY;
+               }
+               break;
+
+       case UPIO_PORT:
+               *res = request_region(up->port.iobase, size, "serial");
+               if (!*res)
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void m32r_sio_release_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long start, offset = 0, size = 0;
+
+       size <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_MEM:
+               if (up->port.mapbase) {
+                       /*
+                        * Unmap the area.
+                        */
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+
+                       start = up->port.mapbase;
+
+                       if (size)
+                               release_mem_region(start + offset, size);
+                       release_mem_region(start, 8 << up->port.regshift);
+               }
+               break;
+
+       case UPIO_PORT:
+               start = up->port.iobase;
+
+               if (size)
+                       release_region(start + offset, size);
+               release_region(start + offset, 8 << up->port.regshift);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int m32r_sio_request_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct resource *res = NULL;
+       int ret = 0;
+
+       ret = m32r_sio_request_std_resource(up, &res);
+
+       /*
+        * If we have a mapbase, then request that as well.
+        */
+       if (ret == 0 && up->port.flags & UPF_IOREMAP) {
+               int size = res->end - res->start + 1;
+
+               up->port.membase = ioremap(up->port.mapbase, size);
+               if (!up->port.membase)
+                       ret = -ENOMEM;
+       }
+
+       if (ret < 0) {
+               if (res)
+                       release_resource(res);
+       }
+
+       return ret;
+}
+
+static void m32r_sio_config_port(struct uart_port *port, int flags)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
+       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int
+m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->irq >= nr_irqs || ser->irq < 0 ||
+           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+           ser->type >= ARRAY_SIZE(uart_config))
+               return -EINVAL;
+       return 0;
+}
+
+static const char *
+m32r_sio_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops m32r_sio_pops = {
+       .tx_empty       = m32r_sio_tx_empty,
+       .set_mctrl      = m32r_sio_set_mctrl,
+       .get_mctrl      = m32r_sio_get_mctrl,
+       .stop_tx        = m32r_sio_stop_tx,
+       .start_tx       = m32r_sio_start_tx,
+       .stop_rx        = m32r_sio_stop_rx,
+       .enable_ms      = m32r_sio_enable_ms,
+       .break_ctl      = m32r_sio_break_ctl,
+       .startup        = m32r_sio_startup,
+       .shutdown       = m32r_sio_shutdown,
+       .set_termios    = m32r_sio_set_termios,
+       .pm             = m32r_sio_pm,
+       .type           = m32r_sio_type,
+       .release_port   = m32r_sio_release_port,
+       .request_port   = m32r_sio_request_port,
+       .config_port    = m32r_sio_config_port,
+       .verify_port    = m32r_sio_verify_port,
+};
+
+static struct uart_sio_port m32r_sio_ports[UART_NR];
+
+static void __init m32r_sio_init_ports(void)
+{
+       struct uart_sio_port *up;
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
+            i++, up++) {
+               up->port.iobase   = old_serial_port[i].port;
+               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+               up->port.uartclk  = old_serial_port[i].baud_base * 16;
+               up->port.flags    = old_serial_port[i].flags;
+               up->port.membase  = old_serial_port[i].iomem_base;
+               up->port.iotype   = old_serial_port[i].io_type;
+               up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               up->port.ops      = &m32r_sio_pops;
+       }
+}
+
+static void __init m32r_sio_register_ports(struct uart_driver *drv)
+{
+       int i;
+
+       m32r_sio_init_ports();
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_sio_port *up = &m32r_sio_ports[i];
+
+               up->port.line = i;
+               up->port.ops = &m32r_sio_pops;
+               init_timer(&up->timer);
+               up->timer.function = m32r_sio_timeout;
+
+               /*
+                * ALPHA_KLUDGE_MCR needs to be killed.
+                */
+               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+               up->mcr_force = ALPHA_KLUDGE_MCR;
+
+               uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_sio_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = sio_in(up, SIOSTS);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & UART_EMPTY) != UART_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout)
+                       udelay(1);
+       }
+}
+
+static void m32r_sio_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       wait_for_xmitr(up);
+       sio_out(up, SIOTXB, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void m32r_sio_console_write(struct console *co, const char *s,
+       unsigned int count)
+{
+       struct uart_sio_port *up = &m32r_sio_ports[co->index];
+       unsigned int ier;
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = sio_in(up, SIOTRCR);
+       sio_out(up, SIOTRCR, 0);
+
+       uart_console_write(&up->port, s, count, m32r_sio_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, SIOTRCR, ier);
+}
+
+static int __init m32r_sio_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       port = &m32r_sio_ports[co->index].port;
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver m32r_sio_reg;
+static struct console m32r_sio_console = {
+       .name           = "ttyS",
+       .write          = m32r_sio_console_write,
+       .device         = uart_console_device,
+       .setup          = m32r_sio_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &m32r_sio_reg,
+};
+
+static int __init m32r_sio_console_init(void)
+{
+       sio_reset();
+       sio_init();
+       m32r_sio_init_ports();
+       register_console(&m32r_sio_console);
+       return 0;
+}
+console_initcall(m32r_sio_console_init);
+
+#define M32R_SIO_CONSOLE       &m32r_sio_console
+#else
+#define M32R_SIO_CONSOLE       NULL
+#endif
+
+static struct uart_driver m32r_sio_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sio",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = UART_NR,
+       .cons                   = M32R_SIO_CONSOLE,
+};
+
+/**
+ *     m32r_sio_suspend_port - suspend one serial port
+ *     @line: serial line number
+ *
+ *     Suspend one serial port.
+ */
+void m32r_sio_suspend_port(int line)
+{
+       uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+/**
+ *     m32r_sio_resume_port - resume one serial port
+ *     @line: serial line number
+ *
+ *     Resume one serial port.
+ */
+void m32r_sio_resume_port(int line)
+{
+       uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+static int __init m32r_sio_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: M32R SIO driver\n");
+
+       for (i = 0; i < nr_irqs; i++)
+               spin_lock_init(&irq_lists[i].lock);
+
+       ret = uart_register_driver(&m32r_sio_reg);
+       if (ret >= 0)
+               m32r_sio_register_ports(&m32r_sio_reg);
+
+       return ret;
+}
+
+static void __exit m32r_sio_exit(void)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
+
+       uart_unregister_driver(&m32r_sio_reg);
+}
+
+module_init(m32r_sio_init);
+module_exit(m32r_sio_exit);
+
+EXPORT_SYMBOL(m32r_sio_suspend_port);
+EXPORT_SYMBOL(m32r_sio_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
new file mode 100644 (file)
index 0000000..e9b7e11
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  m32r_sio.h
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.h.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+struct m32r_sio_probe {
+       struct module   *owner;
+       int             (*pci_init_one)(struct pci_dev *dev);
+       void            (*pci_remove_one)(struct pci_dev *dev);
+       void            (*pnp_init)(void);
+};
+
+int m32r_sio_register_probe(struct m32r_sio_probe *probe);
+void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
+void m32r_sio_get_irq_map(unsigned int *map);
+void m32r_sio_suspend_port(int line);
+void m32r_sio_resume_port(int line);
+
+struct old_serial_port {
+       unsigned int uart;
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       unsigned int flags;
+       unsigned char io_type;
+       unsigned char __iomem *iomem_base;
+       unsigned short iomem_reg_shift;
+};
+
+#define _INLINE_ inline
+
+#define PROBE_RSA      (1 << 0)
+#define PROBE_ANY      (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/tty/serial/m32r_sio_reg.h b/drivers/tty/serial/m32r_sio_reg.h
new file mode 100644 (file)
index 0000000..4671473
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * m32r_sio_reg.h
+ *
+ * Copyright (C) 1992, 1994 by Theodore Ts'o.
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ *
+ * These are the UART port assignments, expressed as offsets from the base
+ * register.  These assignments should hold for any serial port based on
+ * a 8250, 16450, or 16550(A).
+ */
+
+#ifndef _M32R_SIO_REG_H
+#define _M32R_SIO_REG_H
+
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define SIOCR          0x000
+#define SIOMOD0                0x002
+#define SIOMOD1                0x004
+#define SIOSTS         0x006
+#define SIOTRCR                0x008
+#define SIOBAUR                0x00a
+// #define SIORBAUR    0x018
+#define SIOTXB         0x00c
+#define SIORXB         0x00e
+
+#define UART_RX                ((unsigned long) PLD_ESIO0RXB)
+                               /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                ((unsigned long) PLD_ESIO0TXB)
+                               /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       ((unsigned long) PLD_ESIO0INTCR)
+                               /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       ((unsigned long) PLD_ESIO0STS)
+                               /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define SIOCR          0x000
+#define SIOMOD0                0x004
+#define SIOMOD1                0x008
+#define SIOSTS         0x00c
+#define SIOTRCR                0x010
+#define SIOBAUR                0x014
+#define SIORBAUR       0x018
+#define SIOTXB         0x01c
+#define SIORXB         0x020
+
+#define UART_RX                M32R_SIO0_RXB_PORTL     /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                M32R_SIO0_TXB_PORTL     /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       M32R_SIO0_TRCR_PORTL    /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       M32R_SIO0_STS_PORTL     /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+#define UART_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ * These are the definitions for the Line Control Register
+ *
+ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
+ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
+ */
+#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
+#define UART_LCR_SBC   0x40    /* Set break control */
+#define UART_LCR_SPAR  0x20    /* Stick parity (?) */
+#define UART_LCR_EPAR  0x10    /* Even parity select */
+#define UART_LCR_PARITY        0x08    /* Parity Enable */
+#define UART_LCR_STOP  0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
+#define UART_LCR_WLEN5  0x00   /* Wordlength: 5 bits */
+#define UART_LCR_WLEN6  0x01   /* Wordlength: 6 bits */
+#define UART_LCR_WLEN7  0x02   /* Wordlength: 7 bits */
+#define UART_LCR_WLEN8  0x03   /* Wordlength: 8 bits */
+
+/*
+ * These are the definitions for the Line Status Register
+ */
+#define UART_LSR_TEMT  0x02    /* Transmitter empty */
+#define UART_LSR_THRE  0x01    /* Transmit-hold-register empty */
+#define UART_LSR_BI    0x00    /* Break interrupt indicator */
+#define UART_LSR_FE    0x80    /* Frame error indicator */
+#define UART_LSR_PE    0x40    /* Parity error indicator */
+#define UART_LSR_OE    0x20    /* Overrun error indicator */
+#define UART_LSR_DR    0x04    /* Receiver data ready */
+
+/*
+ * These are the definitions for the Interrupt Identification Register
+ */
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI   0x00    /* Modem status interrupt */
+#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
+#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
+#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
+
+/*
+ * These are the definitions for the Interrupt Enable Register
+ */
+#define UART_IER_MSI   0x00    /* Enable Modem status interrupt */
+#define UART_IER_RLSI  0x08    /* Enable receiver line status interrupt */
+#define UART_IER_THRI  0x03    /* Enable Transmitter holding register int. */
+#define UART_IER_RDI   0x04    /* Enable receiver data interrupt */
+
+#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
new file mode 100644 (file)
index 0000000..7b951ad
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ *
+ *  Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
+ * to use polling for flow control. TX empty IRQ is unusable, since
+ * writing conf clears FIFO buffer and we cannot have this interrupt
+ * always asking us for attention.
+ *
+ * Example platform data:
+
+ static struct plat_max3100 max3100_plat_data = {
+ .loopback = 0,
+ .crystal = 0,
+ .poll_time = 100,
+ };
+
+ static struct spi_board_info spi_board_info[] = {
+ {
+ .modalias     = "max3100",
+ .platform_data        = &max3100_plat_data,
+ .irq          = IRQ_EINT12,
+ .max_speed_hz = 5*1000*1000,
+ .chip_select  = 0,
+ },
+ };
+
+ * The initial minor number is 209 in the low-density serial port:
+ * mknod /dev/ttyMAX0 c 204 209
+ */
+
+#define MAX3100_MAJOR 204
+#define MAX3100_MINOR 209
+/* 4 MAX3100s should be enough for everyone */
+#define MAX_MAX3100 4
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+
+#include <linux/serial_max3100.h>
+
+#define MAX3100_C    (1<<14)
+#define MAX3100_D    (0<<14)
+#define MAX3100_W    (1<<15)
+#define MAX3100_RX   (0<<15)
+
+#define MAX3100_WC   (MAX3100_W  | MAX3100_C)
+#define MAX3100_RC   (MAX3100_RX | MAX3100_C)
+#define MAX3100_WD   (MAX3100_W  | MAX3100_D)
+#define MAX3100_RD   (MAX3100_RX | MAX3100_D)
+#define MAX3100_CMD  (3 << 14)
+
+#define MAX3100_T    (1<<14)
+#define MAX3100_R    (1<<15)
+
+#define MAX3100_FEN  (1<<13)
+#define MAX3100_SHDN (1<<12)
+#define MAX3100_TM   (1<<11)
+#define MAX3100_RM   (1<<10)
+#define MAX3100_PM   (1<<9)
+#define MAX3100_RAM  (1<<8)
+#define MAX3100_IR   (1<<7)
+#define MAX3100_ST   (1<<6)
+#define MAX3100_PE   (1<<5)
+#define MAX3100_L    (1<<4)
+#define MAX3100_BAUD (0xf)
+
+#define MAX3100_TE   (1<<10)
+#define MAX3100_RAFE (1<<10)
+#define MAX3100_RTS  (1<<9)
+#define MAX3100_CTS  (1<<9)
+#define MAX3100_PT   (1<<8)
+#define MAX3100_DATA (0xff)
+
+#define MAX3100_RT   (MAX3100_R | MAX3100_T)
+#define MAX3100_RTC  (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE)
+
+/* the following simulate a status reg for ignore_status_mask */
+#define MAX3100_STATUS_PE 1
+#define MAX3100_STATUS_FE 2
+#define MAX3100_STATUS_OE 4
+
+struct max3100_port {
+       struct uart_port port;
+       struct spi_device *spi;
+
+       int cts;                /* last CTS received for flow ctrl */
+       int tx_empty;           /* last TX empty bit */
+
+       spinlock_t conf_lock;   /* shared data */
+       int conf_commit;        /* need to make changes */
+       int conf;               /* configuration for the MAX31000
+                                * (bits 0-7, bits 8-11 are irqs) */
+       int rts_commit;         /* need to change rts */
+       int rts;                /* rts status */
+       int baud;               /* current baud rate */
+
+       int parity;             /* keeps track if we should send parity */
+#define MAX3100_PARITY_ON 1
+#define MAX3100_PARITY_ODD 2
+#define MAX3100_7BIT 4
+       int rx_enabled;         /* if we should rx chars */
+
+       int irq;                /* irq assigned to the max3100 */
+
+       int minor;              /* minor number */
+       int crystal;            /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
+       int loopback;           /* 1 if we are in loopback mode */
+
+       /* for handling irqs: need workqueue since we do spi_sync */
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+       /* set to 1 to make the workhandler exit as soon as possible */
+       int  force_end_work;
+       /* need to know we are suspending to avoid deadlock on workqueue */
+       int suspending;
+
+       /* hook for suspending MAX3100 via dedicated pin */
+       void (*max3100_hw_suspend) (int suspend);
+
+       /* poll time (in ms) for ctrl lines */
+       int poll_time;
+       /* and its timer */
+       struct timer_list       timer;
+};
+
+static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
+static DEFINE_MUTEX(max3100s_lock);               /* race on probe */
+
+static int max3100_do_parity(struct max3100_port *s, u16 c)
+{
+       int parity;
+
+       if (s->parity & MAX3100_PARITY_ODD)
+               parity = 1;
+       else
+               parity = 0;
+
+       if (s->parity & MAX3100_7BIT)
+               c &= 0x7f;
+       else
+               c &= 0xff;
+
+       parity = parity ^ (hweight8(c) & 1);
+       return parity;
+}
+
+static int max3100_check_parity(struct max3100_port *s, u16 c)
+{
+       return max3100_do_parity(s, c) == ((c >> 8) & 1);
+}
+
+static void max3100_calc_parity(struct max3100_port *s, u16 *c)
+{
+       if (s->parity & MAX3100_7BIT)
+               *c &= 0x7f;
+       else
+               *c &= 0xff;
+
+       if (s->parity & MAX3100_PARITY_ON)
+               *c |= max3100_do_parity(s, *c) << 8;
+}
+
+static void max3100_work(struct work_struct *w);
+
+static void max3100_dowork(struct max3100_port *s)
+{
+       if (!s->force_end_work && !work_pending(&s->work) &&
+           !freezing(current) && !s->suspending)
+               queue_work(s->workqueue, &s->work);
+}
+
+static void max3100_timeout(unsigned long data)
+{
+       struct max3100_port *s = (struct max3100_port *)data;
+
+       if (s->port.state) {
+               max3100_dowork(s);
+               mod_timer(&s->timer, jiffies + s->poll_time);
+       }
+}
+
+static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
+{
+       struct spi_message message;
+       u16 etx, erx;
+       int status;
+       struct spi_transfer tran = {
+               .tx_buf = &etx,
+               .rx_buf = &erx,
+               .len = 2,
+       };
+
+       etx = cpu_to_be16(tx);
+       spi_message_init(&message);
+       spi_message_add_tail(&tran, &message);
+       status = spi_sync(s->spi, &message);
+       if (status) {
+               dev_warn(&s->spi->dev, "error while calling spi_sync\n");
+               return -EIO;
+       }
+       *rx = be16_to_cpu(erx);
+       s->tx_empty = (*rx & MAX3100_T) > 0;
+       dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx);
+       return 0;
+}
+
+static int max3100_handlerx(struct max3100_port *s, u16 rx)
+{
+       unsigned int ch, flg, status = 0;
+       int ret = 0, cts;
+
+       if (rx & MAX3100_R && s->rx_enabled) {
+               dev_dbg(&s->spi->dev, "%s\n", __func__);
+               ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff);
+               if (rx & MAX3100_RAFE) {
+                       s->port.icount.frame++;
+                       flg = TTY_FRAME;
+                       status |= MAX3100_STATUS_FE;
+               } else {
+                       if (s->parity & MAX3100_PARITY_ON) {
+                               if (max3100_check_parity(s, rx)) {
+                                       s->port.icount.rx++;
+                                       flg = TTY_NORMAL;
+                               } else {
+                                       s->port.icount.parity++;
+                                       flg = TTY_PARITY;
+                                       status |= MAX3100_STATUS_PE;
+                               }
+                       } else {
+                               s->port.icount.rx++;
+                               flg = TTY_NORMAL;
+                       }
+               }
+               uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg);
+               ret = 1;
+       }
+
+       cts = (rx & MAX3100_CTS) > 0;
+       if (s->cts != cts) {
+               s->cts = cts;
+               uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
+       }
+
+       return ret;
+}
+
+static void max3100_work(struct work_struct *w)
+{
+       struct max3100_port *s = container_of(w, struct max3100_port, work);
+       int rxchars;
+       u16 tx, rx;
+       int conf, cconf, rts, crts;
+       struct circ_buf *xmit = &s->port.state->xmit;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       rxchars = 0;
+       do {
+               spin_lock(&s->conf_lock);
+               conf = s->conf;
+               cconf = s->conf_commit;
+               s->conf_commit = 0;
+               rts = s->rts;
+               crts = s->rts_commit;
+               s->rts_commit = 0;
+               spin_unlock(&s->conf_lock);
+               if (cconf)
+                       max3100_sr(s, MAX3100_WC | conf, &rx);
+               if (crts) {
+                       max3100_sr(s, MAX3100_WD | MAX3100_TE |
+                                  (s->rts ? MAX3100_RTS : 0), &rx);
+                       rxchars += max3100_handlerx(s, rx);
+               }
+
+               max3100_sr(s, MAX3100_RD, &rx);
+               rxchars += max3100_handlerx(s, rx);
+
+               if (rx & MAX3100_T) {
+                       tx = 0xffff;
+                       if (s->port.x_char) {
+                               tx = s->port.x_char;
+                               s->port.icount.tx++;
+                               s->port.x_char = 0;
+                       } else if (!uart_circ_empty(xmit) &&
+                                  !uart_tx_stopped(&s->port)) {
+                               tx = xmit->buf[xmit->tail];
+                               xmit->tail = (xmit->tail + 1) &
+                                       (UART_XMIT_SIZE - 1);
+                               s->port.icount.tx++;
+                       }
+                       if (tx != 0xffff) {
+                               max3100_calc_parity(s, &tx);
+                               tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0);
+                               max3100_sr(s, tx, &rx);
+                               rxchars += max3100_handlerx(s, rx);
+                       }
+               }
+
+               if (rxchars > 16 && s->port.state->port.tty != NULL) {
+                       tty_flip_buffer_push(s->port.state->port.tty);
+                       rxchars = 0;
+               }
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&s->port);
+
+       } while (!s->force_end_work &&
+                !freezing(current) &&
+                ((rx & MAX3100_R) ||
+                 (!uart_circ_empty(xmit) &&
+                  !uart_tx_stopped(&s->port))));
+
+       if (rxchars > 0 && s->port.state->port.tty != NULL)
+               tty_flip_buffer_push(s->port.state->port.tty);
+}
+
+static irqreturn_t max3100_irq(int irqno, void *dev_id)
+{
+       struct max3100_port *s = dev_id;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       max3100_dowork(s);
+       return IRQ_HANDLED;
+}
+
+static void max3100_enable_ms(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       if (s->poll_time > 0)
+               mod_timer(&s->timer, jiffies);
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static void max3100_start_tx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       max3100_dowork(s);
+}
+
+static void max3100_stop_rx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       s->rx_enabled = 0;
+       spin_lock(&s->conf_lock);
+       s->conf &= ~MAX3100_RM;
+       s->conf_commit = 1;
+       spin_unlock(&s->conf_lock);
+       max3100_dowork(s);
+}
+
+static unsigned int max3100_tx_empty(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       /* may not be truly up-to-date */
+       max3100_dowork(s);
+       return s->tx_empty;
+}
+
+static unsigned int max3100_get_mctrl(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       /* may not be truly up-to-date */
+       max3100_dowork(s);
+       /* always assert DCD and DSR since these lines are not wired */
+       return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int rts;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       rts = (mctrl & TIOCM_RTS) > 0;
+
+       spin_lock(&s->conf_lock);
+       if (s->rts != rts) {
+               s->rts = rts;
+               s->rts_commit = 1;
+               max3100_dowork(s);
+       }
+       spin_unlock(&s->conf_lock);
+}
+
+static void
+max3100_set_termios(struct uart_port *port, struct ktermios *termios,
+                   struct ktermios *old)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int baud = 0;
+       unsigned cflag;
+       u32 param_new, param_mask, parity = 0;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       cflag = termios->c_cflag;
+       param_new = 0;
+       param_mask = 0;
+
+       baud = tty_termios_baud_rate(termios);
+       param_new = s->conf & MAX3100_BAUD;
+       switch (baud) {
+       case 300:
+               if (s->crystal)
+                       baud = s->baud;
+               else
+                       param_new = 15;
+               break;
+       case 600:
+               param_new = 14 + s->crystal;
+               break;
+       case 1200:
+               param_new = 13 + s->crystal;
+               break;
+       case 2400:
+               param_new = 12 + s->crystal;
+               break;
+       case 4800:
+               param_new = 11 + s->crystal;
+               break;
+       case 9600:
+               param_new = 10 + s->crystal;
+               break;
+       case 19200:
+               param_new = 9 + s->crystal;
+               break;
+       case 38400:
+               param_new = 8 + s->crystal;
+               break;
+       case 57600:
+               param_new = 1 + s->crystal;
+               break;
+       case 115200:
+               param_new = 0 + s->crystal;
+               break;
+       case 230400:
+               if (s->crystal)
+                       param_new = 0;
+               else
+                       baud = s->baud;
+               break;
+       default:
+               baud = s->baud;
+       }
+       tty_termios_encode_baud_rate(termios, baud, baud);
+       s->baud = baud;
+       param_mask |= MAX3100_BAUD;
+
+       if ((cflag & CSIZE) == CS8) {
+               param_new &= ~MAX3100_L;
+               parity &= ~MAX3100_7BIT;
+       } else {
+               param_new |= MAX3100_L;
+               parity |= MAX3100_7BIT;
+               cflag = (cflag & ~CSIZE) | CS7;
+       }
+       param_mask |= MAX3100_L;
+
+       if (cflag & CSTOPB)
+               param_new |= MAX3100_ST;
+       else
+               param_new &= ~MAX3100_ST;
+       param_mask |= MAX3100_ST;
+
+       if (cflag & PARENB) {
+               param_new |= MAX3100_PE;
+               parity |= MAX3100_PARITY_ON;
+       } else {
+               param_new &= ~MAX3100_PE;
+               parity &= ~MAX3100_PARITY_ON;
+       }
+       param_mask |= MAX3100_PE;
+
+       if (cflag & PARODD)
+               parity |= MAX3100_PARITY_ODD;
+       else
+               parity &= ~MAX3100_PARITY_ODD;
+
+       /* mask termios capabilities we don't support */
+       cflag &= ~CMSPAR;
+       termios->c_cflag = cflag;
+
+       s->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               s->port.ignore_status_mask |=
+                       MAX3100_STATUS_PE | MAX3100_STATUS_FE |
+                       MAX3100_STATUS_OE;
+
+       /* we are sending char from a workqueue so enable */
+       s->port.state->port.tty->low_latency = 1;
+
+       if (s->poll_time > 0)
+               del_timer_sync(&s->timer);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_lock(&s->conf_lock);
+       s->conf = (s->conf & ~param_mask) | (param_new & param_mask);
+       s->conf_commit = 1;
+       s->parity = parity;
+       spin_unlock(&s->conf_lock);
+       max3100_dowork(s);
+
+       if (UART_ENABLE_MS(&s->port, termios->c_cflag))
+               max3100_enable_ms(&s->port);
+}
+
+static void max3100_shutdown(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (s->suspending)
+               return;
+
+       s->force_end_work = 1;
+
+       if (s->poll_time > 0)
+               del_timer_sync(&s->timer);
+
+       if (s->workqueue) {
+               flush_workqueue(s->workqueue);
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+       }
+       if (s->irq)
+               free_irq(s->irq, s);
+
+       /* set shutdown mode to save power */
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(1);
+       else  {
+               u16 tx, rx;
+
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(s, tx, &rx);
+       }
+}
+
+static int max3100_startup(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       char b[12];
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       s->conf = MAX3100_RM;
+       s->baud = s->crystal ? 230400 : 115200;
+       s->rx_enabled = 1;
+
+       if (s->suspending)
+               return 0;
+
+       s->force_end_work = 0;
+       s->parity = 0;
+       s->rts = 0;
+
+       sprintf(b, "max3100-%d", s->minor);
+       s->workqueue = create_freezable_workqueue(b);
+       if (!s->workqueue) {
+               dev_warn(&s->spi->dev, "cannot create workqueue\n");
+               return -EBUSY;
+       }
+       INIT_WORK(&s->work, max3100_work);
+
+       if (request_irq(s->irq, max3100_irq,
+                       IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
+               dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
+               s->irq = 0;
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+               return -EBUSY;
+       }
+
+       if (s->loopback) {
+               u16 tx, rx;
+               tx = 0x4001;
+               max3100_sr(s, tx, &rx);
+       }
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(0);
+       s->conf_commit = 1;
+       max3100_dowork(s);
+       /* wait for clock to settle */
+       msleep(50);
+
+       max3100_enable_ms(&s->port);
+
+       return 0;
+}
+
+static const char *max3100_type(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL;
+}
+
+static void max3100_release_port(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static void max3100_config_port(struct uart_port *port, int flags)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (flags & UART_CONFIG_TYPE)
+               s->port.type = PORT_MAX3100;
+}
+
+static int max3100_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+       int ret = -EINVAL;
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100)
+               ret = 0;
+       return ret;
+}
+
+static void max3100_stop_tx(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static int max3100_request_port(struct uart_port *port)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+       return 0;
+}
+
+static void max3100_break_ctl(struct uart_port *port, int break_state)
+{
+       struct max3100_port *s = container_of(port,
+                                             struct max3100_port,
+                                             port);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+}
+
+static struct uart_ops max3100_ops = {
+       .tx_empty       = max3100_tx_empty,
+       .set_mctrl      = max3100_set_mctrl,
+       .get_mctrl      = max3100_get_mctrl,
+       .stop_tx        = max3100_stop_tx,
+       .start_tx       = max3100_start_tx,
+       .stop_rx        = max3100_stop_rx,
+       .enable_ms      = max3100_enable_ms,
+       .break_ctl      = max3100_break_ctl,
+       .startup        = max3100_startup,
+       .shutdown       = max3100_shutdown,
+       .set_termios    = max3100_set_termios,
+       .type           = max3100_type,
+       .release_port   = max3100_release_port,
+       .request_port   = max3100_request_port,
+       .config_port    = max3100_config_port,
+       .verify_port    = max3100_verify_port,
+};
+
+static struct uart_driver max3100_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyMAX",
+       .dev_name       = "ttyMAX",
+       .major          = MAX3100_MAJOR,
+       .minor          = MAX3100_MINOR,
+       .nr             = MAX_MAX3100,
+};
+static int uart_driver_registered;
+
+static int __devinit max3100_probe(struct spi_device *spi)
+{
+       int i, retval;
+       struct plat_max3100 *pdata;
+       u16 tx, rx;
+
+       mutex_lock(&max3100s_lock);
+
+       if (!uart_driver_registered) {
+               uart_driver_registered = 1;
+               retval = uart_register_driver(&max3100_uart_driver);
+               if (retval) {
+                       printk(KERN_ERR "Couldn't register max3100 uart driver\n");
+                       mutex_unlock(&max3100s_lock);
+                       return retval;
+               }
+       }
+
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (!max3100s[i])
+                       break;
+       if (i == MAX_MAX3100) {
+               dev_warn(&spi->dev, "too many MAX3100 chips\n");
+               mutex_unlock(&max3100s_lock);
+               return -ENOMEM;
+       }
+
+       max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
+       if (!max3100s[i]) {
+               dev_warn(&spi->dev,
+                        "kmalloc for max3100 structure %d failed!\n", i);
+               mutex_unlock(&max3100s_lock);
+               return -ENOMEM;
+       }
+       max3100s[i]->spi = spi;
+       max3100s[i]->irq = spi->irq;
+       spin_lock_init(&max3100s[i]->conf_lock);
+       dev_set_drvdata(&spi->dev, max3100s[i]);
+       pdata = spi->dev.platform_data;
+       max3100s[i]->crystal = pdata->crystal;
+       max3100s[i]->loopback = pdata->loopback;
+       max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
+       if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
+               max3100s[i]->poll_time = 1;
+       max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
+       max3100s[i]->minor = i;
+       init_timer(&max3100s[i]->timer);
+       max3100s[i]->timer.function = max3100_timeout;
+       max3100s[i]->timer.data = (unsigned long) max3100s[i];
+
+       dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
+       max3100s[i]->port.irq = max3100s[i]->irq;
+       max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
+       max3100s[i]->port.fifosize = 16;
+       max3100s[i]->port.ops = &max3100_ops;
+       max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       max3100s[i]->port.line = i;
+       max3100s[i]->port.type = PORT_MAX3100;
+       max3100s[i]->port.dev = &spi->dev;
+       retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
+       if (retval < 0)
+               dev_warn(&spi->dev,
+                        "uart_add_one_port failed for line %d with error %d\n",
+                        i, retval);
+
+       /* set shutdown mode to save power. Will be woken-up on open */
+       if (max3100s[i]->max3100_hw_suspend)
+               max3100s[i]->max3100_hw_suspend(1);
+       else {
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(max3100s[i], tx, &rx);
+       }
+       mutex_unlock(&max3100s_lock);
+       return 0;
+}
+
+static int __devexit max3100_remove(struct spi_device *spi)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+       int i;
+
+       mutex_lock(&max3100s_lock);
+
+       /* find out the index for the chip we are removing */
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (max3100s[i] == s)
+                       break;
+
+       dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
+       uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
+       kfree(max3100s[i]);
+       max3100s[i] = NULL;
+
+       /* check if this is the last chip we have */
+       for (i = 0; i < MAX_MAX3100; i++)
+               if (max3100s[i]) {
+                       mutex_unlock(&max3100s_lock);
+                       return 0;
+               }
+       pr_debug("removing max3100 driver\n");
+       uart_unregister_driver(&max3100_uart_driver);
+
+       mutex_unlock(&max3100s_lock);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int max3100_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       disable_irq(s->irq);
+
+       s->suspending = 1;
+       uart_suspend_port(&max3100_uart_driver, &s->port);
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(1);
+       else {
+               /* no HW suspend, so do SW one */
+               u16 tx, rx;
+
+               tx = MAX3100_WC | MAX3100_SHDN;
+               max3100_sr(s, tx, &rx);
+       }
+       return 0;
+}
+
+static int max3100_resume(struct spi_device *spi)
+{
+       struct max3100_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&s->spi->dev, "%s\n", __func__);
+
+       if (s->max3100_hw_suspend)
+               s->max3100_hw_suspend(0);
+       uart_resume_port(&max3100_uart_driver, &s->port);
+       s->suspending = 0;
+
+       enable_irq(s->irq);
+
+       s->conf_commit = 1;
+       if (s->workqueue)
+               max3100_dowork(s);
+
+       return 0;
+}
+
+#else
+#define max3100_suspend NULL
+#define max3100_resume  NULL
+#endif
+
+static struct spi_driver max3100_driver = {
+       .driver = {
+               .name           = "max3100",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = max3100_probe,
+       .remove         = __devexit_p(max3100_remove),
+       .suspend        = max3100_suspend,
+       .resume         = max3100_resume,
+};
+
+static int __init max3100_init(void)
+{
+       return spi_register_driver(&max3100_driver);
+}
+module_init(max3100_init);
+
+static void __exit max3100_exit(void)
+{
+       spi_unregister_driver(&max3100_driver);
+}
+module_exit(max3100_exit);
+
+MODULE_DESCRIPTION("MAX3100 driver");
+MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:max3100");
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
new file mode 100644 (file)
index 0000000..a1fe304
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *  max3107.c - spi uart protocol driver for Maxim 3107
+ *  Based on max3100.c
+ *     by Christian Pellegrin <chripell@evolware.org>
+ *  and        max3110.c
+ *     by Feng Tang <feng.tang@intel.com>
+ *
+ *  Copyright (C) Aavamobile 2009
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/sfi.h>
+#include <asm/mrst.h>
+#include "max3107.h"
+
+/* GPIO direction to input function */
+static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[1];             /* Buffer for SPI transfer */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO configuration register */
+       buf[0] = MAX3107_GPIOCFG_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Set GPIO to input */
+       buf[0] &= ~(0x0001 << offset);
+
+       /* Write new GPIO configuration register value */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* GPIO direction to output function */
+static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[2];     /* Buffer for SPI transfers */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO configuration and data registers */
+       buf[0] = MAX3107_GPIOCFG_REG;
+       buf[1] = MAX3107_GPIODATA_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
+               dev_err(&s->spi->dev, "SPI transfer gpio failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Set GPIO to output */
+       buf[0] |= (0x0001 << offset);
+       /* Set value */
+       if (value)
+               buf[1] |= (0x0001 << offset);
+       else
+               buf[1] &= ~(0x0001 << offset);
+
+       /* Write new GPIO configuration and data register values */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
+       buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for GPIO conf data w failed\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* GPIO value query function */
+static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[1];     /* Buffer for SPI transfer */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return -EINVAL;
+       }
+
+       /* Read current GPIO data register */
+       buf[0] = MAX3107_GPIODATA_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n");
+               return -EIO;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+
+       /* Return value */
+       return buf[0] & (0x0001 << offset);
+}
+
+/* GPIO value set function */
+static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct max3107_port *s = container_of(chip, struct max3107_port, chip);
+       u16 buf[2];     /* Buffer for SPI transfers */
+
+       if (offset >= MAX3107_GPIO_COUNT) {
+               dev_err(&s->spi->dev, "Invalid GPIO\n");
+               return;
+       }
+
+       /* Read current GPIO configuration registers*/
+       buf[0] = MAX3107_GPIODATA_REG;
+       buf[1] = MAX3107_GPIOCFG_REG;
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for GPIO data and config read failed\n");
+               return;
+       }
+       buf[0] &= MAX3107_SPI_RX_DATA_MASK;
+       buf[1] &= MAX3107_SPI_RX_DATA_MASK;
+
+       if (!(buf[1] & (0x0001 << offset))) {
+               /* Configured as input, can't set value */
+               dev_warn(&s->spi->dev,
+                               "Trying to set value for input GPIO\n");
+               return;
+       }
+
+       /* Set value */
+       if (value)
+               buf[0] |= (0x0001 << offset);
+       else
+               buf[0] &= ~(0x0001 << offset);
+
+       /* Write new GPIO data register value */
+       buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 2))
+               dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n");
+}
+
+/* GPIO chip data */
+static struct gpio_chip max3107_gpio_chip = {
+       .owner                  = THIS_MODULE,
+       .direction_input        = max3107_gpio_direction_in,
+       .direction_output       = max3107_gpio_direction_out,
+       .get                    = max3107_gpio_get,
+       .set                    = max3107_gpio_set,
+       .can_sleep              = 1,
+       .base                   = MAX3107_GPIO_BASE,
+       .ngpio                  = MAX3107_GPIO_COUNT,
+};
+
+/**
+ *     max3107_aava_reset      -       reset on AAVA systems
+ *     @spi: The SPI device we are probing
+ *
+ *     Reset the device ready for probing.
+ */
+
+static int max3107_aava_reset(struct spi_device *spi)
+{
+       /* Reset the chip */
+       if (gpio_request(MAX3107_RESET_GPIO, "max3107")) {
+               pr_err("Requesting RESET GPIO failed\n");
+               return -EIO;
+       }
+       if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) {
+               pr_err("Setting RESET GPIO to 0 failed\n");
+               gpio_free(MAX3107_RESET_GPIO);
+               return -EIO;
+       }
+       msleep(MAX3107_RESET_DELAY);
+       if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) {
+               pr_err("Setting RESET GPIO to 1 failed\n");
+               gpio_free(MAX3107_RESET_GPIO);
+               return -EIO;
+       }
+       gpio_free(MAX3107_RESET_GPIO);
+       msleep(MAX3107_WAKEUP_DELAY);
+       return 0;
+}
+
+static int max3107_aava_configure(struct max3107_port *s)
+{
+       int retval;
+
+       /* Initialize GPIO chip data */
+       s->chip = max3107_gpio_chip;
+       s->chip.label = s->spi->modalias;
+       s->chip.dev = &s->spi->dev;
+
+       /* Add GPIO chip */
+       retval = gpiochip_add(&s->chip);
+       if (retval) {
+               dev_err(&s->spi->dev, "Adding GPIO chip failed\n");
+               return retval;
+       }
+
+       /* Temporary fix for EV2 boot problems, set modem reset to 0 */
+       max3107_gpio_direction_out(&s->chip, 3, 0);
+       return 0;
+}
+
+#if 0
+/* This will get enabled once we have the board stuff merged for this
+   specific case */
+
+static const struct baud_table brg13_ext[] = {
+       { 300,    MAX3107_BRG13_B300 },
+       { 600,    MAX3107_BRG13_B600 },
+       { 1200,   MAX3107_BRG13_B1200 },
+       { 2400,   MAX3107_BRG13_B2400 },
+       { 4800,   MAX3107_BRG13_B4800 },
+       { 9600,   MAX3107_BRG13_B9600 },
+       { 19200,  MAX3107_BRG13_B19200 },
+       { 57600,  MAX3107_BRG13_B57600 },
+       { 115200, MAX3107_BRG13_B115200 },
+       { 230400, MAX3107_BRG13_B230400 },
+       { 460800, MAX3107_BRG13_B460800 },
+       { 921600, MAX3107_BRG13_B921600 },
+       { 0, 0 }
+};
+
+static void max3107_aava_init(struct max3107_port *s)
+{
+       /*override for AAVA SC specific*/
+       if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) {
+               if (get_koski_build_id() <= KOSKI_EV2)
+                       if (s->ext_clk) {
+                               s->brg_cfg = MAX3107_BRG13_B9600;
+                               s->baud_tbl = (struct baud_table *)brg13_ext;
+                       }
+       }
+}
+#endif
+
+static int __devexit max3107_aava_remove(struct spi_device *spi)
+{
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       /* Remove GPIO chip */
+       if (gpiochip_remove(&s->chip))
+               dev_warn(&spi->dev, "Removing GPIO chip failed\n");
+
+       /* Then do the default remove */
+       return max3107_remove(spi);
+}
+
+/* Platform data */
+static struct max3107_plat aava_plat_data = {
+       .loopback               = 0,
+       .ext_clk                = 1,
+/*     .init                   = max3107_aava_init, */
+       .configure              = max3107_aava_configure,
+       .hw_suspend             = max3107_hw_susp,
+       .polled_mode            = 0,
+       .poll_time              = 0,
+};
+
+
+static int __devinit max3107_probe_aava(struct spi_device *spi)
+{
+       int err = max3107_aava_reset(spi);
+       if (err < 0)
+               return err;
+       return max3107_probe(spi, &aava_plat_data);
+}
+
+/* Spi driver data */
+static struct spi_driver max3107_driver = {
+       .driver = {
+               .name           = "aava-max3107",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = max3107_probe_aava,
+       .remove         = __devexit_p(max3107_aava_remove),
+       .suspend        = max3107_suspend,
+       .resume         = max3107_resume,
+};
+
+/* Driver init function */
+static int __init max3107_init(void)
+{
+       return spi_register_driver(&max3107_driver);
+}
+
+/* Driver exit function */
+static void __exit max3107_exit(void)
+{
+       spi_unregister_driver(&max3107_driver);
+}
+
+module_init(max3107_init);
+module_exit(max3107_exit);
+
+MODULE_DESCRIPTION("MAX3107 driver");
+MODULE_AUTHOR("Aavamobile");
+MODULE_ALIAS("aava-max3107-spi");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
new file mode 100644 (file)
index 0000000..750b4f6
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ *  max3107.c - spi uart protocol driver for Maxim 3107
+ *  Based on max3100.c
+ *     by Christian Pellegrin <chripell@evolware.org>
+ *  and        max3110.c
+ *     by Feng Tang <feng.tang@intel.com>
+ *
+ *  Copyright (C) Aavamobile 2009
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/freezer.h>
+#include "max3107.h"
+
+static const struct baud_table brg26_ext[] = {
+       { 300,    MAX3107_BRG26_B300 },
+       { 600,    MAX3107_BRG26_B600 },
+       { 1200,   MAX3107_BRG26_B1200 },
+       { 2400,   MAX3107_BRG26_B2400 },
+       { 4800,   MAX3107_BRG26_B4800 },
+       { 9600,   MAX3107_BRG26_B9600 },
+       { 19200,  MAX3107_BRG26_B19200 },
+       { 57600,  MAX3107_BRG26_B57600 },
+       { 115200, MAX3107_BRG26_B115200 },
+       { 230400, MAX3107_BRG26_B230400 },
+       { 460800, MAX3107_BRG26_B460800 },
+       { 921600, MAX3107_BRG26_B921600 },
+       { 0, 0 }
+};
+
+static const struct baud_table brg13_int[] = {
+       { 300,    MAX3107_BRG13_IB300 },
+       { 600,    MAX3107_BRG13_IB600 },
+       { 1200,   MAX3107_BRG13_IB1200 },
+       { 2400,   MAX3107_BRG13_IB2400 },
+       { 4800,   MAX3107_BRG13_IB4800 },
+       { 9600,   MAX3107_BRG13_IB9600 },
+       { 19200,  MAX3107_BRG13_IB19200 },
+       { 57600,  MAX3107_BRG13_IB57600 },
+       { 115200, MAX3107_BRG13_IB115200 },
+       { 230400, MAX3107_BRG13_IB230400 },
+       { 460800, MAX3107_BRG13_IB460800 },
+       { 921600, MAX3107_BRG13_IB921600 },
+       { 0, 0 }
+};
+
+static u32 get_new_brg(int baud, struct max3107_port *s)
+{
+       int i;
+       const struct baud_table *baud_tbl = s->baud_tbl;
+
+       for (i = 0; i < 13; i++) {
+               if (baud == baud_tbl[i].baud)
+                       return baud_tbl[i].new_brg;
+       }
+
+       return 0;
+}
+
+/* Perform SPI transfer for write/read of device register(s) */
+int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
+{
+       struct spi_message spi_msg;
+       struct spi_transfer spi_xfer;
+
+       /* Initialize SPI ,message */
+       spi_message_init(&spi_msg);
+
+       /* Initialize SPI transfer */
+       memset(&spi_xfer, 0, sizeof spi_xfer);
+       spi_xfer.len = len;
+       spi_xfer.tx_buf = tx;
+       spi_xfer.rx_buf = rx;
+       spi_xfer.speed_hz = MAX3107_SPI_SPEED;
+
+       /* Add SPI transfer to SPI message */
+       spi_message_add_tail(&spi_xfer, &spi_msg);
+
+#ifdef DBG_TRACE_SPI_DATA
+       {
+               int i;
+               pr_info("tx len %d:\n", spi_xfer.len);
+               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
+                       pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
+               pr_info("\n");
+       }
+#endif
+
+       /* Perform synchronous SPI transfer */
+       if (spi_sync(s->spi, &spi_msg)) {
+               dev_err(&s->spi->dev, "spi_sync failure\n");
+               return -EIO;
+       }
+
+#ifdef DBG_TRACE_SPI_DATA
+       if (spi_xfer.rx_buf) {
+               int i;
+               pr_info("rx len %d:\n", spi_xfer.len);
+               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
+                       pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
+               pr_info("\n");
+       }
+#endif
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_rw);
+
+/* Puts received data to circular buffer */
+static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
+                                       int len)
+{
+       struct uart_port *port = &s->port;
+       struct tty_struct *tty;
+
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       /* Insert received data */
+       tty_insert_flip_string(tty, data, len);
+       /* Update RX counter */
+       port->icount.rx += len;
+}
+
+/* Handle data receiving */
+static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
+{
+       int i;
+       int j;
+       int len;                                /* SPI transfer buffer length */
+       u16 *buf;
+       u8 *valid_str;
+
+       if (!s->rx_enabled)
+               /* RX is disabled */
+               return;
+
+       if (rxlvl == 0) {
+               /* RX fifo is empty */
+               return;
+       } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
+               dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
+               /* Ensure sanity of RX level */
+               rxlvl = MAX3107_RX_FIFO_SIZE;
+       }
+       if ((s->rxbuf == 0) || (s->rxstr == 0)) {
+               dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
+               return;
+       }
+       buf = s->rxbuf;
+       valid_str = s->rxstr;
+       while (rxlvl) {
+               pr_debug("rxlvl %d\n", rxlvl);
+               /* Clear buffer */
+               memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
+               len = 0;
+               if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
+                       /* First disable RX FIFO interrupt */
+                       pr_debug("Disabling RX INT\n");
+                       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
+                       buf[0] |= s->irqen_reg;
+                       len++;
+               }
+               /* Just increase the length by amount of words in FIFO since
+                * buffer was zeroed and SPI transfer of 0x0000 means reading
+                * from RX FIFO
+                */
+               len += rxlvl;
+               /* Append RX level query */
+               buf[len] = MAX3107_RXFIFOLVL_REG;
+               len++;
+
+               /* Perform the SPI transfer */
+               if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
+                       dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
+                       return;
+               }
+
+               /* Skip RX FIFO interrupt disabling word if it was added */
+               j = ((len - 1) - rxlvl);
+               /* Read received words */
+               for (i = 0; i < rxlvl; i++, j++)
+                       valid_str[i] = (u8)buf[j];
+               put_data_to_circ_buf(s, valid_str, rxlvl);
+               /* Get new RX level */
+               rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
+       }
+
+       if (s->rx_enabled) {
+               /* RX still enabled, re-enable RX FIFO interrupt */
+               pr_debug("Enabling RX INT\n");
+               buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+               s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
+               buf[0] |= s->irqen_reg;
+               if (max3107_rw(s, (u8 *)buf, NULL, 2))
+                       dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
+       }
+
+       /* Push the received data to receivers */
+       if (s->port.state->port.tty)
+               tty_flip_buffer_push(s->port.state->port.tty);
+}
+
+
+/* Handle data sending */
+static void max3107_handletx(struct max3107_port *s)
+{
+       struct circ_buf *xmit = &s->port.state->xmit;
+       int i;
+       unsigned long flags;
+       int len;                                /* SPI transfer buffer length */
+       u16 *buf;
+
+       if (!s->tx_fifo_empty)
+               /* Don't send more data before previous data is sent */
+               return;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+               /* No data to send or TX is stopped */
+               return;
+
+       if (!s->txbuf) {
+               dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
+               return;
+       }
+       buf = s->txbuf;
+       /* Get length of data pending in circular buffer */
+       len = uart_circ_chars_pending(xmit);
+       if (len) {
+               /* Limit to size of TX FIFO */
+               if (len > MAX3107_TX_FIFO_SIZE)
+                       len = MAX3107_TX_FIFO_SIZE;
+
+               pr_debug("txlen %d\n", len);
+
+               /* Update TX counter */
+               s->port.icount.tx += len;
+
+               /* TX FIFO will no longer be empty */
+               s->tx_fifo_empty = 0;
+
+               i = 0;
+               if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
+                       /* First disable TX empty interrupt */
+                       pr_debug("Disabling TE INT\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
+                       buf[i] |= s->irqen_reg;
+                       i++;
+                       len++;
+               }
+               /* Add data to send */
+               spin_lock_irqsave(&s->port.lock, flags);
+               for ( ; i < len ; i++) {
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
+                       buf[i] |= ((u16)xmit->buf[xmit->tail] &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               }
+               spin_unlock_irqrestore(&s->port.lock, flags);
+               if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
+                       /* Enable TX empty interrupt */
+                       pr_debug("Enabling TE INT\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
+                       s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
+                       buf[i] |= s->irqen_reg;
+                       i++;
+                       len++;
+               }
+               if (!s->tx_enabled) {
+                       /* Enable TX */
+                       pr_debug("Enable TX\n");
+                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+                       spin_lock_irqsave(&s->data_lock, flags);
+                       s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
+                       buf[i] |= s->mode1_reg;
+                       spin_unlock_irqrestore(&s->data_lock, flags);
+                       s->tx_enabled = 1;
+                       i++;
+                       len++;
+               }
+
+               /* Perform the SPI transfer */
+               if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
+                       dev_err(&s->spi->dev,
+                               "SPI transfer TX handling failed\n");
+                       return;
+               }
+       }
+
+       /* Indicate wake up if circular buffer is getting low on data */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&s->port);
+
+}
+
+/* Handle interrupts
+ * Also reads and returns current RX FIFO level
+ */
+static u16 handle_interrupt(struct max3107_port *s)
+{
+       u16 buf[4];     /* Buffer for SPI transfers */
+       u8 irq_status;
+       u16 rx_level;
+       unsigned long flags;
+
+       /* Read IRQ status register */
+       buf[0] = MAX3107_IRQSTS_REG;
+       /* Read status IRQ status register */
+       buf[1] = MAX3107_STS_IRQSTS_REG;
+       /* Read LSR IRQ status register */
+       buf[2] = MAX3107_LSR_IRQSTS_REG;
+       /* Query RX level */
+       buf[3] = MAX3107_RXFIFOLVL_REG;
+
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
+               dev_err(&s->spi->dev,
+                       "SPI transfer for INTR handling failed\n");
+               return 0;
+       }
+
+       irq_status = (u8)buf[0];
+       pr_debug("IRQSTS %x\n", irq_status);
+       rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
+
+       if (irq_status & MAX3107_IRQ_LSR_BIT) {
+               /* LSR interrupt */
+               if (buf[2] & MAX3107_LSR_RXTO_BIT)
+                       /* RX timeout interrupt,
+                        * handled by normal RX handling
+                        */
+                       pr_debug("RX TO INT\n");
+       }
+
+       if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
+               /* Tx empty interrupt,
+                * disable TX and set tx_fifo_empty flag
+                */
+               pr_debug("TE INT, disabling TX\n");
+               buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+               spin_lock_irqsave(&s->data_lock, flags);
+               s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
+               buf[0] |= s->mode1_reg;
+               spin_unlock_irqrestore(&s->data_lock, flags);
+               if (max3107_rw(s, (u8 *)buf, NULL, 2))
+                       dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
+               s->tx_enabled = 0;
+               s->tx_fifo_empty = 1;
+       }
+
+       if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
+               /* RX FIFO interrupt,
+                * handled by normal RX handling
+                */
+               pr_debug("RFIFO INT\n");
+
+       /* Return RX level */
+       return rx_level;
+}
+
+/* Trigger work thread*/
+static void max3107_dowork(struct max3107_port *s)
+{
+       if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
+               queue_work(s->workqueue, &s->work);
+       else
+               dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
+}
+
+/* Work thread */
+static void max3107_work(struct work_struct *w)
+{
+       struct max3107_port *s = container_of(w, struct max3107_port, work);
+       u16 rxlvl = 0;
+       int len;        /* SPI transfer buffer length */
+       u16 buf[5];     /* Buffer for SPI transfers */
+       unsigned long flags;
+
+       /* Start by reading current RX FIFO level */
+       buf[0] = MAX3107_RXFIFOLVL_REG;
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
+               rxlvl = 0;
+       } else {
+               rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
+       }
+
+       do {
+               pr_debug("rxlvl %d\n", rxlvl);
+
+               /* Handle RX */
+               max3107_handlerx(s, rxlvl);
+               rxlvl = 0;
+
+               if (s->handle_irq) {
+                       /* Handle pending interrupts
+                        * We also get new RX FIFO level since new data may
+                        * have been received while pushing received data to
+                        * receivers
+                        */
+                       s->handle_irq = 0;
+                       rxlvl = handle_interrupt(s);
+               }
+
+               /* Handle TX */
+               max3107_handletx(s);
+
+               /* Handle configuration changes */
+               len = 0;
+               spin_lock_irqsave(&s->data_lock, flags);
+               if (s->mode1_commit) {
+                       pr_debug("mode1_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+                       buf[len++] |= s->mode1_reg;
+                       s->mode1_commit = 0;
+               }
+               if (s->lcr_commit) {
+                       pr_debug("lcr_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
+                       buf[len++] |= s->lcr_reg;
+                       s->lcr_commit = 0;
+               }
+               if (s->brg_commit) {
+                       pr_debug("brg_commit\n");
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
+                       buf[len++] |= ((s->brg_cfg >> 16) &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
+                       buf[len++] |= ((s->brg_cfg >> 8) &
+                                               MAX3107_SPI_TX_DATA_MASK);
+                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
+                       buf[len++] |= ((s->brg_cfg) & 0xff);
+                       s->brg_commit = 0;
+               }
+               spin_unlock_irqrestore(&s->data_lock, flags);
+
+               if (len > 0) {
+                       if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
+                               dev_err(&s->spi->dev,
+                                       "SPI transfer config failed\n");
+               }
+
+               /* Reloop if interrupt handling indicated data in RX FIFO */
+       } while (rxlvl);
+
+}
+
+/* Set sleep mode */
+static void max3107_set_sleep(struct max3107_port *s, int mode)
+{
+       u16 buf[1];     /* Buffer for SPI transfer */
+       unsigned long flags;
+       pr_debug("enter, mode %d\n", mode);
+
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
+       spin_lock_irqsave(&s->data_lock, flags);
+       switch (mode) {
+       case MAX3107_DISABLE_FORCED_SLEEP:
+                       s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
+                       break;
+       case MAX3107_ENABLE_FORCED_SLEEP:
+                       s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
+                       break;
+       case MAX3107_DISABLE_AUTOSLEEP:
+                       s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
+                       break;
+       case MAX3107_ENABLE_AUTOSLEEP:
+                       s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
+                       break;
+       default:
+               spin_unlock_irqrestore(&s->data_lock, flags);
+               dev_warn(&s->spi->dev, "invalid sleep mode\n");
+               return;
+       }
+       buf[0] |= s->mode1_reg;
+       spin_unlock_irqrestore(&s->data_lock, flags);
+
+       if (max3107_rw(s, (u8 *)buf, NULL, 2))
+               dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
+
+       if (mode == MAX3107_DISABLE_AUTOSLEEP ||
+                       mode == MAX3107_DISABLE_FORCED_SLEEP)
+               msleep(MAX3107_WAKEUP_DELAY);
+}
+
+/* Perform full register initialization */
+static void max3107_register_init(struct max3107_port *s)
+{
+       u16 buf[11];    /* Buffer for SPI transfers */
+
+       /* 1. Configure baud rate, 9600 as default */
+       s->baud = 9600;
+       /* the below is default*/
+       if (s->ext_clk) {
+               s->brg_cfg = MAX3107_BRG26_B9600;
+               s->baud_tbl = (struct baud_table *)brg26_ext;
+       } else {
+               s->brg_cfg = MAX3107_BRG13_IB9600;
+               s->baud_tbl = (struct baud_table *)brg13_int;
+       }
+
+       if (s->pdata->init)
+               s->pdata->init(s);
+
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
+               | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
+               | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
+       buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
+               | ((s->brg_cfg) & 0xff);
+
+       /* 2. Configure LCR register, 8N1 mode by default */
+       s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
+       buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
+               | s->lcr_reg;
+
+       /* 3. Configure MODE 1 register */
+       s->mode1_reg = 0;
+       /* Enable IRQ pin */
+       s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
+       /* Disable TX */
+       s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
+       s->tx_enabled = 0;
+       /* RX is enabled */
+       s->rx_enabled = 1;
+       buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
+               | s->mode1_reg;
+
+       /* 4. Configure MODE 2 register */
+       buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
+       if (s->loopback) {
+               /* Enable loopback */
+               buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
+       }
+       /* Reset FIFOs */
+       buf[5] |= MAX3107_MODE2_FIFORST_BIT;
+       s->tx_fifo_empty = 1;
+
+       /* 5. Configure FIFO trigger level register */
+       buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
+       /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
+       buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
+
+       /* 6. Configure flow control levels */
+       buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
+       /* Flow control halt level 96, resume level 48 */
+       buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
+
+       /* 7. Configure flow control */
+       buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
+       /* Enable auto CTS and auto RTS flow control */
+       buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
+
+       /* 8. Configure RX timeout register */
+       buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
+       /* Timeout after 48 character intervals */
+       buf[9] |= 0x0030;
+
+       /* 9. Configure LSR interrupt enable register */
+       buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
+       /* Enable RX timeout interrupt */
+       buf[10] |= MAX3107_LSR_RXTO_BIT;
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 22))
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+
+       /* 10. Clear IRQ status register by reading it */
+       buf[0] = MAX3107_IRQSTS_REG;
+
+       /* 11. Configure interrupt enable register */
+       /* Enable LSR interrupt */
+       s->irqen_reg = MAX3107_IRQ_LSR_BIT;
+       /* Enable RX FIFO interrupt */
+       s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
+               | s->irqen_reg;
+
+       /* 12. Clear FIFO reset that was set in step 6 */
+       buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
+       if (s->loopback) {
+               /* Keep loopback enabled */
+               buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
+       }
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+
+}
+
+/* IRQ handler */
+static irqreturn_t max3107_irq(int irqno, void *dev_id)
+{
+       struct max3107_port *s = dev_id;
+
+       if (irqno != s->spi->irq) {
+               /* Unexpected IRQ */
+               return IRQ_NONE;
+       }
+
+       /* Indicate irq */
+       s->handle_irq = 1;
+
+       /* Trigger work thread */
+       max3107_dowork(s);
+
+       return IRQ_HANDLED;
+}
+
+/* HW suspension function
+ *
+ * Currently autosleep is used to decrease current consumption, alternative
+ * approach would be to set the chip to reset mode if UART is not being
+ * used but that would mess the GPIOs
+ *
+ */
+void max3107_hw_susp(struct max3107_port *s, int suspend)
+{
+       pr_debug("enter, suspend %d\n", suspend);
+
+       if (suspend) {
+               /* Suspend requested,
+                * enable autosleep to decrease current consumption
+                */
+               s->suspended = 1;
+               max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
+       } else {
+               /* Resume requested,
+                * disable autosleep
+                */
+               s->suspended = 0;
+               max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
+       }
+}
+EXPORT_SYMBOL_GPL(max3107_hw_susp);
+
+/* Modem status IRQ enabling */
+static void max3107_enable_ms(struct uart_port *port)
+{
+       /* Modem status not supported */
+}
+
+/* Data send function */
+static void max3107_start_tx(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       /* Trigger work thread for sending data */
+       max3107_dowork(s);
+}
+
+/* Function for checking that there is no pending transfers */
+static unsigned int max3107_tx_empty(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       pr_debug("returning %d\n",
+                 (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
+       return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
+}
+
+/* Function for stopping RX */
+static void max3107_stop_rx(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       unsigned long flags;
+
+       /* Set RX disabled in MODE 1 register */
+       spin_lock_irqsave(&s->data_lock, flags);
+       s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
+       s->mode1_commit = 1;
+       spin_unlock_irqrestore(&s->data_lock, flags);
+       /* Set RX disabled */
+       s->rx_enabled = 0;
+       /* Trigger work thread for doing the actual configuration change */
+       max3107_dowork(s);
+}
+
+/* Function for returning control pin states */
+static unsigned int max3107_get_mctrl(struct uart_port *port)
+{
+       /* DCD and DSR are not wired and CTS/RTS is handled automatically
+        * so just indicate DSR and CAR asserted
+        */
+       return TIOCM_DSR | TIOCM_CAR;
+}
+
+/* Function for setting control pin states */
+static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
+        * so do nothing
+        */
+}
+
+/* Function for configuring UART parameters */
+static void max3107_set_termios(struct uart_port *port,
+                               struct ktermios *termios,
+                               struct ktermios *old)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       struct tty_struct *tty;
+       int baud;
+       u16 new_lcr = 0;
+       u32 new_brg = 0;
+       unsigned long flags;
+
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       /* Get new LCR register values */
+       /* Word size */
+       if ((termios->c_cflag & CSIZE) == CS7)
+               new_lcr |= MAX3107_LCR_WORD_LEN_7;
+       else
+               new_lcr |= MAX3107_LCR_WORD_LEN_8;
+
+       /* Parity */
+       if (termios->c_cflag & PARENB) {
+               new_lcr |= MAX3107_LCR_PARITY_BIT;
+               if (!(termios->c_cflag & PARODD))
+                       new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
+       }
+
+       /* Stop bits */
+       if (termios->c_cflag & CSTOPB) {
+               /* 2 stop bits */
+               new_lcr |= MAX3107_LCR_STOPLEN_BIT;
+       }
+
+       /* Mask termios capabilities we don't support */
+       termios->c_cflag &= ~CMSPAR;
+
+       /* Set status ignore mask */
+       s->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
+
+       /* Set low latency to immediately handle pushed data */
+       s->port.state->port.tty->low_latency = 1;
+
+       /* Get new baud rate generator configuration */
+       baud = tty_get_baud_rate(tty);
+
+       spin_lock_irqsave(&s->data_lock, flags);
+       new_brg = get_new_brg(baud, s);
+       /* if can't find the corrent config, use previous */
+       if (!new_brg) {
+               baud = s->baud;
+               new_brg = s->brg_cfg;
+       }
+       spin_unlock_irqrestore(&s->data_lock, flags);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+       s->baud = baud;
+
+       /* Update timeout according to new baud rate */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_lock_irqsave(&s->data_lock, flags);
+       if (s->lcr_reg != new_lcr) {
+               s->lcr_reg = new_lcr;
+               s->lcr_commit = 1;
+       }
+       if (s->brg_cfg != new_brg) {
+               s->brg_cfg = new_brg;
+               s->brg_commit = 1;
+       }
+       spin_unlock_irqrestore(&s->data_lock, flags);
+
+       /* Trigger work thread for doing the actual configuration change */
+       max3107_dowork(s);
+}
+
+/* Port shutdown function */
+static void max3107_shutdown(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       if (s->suspended && s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Free the interrupt */
+       free_irq(s->spi->irq, s);
+
+       if (s->workqueue) {
+               /* Flush and destroy work queue */
+               flush_workqueue(s->workqueue);
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+       }
+
+       /* Suspend HW */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 1);
+}
+
+/* Port startup function */
+static int max3107_startup(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+
+       /* Initialize work queue */
+       s->workqueue = create_freezable_workqueue("max3107");
+       if (!s->workqueue) {
+               dev_err(&s->spi->dev, "Workqueue creation failed\n");
+               return -EBUSY;
+       }
+       INIT_WORK(&s->work, max3107_work);
+
+       /* Setup IRQ */
+       if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
+                       "max3107", s)) {
+               dev_err(&s->spi->dev, "IRQ reguest failed\n");
+               destroy_workqueue(s->workqueue);
+               s->workqueue = NULL;
+               return -EBUSY;
+       }
+
+       /* Resume HW */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Init registers */
+       max3107_register_init(s);
+
+       return 0;
+}
+
+/* Port type function */
+static const char *max3107_type(struct uart_port *port)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       return s->spi->modalias;
+}
+
+/* Port release function */
+static void max3107_release_port(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+/* Port request function */
+static int max3107_request_port(struct uart_port *port)
+{
+       /* Do nothing */
+       return 0;
+}
+
+/* Port config function */
+static void max3107_config_port(struct uart_port *port, int flags)
+{
+       struct max3107_port *s = container_of(port, struct max3107_port, port);
+       s->port.type = PORT_MAX3107;
+}
+
+/* Port verify function */
+static int max3107_verify_port(struct uart_port *port,
+                               struct serial_struct *ser)
+{
+       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
+               return 0;
+
+       return -EINVAL;
+}
+
+/* Port stop TX function */
+static void max3107_stop_tx(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+/* Port break control function */
+static void max3107_break_ctl(struct uart_port *port, int break_state)
+{
+       /* We don't support break control, do nothing */
+}
+
+
+/* Port functions */
+static struct uart_ops max3107_ops = {
+       .tx_empty       = max3107_tx_empty,
+       .set_mctrl      = max3107_set_mctrl,
+       .get_mctrl      = max3107_get_mctrl,
+       .stop_tx        = max3107_stop_tx,
+       .start_tx       = max3107_start_tx,
+       .stop_rx        = max3107_stop_rx,
+       .enable_ms      = max3107_enable_ms,
+       .break_ctl      = max3107_break_ctl,
+       .startup        = max3107_startup,
+       .shutdown       = max3107_shutdown,
+       .set_termios    = max3107_set_termios,
+       .type           = max3107_type,
+       .release_port   = max3107_release_port,
+       .request_port   = max3107_request_port,
+       .config_port    = max3107_config_port,
+       .verify_port    = max3107_verify_port,
+};
+
+/* UART driver data */
+static struct uart_driver max3107_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyMAX",
+       .dev_name       = "ttyMAX",
+       .nr             = 1,
+};
+
+static int driver_registered = 0;
+
+
+
+/* 'Generic' platform data */
+static struct max3107_plat generic_plat_data = {
+       .loopback               = 0,
+       .ext_clk                = 1,
+       .hw_suspend             = max3107_hw_susp,
+       .polled_mode            = 0,
+       .poll_time              = 0,
+};
+
+
+/*******************************************************************/
+
+/**
+ *     max3107_probe           -       SPI bus probe entry point
+ *     @spi: the spi device
+ *
+ *     SPI wants us to probe this device and if appropriate claim it.
+ *     Perform any platform specific requirements and then initialise
+ *     the device.
+ */
+
+int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
+{
+       struct max3107_port *s;
+       u16 buf[2];     /* Buffer for SPI transfers */
+       int retval;
+
+       pr_info("enter max3107 probe\n");
+
+       /* Allocate port structure */
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s) {
+               pr_err("Allocating port structure failed\n");
+               return -ENOMEM;
+       }
+
+       s->pdata = pdata;
+
+       /* SPI Rx buffer
+        * +2 for RX FIFO interrupt
+        * disabling and RX level query
+        */
+       s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
+       if (!s->rxbuf) {
+               pr_err("Allocating RX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free4;
+       }
+       s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
+       if (!s->rxstr) {
+               pr_err("Allocating RX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free3;
+       }
+       /* SPI Tx buffer
+        * SPI transfer buffer
+        * +3 for TX FIFO empty
+        * interrupt disabling and
+        * enabling and TX enabling
+        */
+       s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
+       if (!s->txbuf) {
+               pr_err("Allocating TX buffer failed\n");
+               retval = -ENOMEM;
+               goto err_free2;
+       }
+       /* Initialize shared data lock */
+       spin_lock_init(&s->data_lock);
+
+       /* SPI intializations */
+       dev_set_drvdata(&spi->dev, s);
+       spi->mode = SPI_MODE_0;
+       spi->dev.platform_data = pdata;
+       spi->bits_per_word = 16;
+       s->ext_clk = pdata->ext_clk;
+       s->loopback = pdata->loopback;
+       spi_setup(spi);
+       s->spi = spi;
+
+       /* Check REV ID to ensure we are talking to what we expect */
+       buf[0] = MAX3107_REVID_REG;
+       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
+               dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
+               retval = -EIO;
+               goto err_free1;
+       }
+       if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
+               (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
+               dev_err(&s->spi->dev, "REVID %x does not match\n",
+                               (buf[0] & MAX3107_SPI_RX_DATA_MASK));
+               retval = -ENODEV;
+               goto err_free1;
+       }
+
+       /* Disable all interrupts */
+       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
+       buf[0] |= 0x0000;
+
+       /* Configure clock source */
+       buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
+       if (s->ext_clk) {
+               /* External clock */
+               buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
+       }
+
+       /* PLL bypass ON */
+       buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
+
+       /* Perform SPI transfer */
+       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
+               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
+               retval = -EIO;
+               goto err_free1;
+       }
+
+       /* Register UART driver */
+       if (!driver_registered) {
+               retval = uart_register_driver(&max3107_uart_driver);
+               if (retval) {
+                       dev_err(&s->spi->dev, "Registering UART driver failed\n");
+                       goto err_free1;
+               }
+               driver_registered = 1;
+       }
+
+       /* Initialize UART port data */
+       s->port.fifosize = 128;
+       s->port.ops = &max3107_ops;
+       s->port.line = 0;
+       s->port.dev = &spi->dev;
+       s->port.uartclk = 9600;
+       s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       s->port.irq = s->spi->irq;
+       s->port.type = PORT_MAX3107;
+
+       /* Add UART port */
+       retval = uart_add_one_port(&max3107_uart_driver, &s->port);
+       if (retval < 0) {
+               dev_err(&s->spi->dev, "Adding UART port failed\n");
+               goto err_free1;
+       }
+
+       if (pdata->configure) {
+               retval = pdata->configure(s);
+               if (retval < 0)
+                       goto err_free1;
+       }
+
+       /* Go to suspend mode */
+       if (pdata->hw_suspend)
+               pdata->hw_suspend(s, 1);
+
+       return 0;
+
+err_free1:
+       kfree(s->txbuf);
+err_free2:
+       kfree(s->rxstr);
+err_free3:
+       kfree(s->rxbuf);
+err_free4:
+       kfree(s);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(max3107_probe);
+
+/* Driver remove function */
+int max3107_remove(struct spi_device *spi)
+{
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_info("enter max3107 remove\n");
+
+       /* Remove port */
+       if (uart_remove_one_port(&max3107_uart_driver, &s->port))
+               dev_warn(&s->spi->dev, "Removing UART port failed\n");
+
+
+       /* Free TxRx buffer */
+       kfree(s->rxbuf);
+       kfree(s->rxstr);
+       kfree(s->txbuf);
+
+       /* Free port structure */
+       kfree(s);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_remove);
+
+/* Driver suspend function */
+int max3107_suspend(struct spi_device *spi, pm_message_t state)
+{
+#ifdef CONFIG_PM
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_debug("enter suspend\n");
+
+       /* Suspend UART port */
+       uart_suspend_port(&max3107_uart_driver, &s->port);
+
+       /* Go to suspend mode */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 1);
+#endif /* CONFIG_PM */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_suspend);
+
+/* Driver resume function */
+int max3107_resume(struct spi_device *spi)
+{
+#ifdef CONFIG_PM
+       struct max3107_port *s = dev_get_drvdata(&spi->dev);
+
+       pr_debug("enter resume\n");
+
+       /* Resume from suspend */
+       if (s->pdata->hw_suspend)
+               s->pdata->hw_suspend(s, 0);
+
+       /* Resume UART port */
+       uart_resume_port(&max3107_uart_driver, &s->port);
+#endif /* CONFIG_PM */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max3107_resume);
+
+static int max3107_probe_generic(struct spi_device *spi)
+{
+       return max3107_probe(spi, &generic_plat_data);
+}
+
+/* Spi driver data */
+static struct spi_driver max3107_driver = {
+       .driver = {
+               .name           = "max3107",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = max3107_probe_generic,
+       .remove         = __devexit_p(max3107_remove),
+       .suspend        = max3107_suspend,
+       .resume         = max3107_resume,
+};
+
+/* Driver init function */
+static int __init max3107_init(void)
+{
+       pr_info("enter max3107 init\n");
+       return spi_register_driver(&max3107_driver);
+}
+
+/* Driver exit function */
+static void __exit max3107_exit(void)
+{
+       pr_info("enter max3107 exit\n");
+       /* Unregister UART driver */
+       if (driver_registered)
+               uart_unregister_driver(&max3107_uart_driver);
+       spi_unregister_driver(&max3107_driver);
+}
+
+module_init(max3107_init);
+module_exit(max3107_exit);
+
+MODULE_DESCRIPTION("MAX3107 driver");
+MODULE_AUTHOR("Aavamobile");
+MODULE_ALIAS("max3107-spi");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h
new file mode 100644 (file)
index 0000000..7ab6323
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * max3107.h - spi uart protocol driver header for Maxim 3107
+ *
+ * Copyright (C) Aavamobile 2009
+ * Based on serial_max3100.h by Christian Pellegrin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MAX3107_H
+#define _MAX3107_H
+
+/* Serial error status definitions */
+#define MAX3107_PARITY_ERROR   1
+#define MAX3107_FRAME_ERROR    2
+#define MAX3107_OVERRUN_ERROR  4
+#define MAX3107_ALL_ERRORS     (MAX3107_PARITY_ERROR | \
+                                MAX3107_FRAME_ERROR | \
+                                MAX3107_OVERRUN_ERROR)
+
+/* GPIO definitions */
+#define MAX3107_GPIO_BASE      88
+#define MAX3107_GPIO_COUNT     4
+
+
+/* GPIO connected to chip's reset pin */
+#define MAX3107_RESET_GPIO     87
+
+
+/* Chip reset delay */
+#define MAX3107_RESET_DELAY    10
+
+/* Chip wakeup delay */
+#define MAX3107_WAKEUP_DELAY   50
+
+
+/* Sleep mode definitions */
+#define MAX3107_DISABLE_FORCED_SLEEP   0
+#define MAX3107_ENABLE_FORCED_SLEEP    1
+#define MAX3107_DISABLE_AUTOSLEEP      2
+#define MAX3107_ENABLE_AUTOSLEEP       3
+
+
+/* Definitions for register access with SPI transfers
+ *
+ * SPI transfer format:
+ *
+ * Master to slave bits xzzzzzzzyyyyyyyy
+ * Slave to master bits aaaaaaaabbbbbbbb
+ *
+ * where:
+ * x = 0 for reads, 1 for writes
+ * z = register address
+ * y = new register value if write, 0 if read
+ * a = unspecified
+ * b = register value if read, unspecified if write
+ */
+
+/* SPI speed */
+#define MAX3107_SPI_SPEED      (3125000 * 2)
+
+/* Write bit */
+#define MAX3107_WRITE_BIT      (1 << 15)
+
+/* SPI TX data mask */
+#define MAX3107_SPI_RX_DATA_MASK       (0x00ff)
+
+/* SPI RX data mask */
+#define MAX3107_SPI_TX_DATA_MASK       (0x00ff)
+
+/* Register access masks */
+#define MAX3107_RHR_REG                        (0x0000) /* RX FIFO */
+#define MAX3107_THR_REG                        (0x0000) /* TX FIFO */
+#define MAX3107_IRQEN_REG              (0x0100) /* IRQ enable */
+#define MAX3107_IRQSTS_REG             (0x0200) /* IRQ status */
+#define MAX3107_LSR_IRQEN_REG          (0x0300) /* LSR IRQ enable */
+#define MAX3107_LSR_IRQSTS_REG         (0x0400) /* LSR IRQ status */
+#define MAX3107_SPCHR_IRQEN_REG                (0x0500) /* Special char IRQ enable */
+#define MAX3107_SPCHR_IRQSTS_REG       (0x0600) /* Special char IRQ status */
+#define MAX3107_STS_IRQEN_REG          (0x0700) /* Status IRQ enable */
+#define MAX3107_STS_IRQSTS_REG         (0x0800) /* Status IRQ status */
+#define MAX3107_MODE1_REG              (0x0900) /* MODE1 */
+#define MAX3107_MODE2_REG              (0x0a00) /* MODE2 */
+#define MAX3107_LCR_REG                        (0x0b00) /* LCR */
+#define MAX3107_RXTO_REG               (0x0c00) /* RX timeout */
+#define MAX3107_HDPIXDELAY_REG         (0x0d00) /* Auto transceiver delays */
+#define MAX3107_IRDA_REG               (0x0e00) /* IRDA settings */
+#define MAX3107_FLOWLVL_REG            (0x0f00) /* Flow control levels */
+#define MAX3107_FIFOTRIGLVL_REG                (0x1000) /* FIFO IRQ trigger levels */
+#define MAX3107_TXFIFOLVL_REG          (0x1100) /* TX FIFO level */
+#define MAX3107_RXFIFOLVL_REG          (0x1200) /* RX FIFO level */
+#define MAX3107_FLOWCTRL_REG           (0x1300) /* Flow control */
+#define MAX3107_XON1_REG               (0x1400) /* XON1 character */
+#define MAX3107_XON2_REG               (0x1500) /* XON2 character */
+#define MAX3107_XOFF1_REG              (0x1600) /* XOFF1 character */
+#define MAX3107_XOFF2_REG              (0x1700) /* XOFF2 character */
+#define MAX3107_GPIOCFG_REG            (0x1800) /* GPIO config */
+#define MAX3107_GPIODATA_REG           (0x1900) /* GPIO data */
+#define MAX3107_PLLCFG_REG             (0x1a00) /* PLL config */
+#define MAX3107_BRGCFG_REG             (0x1b00) /* Baud rate generator conf */
+#define MAX3107_BRGDIVLSB_REG          (0x1c00) /* Baud rate divisor LSB */
+#define MAX3107_BRGDIVMSB_REG          (0x1d00) /* Baud rate divisor MSB */
+#define MAX3107_CLKSRC_REG             (0x1e00) /* Clock source */
+#define MAX3107_REVID_REG              (0x1f00) /* Revision identification */
+
+/* IRQ register bits */
+#define MAX3107_IRQ_LSR_BIT    (1 << 0) /* LSR interrupt */
+#define MAX3107_IRQ_SPCHR_BIT  (1 << 1) /* Special char interrupt */
+#define MAX3107_IRQ_STS_BIT    (1 << 2) /* Status interrupt */
+#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
+#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
+#define MAX3107_IRQ_TXEMPTY_BIT        (1 << 5) /* TX FIFO empty interrupt */
+#define MAX3107_IRQ_RXEMPTY_BIT        (1 << 6) /* RX FIFO empty interrupt */
+#define MAX3107_IRQ_CTS_BIT    (1 << 7) /* CTS interrupt */
+
+/* LSR register bits */
+#define MAX3107_LSR_RXTO_BIT   (1 << 0) /* RX timeout */
+#define MAX3107_LSR_RXOVR_BIT  (1 << 1) /* RX overrun */
+#define MAX3107_LSR_RXPAR_BIT  (1 << 2) /* RX parity error */
+#define MAX3107_LSR_FRERR_BIT  (1 << 3) /* Frame error */
+#define MAX3107_LSR_RXBRK_BIT  (1 << 4) /* RX break */
+#define MAX3107_LSR_RXNOISE_BIT        (1 << 5) /* RX noise */
+#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
+#define MAX3107_LSR_CTS_BIT    (1 << 7) /* CTS pin state */
+
+/* Special character register bits */
+#define MAX3107_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
+#define MAX3107_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
+#define MAX3107_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
+#define MAX3107_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
+#define MAX3107_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
+#define MAX3107_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
+#define MAX3107_SPCHR_UNDEF6_BIT       (1 << 6) /* Undefined/not used */
+#define MAX3107_SPCHR_UNDEF7_BIT       (1 << 7) /* Undefined/not used */
+
+/* Status register bits */
+#define MAX3107_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
+#define MAX3107_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
+#define MAX3107_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
+#define MAX3107_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
+#define MAX3107_STS_UNDEF4_BIT         (1 << 4) /* Undefined/not used */
+#define MAX3107_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
+#define MAX3107_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
+#define MAX3107_STS_UNDEF7_BIT         (1 << 7) /* Undefined/not used */
+
+/* MODE1 register bits */
+#define MAX3107_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
+#define MAX3107_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
+#define MAX3107_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
+#define MAX3107_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
+#define MAX3107_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
+#define MAX3107_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
+#define MAX3107_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
+#define MAX3107_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
+
+/* MODE2 register bits */
+#define MAX3107_MODE2_RST_BIT          (1 << 0) /* Chip reset */
+#define MAX3107_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
+#define MAX3107_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
+#define MAX3107_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
+#define MAX3107_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
+#define MAX3107_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
+#define MAX3107_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
+#define MAX3107_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
+
+/* LCR register bits */
+#define MAX3107_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
+#define MAX3107_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
+                                                 *
+                                                 * Word length bits table:
+                                                 * 00 -> 5 bit words
+                                                 * 01 -> 6 bit words
+                                                 * 10 -> 7 bit words
+                                                 * 11 -> 8 bit words
+                                                 */
+#define MAX3107_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
+                                                 *
+                                                 * STOP length bit table:
+                                                 * 0 -> 1 stop bit
+                                                 * 1 -> 1-1.5 stop bits if
+                                                 *      word length is 5,
+                                                 *      2 stop bits otherwise
+                                                 */
+#define MAX3107_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
+#define MAX3107_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
+#define MAX3107_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
+#define MAX3107_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
+#define MAX3107_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
+#define MAX3107_LCR_WORD_LEN_5         (0x0000)
+#define MAX3107_LCR_WORD_LEN_6         (0x0001)
+#define MAX3107_LCR_WORD_LEN_7         (0x0002)
+#define MAX3107_LCR_WORD_LEN_8         (0x0003)
+
+
+/* IRDA register bits */
+#define MAX3107_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
+#define MAX3107_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
+#define MAX3107_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
+#define MAX3107_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
+#define MAX3107_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
+#define MAX3107_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
+#define MAX3107_IRDA_UNDEF6_BIT                (1 << 6) /* Undefined/not used */
+#define MAX3107_IRDA_UNDEF7_BIT                (1 << 7) /* Undefined/not used */
+
+/* Flow control trigger level register masks */
+#define MAX3107_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
+#define MAX3107_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
+#define MAX3107_FLOWLVL_HALT(words)    ((words/8) & 0x000f)
+#define MAX3107_FLOWLVL_RES(words)     (((words/8) & 0x000f) << 4)
+
+/* FIFO interrupt trigger level register masks */
+#define MAX3107_FIFOTRIGLVL_TX_MASK    (0x000f) /* TX FIFO trigger level */
+#define MAX3107_FIFOTRIGLVL_RX_MASK    (0x00f0) /* RX FIFO trigger level */
+#define MAX3107_FIFOTRIGLVL_TX(words)  ((words/8) & 0x000f)
+#define MAX3107_FIFOTRIGLVL_RX(words)  (((words/8) & 0x000f) << 4)
+
+/* Flow control register bits */
+#define MAX3107_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
+#define MAX3107_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
+#define MAX3107_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
+                                                 * are used in conjunction with
+                                                 * XOFF2 for definition of
+                                                 * special character */
+#define MAX3107_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
+#define MAX3107_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
+#define MAX3107_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
+                                                 *
+                                                 * SWFLOW bits 1 & 0 table:
+                                                 * 00 -> no transmitter flow
+                                                 *       control
+                                                 * 01 -> receiver compares
+                                                 *       XON2 and XOFF2
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 10 -> receiver compares
+                                                 *       XON1 and XOFF1
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 11 -> receiver compares
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2 and controls
+                                                 *       transmitter
+                                                 */
+#define MAX3107_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
+#define MAX3107_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
+                                                 *
+                                                 * SWFLOW bits 3 & 2 table:
+                                                 * 00 -> no received flow
+                                                 *       control
+                                                 * 01 -> transmitter generates
+                                                 *       XON2 and XOFF2
+                                                 * 10 -> transmitter generates
+                                                 *       XON1 and XOFF1
+                                                 * 11 -> transmitter generates
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2
+                                                 */
+
+/* GPIO configuration register bits */
+#define MAX3107_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
+#define MAX3107_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
+#define MAX3107_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
+#define MAX3107_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
+#define MAX3107_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
+#define MAX3107_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
+#define MAX3107_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
+#define MAX3107_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
+
+/* GPIO DATA register bits */
+#define MAX3107_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
+#define MAX3107_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
+#define MAX3107_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
+#define MAX3107_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
+#define MAX3107_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
+#define MAX3107_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
+#define MAX3107_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
+#define MAX3107_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
+
+/* PLL configuration register masks */
+#define MAX3107_PLLCFG_PREDIV_MASK     (0x003f) /* PLL predivision value */
+#define MAX3107_PLLCFG_PLLFACTOR_MASK  (0x00c0) /* PLL multiplication factor */
+
+/* Baud rate generator configuration register masks and bits */
+#define MAX3107_BRGCFG_FRACT_MASK      (0x000f) /* Fractional portion of
+                                                 * Baud rate generator divisor
+                                                 */
+#define MAX3107_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
+#define MAX3107_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
+#define MAX3107_BRGCFG_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
+#define MAX3107_BRGCFG_UNDEF7_BIT      (1 << 7) /* Undefined/not used */
+
+/* Clock source register bits */
+#define MAX3107_CLKSRC_INTOSC_BIT      (1 << 0) /* Internal osc enable */
+#define MAX3107_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
+#define MAX3107_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
+#define MAX3107_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
+#define MAX3107_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
+#define MAX3107_CLKSRC_UNDEF5_BIT      (1 << 5) /* Undefined/not used */
+#define MAX3107_CLKSRC_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
+#define MAX3107_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
+
+
+/* HW definitions */
+#define MAX3107_RX_FIFO_SIZE   128
+#define MAX3107_TX_FIFO_SIZE   128
+#define MAX3107_REVID1         0x00a0
+#define MAX3107_REVID2         0x00a1
+
+
+/* Baud rate generator configuration values for external clock 13MHz */
+#define MAX3107_BRG13_B300     (0x0A9400 | 0x05)
+#define MAX3107_BRG13_B600     (0x054A00 | 0x03)
+#define MAX3107_BRG13_B1200    (0x02A500 | 0x01)
+#define MAX3107_BRG13_B2400    (0x015200 | 0x09)
+#define MAX3107_BRG13_B4800    (0x00A900 | 0x04)
+#define MAX3107_BRG13_B9600    (0x005400 | 0x0A)
+#define MAX3107_BRG13_B19200   (0x002A00 | 0x05)
+#define MAX3107_BRG13_B38400   (0x001500 | 0x03)
+#define MAX3107_BRG13_B57600   (0x000E00 | 0x02)
+#define MAX3107_BRG13_B115200  (0x000700 | 0x01)
+#define MAX3107_BRG13_B230400  (0x000300 | 0x08)
+#define MAX3107_BRG13_B460800  (0x000100 | 0x0c)
+#define MAX3107_BRG13_B921600  (0x000100 | 0x1c)
+
+/* Baud rate generator configuration values for external clock 26MHz */
+#define MAX3107_BRG26_B300     (0x152800 | 0x0A)
+#define MAX3107_BRG26_B600     (0x0A9400 | 0x05)
+#define MAX3107_BRG26_B1200    (0x054A00 | 0x03)
+#define MAX3107_BRG26_B2400    (0x02A500 | 0x01)
+#define MAX3107_BRG26_B4800    (0x015200 | 0x09)
+#define MAX3107_BRG26_B9600    (0x00A900 | 0x04)
+#define MAX3107_BRG26_B19200   (0x005400 | 0x0A)
+#define MAX3107_BRG26_B38400   (0x002A00 | 0x05)
+#define MAX3107_BRG26_B57600   (0x001C00 | 0x03)
+#define MAX3107_BRG26_B115200  (0x000E00 | 0x02)
+#define MAX3107_BRG26_B230400  (0x000700 | 0x01)
+#define MAX3107_BRG26_B460800  (0x000300 | 0x08)
+#define MAX3107_BRG26_B921600  (0x000100 | 0x0C)
+
+/* Baud rate generator configuration values for internal clock */
+#define MAX3107_BRG13_IB300    (0x008000 | 0x00)
+#define MAX3107_BRG13_IB600    (0x004000 | 0x00)
+#define MAX3107_BRG13_IB1200   (0x002000 | 0x00)
+#define MAX3107_BRG13_IB2400   (0x001000 | 0x00)
+#define MAX3107_BRG13_IB4800   (0x000800 | 0x00)
+#define MAX3107_BRG13_IB9600   (0x000400 | 0x00)
+#define MAX3107_BRG13_IB19200  (0x000200 | 0x00)
+#define MAX3107_BRG13_IB38400  (0x000100 | 0x00)
+#define MAX3107_BRG13_IB57600  (0x000000 | 0x0B)
+#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
+#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
+#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
+#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
+
+
+struct baud_table {
+       int baud;
+       u32 new_brg;
+};
+
+struct max3107_port {
+       /* UART port structure */
+       struct uart_port port;
+
+       /* SPI device structure */
+       struct spi_device *spi;
+
+#if defined(CONFIG_GPIOLIB)
+       /* GPIO chip stucture */
+       struct gpio_chip chip;
+#endif
+
+       /* Workqueue that does all the magic */
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       /* Lock for shared data */
+       spinlock_t data_lock;
+
+       /* Device configuration */
+       int ext_clk;            /* 1 if external clock used */
+       int loopback;           /* Current loopback mode state */
+       int baud;                       /* Current baud rate */
+
+       /* State flags */
+       int suspended;          /* Indicates suspend mode */
+       int tx_fifo_empty;      /* Flag for TX FIFO state */
+       int rx_enabled;         /* Flag for receiver state */
+       int tx_enabled;         /* Flag for transmitter state */
+
+       u16 irqen_reg;          /* Current IRQ enable register value */
+       /* Shared data */
+       u16 mode1_reg;          /* Current mode1 register value*/
+       int mode1_commit;       /* Flag for setting new mode1 register value */
+       u16 lcr_reg;            /* Current LCR register value */
+       int lcr_commit;         /* Flag for setting new LCR register value */
+       u32 brg_cfg;            /* Current Baud rate generator config  */
+       int brg_commit;         /* Flag for setting new baud rate generator
+                                * config
+                                */
+       struct baud_table *baud_tbl;
+       int handle_irq;         /* Indicates that IRQ should be handled */
+
+       /* Rx buffer and str*/
+       u16 *rxbuf;
+       u8  *rxstr;
+       /* Tx buffer*/
+       u16 *txbuf;
+
+       struct max3107_plat *pdata;     /* Platform data */
+};
+
+/* Platform data structure */
+struct max3107_plat {
+       /* Loopback mode enable */
+       int loopback;
+       /* External clock enable */
+       int ext_clk;
+       /* Called during the register initialisation */
+       void (*init)(struct max3107_port *s);
+       /* Called when the port is found and configured */
+       int (*configure)(struct max3107_port *s);
+       /* HW suspend function */
+       void (*hw_suspend) (struct max3107_port *s, int suspend);
+       /* Polling mode enable */
+       int polled_mode;
+       /* Polling period if polling mode enabled */
+       int poll_time;
+};
+
+extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
+extern void max3107_hw_susp(struct max3107_port *s, int suspend);
+extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
+extern int max3107_remove(struct spi_device *spi);
+extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
+extern int max3107_resume(struct spi_device *spi);
+
+#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
new file mode 100644 (file)
index 0000000..3394b7c
--- /dev/null
@@ -0,0 +1,662 @@
+/****************************************************************************/
+
+/*
+ *     mcf.c -- Freescale ColdFire UART driver
+ *
+ *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/nettel.h>
+
+/****************************************************************************/
+
+/*
+ *     Some boards implement the DTR/DCD lines using GPIO lines, most
+ *     don't. Dummy out the access macros for those that don't. Those
+ *     that do should define these macros somewhere in there board
+ *     specific inlude files.
+ */
+#if !defined(mcf_getppdcd)
+#define        mcf_getppdcd(p)         (1)
+#endif
+#if !defined(mcf_getppdtr)
+#define        mcf_getppdtr(p)         (1)
+#endif
+#if !defined(mcf_setppdtr)
+#define        mcf_setppdtr(p, v)      do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/*
+ *     Local per-uart structure.
+ */
+struct mcf_uart {
+       struct uart_port        port;
+       unsigned int            sigs;           /* Local copy of line sigs */
+       unsigned char           imr;            /* Local IMR mirror */
+};
+
+/****************************************************************************/
+
+static unsigned int mcf_tx_empty(struct uart_port *port)
+{
+       return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
+               TIOCSER_TEMT : 0;
+}
+
+/****************************************************************************/
+
+static unsigned int mcf_get_mctrl(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned int sigs;
+
+       sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
+               0 : TIOCM_CTS;
+       sigs |= (pp->sigs & TIOCM_RTS);
+       sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
+       sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
+
+       return sigs;
+}
+
+/****************************************************************************/
+
+static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->sigs = sigs;
+       mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
+       if (sigs & TIOCM_RTS)
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
+       else
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
+}
+
+/****************************************************************************/
+
+static void mcf_start_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr |= MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr &= ~MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_rx(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+
+       pp->imr &= ~MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+}
+
+/****************************************************************************/
+
+static void mcf_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
+       else
+               writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_enable_ms(struct uart_port *port)
+{
+}
+
+/****************************************************************************/
+
+static int mcf_startup(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Reset UART, get it into known state... */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       /* Enable the UART transmitter and receiver */
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+
+       /* Enable RX interrupts now */
+       pp->imr = MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_shutdown(struct uart_port *port)
+{
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       /* Disable UART transmitter and receiver */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, baudclk;
+#if defined(CONFIG_M5272)
+       unsigned int baudfr;
+#endif
+       unsigned char mr1, mr2;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+#if defined(CONFIG_M5272)
+       baudclk = (MCF_BUSCLK / baud) / 32;
+       baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
+#else
+       baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
+#endif
+
+       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
+       mr2 = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5: mr1 |= MCFUART_MR1_CS5; break;
+       case CS6: mr1 |= MCFUART_MR1_CS6; break;
+       case CS7: mr1 |= MCFUART_MR1_CS7; break;
+       case CS8:
+       default:  mr1 |= MCFUART_MR1_CS8; break;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYMARK;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYSPACE;
+               } else {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYODD;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYEVEN;
+               }
+       } else {
+               mr1 |= MCFUART_MR1_PARITYNONE;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               mr2 |= MCFUART_MR2_STOP2;
+       else
+               mr2 |= MCFUART_MR2_STOP1;
+
+       if (termios->c_cflag & CRTSCTS) {
+               mr1 |= MCFUART_MR1_RXRTS;
+               mr2 |= MCFUART_MR2_TXCTS;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
+       writeb(mr1, port->membase + MCFUART_UMR);
+       writeb(mr2, port->membase + MCFUART_UMR);
+       writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
+       writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
+#if defined(CONFIG_M5272)
+       writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
+#endif
+       writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
+               port->membase + MCFUART_UCSR);
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_rx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       unsigned char status, ch, flag;
+
+       while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
+               ch = readb(port->membase + MCFUART_URB);
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (status & MCFUART_USR_RXERR) {
+                       writeb(MCFUART_UCR_CMDRESETERR,
+                               port->membase + MCFUART_UCR);
+
+                       if (status & MCFUART_USR_RXBREAK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & MCFUART_USR_RXPARITY) {
+                               port->icount.parity++;
+                       } else if (status & MCFUART_USR_RXOVERRUN) {
+                               port->icount.overrun++;
+                       } else if (status & MCFUART_USR_RXFRAMING) {
+                               port->icount.frame++;
+                       }
+
+                       status &= port->read_status_mask;
+
+                       if (status & MCFUART_USR_RXBREAK)
+                               flag = TTY_BREAK;
+                       else if (status & MCFUART_USR_RXPARITY)
+                               flag = TTY_PARITY;
+                       else if (status & MCFUART_USR_RXFRAMING)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
+       }
+
+       tty_flip_buffer_push(port->state->port.tty);
+}
+
+/****************************************************************************/
+
+static void mcf_tx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = &pp->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               writeb(port->x_char, port->membase + MCFUART_UTB);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
+               if (xmit->head == xmit->tail)
+                       break;
+               writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (xmit->head == xmit->tail) {
+               pp->imr &= ~MCFUART_UIR_TXREADY;
+               writeb(pp->imr, port->membase + MCFUART_UIMR);
+       }
+}
+
+/****************************************************************************/
+
+static irqreturn_t mcf_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+       unsigned int isr;
+       irqreturn_t ret = IRQ_NONE;
+
+       isr = readb(port->membase + MCFUART_UISR) & pp->imr;
+
+       spin_lock(&port->lock);
+       if (isr & MCFUART_UIR_RXREADY) {
+               mcf_rx_chars(pp);
+               ret = IRQ_HANDLED;
+       }
+       if (isr & MCFUART_UIR_TXREADY) {
+               mcf_tx_chars(pp);
+               ret = IRQ_HANDLED;
+       }
+       spin_unlock(&port->lock);
+
+       return ret;
+}
+
+/****************************************************************************/
+
+static void mcf_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_MCF;
+       port->fifosize = MCFUART_TXFIFOSIZE;
+
+       /* Clear mask, so no surprise interrupts. */
+       writeb(0, port->membase + MCFUART_UIMR);
+
+       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
+               printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
+                       "interrupt vector=%d\n", port->line, port->irq);
+}
+
+/****************************************************************************/
+
+static const char *mcf_type(struct uart_port *port)
+{
+       return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
+}
+
+/****************************************************************************/
+
+static int mcf_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+/****************************************************************************/
+
+static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
+               return -EINVAL;
+       return 0;
+}
+
+/****************************************************************************/
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static const struct uart_ops mcf_uart_ops = {
+       .tx_empty       = mcf_tx_empty,
+       .get_mctrl      = mcf_get_mctrl,
+       .set_mctrl      = mcf_set_mctrl,
+       .start_tx       = mcf_start_tx,
+       .stop_tx        = mcf_stop_tx,
+       .stop_rx        = mcf_stop_rx,
+       .enable_ms      = mcf_enable_ms,
+       .break_ctl      = mcf_break_ctl,
+       .startup        = mcf_startup,
+       .shutdown       = mcf_shutdown,
+       .set_termios    = mcf_set_termios,
+       .type           = mcf_type,
+       .request_port   = mcf_request_port,
+       .release_port   = mcf_release_port,
+       .config_port    = mcf_config_port,
+       .verify_port    = mcf_verify_port,
+};
+
+static struct mcf_uart mcf_ports[4];
+
+#define        MCF_MAXPORTS    ARRAY_SIZE(mcf_ports)
+
+/****************************************************************************/
+#if defined(CONFIG_SERIAL_MCF_CONSOLE)
+/****************************************************************************/
+
+int __init early_mcf_setup(struct mcf_platform_uart *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) port->mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+               port->ops = &mcf_uart_ops;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(mcf_ports + co->index)->port;
+       int i;
+
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+       writeb(c, port->membase + MCFUART_UTB);
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+}
+
+/****************************************************************************/
+
+static void mcf_console_write(struct console *co, const char *s, unsigned int count)
+{
+       for (; (count); count--, s++) {
+               mcf_console_putc(co, *s);
+               if (*s == '\n')
+                       mcf_console_putc(co, '\r');
+       }
+}
+
+/****************************************************************************/
+
+static int __init mcf_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = CONFIG_SERIAL_MCF_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
+               co->index = 0;
+       port = &mcf_ports[co->index].port;
+       if (port->membase == 0)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/****************************************************************************/
+
+static struct uart_driver mcf_driver;
+
+static struct console mcf_console = {
+       .name           = "ttyS",
+       .write          = mcf_console_write,
+       .device         = uart_console_device,
+       .setup          = mcf_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &mcf_driver,
+};
+
+static int __init mcf_console_init(void)
+{
+       register_console(&mcf_console);
+       return 0;
+}
+
+console_initcall(mcf_console_init);
+
+#define        MCF_CONSOLE     &mcf_console
+
+/****************************************************************************/
+#else
+/****************************************************************************/
+
+#define        MCF_CONSOLE     NULL
+
+/****************************************************************************/
+#endif /* CONFIG_MCF_CONSOLE */
+/****************************************************************************/
+
+/*
+ *     Define the mcf UART driver structure.
+ */
+static struct uart_driver mcf_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "mcf",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = MCF_MAXPORTS,
+       .cons           = MCF_CONSOLE,
+};
+
+/****************************************************************************/
+
+static int __devinit mcf_probe(struct platform_device *pdev)
+{
+       struct mcf_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) platp[i].mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->ops = &mcf_uart_ops;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+
+               uart_add_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static int __devexit mcf_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; (i < MCF_MAXPORTS); i++) {
+               port = &mcf_ports[i].port;
+               if (port)
+                       uart_remove_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static struct platform_driver mcf_platform_driver = {
+       .probe          = mcf_probe,
+       .remove         = __devexit_p(mcf_remove),
+       .driver         = {
+               .name   = "mcfuart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/****************************************************************************/
+
+static int __init mcf_init(void)
+{
+       int rc;
+
+       printk("ColdFire internal UART serial driver\n");
+
+       rc = uart_register_driver(&mcf_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&mcf_platform_driver);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+/****************************************************************************/
+
+static void __exit mcf_exit(void)
+{
+       platform_driver_unregister(&mcf_platform_driver);
+       uart_unregister_driver(&mcf_driver);
+}
+
+/****************************************************************************/
+
+module_init(mcf_init);
+module_exit(mcf_exit);
+
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Freescale ColdFire UART driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mcfuart");
+
+/****************************************************************************/
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
new file mode 100644 (file)
index 0000000..d40010a
--- /dev/null
@@ -0,0 +1,1513 @@
+/*
+ * mfd.c: driver for High Speed UART device of Intel Medfield platform
+ *
+ * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
+ *
+ * (C) Copyright 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+/* Notes:
+ * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
+ *    2/3 chan to port 1, 4/5 chan to port 3. Even number chans
+ *    are used for RX, odd chans for TX
+ *
+ * 2. In A0 stepping, UART will not support TX half empty flag
+ *
+ * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
+ *    asserted, only when the HW is reset the DDCD and DDSR will
+ *    be triggered
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/slab.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial_mfd.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+
+#define  MFD_HSU_A0_STEPPING   1
+
+#define HSU_DMA_BUF_SIZE       2048
+
+#define chan_readl(chan, offset)       readl(chan->reg + offset)
+#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
+
+#define mfd_readl(obj, offset)         readl(obj->reg + offset)
+#define mfd_writel(obj, offset, val)   writel(val, obj->reg + offset)
+
+#define HSU_DMA_TIMEOUT_CHECK_FREQ     (HZ/10)
+
+struct hsu_dma_buffer {
+       u8              *buf;
+       dma_addr_t      dma_addr;
+       u32             dma_size;
+       u32             ofs;
+};
+
+struct hsu_dma_chan {
+       u32     id;
+       enum dma_data_direction dirt;
+       struct uart_hsu_port    *uport;
+       void __iomem            *reg;
+       struct timer_list       rx_timer; /* only needed by RX channel */
+};
+
+struct uart_hsu_port {
+       struct uart_port        port;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned int            lsr_break_flag;
+       char                    name[12];
+       int                     index;
+       struct device           *dev;
+
+       struct hsu_dma_chan     *txc;
+       struct hsu_dma_chan     *rxc;
+       struct hsu_dma_buffer   txbuf;
+       struct hsu_dma_buffer   rxbuf;
+       int                     use_dma;        /* flag for DMA/PIO */
+       int                     running;
+       int                     dma_tx_on;
+};
+
+/* Top level data structure of HSU */
+struct hsu_port {
+       void __iomem    *reg;
+       unsigned long   paddr;
+       unsigned long   iolen;
+       u32             irq;
+
+       struct uart_hsu_port    port[3];
+       struct hsu_dma_chan     chans[10];
+
+       struct dentry *debugfs;
+};
+
+static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
+{
+       unsigned int val;
+
+       if (offset > UART_MSR) {
+               offset <<= 2;
+               val = readl(up->port.membase + offset);
+       } else
+               val = (unsigned int)readb(up->port.membase + offset);
+
+       return val;
+}
+
+static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
+{
+       if (offset > UART_MSR) {
+               offset <<= 2;
+               writel(value, up->port.membase + offset);
+       } else {
+               unsigned char val = value & 0xff;
+               writeb(val, up->port.membase + offset);
+       }
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define HSU_REGS_BUFSIZE       1024
+
+static int hsu_show_regs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct uart_hsu_port *up = file->private_data;
+       char *buf;
+       u32 len = 0;
+       ssize_t ret;
+
+       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MFD HSU port[%d] regs:\n", up->index);
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "=================================\n");
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
+
+       if (len > HSU_REGS_BUFSIZE)
+               len = HSU_REGS_BUFSIZE;
+
+       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct hsu_dma_chan *chan = file->private_data;
+       char *buf;
+       u32 len = 0;
+       ssize_t ret;
+
+       buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MFD HSU DMA channel [%d] regs:\n", chan->id);
+
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "=================================\n");
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
+       len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+                       "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
+
+       if (len > HSU_REGS_BUFSIZE)
+               len = HSU_REGS_BUFSIZE;
+
+       ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations port_regs_ops = {
+       .owner          = THIS_MODULE,
+       .open           = hsu_show_regs_open,
+       .read           = port_show_regs,
+       .llseek         = default_llseek,
+};
+
+static const struct file_operations dma_regs_ops = {
+       .owner          = THIS_MODULE,
+       .open           = hsu_show_regs_open,
+       .read           = dma_show_regs,
+       .llseek         = default_llseek,
+};
+
+static int hsu_debugfs_init(struct hsu_port *hsu)
+{
+       int i;
+       char name[32];
+
+       hsu->debugfs = debugfs_create_dir("hsu", NULL);
+       if (!hsu->debugfs)
+               return -ENOMEM;
+
+       for (i = 0; i < 3; i++) {
+               snprintf(name, sizeof(name), "port_%d_regs", i);
+               debugfs_create_file(name, S_IFREG | S_IRUGO,
+                       hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
+       }
+
+       for (i = 0; i < 6; i++) {
+               snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
+               debugfs_create_file(name, S_IFREG | S_IRUGO,
+                       hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
+       }
+
+       return 0;
+}
+
+static void hsu_debugfs_remove(struct hsu_port *hsu)
+{
+       if (hsu->debugfs)
+               debugfs_remove_recursive(hsu->debugfs);
+}
+
+#else
+static inline int hsu_debugfs_init(struct hsu_port *hsu)
+{
+       return 0;
+}
+
+static inline void hsu_debugfs_remove(struct hsu_port *hsu)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static void serial_hsu_enable_ms(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+void hsu_dma_tx(struct uart_hsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       struct hsu_dma_buffer *dbuf = &up->txbuf;
+       int count;
+
+       /* test_and_set_bit may be better, but anyway it's in lock protected mode */
+       if (up->dma_tx_on)
+               return;
+
+       /* Update the circ buf info */
+       xmit->tail += dbuf->ofs;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       up->port.icount.tx += dbuf->ofs;
+       dbuf->ofs = 0;
+
+       /* Disable the channel */
+       chan_writel(up->txc, HSU_CH_CR, 0x0);
+
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
+               dma_sync_single_for_device(up->port.dev,
+                                          dbuf->dma_addr,
+                                          dbuf->dma_size,
+                                          DMA_TO_DEVICE);
+
+               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               dbuf->ofs = count;
+
+               /* Reprogram the channel */
+               chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
+               chan_writel(up->txc, HSU_CH_D0TSR, count);
+
+               /* Reenable the channel */
+               chan_writel(up->txc, HSU_CH_DCR, 0x1
+                                                | (0x1 << 8)
+                                                | (0x1 << 16)
+                                                | (0x1 << 24));
+               up->dma_tx_on = 1;
+               chan_writel(up->txc, HSU_CH_CR, 0x1);
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+}
+
+/* The buffer is already cache coherent */
+void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
+{
+       dbuf->ofs = 0;
+
+       chan_writel(rxc, HSU_CH_BSR, 32);
+       chan_writel(rxc, HSU_CH_MOTSR, 4);
+
+       chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
+       chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
+       chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
+                                        | (0x1 << 16)
+                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
+                                        );
+       chan_writel(rxc, HSU_CH_CR, 0x3);
+
+       mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
+}
+
+/* Protected by spin_lock_irqsave(port->lock) */
+static void serial_hsu_start_tx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       if (up->use_dma) {
+               hsu_dma_tx(up);
+       } else if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_hsu_stop_tx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       struct hsu_dma_chan *txc = up->txc;
+
+       if (up->use_dma)
+               chan_writel(txc, HSU_CH_CR, 0x0);
+       else if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+/* This is always called in spinlock protected mode, so
+ * modify timeout timer is safe here */
+void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+{
+       struct hsu_dma_buffer *dbuf = &up->rxbuf;
+       struct hsu_dma_chan *chan = up->rxc;
+       struct uart_port *port = &up->port;
+       struct tty_struct *tty = port->state->port.tty;
+       int count;
+
+       if (!tty)
+               return;
+
+       /*
+        * First need to know how many is already transferred,
+        * then check if its a timeout DMA irq, and return
+        * the trail bytes out, push them up and reenable the
+        * channel
+        */
+
+       /* Timeout IRQ, need wait some time, see Errata 2 */
+       if (int_sts & 0xf00)
+               udelay(2);
+
+       /* Stop the channel */
+       chan_writel(chan, HSU_CH_CR, 0x0);
+
+       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
+       if (!count) {
+               /* Restart the channel before we leave */
+               chan_writel(chan, HSU_CH_CR, 0x3);
+               return;
+       }
+       del_timer(&chan->rx_timer);
+
+       dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
+                       dbuf->dma_size, DMA_FROM_DEVICE);
+
+       /*
+        * Head will only wrap around when we recycle
+        * the DMA buffer, and when that happens, we
+        * explicitly set tail to 0. So head will
+        * always be greater than tail.
+        */
+       tty_insert_flip_string(tty, dbuf->buf, count);
+       port->icount.rx += count;
+
+       dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
+                       dbuf->dma_size, DMA_FROM_DEVICE);
+
+       /* Reprogram the channel */
+       chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
+       chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
+       chan_writel(chan, HSU_CH_DCR, 0x1
+                                        | (0x1 << 8)
+                                        | (0x1 << 16)
+                                        | (0x1 << 24)  /* timeout bit, see HSU Errata 1 */
+                                        );
+       tty_flip_buffer_push(tty);
+
+       chan_writel(chan, HSU_CH_CR, 0x3);
+       chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
+       add_timer(&chan->rx_timer);
+
+}
+
+static void serial_hsu_stop_rx(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       struct hsu_dma_chan *chan = up->rxc;
+
+       if (up->use_dma)
+               chan_writel(chan, HSU_CH_CR, 0x2);
+       else {
+               up->ier &= ~UART_IER_RLSI;
+               up->port.read_status_mask &= ~UART_LSR_DR;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static inline void receive_chars(struct uart_hsu_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch, flag;
+       unsigned int max_count = 256;
+
+       if (!tty)
+               return;
+
+       do {
+               ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+
+                       dev_warn(up->dev, "We really rush into ERR/BI case"
+                               "status = 0x%02x", *status);
+                       /* For statistics only */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /* Mask off conditions which should be ignored. */
+                       *status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+                       if (up->port.cons &&
+                               up->port.cons->index == up->port.line) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && max_count--);
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_hsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_hsu_stop_tx(&up->port);
+               return;
+       }
+
+#ifndef MFD_HSU_A0_STEPPING
+       count = up->port.fifosize / 2;
+#else
+       /*
+        * A0 only supports fully empty IRQ, and the first char written
+        * into it won't clear the EMPT bit, so we may need be cautious
+        * by useing a shorter buffer
+        */
+       count = up->port.fifosize - 4;
+#endif
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_hsu_stop_tx(&up->port);
+}
+
+static inline void check_modem_status(struct uart_hsu_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       /* We may only get DDCD when HW init and reset */
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       /* Will start/stop_tx accordingly */
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static irqreturn_t port_irq(int irq, void *dev_id)
+{
+       struct uart_hsu_port *up = dev_id;
+       unsigned int iir, lsr;
+       unsigned long flags;
+
+       if (unlikely(!up->running))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->use_dma) {
+               lsr = serial_in(up, UART_LSR);
+               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE)))
+                       dev_warn(up->dev,
+                               "Got lsr irq while using DMA, lsr = 0x%2x\n",
+                               lsr);
+               check_modem_status(up);
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return IRQ_HANDLED;
+       }
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return IRQ_NONE;
+       }
+
+       lsr = serial_in(up, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(up, &lsr);
+       check_modem_status(up);
+
+       /* lsr will be renewed during the receive_chars */
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static inline void dma_chan_irq(struct hsu_dma_chan *chan)
+{
+       struct uart_hsu_port *up = chan->uport;
+       unsigned long flags;
+       u32 int_sts;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (!up->use_dma || !up->running)
+               goto exit;
+
+       /*
+        * No matter what situation, need read clear the IRQ status
+        * There is a bug, see Errata 5, HSD 2900918
+        */
+       int_sts = chan_readl(chan, HSU_CH_SR);
+
+       /* Rx channel */
+       if (chan->dirt == DMA_FROM_DEVICE)
+               hsu_dma_rx(up, int_sts);
+
+       /* Tx channel */
+       if (chan->dirt == DMA_TO_DEVICE) {
+               chan_writel(chan, HSU_CH_CR, 0x0);
+               up->dma_tx_on = 0;
+               hsu_dma_tx(up);
+       }
+
+exit:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       return;
+}
+
+static irqreturn_t dma_irq(int irq, void *dev_id)
+{
+       struct hsu_port *hsu = dev_id;
+       u32 int_sts, i;
+
+       int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
+
+       /* Currently we only have 6 channels may be used */
+       for (i = 0; i < 6; i++) {
+               if (int_sts & 0x1)
+                       dma_chan_irq(&hsu->chans[i]);
+               int_sts >>= 1;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_hsu_tx_empty(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/*
+ * What special to do:
+ * 1. chose the 64B fifo mode
+ * 2. make sure not to select half empty mode for A0 stepping
+ * 3. start dma or pio depends on configuration
+ * 4. we only allocate dma memory when needed
+ */
+static int serial_hsu_startup(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+
+       /* Clear the interrupt registers. */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /* Now, initialize the UART, default is 8n1 */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       if (!up->use_dma)
+               up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
+       else
+               up->ier = 0;
+       serial_out(up, UART_IER, up->ier);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* DMA init */
+       if (up->use_dma) {
+               struct hsu_dma_buffer *dbuf;
+               struct circ_buf *xmit = &port->state->xmit;
+
+               up->dma_tx_on = 0;
+
+               /* First allocate the RX buffer */
+               dbuf = &up->rxbuf;
+               dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
+               if (!dbuf->buf) {
+                       up->use_dma = 0;
+                       goto exit;
+               }
+               dbuf->dma_addr = dma_map_single(port->dev,
+                                               dbuf->buf,
+                                               HSU_DMA_BUF_SIZE,
+                                               DMA_FROM_DEVICE);
+               dbuf->dma_size = HSU_DMA_BUF_SIZE;
+
+               /* Start the RX channel right now */
+               hsu_dma_start_rx_chan(up->rxc, dbuf);
+
+               /* Next init the TX DMA */
+               dbuf = &up->txbuf;
+               dbuf->buf = xmit->buf;
+               dbuf->dma_addr = dma_map_single(port->dev,
+                                              dbuf->buf,
+                                              UART_XMIT_SIZE,
+                                              DMA_TO_DEVICE);
+               dbuf->dma_size = UART_XMIT_SIZE;
+
+               /* This should not be changed all around */
+               chan_writel(up->txc, HSU_CH_BSR, 32);
+               chan_writel(up->txc, HSU_CH_MOTSR, 4);
+               dbuf->ofs = 0;
+       }
+
+exit:
+        /* And clear the interrupt registers again for luck. */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       up->running = 1;
+       return 0;
+}
+
+static void serial_hsu_shutdown(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       unsigned long flags;
+
+       del_timer_sync(&up->rxc->rx_timer);
+
+       /* Disable interrupts from this port */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+       up->running = 0;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* Disable break condition and FIFOs */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+static void
+serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_hsu_port *up =
+                       container_of(port, struct uart_hsu_port, port);
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+       u32 ps, mul;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       /* CMSPAR isn't supported by this driver */
+       if (tty)
+               tty->termios->c_cflag &= ~CMSPAR;
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * The base clk is 50Mhz, and the baud rate come from:
+        *      baud = 50M * MUL / (DIV * PS * DLAB)
+        *
+        * For those basic low baud rate we can get the direct
+        * scalar from 2746800, like 115200 = 2746800/24. For those
+        * higher baud rate, we handle them case by case, mainly by
+        * adjusting the MUL/PS registers, and DIV register is kept
+        * as default value 0x3d09 to make things simple
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+
+       quot = 1;
+       ps = 0x10;
+       mul = 0x3600;
+       switch (baud) {
+       case 3500000:
+               mul = 0x3345;
+               ps = 0xC;
+               break;
+       case 1843200:
+               mul = 0x2400;
+               break;
+       case 3000000:
+       case 2500000:
+       case 2000000:
+       case 1500000:
+       case 1000000:
+       case 500000:
+               /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
+               mul = baud / 500000 * 0x9C4;
+               break;
+       default:
+               /* Use uart_get_divisor to get quot for other baud rates */
+               quot = 0;
+       }
+
+       if (!quot)
+               quot = uart_get_divisor(port, baud);
+
+       if ((up->port.uartclk / quot) < (2400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
+       else if ((up->port.uartclk / quot) < (230400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
+       else
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
+
+       fcr |= UART_FCR_HSU_64B_FIFO;
+#ifdef MFD_HSU_A0_STEPPING
+       /* A0 doesn't support half empty IRQ */
+       fcr |= UART_FCR_FULL_EMPT_TXI;
+#endif
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /* Characters to ignore */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /* Ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts, disable
+        * MSI by default
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
+       else
+               up->mcr &= ~UART_MCR_AFE;
+
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
+       serial_out(up, UART_MUL, mul);                  /* set MUL */
+       serial_out(up, UART_PS, ps);                    /* set PS */
+       up->lcr = cval;                                 /* Save LCR */
+       serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+       serial_out(up, UART_FCR, fcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_hsu_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+}
+
+static void serial_hsu_release_port(struct uart_port *port)
+{
+}
+
+static int serial_hsu_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_hsu_config_port(struct uart_port *port, int flags)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       up->port.type = PORT_MFD;
+}
+
+static int
+serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* We don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static const char *
+serial_hsu_type(struct uart_port *port)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+       return up->name;
+}
+
+/* Mainly for uart console use */
+static struct uart_hsu_port *serial_hsu_ports[3];
+static struct uart_driver serial_hsu_reg;
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/* Wait for transmitter & holding register to empty */
+static inline void wait_for_xmitr(struct uart_hsu_port *up)
+{
+       unsigned int status, tmout = 1000;
+
+       /* Wait up to 1ms for the character to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while (!(status & BOTH_EMPTY));
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void serial_hsu_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_hsu_port *up =
+               container_of(port, struct uart_hsu_port, port);
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void
+serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_hsu_port *up = serial_hsu_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /* First save the IER then disable the interrupts */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static struct console serial_hsu_console;
+
+static int __init
+serial_hsu_console_setup(struct console *co, char *options)
+{
+       struct uart_hsu_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       if (co->index == -1 || co->index >= serial_hsu_reg.nr)
+               co->index = 0;
+       up = serial_hsu_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
+
+       return ret;
+}
+
+static struct console serial_hsu_console = {
+       .name           = "ttyMFD",
+       .write          = serial_hsu_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_hsu_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = 2,
+       .data           = &serial_hsu_reg,
+};
+#endif
+
+struct uart_ops serial_hsu_pops = {
+       .tx_empty       = serial_hsu_tx_empty,
+       .set_mctrl      = serial_hsu_set_mctrl,
+       .get_mctrl      = serial_hsu_get_mctrl,
+       .stop_tx        = serial_hsu_stop_tx,
+       .start_tx       = serial_hsu_start_tx,
+       .stop_rx        = serial_hsu_stop_rx,
+       .enable_ms      = serial_hsu_enable_ms,
+       .break_ctl      = serial_hsu_break_ctl,
+       .startup        = serial_hsu_startup,
+       .shutdown       = serial_hsu_shutdown,
+       .set_termios    = serial_hsu_set_termios,
+       .pm             = serial_hsu_pm,
+       .type           = serial_hsu_type,
+       .release_port   = serial_hsu_release_port,
+       .request_port   = serial_hsu_request_port,
+       .config_port    = serial_hsu_config_port,
+       .verify_port    = serial_hsu_verify_port,
+};
+
+static struct uart_driver serial_hsu_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "MFD serial",
+       .dev_name       = "ttyMFD",
+       .major          = TTY_MAJOR,
+       .minor          = 128,
+       .nr             = 3,
+};
+
+#ifdef CONFIG_PM
+static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+
+       /* Make sure this is not the internal dma controller */
+       if (priv && (pdev->device != 0x081E)) {
+               up = priv;
+               uart_suspend_port(&serial_hsu_reg, &up->port);
+       }
+
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+        return 0;
+}
+
+static int serial_hsu_resume(struct pci_dev *pdev)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               dev_warn(&pdev->dev,
+                       "HSU: can't re-enable device, try to continue\n");
+
+       if (priv && (pdev->device != 0x081E)) {
+               up = priv;
+               uart_resume_port(&serial_hsu_reg, &up->port);
+       }
+       return 0;
+}
+#else
+#define serial_hsu_suspend     NULL
+#define serial_hsu_resume      NULL
+#endif
+
+/* temp global pointer before we settle down on using one or four PCI dev */
+static struct hsu_port *phsu;
+
+static int serial_hsu_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       struct uart_hsu_port *uport;
+       int index, ret;
+
+       printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
+               pdev->vendor, pdev->device);
+
+       switch (pdev->device) {
+       case 0x081B:
+               index = 0;
+               break;
+       case 0x081C:
+               index = 1;
+               break;
+       case 0x081D:
+               index = 2;
+               break;
+       case 0x081E:
+               /* internal DMA controller */
+               index = 3;
+               break;
+       default:
+               dev_err(&pdev->dev, "HSU: out of index!");
+               return -ENODEV;
+       }
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       if (index == 3) {
+               /* DMA controller */
+               ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
+               if (ret) {
+                       dev_err(&pdev->dev, "can not get IRQ\n");
+                       goto err_disable;
+               }
+               pci_set_drvdata(pdev, phsu);
+       } else {
+               /* UART port 0~2 */
+               uport = &phsu->port[index];
+               uport->port.irq = pdev->irq;
+               uport->port.dev = &pdev->dev;
+               uport->dev = &pdev->dev;
+
+               ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
+               if (ret) {
+                       dev_err(&pdev->dev, "can not get IRQ\n");
+                       goto err_disable;
+               }
+               uart_add_one_port(&serial_hsu_reg, &uport->port);
+
+#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+               if (index == 2) {
+                       register_console(&serial_hsu_console);
+                       uport->port.cons = &serial_hsu_console;
+               }
+#endif
+               pci_set_drvdata(pdev, uport);
+       }
+
+       return 0;
+
+err_disable:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void hsu_dma_rx_timeout(unsigned long data)
+{
+       struct hsu_dma_chan *chan = (void *)data;
+       struct uart_hsu_port *up = chan->uport;
+       struct hsu_dma_buffer *dbuf = &up->rxbuf;
+       int count = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
+
+       if (!count) {
+               mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
+               goto exit;
+       }
+
+       hsu_dma_rx(up, 0);
+exit:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void hsu_global_init(void)
+{
+       struct hsu_port *hsu;
+       struct uart_hsu_port *uport;
+       struct hsu_dma_chan *dchan;
+       int i, ret;
+
+       hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
+       if (!hsu)
+               return;
+
+       /* Get basic io resource and map it */
+       hsu->paddr = 0xffa28000;
+       hsu->iolen = 0x1000;
+
+       if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
+               pr_warning("HSU: error in request mem region\n");
+
+       hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
+       if (!hsu->reg) {
+               pr_err("HSU: error in ioremap\n");
+               ret = -ENOMEM;
+               goto err_free_region;
+       }
+
+       /* Initialise the 3 UART ports */
+       uport = hsu->port;
+       for (i = 0; i < 3; i++) {
+               uport->port.type = PORT_MFD;
+               uport->port.iotype = UPIO_MEM;
+               uport->port.mapbase = (resource_size_t)hsu->paddr
+                                       + HSU_PORT_REG_OFFSET
+                                       + i * HSU_PORT_REG_LENGTH;
+               uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
+                                       + i * HSU_PORT_REG_LENGTH;
+
+               sprintf(uport->name, "hsu_port%d", i);
+               uport->port.fifosize = 64;
+               uport->port.ops = &serial_hsu_pops;
+               uport->port.line = i;
+               uport->port.flags = UPF_IOREMAP;
+               /* set the scalable maxim support rate to 2746800 bps */
+               uport->port.uartclk = 115200 * 24 * 16;
+
+               uport->running = 0;
+               uport->txc = &hsu->chans[i * 2];
+               uport->rxc = &hsu->chans[i * 2 + 1];
+
+               serial_hsu_ports[i] = uport;
+               uport->index = i;
+               uport++;
+       }
+
+       /* Initialise 6 dma channels */
+       dchan = hsu->chans;
+       for (i = 0; i < 6; i++) {
+               dchan->id = i;
+               dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+               dchan->uport = &hsu->port[i/2];
+               dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
+                               i * HSU_DMA_CHANS_REG_LENGTH;
+
+               /* Work around for RX */
+               if (dchan->dirt == DMA_FROM_DEVICE) {
+                       init_timer(&dchan->rx_timer);
+                       dchan->rx_timer.function = hsu_dma_rx_timeout;
+                       dchan->rx_timer.data = (unsigned long)dchan;
+               }
+               dchan++;
+       }
+
+       phsu = hsu;
+       hsu_debugfs_init(hsu);
+       return;
+
+err_free_region:
+       release_mem_region(hsu->paddr, hsu->iolen);
+       kfree(hsu);
+       return;
+}
+
+static void serial_hsu_remove(struct pci_dev *pdev)
+{
+       void *priv = pci_get_drvdata(pdev);
+       struct uart_hsu_port *up;
+
+       if (!priv)
+               return;
+
+       /* For port 0/1/2, priv is the address of uart_hsu_port */
+       if (pdev->device != 0x081E) {
+               up = priv;
+               uart_remove_one_port(&serial_hsu_reg, &up->port);
+       }
+
+       pci_set_drvdata(pdev, NULL);
+       free_irq(pdev->irq, priv);
+       pci_disable_device(pdev);
+}
+
+/* First 3 are UART ports, and the 4th is the DMA */
+static const struct pci_device_id pci_ids[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
+       {},
+};
+
+static struct pci_driver hsu_pci_driver = {
+       .name =         "HSU serial",
+       .id_table =     pci_ids,
+       .probe =        serial_hsu_probe,
+       .remove =       __devexit_p(serial_hsu_remove),
+       .suspend =      serial_hsu_suspend,
+       .resume =       serial_hsu_resume,
+};
+
+static int __init hsu_pci_init(void)
+{
+       int ret;
+
+       hsu_global_init();
+
+       ret = uart_register_driver(&serial_hsu_reg);
+       if (ret)
+               return ret;
+
+       return pci_register_driver(&hsu_pci_driver);
+}
+
+static void __exit hsu_pci_exit(void)
+{
+       pci_unregister_driver(&hsu_pci_driver);
+       uart_unregister_driver(&serial_hsu_reg);
+
+       hsu_debugfs_remove(phsu);
+
+       kfree(phsu);
+}
+
+module_init(hsu_pci_init);
+module_exit(hsu_pci_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:medfield-hsu");
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
new file mode 100644 (file)
index 0000000..126ec7f
--- /dev/null
@@ -0,0 +1,1527 @@
+/*
+ * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
+ *
+ * FIXME According to the usermanual the status bits in the status register
+ * are only updated when the peripherals access the FIFO and not when the
+ * CPU access them. So since we use this bits to know when we stop writing
+ * and reading, they may not be updated in-time and a race condition may
+ * exists. But I haven't be able to prove this and I don't care. But if
+ * any problem arises, it might worth checking. The TX/RX FIFO Stats
+ * registers should be used in addition.
+ * Update: Actually, they seem updated ... At least the bits we use.
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Some of the code has been inspired/copied from the 2.4 code written
+ * by Dale Farnsworth <dfarnsworth@mvista.com>.
+ *
+ * Copyright (C) 2008 Freescale Semiconductor Inc.
+ *                    John Rigby <jrigby@gmail.com>
+ * Added support for MPC5121
+ * Copyright (C) 2006 Secret Lab Technologies Ltd.
+ *                    Grant Likely <grant.likely@secretlab.ca>
+ * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#undef DEBUG
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_PSC_MAJOR       204
+#define SERIAL_PSC_MINOR       148
+
+
+#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
+
+
+static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
+       /* Rem: - We use the read_status_mask as a shadow of
+        *        psc->mpc52xx_psc_imr
+        *      - It's important that is array is all zero on start as we
+        *        use it to know if it's initialized or not ! If it's not sure
+        *        it's cleared, then a memset(...,0,...) should be added to
+        *        the console_init
+        */
+
+/* lookup table for matching device nodes to index numbers */
+static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
+
+static void mpc52xx_uart_of_enumerate(void);
+
+
+#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
+
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
+static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
+
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port) \
+       ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port)     (0)
+#endif
+
+/* ======================================================================== */
+/* PSC fifo operations for isolating differences between 52xx and 512x      */
+/* ======================================================================== */
+
+struct psc_ops {
+       void            (*fifo_init)(struct uart_port *port);
+       int             (*raw_rx_rdy)(struct uart_port *port);
+       int             (*raw_tx_rdy)(struct uart_port *port);
+       int             (*rx_rdy)(struct uart_port *port);
+       int             (*tx_rdy)(struct uart_port *port);
+       int             (*tx_empty)(struct uart_port *port);
+       void            (*stop_rx)(struct uart_port *port);
+       void            (*start_tx)(struct uart_port *port);
+       void            (*stop_tx)(struct uart_port *port);
+       void            (*rx_clr_irq)(struct uart_port *port);
+       void            (*tx_clr_irq)(struct uart_port *port);
+       void            (*write_char)(struct uart_port *port, unsigned char c);
+       unsigned char   (*read_char)(struct uart_port *port);
+       void            (*cw_disable_ints)(struct uart_port *port);
+       void            (*cw_restore_ints)(struct uart_port *port);
+       unsigned int    (*set_baudrate)(struct uart_port *port,
+                                       struct ktermios *new,
+                                       struct ktermios *old);
+       int             (*clock)(struct uart_port *port, int enable);
+       int             (*fifoc_init)(void);
+       void            (*fifoc_uninit)(void);
+       void            (*get_irq)(struct uart_port *, struct device_node *);
+       irqreturn_t     (*handle_irq)(struct uart_port *port);
+};
+
+/* setting the prescaler and divisor reg is common for all chips */
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
+                                      u16 prescaler, unsigned int divisor)
+{
+       /* select prescaler */
+       out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
+       out_8(&psc->ctur, divisor >> 8);
+       out_8(&psc->ctlr, divisor & 0xff);
+}
+
+#ifdef CONFIG_PPC_MPC52xx
+#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
+static void mpc52xx_psc_fifo_init(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
+
+       out_8(&fifo->rfcntl, 0x00);
+       out_be16(&fifo->rfalarm, 0x1ff);
+       out_8(&fifo->tfcntl, 0x07);
+       out_be16(&fifo->tfalarm, 0x80);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_RXRDY;
+}
+
+static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXRDY;
+}
+
+
+static int mpc52xx_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_RXRDY;
+}
+
+static int mpc52xx_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_isr)
+           & port->read_status_mask
+           & MPC52xx_PSC_IMR_TXRDY;
+}
+
+static int mpc52xx_psc_tx_empty(struct uart_port *port)
+{
+       return in_be16(&PSC(port)->mpc52xx_psc_status)
+           & MPC52xx_PSC_SR_TXEMP;
+}
+
+static void mpc52xx_psc_start_tx(struct uart_port *port)
+{
+       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_tx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_stop_rx(struct uart_port *port)
+{
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
+{
+}
+
+static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
+}
+
+static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
+{
+       return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+}
+
+static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
+}
+
+static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+
+       /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 32);
+       divisor = (port->uartclk + 16 * baud) / (32 * baud);
+
+       /* enable the /32 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
+}
+
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
+                                             struct ktermios *new,
+                                             struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+       u16 prescaler;
+
+       /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
+        * ipb freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (32 * 0xffff) + 1,
+                                 port->uartclk / 4);
+       divisor = (port->uartclk + 2 * baud) / (4 * baud);
+
+       /* select the proper prescaler and set the divisor */
+       if (divisor > 0xffff) {
+               divisor = (divisor + 4) / 8;
+               prescaler = 0xdd00; /* /32 */
+       } else
+               prescaler = 0xff00; /* /4 */
+       mpc52xx_set_divisor(PSC(port), prescaler, divisor);
+       return baud;
+}
+
+static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+       port->irqflags = IRQF_DISABLED;
+       port->irq = irq_of_parse_and_map(np, 0);
+}
+
+/* 52xx specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
+{
+       return mpc5xxx_uart_process_int(port);
+}
+
+static struct psc_ops mpc52xx_psc_ops = {
+       .fifo_init = mpc52xx_psc_fifo_init,
+       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+       .rx_rdy = mpc52xx_psc_rx_rdy,
+       .tx_rdy = mpc52xx_psc_tx_rdy,
+       .tx_empty = mpc52xx_psc_tx_empty,
+       .stop_rx = mpc52xx_psc_stop_rx,
+       .start_tx = mpc52xx_psc_start_tx,
+       .stop_tx = mpc52xx_psc_stop_tx,
+       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+       .write_char = mpc52xx_psc_write_char,
+       .read_char = mpc52xx_psc_read_char,
+       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+       .set_baudrate = mpc5200_psc_set_baudrate,
+       .get_irq = mpc52xx_psc_get_irq,
+       .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+static struct psc_ops mpc5200b_psc_ops = {
+       .fifo_init = mpc52xx_psc_fifo_init,
+       .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+       .rx_rdy = mpc52xx_psc_rx_rdy,
+       .tx_rdy = mpc52xx_psc_tx_rdy,
+       .tx_empty = mpc52xx_psc_tx_empty,
+       .stop_rx = mpc52xx_psc_stop_rx,
+       .start_tx = mpc52xx_psc_start_tx,
+       .stop_tx = mpc52xx_psc_stop_tx,
+       .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+       .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+       .write_char = mpc52xx_psc_write_char,
+       .read_char = mpc52xx_psc_read_char,
+       .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+       .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+       .set_baudrate = mpc5200b_psc_set_baudrate,
+       .get_irq = mpc52xx_psc_get_irq,
+       .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+#endif /* CONFIG_MPC52xx */
+
+#ifdef CONFIG_PPC_MPC512x
+#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+
+/* PSC FIFO Controller for mpc512x */
+struct psc_fifoc {
+       u32 fifoc_cmd;
+       u32 fifoc_int;
+       u32 fifoc_dma;
+       u32 fifoc_axe;
+       u32 fifoc_debug;
+};
+
+static struct psc_fifoc __iomem *psc_fifoc;
+static unsigned int psc_fifoc_irq;
+
+static void mpc512x_psc_fifo_init(struct uart_port *port)
+{
+       /* /32 prescaler */
+       out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
+
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->txalarm, 1);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+       out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+       out_be32(&FIFO_512x(port)->rxalarm, 1);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+
+       out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
+       out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
+}
+
+static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
+{
+       return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
+}
+
+static int mpc512x_psc_rx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->rxsr)
+           & in_be32(&FIFO_512x(port)->rximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_rdy(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & in_be32(&FIFO_512x(port)->tximr)
+           & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc512x_psc_tx_empty(struct uart_port *port)
+{
+       return in_be32(&FIFO_512x(port)->txsr)
+           & MPC512x_PSC_FIFO_EMPTY;
+}
+
+static void mpc512x_psc_stop_rx(struct uart_port *port)
+{
+       unsigned long rx_fifo_imr;
+
+       rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
+       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
+}
+
+static void mpc512x_psc_start_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_stop_tx(struct uart_port *port)
+{
+       unsigned long tx_fifo_imr;
+
+       tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
+       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+       out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
+}
+
+static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
+}
+
+static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
+{
+       out_8(&FIFO_512x(port)->txdata_8, c);
+}
+
+static unsigned char mpc512x_psc_read_char(struct uart_port *port)
+{
+       return in_8(&FIFO_512x(port)->rxdata_8);
+}
+
+static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
+{
+       port->read_status_mask =
+               in_be32(&FIFO_512x(port)->tximr) << 16 |
+               in_be32(&FIFO_512x(port)->rximr);
+       out_be32(&FIFO_512x(port)->tximr, 0);
+       out_be32(&FIFO_512x(port)->rximr, 0);
+}
+
+static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
+{
+       out_be32(&FIFO_512x(port)->tximr,
+               (port->read_status_mask >> 16) & 0x7f);
+       out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
+}
+
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
+                                            struct ktermios *new,
+                                            struct ktermios *old)
+{
+       unsigned int baud;
+       unsigned int divisor;
+
+       /*
+        * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
+        * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
+        * Furthermore, it states that "After reset, the prescaler by 10
+        * for the UART mode is selected", but the reset register value is
+        * 0x0000 which means a /32 prescaler. This is wrong.
+        *
+        * In reality using /32 prescaler doesn't work, as it is not supported!
+        * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
+        * Chapter 4.1 PSC in UART Mode.
+        * Calculate with a /16 prescaler here.
+        */
+
+       /* uartclk contains the ips freq */
+       baud = uart_get_baud_rate(port, new, old,
+                                 port->uartclk / (16 * 0xffff) + 1,
+                                 port->uartclk / 16);
+       divisor = (port->uartclk + 8 * baud) / (16 * baud);
+
+       /* enable the /16 prescaler and set the divisor */
+       mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+       return baud;
+}
+
+/* Init PSC FIFO Controller */
+static int __init mpc512x_psc_fifoc_init(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL,
+                                    "fsl,mpc5121-psc-fifo");
+       if (!np) {
+               pr_err("%s: Can't find FIFOC node\n", __func__);
+               return -ENODEV;
+       }
+
+       psc_fifoc = of_iomap(np, 0);
+       if (!psc_fifoc) {
+               pr_err("%s: Can't map FIFOC\n", __func__);
+               of_node_put(np);
+               return -ENODEV;
+       }
+
+       psc_fifoc_irq = irq_of_parse_and_map(np, 0);
+       of_node_put(np);
+       if (psc_fifoc_irq == NO_IRQ) {
+               pr_err("%s: Can't get FIFOC irq\n", __func__);
+               iounmap(psc_fifoc);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit mpc512x_psc_fifoc_uninit(void)
+{
+       iounmap(psc_fifoc);
+}
+
+/* 512x specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
+{
+       unsigned long fifoc_int;
+       int psc_num;
+
+       /* Read pending PSC FIFOC interrupts */
+       fifoc_int = in_be32(&psc_fifoc->fifoc_int);
+
+       /* Check if it is an interrupt for this port */
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       if (test_bit(psc_num, &fifoc_int) ||
+           test_bit(psc_num + 16, &fifoc_int))
+               return mpc5xxx_uart_process_int(port);
+
+       return IRQ_NONE;
+}
+
+static int mpc512x_psc_clock(struct uart_port *port, int enable)
+{
+       struct clk *psc_clk;
+       int psc_num;
+       char clk_name[10];
+
+       if (uart_console(port))
+               return 0;
+
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
+       psc_clk = clk_get(port->dev, clk_name);
+       if (IS_ERR(psc_clk)) {
+               dev_err(port->dev, "Failed to get PSC clock entry!\n");
+               return -ENODEV;
+       }
+
+       dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
+
+       if (enable)
+               clk_enable(psc_clk);
+       else
+               clk_disable(psc_clk);
+
+       return 0;
+}
+
+static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+       port->irqflags = IRQF_SHARED;
+       port->irq = psc_fifoc_irq;
+}
+
+static struct psc_ops mpc512x_psc_ops = {
+       .fifo_init = mpc512x_psc_fifo_init,
+       .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
+       .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
+       .rx_rdy = mpc512x_psc_rx_rdy,
+       .tx_rdy = mpc512x_psc_tx_rdy,
+       .tx_empty = mpc512x_psc_tx_empty,
+       .stop_rx = mpc512x_psc_stop_rx,
+       .start_tx = mpc512x_psc_start_tx,
+       .stop_tx = mpc512x_psc_stop_tx,
+       .rx_clr_irq = mpc512x_psc_rx_clr_irq,
+       .tx_clr_irq = mpc512x_psc_tx_clr_irq,
+       .write_char = mpc512x_psc_write_char,
+       .read_char = mpc512x_psc_read_char,
+       .cw_disable_ints = mpc512x_psc_cw_disable_ints,
+       .cw_restore_ints = mpc512x_psc_cw_restore_ints,
+       .set_baudrate = mpc512x_psc_set_baudrate,
+       .clock = mpc512x_psc_clock,
+       .fifoc_init = mpc512x_psc_fifoc_init,
+       .fifoc_uninit = mpc512x_psc_fifoc_uninit,
+       .get_irq = mpc512x_psc_get_irq,
+       .handle_irq = mpc512x_psc_handle_irq,
+};
+#endif
+
+static struct psc_ops *psc_ops;
+
+/* ======================================================================== */
+/* UART operations                                                          */
+/* ======================================================================== */
+
+static unsigned int
+mpc52xx_uart_tx_empty(struct uart_port *port)
+{
+       return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
+}
+
+static void
+mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       if (mctrl & TIOCM_RTS)
+               out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+       else
+               out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
+}
+
+static unsigned int
+mpc52xx_uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = TIOCM_DSR;
+       u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+
+       if (!(status & MPC52xx_PSC_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & MPC52xx_PSC_DCD))
+               ret |= TIOCM_CAR;
+
+       return ret;
+}
+
+static void
+mpc52xx_uart_stop_tx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->stop_tx(port);
+}
+
+static void
+mpc52xx_uart_start_tx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->start_tx(port);
+}
+
+static void
+mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->x_char = ch;
+       if (ch) {
+               /* Make sure tx interrupts are on */
+               /* Truly necessary ??? They should be anyway */
+               psc_ops->start_tx(port);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+mpc52xx_uart_stop_rx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       psc_ops->stop_rx(port);
+}
+
+static void
+mpc52xx_uart_enable_ms(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+
+       /* clear D_*-bits by reading them */
+       in_8(&psc->mpc52xx_psc_ipcr);
+       /* enable CTS and DCD as IPC interrupts */
+       out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void
+mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (ctl == -1)
+               out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
+       else
+               out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int
+mpc52xx_uart_startup(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       int ret;
+
+       if (psc_ops->clock) {
+               ret = psc_ops->clock(port, 1);
+               if (ret)
+                       return ret;
+       }
+
+       /* Request IRQ */
+       ret = request_irq(port->irq, mpc52xx_uart_int,
+                         port->irqflags, "mpc52xx_psc_uart", port);
+       if (ret)
+               return ret;
+
+       /* Reset/activate the port, clear and enable interrupts */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
+
+       psc_ops->fifo_init(port);
+
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+       return 0;
+}
+
+static void
+mpc52xx_uart_shutdown(struct uart_port *port)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+
+       /* Shut down the port.  Leave TX active if on a console port */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       if (!uart_console(port))
+               out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       port->read_status_mask = 0;
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+
+       if (psc_ops->clock)
+               psc_ops->clock(port, 0);
+
+       /* Release interrupt */
+       free_irq(port->irq, port);
+}
+
+static void
+mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
+                        struct ktermios *old)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       unsigned long flags;
+       unsigned char mr1, mr2;
+       unsigned int j;
+       unsigned int baud;
+
+       /* Prepare what we're gonna write */
+       mr1 = 0;
+
+       switch (new->c_cflag & CSIZE) {
+       case CS5:       mr1 |= MPC52xx_PSC_MODE_5_BITS;
+               break;
+       case CS6:       mr1 |= MPC52xx_PSC_MODE_6_BITS;
+               break;
+       case CS7:       mr1 |= MPC52xx_PSC_MODE_7_BITS;
+               break;
+       case CS8:
+       default:        mr1 |= MPC52xx_PSC_MODE_8_BITS;
+       }
+
+       if (new->c_cflag & PARENB) {
+               mr1 |= (new->c_cflag & PARODD) ?
+                       MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
+       } else
+               mr1 |= MPC52xx_PSC_MODE_PARNONE;
+
+
+       mr2 = 0;
+
+       if (new->c_cflag & CSTOPB)
+               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
+       else
+               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
+                       MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
+                       MPC52xx_PSC_MODE_ONE_STOP;
+
+       if (new->c_cflag & CRTSCTS) {
+               mr1 |= MPC52xx_PSC_MODE_RXRTS;
+               mr2 |= MPC52xx_PSC_MODE_TXCTS;
+       }
+
+       /* Get the lock */
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Do our best to flush TX & RX, so we don't lose anything */
+       /* But we don't wait indefinitely ! */
+       j = 5000000;    /* Maximum wait */
+       /* FIXME Can't receive chars since set_termios might be called at early
+        * boot for the console, all stuff is not yet ready to receive at that
+        * time and that just makes the kernel oops */
+       /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
+       while (!mpc52xx_uart_tx_empty(port) && --j)
+               udelay(1);
+
+       if (!j)
+               printk(KERN_ERR "mpc52xx_uart.c: "
+                       "Unable to flush RX & TX fifos in-time in set_termios."
+                       "Some chars may have been lost.\n");
+
+       /* Reset the TX & RX */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+       /* Send new mode settings */
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->mode, mr1);
+       out_8(&psc->mode, mr2);
+       baud = psc_ops->set_baudrate(port, new, old);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, new->c_cflag, baud);
+
+       if (UART_ENABLE_MS(port, new->c_cflag))
+               mpc52xx_uart_enable_ms(port);
+
+       /* Reenable TX & RX */
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+       /* We're all set, release the lock */
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *
+mpc52xx_uart_type(struct uart_port *port)
+{
+       /*
+        * We keep using PORT_MPC52xx for historic reasons although it applies
+        * for MPC512x, too, but print "MPC5xxx" to not irritate users
+        */
+       return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
+}
+
+static void
+mpc52xx_uart_release_port(struct uart_port *port)
+{
+       /* remapped by us ? */
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+}
+
+static int
+mpc52xx_uart_request_port(struct uart_port *port)
+{
+       int err;
+
+       if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+               port->membase = ioremap(port->mapbase,
+                                       sizeof(struct mpc52xx_psc));
+
+       if (!port->membase)
+               return -EINVAL;
+
+       err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
+                       "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+
+       if (err && (port->flags & UPF_IOREMAP)) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       return err;
+}
+
+static void
+mpc52xx_uart_config_port(struct uart_port *port, int flags)
+{
+       if ((flags & UART_CONFIG_TYPE)
+               && (mpc52xx_uart_request_port(port) == 0))
+               port->type = PORT_MPC52xx;
+}
+
+static int
+mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
+               return -EINVAL;
+
+       if ((ser->irq != port->irq) ||
+           (ser->io_type != UPIO_MEM) ||
+           (ser->baud_base != port->uartclk)  ||
+           (ser->iomem_base != (void *)port->mapbase) ||
+           (ser->hub6 != 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static struct uart_ops mpc52xx_uart_ops = {
+       .tx_empty       = mpc52xx_uart_tx_empty,
+       .set_mctrl      = mpc52xx_uart_set_mctrl,
+       .get_mctrl      = mpc52xx_uart_get_mctrl,
+       .stop_tx        = mpc52xx_uart_stop_tx,
+       .start_tx       = mpc52xx_uart_start_tx,
+       .send_xchar     = mpc52xx_uart_send_xchar,
+       .stop_rx        = mpc52xx_uart_stop_rx,
+       .enable_ms      = mpc52xx_uart_enable_ms,
+       .break_ctl      = mpc52xx_uart_break_ctl,
+       .startup        = mpc52xx_uart_startup,
+       .shutdown       = mpc52xx_uart_shutdown,
+       .set_termios    = mpc52xx_uart_set_termios,
+/*     .pm             = mpc52xx_uart_pm,              Not supported yet */
+/*     .set_wake       = mpc52xx_uart_set_wake,        Not supported yet */
+       .type           = mpc52xx_uart_type,
+       .release_port   = mpc52xx_uart_release_port,
+       .request_port   = mpc52xx_uart_request_port,
+       .config_port    = mpc52xx_uart_config_port,
+       .verify_port    = mpc52xx_uart_verify_port
+};
+
+
+/* ======================================================================== */
+/* Interrupt handling                                                       */
+/* ======================================================================== */
+
+static inline int
+mpc52xx_uart_int_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char ch, flag;
+       unsigned short status;
+
+       /* While we can read, do so ! */
+       while (psc_ops->raw_rx_rdy(port)) {
+               /* Get the char */
+               ch = psc_ops->read_char(port);
+
+               /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+               if (uart_handle_sysrq_char(port, ch)) {
+                       port->sysrq = 0;
+                       continue;
+               }
+#endif
+
+               /* Store it */
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               status = in_be16(&PSC(port)->mpc52xx_psc_status);
+
+               if (status & (MPC52xx_PSC_SR_PE |
+                             MPC52xx_PSC_SR_FE |
+                             MPC52xx_PSC_SR_RB)) {
+
+                       if (status & MPC52xx_PSC_SR_RB) {
+                               flag = TTY_BREAK;
+                               uart_handle_break(port);
+                               port->icount.brk++;
+                       } else if (status & MPC52xx_PSC_SR_PE) {
+                               flag = TTY_PARITY;
+                               port->icount.parity++;
+                       }
+                       else if (status & MPC52xx_PSC_SR_FE) {
+                               flag = TTY_FRAME;
+                               port->icount.frame++;
+                       }
+
+                       /* Clear error condition */
+                       out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
+
+               }
+               tty_insert_flip_char(tty, ch, flag);
+               if (status & MPC52xx_PSC_SR_OE) {
+                       /*
+                        * Overrun is special, since it's
+                        * reported immediately, and doesn't
+                        * affect the current character
+                        */
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+                       port->icount.overrun++;
+               }
+       }
+
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->lock);
+
+       return psc_ops->raw_rx_rdy(port);
+}
+
+static inline int
+mpc52xx_uart_int_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       /* Process out of band chars */
+       if (port->x_char) {
+               psc_ops->write_char(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       /* Nothing to do ? */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               mpc52xx_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Send chars */
+       while (psc_ops->raw_tx_rdy(port)) {
+               psc_ops->write_char(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       /* Maybe we're done after all */
+       if (uart_circ_empty(xmit)) {
+               mpc52xx_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+static irqreturn_t
+mpc5xxx_uart_process_int(struct uart_port *port)
+{
+       unsigned long pass = ISR_PASS_LIMIT;
+       unsigned int keepgoing;
+       u8 status;
+
+       /* While we have stuff to do, we continue */
+       do {
+               /* If we don't find anything to do, we stop */
+               keepgoing = 0;
+
+               psc_ops->rx_clr_irq(port);
+               if (psc_ops->rx_rdy(port))
+                       keepgoing |= mpc52xx_uart_int_rx_chars(port);
+
+               psc_ops->tx_clr_irq(port);
+               if (psc_ops->tx_rdy(port))
+                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
+
+               status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+               if (status & MPC52xx_PSC_D_DCD)
+                       uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+
+               if (status & MPC52xx_PSC_D_CTS)
+                       uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
+
+               /* Limit number of iteration */
+               if (!(--pass))
+                       keepgoing = 0;
+
+       } while (keepgoing);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+mpc52xx_uart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       irqreturn_t ret;
+
+       spin_lock(&port->lock);
+
+       ret = psc_ops->handle_irq(port);
+
+       spin_unlock(&port->lock);
+
+       return ret;
+}
+
+/* ======================================================================== */
+/* Console ( if applicable )                                                */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
+
+static void __init
+mpc52xx_console_get_options(struct uart_port *port,
+                           int *baud, int *parity, int *bits, int *flow)
+{
+       struct mpc52xx_psc __iomem *psc = PSC(port);
+       unsigned char mr1;
+
+       pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
+
+       /* Read the mode registers */
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       mr1 = in_8(&psc->mode);
+
+       /* CT{U,L}R are write-only ! */
+       *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+
+       /* Parse them */
+       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
+       case MPC52xx_PSC_MODE_5_BITS:
+               *bits = 5;
+               break;
+       case MPC52xx_PSC_MODE_6_BITS:
+               *bits = 6;
+               break;
+       case MPC52xx_PSC_MODE_7_BITS:
+               *bits = 7;
+               break;
+       case MPC52xx_PSC_MODE_8_BITS:
+       default:
+               *bits = 8;
+       }
+
+       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
+               *parity = 'n';
+       else
+               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
+}
+
+static void
+mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+       unsigned int i, j;
+
+       /* Disable interrupts */
+       psc_ops->cw_disable_ints(port);
+
+       /* Wait the TX buffer to be empty */
+       j = 5000000;    /* Maximum wait */
+       while (!mpc52xx_uart_tx_empty(port) && --j)
+               udelay(1);
+
+       /* Write all the chars */
+       for (i = 0; i < count; i++, s++) {
+               /* Line return handling */
+               if (*s == '\n')
+                       psc_ops->write_char(port, '\r');
+
+               /* Send the char */
+               psc_ops->write_char(port, *s);
+
+               /* Wait the TX buffer to be empty */
+               j = 20000;      /* Maximum wait */
+               while (!mpc52xx_uart_tx_empty(port) && --j)
+                       udelay(1);
+       }
+
+       /* Restore interrupt state */
+       psc_ops->cw_restore_ints(port);
+}
+
+
+static int __init
+mpc52xx_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+       struct device_node *np = mpc52xx_uart_nodes[co->index];
+       unsigned int uartclk;
+       struct resource res;
+       int ret;
+
+       int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
+                co, co->index, options);
+
+       if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) {
+               pr_debug("PSC%x out of range\n", co->index);
+               return -EINVAL;
+       }
+
+       if (!np) {
+               pr_debug("PSC%x not found in device tree\n", co->index);
+               return -EINVAL;
+       }
+
+       pr_debug("Console on ttyPSC%x is %s\n",
+                co->index, mpc52xx_uart_nodes[co->index]->full_name);
+
+       /* Fetch register locations */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               pr_debug("Could not get resources for PSC%x\n", co->index);
+               return ret;
+       }
+
+       uartclk = mpc5xxx_get_bus_frequency(np);
+       if (uartclk == 0) {
+               pr_debug("Could not find uart clock frequency!\n");
+               return -EINVAL;
+       }
+
+       /* Basic port init. Needed since we use some uart_??? func before
+        * real init for early access */
+       spin_lock_init(&port->lock);
+       port->uartclk = uartclk;
+       port->ops       = &mpc52xx_uart_ops;
+       port->mapbase = res.start;
+       port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
+       port->irq = irq_of_parse_and_map(np, 0);
+
+       if (port->membase == NULL)
+               return -EINVAL;
+
+       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+                (void *)port->mapbase, port->membase,
+                port->irq, port->uartclk);
+
+       /* Setup the port parameters accoding to options */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
+
+       pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
+                baud, bits, parity, flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver mpc52xx_uart_driver;
+
+static struct console mpc52xx_console = {
+       .name   = "ttyPSC",
+       .write  = mpc52xx_console_write,
+       .device = uart_console_device,
+       .setup  = mpc52xx_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,   /* Specified on the cmdline (e.g. console=ttyPSC0) */
+       .data   = &mpc52xx_uart_driver,
+};
+
+
+static int __init
+mpc52xx_console_init(void)
+{
+       mpc52xx_uart_of_enumerate();
+       register_console(&mpc52xx_console);
+       return 0;
+}
+
+console_initcall(mpc52xx_console_init);
+
+#define MPC52xx_PSC_CONSOLE &mpc52xx_console
+#else
+#define MPC52xx_PSC_CONSOLE NULL
+#endif
+
+
+/* ======================================================================== */
+/* UART Driver                                                              */
+/* ======================================================================== */
+
+static struct uart_driver mpc52xx_uart_driver = {
+       .driver_name    = "mpc52xx_psc_uart",
+       .dev_name       = "ttyPSC",
+       .major          = SERIAL_PSC_MAJOR,
+       .minor          = SERIAL_PSC_MINOR,
+       .nr             = MPC52xx_PSC_MAXNUM,
+       .cons           = MPC52xx_PSC_CONSOLE,
+};
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static struct of_device_id mpc52xx_uart_of_match[] = {
+#ifdef CONFIG_PPC_MPC52xx
+       { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
+       { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by old lite5200 device trees: */
+       { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
+       /* binding used by efika: */
+       { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
+#endif
+#ifdef CONFIG_PPC_MPC512x
+       { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
+#endif
+       {},
+};
+
+static int __devinit
+mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       int idx = -1;
+       unsigned int uartclk;
+       struct uart_port *port = NULL;
+       struct resource res;
+       int ret;
+
+       dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
+
+       /* Check validity & presence */
+       for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
+               if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
+                       break;
+       if (idx >= MPC52xx_PSC_MAXNUM)
+               return -EINVAL;
+       pr_debug("Found %s assigned to ttyPSC%x\n",
+                mpc52xx_uart_nodes[idx]->full_name, idx);
+
+       /* set the uart clock to the input clock of the psc, the different
+        * prescalers are taken into account in the set_baudrate() methods
+        * of the respective chip */
+       uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
+       if (uartclk == 0) {
+               dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
+               return -EINVAL;
+       }
+
+       /* Init the port structure */
+       port = &mpc52xx_uart_ports[idx];
+
+       spin_lock_init(&port->lock);
+       port->uartclk = uartclk;
+       port->fifosize  = 512;
+       port->iotype    = UPIO_MEM;
+       port->flags     = UPF_BOOT_AUTOCONF |
+                         (uart_console(port) ? 0 : UPF_IOREMAP);
+       port->line      = idx;
+       port->ops       = &mpc52xx_uart_ops;
+       port->dev       = &op->dev;
+
+       /* Search for IRQ and mapbase */
+       ret = of_address_to_resource(op->dev.of_node, 0, &res);
+       if (ret)
+               return ret;
+
+       port->mapbase = res.start;
+       if (!port->mapbase) {
+               dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
+               return -EINVAL;
+       }
+
+       psc_ops->get_irq(port, op->dev.of_node);
+       if (port->irq == NO_IRQ) {
+               dev_dbg(&op->dev, "Could not get irq\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+               (void *)port->mapbase, port->irq, port->uartclk);
+
+       /* Add the port to the uart sub-system */
+       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(&op->dev, (void *)port);
+       return 0;
+}
+
+static int
+mpc52xx_uart_of_remove(struct platform_device *op)
+{
+       struct uart_port *port = dev_get_drvdata(&op->dev);
+       dev_set_drvdata(&op->dev, NULL);
+
+       if (port)
+               uart_remove_one_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+
+       if (port)
+               uart_suspend_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+
+static int
+mpc52xx_uart_of_resume(struct platform_device *op)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+
+       if (port)
+               uart_resume_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+#endif
+
+static void
+mpc52xx_uart_of_assign(struct device_node *np)
+{
+       int i;
+
+       /* Find the first free PSC number */
+       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+               if (mpc52xx_uart_nodes[i] == NULL) {
+                       of_node_get(np);
+                       mpc52xx_uart_nodes[i] = np;
+                       return;
+               }
+       }
+}
+
+static void
+mpc52xx_uart_of_enumerate(void)
+{
+       static int enum_done;
+       struct device_node *np;
+       const struct  of_device_id *match;
+       int i;
+
+       if (enum_done)
+               return;
+
+       /* Assign index to each PSC in device tree */
+       for_each_matching_node(np, mpc52xx_uart_of_match) {
+               match = of_match_node(mpc52xx_uart_of_match, np);
+               psc_ops = match->data;
+               mpc52xx_uart_of_assign(np);
+       }
+
+       enum_done = 1;
+
+       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+               if (mpc52xx_uart_nodes[i])
+                       pr_debug("%s assigned to ttyPSC%x\n",
+                                mpc52xx_uart_nodes[i]->full_name, i);
+       }
+}
+
+MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
+
+static struct of_platform_driver mpc52xx_uart_of_driver = {
+       .probe          = mpc52xx_uart_of_probe,
+       .remove         = mpc52xx_uart_of_remove,
+#ifdef CONFIG_PM
+       .suspend        = mpc52xx_uart_of_suspend,
+       .resume         = mpc52xx_uart_of_resume,
+#endif
+       .driver = {
+               .name = "mpc52xx-psc-uart",
+               .owner = THIS_MODULE,
+               .of_match_table = mpc52xx_uart_of_match,
+       },
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_uart_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
+
+       ret = uart_register_driver(&mpc52xx_uart_driver);
+       if (ret) {
+               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+                      __FILE__, ret);
+               return ret;
+       }
+
+       mpc52xx_uart_of_enumerate();
+
+       /*
+        * Map the PSC FIFO Controller and init if on MPC512x.
+        */
+       if (psc_ops && psc_ops->fifoc_init) {
+               ret = psc_ops->fifoc_init();
+               if (ret)
+                       return ret;
+       }
+
+       ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
+       if (ret) {
+               printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
+                      __FILE__, ret);
+               uart_unregister_driver(&mpc52xx_uart_driver);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit
+mpc52xx_uart_exit(void)
+{
+       if (psc_ops->fifoc_uninit)
+               psc_ops->fifoc_uninit();
+
+       of_unregister_platform_driver(&mpc52xx_uart_of_driver);
+       uart_unregister_driver(&mpc52xx_uart_driver);
+}
+
+
+module_init(mpc52xx_uart_init);
+module_exit(mpc52xx_uart_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
new file mode 100644 (file)
index 0000000..6a9c660
--- /dev/null
@@ -0,0 +1,2159 @@
+/*
+ * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
+ * GT64260, MV64340, MV64360, GT96100, ... ).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Based on an old MPSC driver that was in the linuxppc tree.  It appears to
+ * have been created by Chris Zankel (formerly of MontaVista) but there
+ * is no proper Copyright so I'm not sure.  Apparently, parts were also
+ * taken from PPCBoot (now U-Boot).  Also based on drivers/serial/8250.c
+ * by Russell King.
+ *
+ * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+/*
+ * The MPSC interface is much like a typical network controller's interface.
+ * That is, you set up separate rings of descriptors for transmitting and
+ * receiving data.  There is also a pool of buffers with (one buffer per
+ * descriptor) that incoming data are dma'd into or outgoing data are dma'd
+ * out of.
+ *
+ * The MPSC requires two other controllers to be able to work.  The Baud Rate
+ * Generator (BRG) provides a clock at programmable frequencies which determines
+ * the baud rate.  The Serial DMA Controller (SDMA) takes incoming data from the
+ * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
+ * MPSC.  It is actually the SDMA interrupt that the driver uses to keep the
+ * transmit and receive "engines" going (i.e., indicate data has been
+ * transmitted or received).
+ *
+ * NOTES:
+ *
+ * 1) Some chips have an erratum where several regs cannot be
+ * read.  To work around that, we keep a local copy of those regs in
+ * 'mpsc_port_info'.
+ *
+ * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
+ * accesses system mem with coherency enabled.  For that reason, the driver
+ * assumes that coherency for that ctlr has been disabled.  This means
+ * that when in a cache coherent system, the driver has to manually manage
+ * the data cache on the areas that it touches because the dma_* macro are
+ * basically no-ops.
+ *
+ * 3) There is an erratum (on PPC) where you can't use the instruction to do
+ * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
+ * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
+ *
+ * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
+ */
+
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define        MPSC_NUM_CTLRS          2
+
+/*
+ * Descriptors and buffers must be cache line aligned.
+ * Buffers lengths must be multiple of cache line size.
+ * Number of Tx & Rx descriptors must be powers of 2.
+ */
+#define        MPSC_RXR_ENTRIES        32
+#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
+#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
+
+#define        MPSC_TXR_ENTRIES        32
+#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
+#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
+
+#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
+               + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
+
+/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
+struct mpsc_rx_desc {
+       u16 bufsize;
+       u16 bytecnt;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+struct mpsc_tx_desc {
+       u16 bytecnt;
+       u16 shadow;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+/*
+ * Some regs that have the erratum that you can't read them are are shared
+ * between the two MPSC controllers.  This struct contains those shared regs.
+ */
+struct mpsc_shared_regs {
+       phys_addr_t mpsc_routing_base_p;
+       phys_addr_t sdma_intr_base_p;
+
+       void __iomem *mpsc_routing_base;
+       void __iomem *sdma_intr_base;
+
+       u32 MPSC_MRR_m;
+       u32 MPSC_RCRR_m;
+       u32 MPSC_TCRR_m;
+       u32 SDMA_INTR_CAUSE_m;
+       u32 SDMA_INTR_MASK_m;
+};
+
+/* The main driver data structure */
+struct mpsc_port_info {
+       struct uart_port port;  /* Overlay uart_port structure */
+
+       /* Internal driver state for this ctlr */
+       u8 ready;
+       u8 rcv_data;
+       tcflag_t c_iflag;       /* save termios->c_iflag */
+       tcflag_t c_cflag;       /* save termios->c_cflag */
+
+       /* Info passed in from platform */
+       u8 mirror_regs;         /* Need to mirror regs? */
+       u8 cache_mgmt;          /* Need manual cache mgmt? */
+       u8 brg_can_tune;        /* BRG has baud tuning? */
+       u32 brg_clk_src;
+       u16 mpsc_max_idle;
+       int default_baud;
+       int default_bits;
+       int default_parity;
+       int default_flow;
+
+       /* Physical addresses of various blocks of registers (from platform) */
+       phys_addr_t mpsc_base_p;
+       phys_addr_t sdma_base_p;
+       phys_addr_t brg_base_p;
+
+       /* Virtual addresses of various blocks of registers (from platform) */
+       void __iomem *mpsc_base;
+       void __iomem *sdma_base;
+       void __iomem *brg_base;
+
+       /* Descriptor ring and buffer allocations */
+       void *dma_region;
+       dma_addr_t dma_region_p;
+
+       dma_addr_t rxr;         /* Rx descriptor ring */
+       dma_addr_t rxr_p;       /* Phys addr of rxr */
+       u8 *rxb;                /* Rx Ring I/O buf */
+       u8 *rxb_p;              /* Phys addr of rxb */
+       u32 rxr_posn;           /* First desc w/ Rx data */
+
+       dma_addr_t txr;         /* Tx descriptor ring */
+       dma_addr_t txr_p;       /* Phys addr of txr */
+       u8 *txb;                /* Tx Ring I/O buf */
+       u8 *txb_p;              /* Phys addr of txb */
+       int txr_head;           /* Where new data goes */
+       int txr_tail;           /* Where sent data comes off */
+       spinlock_t tx_lock;     /* transmit lock */
+
+       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
+       u32 MPSC_MPCR_m;
+       u32 MPSC_CHR_1_m;
+       u32 MPSC_CHR_2_m;
+       u32 MPSC_CHR_10_m;
+       u32 BRG_BCR_m;
+       struct mpsc_shared_regs *shared_regs;
+};
+
+/* Hooks to platform-specific code */
+int mpsc_platform_register_driver(void);
+void mpsc_platform_unregister_driver(void);
+
+/* Hooks back in to mpsc common to be called by platform-specific code */
+struct mpsc_port_info *mpsc_device_probe(int index);
+struct mpsc_port_info *mpsc_device_remove(int index);
+
+/* Main MPSC Configuration Register Offsets */
+#define        MPSC_MMCRL                      0x0000
+#define        MPSC_MMCRH                      0x0004
+#define        MPSC_MPCR                       0x0008
+#define        MPSC_CHR_1                      0x000c
+#define        MPSC_CHR_2                      0x0010
+#define        MPSC_CHR_3                      0x0014
+#define        MPSC_CHR_4                      0x0018
+#define        MPSC_CHR_5                      0x001c
+#define        MPSC_CHR_6                      0x0020
+#define        MPSC_CHR_7                      0x0024
+#define        MPSC_CHR_8                      0x0028
+#define        MPSC_CHR_9                      0x002c
+#define        MPSC_CHR_10                     0x0030
+#define        MPSC_CHR_11                     0x0034
+
+#define        MPSC_MPCR_FRZ                   (1 << 9)
+#define        MPSC_MPCR_CL_5                  0
+#define        MPSC_MPCR_CL_6                  1
+#define        MPSC_MPCR_CL_7                  2
+#define        MPSC_MPCR_CL_8                  3
+#define        MPSC_MPCR_SBL_1                 0
+#define        MPSC_MPCR_SBL_2                 1
+
+#define        MPSC_CHR_2_TEV                  (1<<1)
+#define        MPSC_CHR_2_TA                   (1<<7)
+#define        MPSC_CHR_2_TTCS                 (1<<9)
+#define        MPSC_CHR_2_REV                  (1<<17)
+#define        MPSC_CHR_2_RA                   (1<<23)
+#define        MPSC_CHR_2_CRD                  (1<<25)
+#define        MPSC_CHR_2_EH                   (1<<31)
+#define        MPSC_CHR_2_PAR_ODD              0
+#define        MPSC_CHR_2_PAR_SPACE            1
+#define        MPSC_CHR_2_PAR_EVEN             2
+#define        MPSC_CHR_2_PAR_MARK             3
+
+/* MPSC Signal Routing */
+#define        MPSC_MRR                        0x0000
+#define        MPSC_RCRR                       0x0004
+#define        MPSC_TCRR                       0x0008
+
+/* Serial DMA Controller Interface Registers */
+#define        SDMA_SDC                        0x0000
+#define        SDMA_SDCM                       0x0008
+#define        SDMA_RX_DESC                    0x0800
+#define        SDMA_RX_BUF_PTR                 0x0808
+#define        SDMA_SCRDP                      0x0810
+#define        SDMA_TX_DESC                    0x0c00
+#define        SDMA_SCTDP                      0x0c10
+#define        SDMA_SFTDP                      0x0c14
+
+#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
+#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
+#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
+#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
+#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
+#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
+#define        SDMA_DESC_CMDSTAT_A             (1<<11)
+#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
+#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
+#define        SDMA_DESC_CMDSTAT_C             (1<<14)
+#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
+#define        SDMA_DESC_CMDSTAT_L             (1<<16)
+#define        SDMA_DESC_CMDSTAT_F             (1<<17)
+#define        SDMA_DESC_CMDSTAT_P             (1<<18)
+#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
+#define        SDMA_DESC_CMDSTAT_O             (1<<31)
+
+#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O \
+               | SDMA_DESC_CMDSTAT_EI)
+
+#define        SDMA_SDC_RFT                    (1<<0)
+#define        SDMA_SDC_SFM                    (1<<1)
+#define        SDMA_SDC_BLMR                   (1<<6)
+#define        SDMA_SDC_BLMT                   (1<<7)
+#define        SDMA_SDC_POVR                   (1<<8)
+#define        SDMA_SDC_RIFB                   (1<<9)
+
+#define        SDMA_SDCM_ERD                   (1<<7)
+#define        SDMA_SDCM_AR                    (1<<15)
+#define        SDMA_SDCM_STD                   (1<<16)
+#define        SDMA_SDCM_TXD                   (1<<23)
+#define        SDMA_SDCM_AT                    (1<<31)
+
+#define        SDMA_0_CAUSE_RXBUF              (1<<0)
+#define        SDMA_0_CAUSE_RXERR              (1<<1)
+#define        SDMA_0_CAUSE_TXBUF              (1<<2)
+#define        SDMA_0_CAUSE_TXEND              (1<<3)
+#define        SDMA_1_CAUSE_RXBUF              (1<<8)
+#define        SDMA_1_CAUSE_RXERR              (1<<9)
+#define        SDMA_1_CAUSE_TXBUF              (1<<10)
+#define        SDMA_1_CAUSE_TXEND              (1<<11)
+
+#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
+               | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
+#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
+               | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
+
+/* SDMA Interrupt registers */
+#define        SDMA_INTR_CAUSE                 0x0000
+#define        SDMA_INTR_MASK                  0x0080
+
+/* Baud Rate Generator Interface Registers */
+#define        BRG_BCR                         0x0000
+#define        BRG_BTR                         0x0004
+
+/*
+ * Define how this driver is known to the outside (we've been assigned a
+ * range on the "Low-density serial ports" major).
+ */
+#define MPSC_MAJOR                     204
+#define MPSC_MINOR_START               44
+#define        MPSC_DRIVER_NAME                "MPSC"
+#define        MPSC_DEV_NAME                   "ttyMM"
+#define        MPSC_VERSION                    "1.00"
+
+static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
+static struct mpsc_shared_regs mpsc_shared_regs;
+static struct uart_driver mpsc_reg;
+
+static void mpsc_start_rx(struct mpsc_port_info *pi);
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
+static void mpsc_release_port(struct uart_port *port);
+/*
+ ******************************************************************************
+ *
+ * Baud Rate Generator Routines (BRG)
+ *
+ ******************************************************************************
+ */
+static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
+
+       if (pi->brg_can_tune)
+               v &= ~(1 << 25);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+
+       writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
+               pi->brg_base + BRG_BTR);
+}
+
+static void mpsc_brg_enable(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v |= (1 << 16);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+}
+
+static void mpsc_brg_disable(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v &= ~(1 << 16);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+}
+
+/*
+ * To set the baud, we adjust the CDV field in the BRG_BCR reg.
+ * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
+ * However, the input clock is divided by 16 in the MPSC b/c of how
+ * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
+ * calculation by 16 to account for that.  So the real calculation
+ * that accounts for the way the mpsc is set up is:
+ * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
+ */
+static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
+{
+       u32     cdv = (pi->port.uartclk / (baud << 5)) - 1;
+       u32     v;
+
+       mpsc_brg_disable(pi);
+       v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
+       v = (v & 0xffff0000) | (cdv & 0xffff);
+
+       if (pi->mirror_regs)
+               pi->BRG_BCR_m = v;
+       writel(v, pi->brg_base + BRG_BCR);
+       mpsc_brg_enable(pi);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Serial DMA Routines (SDMA)
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
+{
+       u32     v;
+
+       pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
+                       pi->port.line, burst_size);
+
+       burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
+
+       if (burst_size < 2)
+               v = 0x0;        /* 1 64-bit word */
+       else if (burst_size < 4)
+               v = 0x1;        /* 2 64-bit words */
+       else if (burst_size < 8)
+               v = 0x2;        /* 4 64-bit words */
+       else
+               v = 0x3;        /* 8 64-bit words */
+
+       writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
+               pi->sdma_base + SDMA_SDC);
+}
+
+static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
+{
+       pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
+               burst_size);
+
+       writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
+               pi->sdma_base + SDMA_SDC);
+       mpsc_sdma_burstsize(pi, burst_size);
+}
+
+static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
+{
+       u32     old, v;
+
+       pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
+
+       old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
+               readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       mask &= 0xf;
+       if (pi->port.line)
+               mask <<= 8;
+       v &= ~mask;
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_MASK_m = v;
+       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       if (pi->port.line)
+               old >>= 8;
+       return old & 0xf;
+}
+
+static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
+{
+       u32     v;
+
+       pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
+
+       v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
+               : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+
+       mask &= 0xf;
+       if (pi->port.line)
+               mask <<= 8;
+       v |= mask;
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_MASK_m = v;
+       writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+}
+
+static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
+
+       if (pi->mirror_regs)
+               pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
+       writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
+                       + pi->port.line);
+}
+
+static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
+               struct mpsc_rx_desc *rxre_p)
+{
+       pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
+               pi->port.line, (u32)rxre_p);
+
+       writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
+}
+
+static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
+               struct mpsc_tx_desc *txre_p)
+{
+       writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
+       writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
+}
+
+static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
+{
+       u32     v;
+
+       v = readl(pi->sdma_base + SDMA_SDCM);
+       if (val)
+               v |= val;
+       else
+               v = 0;
+       wmb();
+       writel(v, pi->sdma_base + SDMA_SDCM);
+       wmb();
+}
+
+static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
+{
+       return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
+}
+
+static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
+{
+       struct mpsc_tx_desc *txre, *txre_p;
+
+       /* If tx isn't running & there's a desc ready to go, start it */
+       if (!mpsc_sdma_tx_active(pi)) {
+               txre = (struct mpsc_tx_desc *)(pi->txr
+                               + (pi->txr_tail * MPSC_TXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)txre,
+                                       (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+
+               if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
+                       txre_p = (struct mpsc_tx_desc *)
+                               (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
+
+                       mpsc_sdma_set_tx_ring(pi, txre_p);
+                       mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
+               }
+       }
+}
+
+static void mpsc_sdma_stop(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
+
+       /* Abort any SDMA transfers */
+       mpsc_sdma_cmd(pi, 0);
+       mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
+
+       /* Clear the SDMA current and first TX and RX pointers */
+       mpsc_sdma_set_tx_ring(pi, NULL);
+       mpsc_sdma_set_rx_ring(pi, NULL);
+
+       /* Disable interrupts */
+       mpsc_sdma_intr_mask(pi, 0xf);
+       mpsc_sdma_intr_ack(pi);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Multi-Protocol Serial Controller Routines (MPSC)
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_hw_init(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
+
+       /* Set up clock routing */
+       if (pi->mirror_regs) {
+               v = pi->shared_regs->MPSC_MRR_m;
+               v &= ~0x1c7;
+               pi->shared_regs->MPSC_MRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+
+               v = pi->shared_regs->MPSC_RCRR_m;
+               v = (v & ~0xf0f) | 0x100;
+               pi->shared_regs->MPSC_RCRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+
+               v = pi->shared_regs->MPSC_TCRR_m;
+               v = (v & ~0xf0f) | 0x100;
+               pi->shared_regs->MPSC_TCRR_m = v;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+       } else {
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+               v &= ~0x1c7;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
+
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+               v = (v & ~0xf0f) | 0x100;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
+
+               v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+               v = (v & ~0xf0f) | 0x100;
+               writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
+       }
+
+       /* Put MPSC in UART mode & enabel Tx/Rx egines */
+       writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
+
+       /* No preamble, 16x divider, low-latency, */
+       writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
+       mpsc_set_baudrate(pi, pi->default_baud);
+
+       if (pi->mirror_regs) {
+               pi->MPSC_CHR_1_m = 0;
+               pi->MPSC_CHR_2_m = 0;
+       }
+       writel(0, pi->mpsc_base + MPSC_CHR_1);
+       writel(0, pi->mpsc_base + MPSC_CHR_2);
+       writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
+       writel(0, pi->mpsc_base + MPSC_CHR_4);
+       writel(0, pi->mpsc_base + MPSC_CHR_5);
+       writel(0, pi->mpsc_base + MPSC_CHR_6);
+       writel(0, pi->mpsc_base + MPSC_CHR_7);
+       writel(0, pi->mpsc_base + MPSC_CHR_8);
+       writel(0, pi->mpsc_base + MPSC_CHR_9);
+       writel(0, pi->mpsc_base + MPSC_CHR_10);
+}
+
+static void mpsc_enter_hunt(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
+
+       if (pi->mirror_regs) {
+               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
+                       pi->mpsc_base + MPSC_CHR_2);
+               /* Erratum prevents reading CHR_2 so just delay for a while */
+               udelay(100);
+       } else {
+               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
+                               pi->mpsc_base + MPSC_CHR_2);
+
+               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
+                       udelay(10);
+       }
+}
+
+static void mpsc_freeze(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v |= MPSC_MPCR_FRZ;
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_unfreeze(struct mpsc_port_info *pi)
+{
+       u32     v;
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v &= ~MPSC_MPCR_FRZ;
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+
+       pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
+}
+
+static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+       v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
+               pi->port.line, len);
+
+       v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
+               readl(pi->mpsc_base + MPSC_MPCR);
+
+       v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
+
+       if (pi->mirror_regs)
+               pi->MPSC_MPCR_m = v;
+       writel(v, pi->mpsc_base + MPSC_MPCR);
+}
+
+static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
+{
+       u32     v;
+
+       pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
+
+       v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
+               readl(pi->mpsc_base + MPSC_CHR_2);
+
+       p &= 0x3;
+       v = (v & ~0xc000c) | (p << 18) | (p << 2);
+
+       if (pi->mirror_regs)
+               pi->MPSC_CHR_2_m = v;
+       writel(v, pi->mpsc_base + MPSC_CHR_2);
+}
+
+/*
+ ******************************************************************************
+ *
+ * Driver Init Routines
+ *
+ ******************************************************************************
+ */
+
+static void mpsc_init_hw(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
+
+       mpsc_brg_init(pi, pi->brg_clk_src);
+       mpsc_brg_enable(pi);
+       mpsc_sdma_init(pi, dma_get_cache_alignment());  /* burst a cacheline */
+       mpsc_sdma_stop(pi);
+       mpsc_hw_init(pi);
+}
+
+static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
+{
+       int rc = 0;
+
+       pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
+               pi->port.line);
+
+       if (!pi->dma_region) {
+               if (!dma_supported(pi->port.dev, 0xffffffff)) {
+                       printk(KERN_ERR "MPSC: Inadequate DMA support\n");
+                       rc = -ENXIO;
+               } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
+                                               MPSC_DMA_ALLOC_SIZE,
+                                               &pi->dma_region_p, GFP_KERNEL))
+                               == NULL) {
+                       printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
+                       rc = -ENOMEM;
+               }
+       }
+
+       return rc;
+}
+
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
+
+       if (pi->dma_region) {
+               dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
+                               pi->dma_region, pi->dma_region_p);
+               pi->dma_region = NULL;
+               pi->dma_region_p = (dma_addr_t)NULL;
+       }
+}
+
+static void mpsc_init_rings(struct mpsc_port_info *pi)
+{
+       struct mpsc_rx_desc *rxre;
+       struct mpsc_tx_desc *txre;
+       dma_addr_t dp, dp_p;
+       u8 *bp, *bp_p;
+       int i;
+
+       pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
+
+       BUG_ON(pi->dma_region == NULL);
+
+       memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
+
+       /*
+        * Descriptors & buffers are multiples of cacheline size and must be
+        * cacheline aligned.
+        */
+       dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
+       dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
+
+       /*
+        * Partition dma region into rx ring descriptor, rx buffers,
+        * tx ring descriptors, and tx buffers.
+        */
+       pi->rxr = dp;
+       pi->rxr_p = dp_p;
+       dp += MPSC_RXR_SIZE;
+       dp_p += MPSC_RXR_SIZE;
+
+       pi->rxb = (u8 *)dp;
+       pi->rxb_p = (u8 *)dp_p;
+       dp += MPSC_RXB_SIZE;
+       dp_p += MPSC_RXB_SIZE;
+
+       pi->rxr_posn = 0;
+
+       pi->txr = dp;
+       pi->txr_p = dp_p;
+       dp += MPSC_TXR_SIZE;
+       dp_p += MPSC_TXR_SIZE;
+
+       pi->txb = (u8 *)dp;
+       pi->txb_p = (u8 *)dp_p;
+
+       pi->txr_head = 0;
+       pi->txr_tail = 0;
+
+       /* Init rx ring descriptors */
+       dp = pi->rxr;
+       dp_p = pi->rxr_p;
+       bp = pi->rxb;
+       bp_p = pi->rxb_p;
+
+       for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
+               rxre = (struct mpsc_rx_desc *)dp;
+
+               rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
+               rxre->bytecnt = cpu_to_be16(0);
+               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+                               | SDMA_DESC_CMDSTAT_L);
+               rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
+               rxre->buf_ptr = cpu_to_be32(bp_p);
+
+               dp += MPSC_RXRE_SIZE;
+               dp_p += MPSC_RXRE_SIZE;
+               bp += MPSC_RXBE_SIZE;
+               bp_p += MPSC_RXBE_SIZE;
+       }
+       rxre->link = cpu_to_be32(pi->rxr_p);    /* Wrap last back to first */
+
+       /* Init tx ring descriptors */
+       dp = pi->txr;
+       dp_p = pi->txr_p;
+       bp = pi->txb;
+       bp_p = pi->txb_p;
+
+       for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
+               txre = (struct mpsc_tx_desc *)dp;
+
+               txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
+               txre->buf_ptr = cpu_to_be32(bp_p);
+
+               dp += MPSC_TXRE_SIZE;
+               dp_p += MPSC_TXRE_SIZE;
+               bp += MPSC_TXBE_SIZE;
+               bp_p += MPSC_TXBE_SIZE;
+       }
+       txre->link = cpu_to_be32(pi->txr_p);    /* Wrap last back to first */
+
+       dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
+                       MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)pi->dma_region,
+                                       (ulong)pi->dma_region
+                                       + MPSC_DMA_ALLOC_SIZE);
+#endif
+
+       return;
+}
+
+static void mpsc_uninit_rings(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
+
+       BUG_ON(pi->dma_region == NULL);
+
+       pi->rxr = 0;
+       pi->rxr_p = 0;
+       pi->rxb = NULL;
+       pi->rxb_p = NULL;
+       pi->rxr_posn = 0;
+
+       pi->txr = 0;
+       pi->txr_p = 0;
+       pi->txb = NULL;
+       pi->txb_p = NULL;
+       pi->txr_head = 0;
+       pi->txr_tail = 0;
+}
+
+static int mpsc_make_ready(struct mpsc_port_info *pi)
+{
+       int rc;
+
+       pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
+
+       if (!pi->ready) {
+               mpsc_init_hw(pi);
+               if ((rc = mpsc_alloc_ring_mem(pi)))
+                       return rc;
+               mpsc_init_rings(pi);
+               pi->ready = 1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
+/*
+ ******************************************************************************
+ *
+ * Interrupt Handling Routines
+ *
+ ******************************************************************************
+ */
+
+static int mpsc_rx_intr(struct mpsc_port_info *pi)
+{
+       struct mpsc_rx_desc *rxre;
+       struct tty_struct *tty = pi->port.state->port.tty;
+       u32     cmdstat, bytes_in, i;
+       int     rc = 0;
+       u8      *bp;
+       char    flag = TTY_NORMAL;
+
+       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
+
+       rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
+
+       dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                       DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+               invalidate_dcache_range((ulong)rxre,
+                               (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+       /*
+        * Loop through Rx descriptors handling ones that have been completed.
+        */
+       while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
+                               & SDMA_DESC_CMDSTAT_O)) {
+               bytes_in = be16_to_cpu(rxre->bytecnt);
+#ifdef CONFIG_CONSOLE_POLL
+               if (unlikely(serial_polled)) {
+                       serial_polled = 0;
+                       return 0;
+               }
+#endif
+               /* Following use of tty struct directly is deprecated */
+               if (unlikely(tty_buffer_request_room(tty, bytes_in)
+                                       < bytes_in)) {
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
+                       /*
+                        * If this failed then we will throw away the bytes
+                        * but must do so to clear interrupts.
+                        */
+               }
+
+               bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_RXBE_SIZE);
+#endif
+
+               /*
+                * Other than for parity error, the manual provides little
+                * info on what data will be in a frame flagged by any of
+                * these errors.  For parity error, it is the last byte in
+                * the buffer that had the error.  As for the rest, I guess
+                * we'll assume there is no data in the buffer.
+                * If there is...it gets lost.
+                */
+               if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+                                               | SDMA_DESC_CMDSTAT_FR
+                                               | SDMA_DESC_CMDSTAT_OR))) {
+
+                       pi->port.icount.rx++;
+
+                       if (cmdstat & SDMA_DESC_CMDSTAT_BR) {   /* Break */
+                               pi->port.icount.brk++;
+
+                               if (uart_handle_break(&pi->port))
+                                       goto next_frame;
+                       } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
+                               pi->port.icount.frame++;
+                       } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
+                               pi->port.icount.overrun++;
+                       }
+
+                       cmdstat &= pi->port.read_status_mask;
+
+                       if (cmdstat & SDMA_DESC_CMDSTAT_BR)
+                               flag = TTY_BREAK;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
+                               flag = TTY_FRAME;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
+                               flag = TTY_OVERRUN;
+                       else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(&pi->port, *bp)) {
+                       bp++;
+                       bytes_in--;
+#ifdef CONFIG_CONSOLE_POLL
+                       if (unlikely(serial_polled)) {
+                               serial_polled = 0;
+                               return 0;
+                       }
+#endif
+                       goto next_frame;
+               }
+
+               if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+                                               | SDMA_DESC_CMDSTAT_FR
+                                               | SDMA_DESC_CMDSTAT_OR)))
+                               && !(cmdstat & pi->port.ignore_status_mask)) {
+                       tty_insert_flip_char(tty, *bp, flag);
+               } else {
+                       for (i=0; i<bytes_in; i++)
+                               tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
+
+                       pi->port.icount.rx += bytes_in;
+               }
+
+next_frame:
+               rxre->bytecnt = cpu_to_be16(0);
+               wmb();
+               rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+                               | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+                               | SDMA_DESC_CMDSTAT_L);
+               wmb();
+               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)rxre,
+                                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+               /* Advance to next descriptor */
+               pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
+               rxre = (struct mpsc_rx_desc *)
+                       (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)rxre,
+                                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               rc = 1;
+       }
+
+       /* Restart rx engine, if its stopped */
+       if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
+               mpsc_start_rx(pi);
+
+       tty_flip_buffer_push(tty);
+       return rc;
+}
+
+static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
+{
+       struct mpsc_tx_desc *txre;
+
+       txre = (struct mpsc_tx_desc *)(pi->txr
+                       + (pi->txr_head * MPSC_TXRE_SIZE));
+
+       txre->bytecnt = cpu_to_be16(count);
+       txre->shadow = txre->bytecnt;
+       wmb();                  /* ensure cmdstat is last field updated */
+       txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
+                       | SDMA_DESC_CMDSTAT_L
+                       | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
+       wmb();
+       dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                       DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+               flush_dcache_range((ulong)txre,
+                               (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+}
+
+static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
+{
+       struct circ_buf *xmit = &pi->port.state->xmit;
+       u8 *bp;
+       u32 i;
+
+       /* Make sure the desc ring isn't full */
+       while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
+                       < (MPSC_TXR_ENTRIES - 1)) {
+               if (pi->port.x_char) {
+                       /*
+                        * Ideally, we should use the TCS field in
+                        * CHR_1 to put the x_char out immediately but
+                        * errata prevents us from being able to read
+                        * CHR_2 to know that its safe to write to
+                        * CHR_1.  Instead, just put it in-band with
+                        * all the other Tx data.
+                        */
+                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+                       *bp = pi->port.x_char;
+                       pi->port.x_char = 0;
+                       i = 1;
+               } else if (!uart_circ_empty(xmit)
+                               && !uart_tx_stopped(&pi->port)) {
+                       i = min((u32)MPSC_TXBE_SIZE,
+                               (u32)uart_circ_chars_pending(xmit));
+                       i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
+                               UART_XMIT_SIZE));
+                       bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+                       memcpy(bp, &xmit->buf[xmit->tail], i);
+                       xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
+
+                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                               uart_write_wakeup(&pi->port);
+               } else { /* All tx data copied into ring bufs */
+                       return;
+               }
+
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_TXBE_SIZE);
+#endif
+               mpsc_setup_tx_desc(pi, i, 1);
+
+               /* Advance to next descriptor */
+               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
+       }
+}
+
+static int mpsc_tx_intr(struct mpsc_port_info *pi)
+{
+       struct mpsc_tx_desc *txre;
+       int rc = 0;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       if (!mpsc_sdma_tx_active(pi)) {
+               txre = (struct mpsc_tx_desc *)(pi->txr
+                               + (pi->txr_tail * MPSC_TXRE_SIZE));
+
+               dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+                               DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)txre,
+                                       (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+
+               while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
+                       rc = 1;
+                       pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
+                       pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
+
+                       /* If no more data to tx, fall out of loop */
+                       if (pi->txr_head == pi->txr_tail)
+                               break;
+
+                       txre = (struct mpsc_tx_desc *)(pi->txr
+                                       + (pi->txr_tail * MPSC_TXRE_SIZE));
+                       dma_cache_sync(pi->port.dev, (void *)txre,
+                                       MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)txre,
+                                               (ulong)txre + MPSC_TXRE_SIZE);
+#endif
+               }
+
+               mpsc_copy_tx_data(pi);
+               mpsc_sdma_start_tx(pi); /* start next desc if ready */
+       }
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+       return rc;
+}
+
+/*
+ * This is the driver's interrupt handler.  To avoid a race, we first clear
+ * the interrupt, then handle any completed Rx/Tx descriptors.  When done
+ * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
+ */
+static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
+{
+       struct mpsc_port_info *pi = dev_id;
+       ulong iflags;
+       int rc = IRQ_NONE;
+
+       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
+
+       spin_lock_irqsave(&pi->port.lock, iflags);
+       mpsc_sdma_intr_ack(pi);
+       if (mpsc_rx_intr(pi))
+               rc = IRQ_HANDLED;
+       if (mpsc_tx_intr(pi))
+               rc = IRQ_HANDLED;
+       spin_unlock_irqrestore(&pi->port.lock, iflags);
+
+       pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
+       return rc;
+}
+
+/*
+ ******************************************************************************
+ *
+ * serial_core.c Interface routines
+ *
+ ******************************************************************************
+ */
+static uint mpsc_tx_empty(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       ulong iflags;
+       uint rc;
+
+       spin_lock_irqsave(&pi->port.lock, iflags);
+       rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
+       spin_unlock_irqrestore(&pi->port.lock, iflags);
+
+       return rc;
+}
+
+static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
+{
+       /* Have no way to set modem control lines AFAICT */
+}
+
+static uint mpsc_get_mctrl(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 mflags, status;
+
+       status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
+               : readl(pi->mpsc_base + MPSC_CHR_10);
+
+       mflags = 0;
+       if (status & 0x1)
+               mflags |= TIOCM_CTS;
+       if (status & 0x2)
+               mflags |= TIOCM_CAR;
+
+       return mflags | TIOCM_DSR;      /* No way to tell if DSR asserted */
+}
+
+static void mpsc_stop_tx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_stop_tx[%d]\n", port->line);
+
+       mpsc_freeze(pi);
+}
+
+static void mpsc_start_tx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       mpsc_unfreeze(pi);
+       mpsc_copy_tx_data(pi);
+       mpsc_sdma_start_tx(pi);
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+
+       pr_debug("mpsc_start_tx[%d]\n", port->line);
+}
+
+static void mpsc_start_rx(struct mpsc_port_info *pi)
+{
+       pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
+
+       if (pi->rcv_data) {
+               mpsc_enter_hunt(pi);
+               mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
+       }
+}
+
+static void mpsc_stop_rx(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
+
+       if (pi->mirror_regs) {
+               writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
+                               pi->mpsc_base + MPSC_CHR_2);
+               /* Erratum prevents reading CHR_2 so just delay for a while */
+               udelay(100);
+       } else {
+               writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
+                               pi->mpsc_base + MPSC_CHR_2);
+
+               while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
+                       udelay(10);
+       }
+
+       mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
+}
+
+static void mpsc_enable_ms(struct uart_port *port)
+{
+}
+
+static void mpsc_break_ctl(struct uart_port *port, int ctl)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       ulong   flags;
+       u32     v;
+
+       v = ctl ? 0x00ff0000 : 0;
+
+       spin_lock_irqsave(&pi->port.lock, flags);
+       if (pi->mirror_regs)
+               pi->MPSC_CHR_1_m = v;
+       writel(v, pi->mpsc_base + MPSC_CHR_1);
+       spin_unlock_irqrestore(&pi->port.lock, flags);
+}
+
+static int mpsc_startup(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 flag = 0;
+       int rc;
+
+       pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
+               port->line, pi->port.irq);
+
+       if ((rc = mpsc_make_ready(pi)) == 0) {
+               /* Setup IRQ handler */
+               mpsc_sdma_intr_ack(pi);
+
+               /* If irq's are shared, need to set flag */
+               if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
+                       flag = IRQF_SHARED;
+
+               if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
+                                       "mpsc-sdma", pi))
+                       printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
+                                       pi->port.irq);
+
+               mpsc_sdma_intr_unmask(pi, 0xf);
+               mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
+                                       + (pi->rxr_posn * MPSC_RXRE_SIZE)));
+       }
+
+       return rc;
+}
+
+static void mpsc_shutdown(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
+
+       mpsc_sdma_stop(pi);
+       free_irq(pi->port.irq, pi);
+}
+
+static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+                struct ktermios *old)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 baud;
+       ulong flags;
+       u32 chr_bits, stop_bits, par;
+
+       pi->c_iflag = termios->c_iflag;
+       pi->c_cflag = termios->c_cflag;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               chr_bits = MPSC_MPCR_CL_5;
+               break;
+       case CS6:
+               chr_bits = MPSC_MPCR_CL_6;
+               break;
+       case CS7:
+               chr_bits = MPSC_MPCR_CL_7;
+               break;
+       case CS8:
+       default:
+               chr_bits = MPSC_MPCR_CL_8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               stop_bits = MPSC_MPCR_SBL_2;
+       else
+               stop_bits = MPSC_MPCR_SBL_1;
+
+       par = MPSC_CHR_2_PAR_EVEN;
+       if (termios->c_cflag & PARENB)
+               if (termios->c_cflag & PARODD)
+                       par = MPSC_CHR_2_PAR_ODD;
+#ifdef CMSPAR
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               par = MPSC_CHR_2_PAR_MARK;
+                       else
+                               par = MPSC_CHR_2_PAR_SPACE;
+               }
+#endif
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
+
+       spin_lock_irqsave(&pi->port.lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       mpsc_set_char_length(pi, chr_bits);
+       mpsc_set_stop_bit_length(pi, stop_bits);
+       mpsc_set_parity(pi, par);
+       mpsc_set_baudrate(pi, baud);
+
+       /* Characters/events to read */
+       pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
+
+       if (termios->c_iflag & INPCK)
+               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
+                       | SDMA_DESC_CMDSTAT_FR;
+
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
+
+       /* Characters/events to ignore */
+       pi->port.ignore_status_mask = 0;
+
+       if (termios->c_iflag & IGNPAR)
+               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
+                       | SDMA_DESC_CMDSTAT_FR;
+
+       if (termios->c_iflag & IGNBRK) {
+               pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
+
+               if (termios->c_iflag & IGNPAR)
+                       pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
+       }
+
+       if ((termios->c_cflag & CREAD)) {
+               if (!pi->rcv_data) {
+                       pi->rcv_data = 1;
+                       mpsc_start_rx(pi);
+               }
+       } else if (pi->rcv_data) {
+               mpsc_stop_rx(port);
+               pi->rcv_data = 0;
+       }
+
+       spin_unlock_irqrestore(&pi->port.lock, flags);
+}
+
+static const char *mpsc_type(struct uart_port *port)
+{
+       pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
+       return MPSC_DRIVER_NAME;
+}
+
+static int mpsc_request_port(struct uart_port *port)
+{
+       /* Should make chip/platform specific call */
+       return 0;
+}
+
+static void mpsc_release_port(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+
+       if (pi->ready) {
+               mpsc_uninit_rings(pi);
+               mpsc_free_ring_mem(pi);
+               pi->ready = 0;
+       }
+}
+
+static void mpsc_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       int rc = 0;
+
+       pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
+               rc = -EINVAL;
+       else if (pi->port.irq != ser->irq)
+               rc = -EINVAL;
+       else if (ser->io_type != SERIAL_IO_MEM)
+               rc = -EINVAL;
+       else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
+               rc = -EINVAL;
+       else if ((void *)pi->port.mapbase != ser->iomem_base)
+               rc = -EINVAL;
+       else if (pi->port.iobase != ser->port)
+               rc = -EINVAL;
+       else if (ser->hub6 != 0)
+               rc = -EINVAL;
+
+       return rc;
+}
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static char poll_buf[2048];
+static int poll_ptr;
+static int poll_cnt;
+static void mpsc_put_poll_char(struct uart_port *port,
+                                                          unsigned char c);
+
+static int mpsc_get_poll_char(struct uart_port *port)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       struct mpsc_rx_desc *rxre;
+       u32     cmdstat, bytes_in, i;
+       u8      *bp;
+
+       if (!serial_polled)
+               serial_polled = 1;
+
+       pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
+
+       if (poll_cnt) {
+               poll_cnt--;
+               return poll_buf[poll_ptr++];
+       }
+       poll_ptr = 0;
+       poll_cnt = 0;
+
+       while (poll_cnt == 0) {
+               rxre = (struct mpsc_rx_desc *)(pi->rxr +
+                      (pi->rxr_posn*MPSC_RXRE_SIZE));
+               dma_cache_sync(pi->port.dev, (void *)rxre,
+                              MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       invalidate_dcache_range((ulong)rxre,
+                       (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               /*
+                * Loop through Rx descriptors handling ones that have
+                * been completed.
+                */
+               while (poll_cnt == 0 &&
+                      !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
+                        SDMA_DESC_CMDSTAT_O)){
+                       bytes_in = be16_to_cpu(rxre->bytecnt);
+                       bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
+                       dma_cache_sync(pi->port.dev, (void *) bp,
+                                      MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_RXBE_SIZE);
+#endif
+                       if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
+                        SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
+                               !(cmdstat & pi->port.ignore_status_mask)) {
+                               poll_buf[poll_cnt] = *bp;
+                               poll_cnt++;
+                       } else {
+                               for (i = 0; i < bytes_in; i++) {
+                                       poll_buf[poll_cnt] = *bp++;
+                                       poll_cnt++;
+                               }
+                               pi->port.icount.rx += bytes_in;
+                       }
+                       rxre->bytecnt = cpu_to_be16(0);
+                       wmb();
+                       rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
+                                                   SDMA_DESC_CMDSTAT_EI |
+                                                   SDMA_DESC_CMDSTAT_F |
+                                                   SDMA_DESC_CMDSTAT_L);
+                       wmb();
+                       dma_cache_sync(pi->port.dev, (void *)rxre,
+                                      MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               flush_dcache_range((ulong)rxre,
+                                          (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+                       /* Advance to next descriptor */
+                       pi->rxr_posn = (pi->rxr_posn + 1) &
+                               (MPSC_RXR_ENTRIES - 1);
+                       rxre = (struct mpsc_rx_desc *)(pi->rxr +
+                                      (pi->rxr_posn * MPSC_RXRE_SIZE));
+                       dma_cache_sync(pi->port.dev, (void *)rxre,
+                                      MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+                       if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                               invalidate_dcache_range((ulong)rxre,
+                                               (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+               }
+
+               /* Restart rx engine, if its stopped */
+               if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
+                       mpsc_start_rx(pi);
+       }
+       if (poll_cnt) {
+               poll_cnt--;
+               return poll_buf[poll_ptr++];
+       }
+
+       return 0;
+}
+
+
+static void mpsc_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+       u32 data;
+
+       data = readl(pi->mpsc_base + MPSC_MPCR);
+       writeb(c, pi->mpsc_base + MPSC_CHR_1);
+       mb();
+       data = readl(pi->mpsc_base + MPSC_CHR_2);
+       data |= MPSC_CHR_2_TTCS;
+       writel(data, pi->mpsc_base + MPSC_CHR_2);
+       mb();
+
+       while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
+}
+#endif
+
+static struct uart_ops mpsc_pops = {
+       .tx_empty       = mpsc_tx_empty,
+       .set_mctrl      = mpsc_set_mctrl,
+       .get_mctrl      = mpsc_get_mctrl,
+       .stop_tx        = mpsc_stop_tx,
+       .start_tx       = mpsc_start_tx,
+       .stop_rx        = mpsc_stop_rx,
+       .enable_ms      = mpsc_enable_ms,
+       .break_ctl      = mpsc_break_ctl,
+       .startup        = mpsc_startup,
+       .shutdown       = mpsc_shutdown,
+       .set_termios    = mpsc_set_termios,
+       .type           = mpsc_type,
+       .release_port   = mpsc_release_port,
+       .request_port   = mpsc_request_port,
+       .config_port    = mpsc_config_port,
+       .verify_port    = mpsc_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = mpsc_get_poll_char,
+       .poll_put_char = mpsc_put_poll_char,
+#endif
+};
+
+/*
+ ******************************************************************************
+ *
+ * Console Interface Routines
+ *
+ ******************************************************************************
+ */
+
+#ifdef CONFIG_SERIAL_MPSC_CONSOLE
+static void mpsc_console_write(struct console *co, const char *s, uint count)
+{
+       struct mpsc_port_info *pi = &mpsc_ports[co->index];
+       u8 *bp, *dp, add_cr = 0;
+       int i;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&pi->tx_lock, iflags);
+
+       while (pi->txr_head != pi->txr_tail) {
+               while (mpsc_sdma_tx_active(pi))
+                       udelay(100);
+               mpsc_sdma_intr_ack(pi);
+               mpsc_tx_intr(pi);
+       }
+
+       while (mpsc_sdma_tx_active(pi))
+               udelay(100);
+
+       while (count > 0) {
+               bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
+
+               for (i = 0; i < MPSC_TXBE_SIZE; i++) {
+                       if (count == 0)
+                               break;
+
+                       if (add_cr) {
+                               *(dp++) = '\r';
+                               add_cr = 0;
+                       } else {
+                               *(dp++) = *s;
+
+                               if (*(s++) == '\n') { /* add '\r' after '\n' */
+                                       add_cr = 1;
+                                       count++;
+                               }
+                       }
+
+                       count--;
+               }
+
+               dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+                               DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+               if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+                       flush_dcache_range((ulong)bp,
+                                       (ulong)bp + MPSC_TXBE_SIZE);
+#endif
+               mpsc_setup_tx_desc(pi, i, 0);
+               pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
+               mpsc_sdma_start_tx(pi);
+
+               while (mpsc_sdma_tx_active(pi))
+                       udelay(100);
+
+               pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
+       }
+
+       spin_unlock_irqrestore(&pi->tx_lock, iflags);
+}
+
+static int __init mpsc_console_setup(struct console *co, char *options)
+{
+       struct mpsc_port_info *pi;
+       int baud, bits, parity, flow;
+
+       pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
+
+       if (co->index >= MPSC_NUM_CTLRS)
+               co->index = 0;
+
+       pi = &mpsc_ports[co->index];
+
+       baud = pi->default_baud;
+       bits = pi->default_bits;
+       parity = pi->default_parity;
+       flow = pi->default_flow;
+
+       if (!pi->port.ops)
+               return -ENODEV;
+
+       spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&pi->port, co, baud, parity, bits, flow);
+}
+
+static struct console mpsc_console = {
+       .name   = MPSC_DEV_NAME,
+       .write  = mpsc_console_write,
+       .device = uart_console_device,
+       .setup  = mpsc_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &mpsc_reg,
+};
+
+static int __init mpsc_late_console_init(void)
+{
+       pr_debug("mpsc_late_console_init: Enter\n");
+
+       if (!(mpsc_console.flags & CON_ENABLED))
+               register_console(&mpsc_console);
+       return 0;
+}
+
+late_initcall(mpsc_late_console_init);
+
+#define MPSC_CONSOLE   &mpsc_console
+#else
+#define MPSC_CONSOLE   NULL
+#endif
+/*
+ ******************************************************************************
+ *
+ * Dummy Platform Driver to extract & map shared register regions
+ *
+ ******************************************************************************
+ */
+static void mpsc_resource_err(char *s)
+{
+       printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
+}
+
+static int mpsc_shared_map_regs(struct platform_device *pd)
+{
+       struct resource *r;
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_ROUTING_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_ROUTING_REG_BLOCK_SIZE,
+                               "mpsc_routing_regs")) {
+               mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+               mpsc_shared_regs.mpsc_routing_base_p = r->start;
+       } else {
+               mpsc_resource_err("MPSC routing base");
+               return -ENOMEM;
+       }
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_SDMA_INTR_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_SDMA_INTR_REG_BLOCK_SIZE,
+                               "sdma_intr_regs")) {
+               mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
+                       MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+               mpsc_shared_regs.sdma_intr_base_p = r->start;
+       } else {
+               iounmap(mpsc_shared_regs.mpsc_routing_base);
+               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+               mpsc_resource_err("SDMA intr base");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void mpsc_shared_unmap_regs(void)
+{
+       if (!mpsc_shared_regs.mpsc_routing_base) {
+               iounmap(mpsc_shared_regs.mpsc_routing_base);
+               release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
+                               MPSC_ROUTING_REG_BLOCK_SIZE);
+       }
+       if (!mpsc_shared_regs.sdma_intr_base) {
+               iounmap(mpsc_shared_regs.sdma_intr_base);
+               release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
+                               MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+       }
+
+       mpsc_shared_regs.mpsc_routing_base = NULL;
+       mpsc_shared_regs.sdma_intr_base = NULL;
+
+       mpsc_shared_regs.mpsc_routing_base_p = 0;
+       mpsc_shared_regs.sdma_intr_base_p = 0;
+}
+
+static int mpsc_shared_drv_probe(struct platform_device *dev)
+{
+       struct mpsc_shared_pdata        *pdata;
+       int                              rc = -ENODEV;
+
+       if (dev->id == 0) {
+               if (!(rc = mpsc_shared_map_regs(dev))) {
+                       pdata = (struct mpsc_shared_pdata *)
+                               dev->dev.platform_data;
+
+                       mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
+                       mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
+                       mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
+                       mpsc_shared_regs.SDMA_INTR_CAUSE_m =
+                               pdata->intr_cause_val;
+                       mpsc_shared_regs.SDMA_INTR_MASK_m =
+                               pdata->intr_mask_val;
+
+                       rc = 0;
+               }
+       }
+
+       return rc;
+}
+
+static int mpsc_shared_drv_remove(struct platform_device *dev)
+{
+       int     rc = -ENODEV;
+
+       if (dev->id == 0) {
+               mpsc_shared_unmap_regs();
+               mpsc_shared_regs.MPSC_MRR_m = 0;
+               mpsc_shared_regs.MPSC_RCRR_m = 0;
+               mpsc_shared_regs.MPSC_TCRR_m = 0;
+               mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
+               mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
+               rc = 0;
+       }
+
+       return rc;
+}
+
+static struct platform_driver mpsc_shared_driver = {
+       .probe  = mpsc_shared_drv_probe,
+       .remove = mpsc_shared_drv_remove,
+       .driver = {
+               .name   = MPSC_SHARED_NAME,
+       },
+};
+
+/*
+ ******************************************************************************
+ *
+ * Driver Interface Routines
+ *
+ ******************************************************************************
+ */
+static struct uart_driver mpsc_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = MPSC_DRIVER_NAME,
+       .dev_name       = MPSC_DEV_NAME,
+       .major          = MPSC_MAJOR,
+       .minor          = MPSC_MINOR_START,
+       .nr             = MPSC_NUM_CTLRS,
+       .cons           = MPSC_CONSOLE,
+};
+
+static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
+               struct platform_device *pd)
+{
+       struct resource *r;
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
+                       && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
+                       "mpsc_regs")) {
+               pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
+               pi->mpsc_base_p = r->start;
+       } else {
+               mpsc_resource_err("MPSC base");
+               goto err;
+       }
+
+       if ((r = platform_get_resource(pd, IORESOURCE_MEM,
+                                       MPSC_SDMA_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
+               pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
+               pi->sdma_base_p = r->start;
+       } else {
+               mpsc_resource_err("SDMA base");
+               if (pi->mpsc_base) {
+                       iounmap(pi->mpsc_base);
+                       pi->mpsc_base = NULL;
+               }
+               goto err;
+       }
+
+       if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
+                       && request_mem_region(r->start,
+                               MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
+               pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
+               pi->brg_base_p = r->start;
+       } else {
+               mpsc_resource_err("BRG base");
+               if (pi->mpsc_base) {
+                       iounmap(pi->mpsc_base);
+                       pi->mpsc_base = NULL;
+               }
+               if (pi->sdma_base) {
+                       iounmap(pi->sdma_base);
+                       pi->sdma_base = NULL;
+               }
+               goto err;
+       }
+       return 0;
+
+err:
+       return -ENOMEM;
+}
+
+static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
+{
+       if (!pi->mpsc_base) {
+               iounmap(pi->mpsc_base);
+               release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
+       }
+       if (!pi->sdma_base) {
+               iounmap(pi->sdma_base);
+               release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
+       }
+       if (!pi->brg_base) {
+               iounmap(pi->brg_base);
+               release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
+       }
+
+       pi->mpsc_base = NULL;
+       pi->sdma_base = NULL;
+       pi->brg_base = NULL;
+
+       pi->mpsc_base_p = 0;
+       pi->sdma_base_p = 0;
+       pi->brg_base_p = 0;
+}
+
+static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
+               struct platform_device *pd, int num)
+{
+       struct mpsc_pdata       *pdata;
+
+       pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+
+       pi->port.uartclk = pdata->brg_clk_freq;
+       pi->port.iotype = UPIO_MEM;
+       pi->port.line = num;
+       pi->port.type = PORT_MPSC;
+       pi->port.fifosize = MPSC_TXBE_SIZE;
+       pi->port.membase = pi->mpsc_base;
+       pi->port.mapbase = (ulong)pi->mpsc_base;
+       pi->port.ops = &mpsc_pops;
+
+       pi->mirror_regs = pdata->mirror_regs;
+       pi->cache_mgmt = pdata->cache_mgmt;
+       pi->brg_can_tune = pdata->brg_can_tune;
+       pi->brg_clk_src = pdata->brg_clk_src;
+       pi->mpsc_max_idle = pdata->max_idle;
+       pi->default_baud = pdata->default_baud;
+       pi->default_bits = pdata->default_bits;
+       pi->default_parity = pdata->default_parity;
+       pi->default_flow = pdata->default_flow;
+
+       /* Initial values of mirrored regs */
+       pi->MPSC_CHR_1_m = pdata->chr_1_val;
+       pi->MPSC_CHR_2_m = pdata->chr_2_val;
+       pi->MPSC_CHR_10_m = pdata->chr_10_val;
+       pi->MPSC_MPCR_m = pdata->mpcr_val;
+       pi->BRG_BCR_m = pdata->bcr_val;
+
+       pi->shared_regs = &mpsc_shared_regs;
+
+       pi->port.irq = platform_get_irq(pd, 0);
+}
+
+static int mpsc_drv_probe(struct platform_device *dev)
+{
+       struct mpsc_port_info   *pi;
+       int                     rc = -ENODEV;
+
+       pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
+
+       if (dev->id < MPSC_NUM_CTLRS) {
+               pi = &mpsc_ports[dev->id];
+
+               if (!(rc = mpsc_drv_map_regs(pi, dev))) {
+                       mpsc_drv_get_platform_data(pi, dev, dev->id);
+                       pi->port.dev = &dev->dev;
+
+                       if (!(rc = mpsc_make_ready(pi))) {
+                               spin_lock_init(&pi->tx_lock);
+                               if (!(rc = uart_add_one_port(&mpsc_reg,
+                                                               &pi->port))) {
+                                       rc = 0;
+                               } else {
+                                       mpsc_release_port((struct uart_port *)
+                                                       pi);
+                                       mpsc_drv_unmap_regs(pi);
+                               }
+                       } else {
+                               mpsc_drv_unmap_regs(pi);
+                       }
+               }
+       }
+
+       return rc;
+}
+
+static int mpsc_drv_remove(struct platform_device *dev)
+{
+       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
+
+       if (dev->id < MPSC_NUM_CTLRS) {
+               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
+               mpsc_release_port((struct uart_port *)
+                               &mpsc_ports[dev->id].port);
+               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
+               return 0;
+       } else {
+               return -ENODEV;
+       }
+}
+
+static struct platform_driver mpsc_driver = {
+       .probe  = mpsc_drv_probe,
+       .remove = mpsc_drv_remove,
+       .driver = {
+               .name   = MPSC_CTLR_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init mpsc_drv_init(void)
+{
+       int     rc;
+
+       printk(KERN_INFO "Serial: MPSC driver\n");
+
+       memset(mpsc_ports, 0, sizeof(mpsc_ports));
+       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
+
+       if (!(rc = uart_register_driver(&mpsc_reg))) {
+               if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
+                       if ((rc = platform_driver_register(&mpsc_driver))) {
+                               platform_driver_unregister(&mpsc_shared_driver);
+                               uart_unregister_driver(&mpsc_reg);
+                       }
+               } else {
+                       uart_unregister_driver(&mpsc_reg);
+               }
+       }
+
+       return rc;
+}
+
+static void __exit mpsc_drv_exit(void)
+{
+       platform_driver_unregister(&mpsc_driver);
+       platform_driver_unregister(&mpsc_shared_driver);
+       uart_unregister_driver(&mpsc_reg);
+       memset(mpsc_ports, 0, sizeof(mpsc_ports));
+       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
+}
+
+module_init(mpsc_drv_init);
+module_exit(mpsc_drv_exit);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
+MODULE_VERSION(MPSC_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
+MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
new file mode 100644 (file)
index 0000000..b62857b
--- /dev/null
@@ -0,0 +1,919 @@
+/*
+ *  mrst_max3110.c - spi uart protocol driver for Maxim 3110
+ *
+ * Copyright (c) 2008-2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Note:
+ * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
+ *    1 word. If SPI master controller doesn't support sclk frequency change,
+ *    then the char need be sent out one by one with some delay
+ *
+ * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE
+ *    interrupt for a low speed UART device
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include <linux/kthread.h>
+#include <linux/spi/spi.h>
+
+#include "mrst_max3110.h"
+
+#define PR_FMT "mrst_max3110: "
+
+#define UART_TX_NEEDED 1
+#define CON_TX_NEEDED  2
+#define BIT_IRQ_PENDING    3
+
+struct uart_max3110 {
+       struct uart_port port;
+       struct spi_device *spi;
+       char name[24];
+
+       wait_queue_head_t wq;
+       struct task_struct *main_thread;
+       struct task_struct *read_thread;
+       struct mutex thread_mutex;;
+
+       u32 baud;
+       u16 cur_conf;
+       u8 clock;
+       u8 parity, word_7bits;
+       u16 irq;
+
+       unsigned long uart_flags;
+
+       /* console related */
+       struct circ_buf con_xmit;
+};
+
+/* global data structure, may need be removed */
+static struct uart_max3110 *pmax;
+
+static void receive_chars(struct uart_max3110 *max,
+                               unsigned char *str, int len);
+static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
+static void max3110_con_receive(struct uart_max3110 *max);
+
+static int max3110_write_then_read(struct uart_max3110 *max,
+               const void *txbuf, void *rxbuf, unsigned len, int always_fast)
+{
+       struct spi_device *spi = max->spi;
+       struct spi_message      message;
+       struct spi_transfer     x;
+       int ret;
+
+       spi_message_init(&message);
+       memset(&x, 0, sizeof x);
+       x.len = len;
+       x.tx_buf = txbuf;
+       x.rx_buf = rxbuf;
+       spi_message_add_tail(&x, &message);
+
+       if (always_fast)
+               x.speed_hz = spi->max_speed_hz;
+       else if (max->baud)
+               x.speed_hz = max->baud;
+
+       /* Do the i/o */
+       ret = spi_sync(spi, &message);
+       return ret;
+}
+
+/* Write a 16b word to the device */
+static int max3110_out(struct uart_max3110 *max, const u16 out)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8  ch;
+       int ret;
+
+       buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return -ENOMEM;
+
+       obuf = buf;
+       ibuf = buf + 4;
+       *obuf = out;
+       ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
+       if (ret) {
+               pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n",
+                               __func__, ret, out);
+               goto exit;
+       }
+
+       /* If some valid data is read back */
+       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
+               ch = *ibuf & 0xff;
+               receive_chars(max, &ch, 1);
+       }
+
+exit:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * This is usually used to read data from SPIC RX FIFO, which doesn't
+ * need any delay like flushing character out.
+ *
+ * Return how many valide bytes are read back
+ */
+static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
+       int i, j, blen;
+
+       blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
+       buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
+       if (!buf) {
+               pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__);
+               return 0;
+       }
+
+       /* tx/rx always have the same length */
+       obuf = buf;
+       ibuf = buf + blen;
+
+       if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
+               kfree(buf);
+               return 0;
+       }
+
+       /* If caller doesn't provide a buffer, then handle received char */
+       pbuf = rxbuf ? rxbuf : valid_str;
+
+       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
+               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
+                       pbuf[j++] = ibuf[i] & 0xff;
+       }
+
+       if (j && (pbuf == valid_str))
+               receive_chars(max, valid_str, j);
+
+       kfree(buf);
+       return j;
+}
+
+static void serial_m3110_con_putchar(struct uart_port *port, int ch)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       struct circ_buf *xmit = &max->con_xmit;
+
+       if (uart_circ_chars_free(xmit)) {
+               xmit->buf[xmit->head] = (char)ch;
+               xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
+       }
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void serial_m3110_con_write(struct console *co,
+                               const char *s, unsigned int count)
+{
+       if (!pmax)
+               return;
+
+       uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
+
+       if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
+               wake_up_process(pmax->main_thread);
+}
+
+static int __init
+serial_m3110_con_setup(struct console *co, char *options)
+{
+       struct uart_max3110 *max = pmax;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       pr_info(PR_FMT "setting up console\n");
+
+       if (co->index == -1)
+               co->index = 0;
+
+       if (!max) {
+               pr_err(PR_FMT "pmax is NULL, return");
+               return -ENODEV;
+       }
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&max->port, co, baud, parity, bits, flow);
+}
+
+static struct tty_driver *serial_m3110_con_device(struct console *co,
+                                                       int *index)
+{
+       struct uart_driver *p = co->data;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+static struct uart_driver serial_m3110_reg;
+static struct console serial_m3110_console = {
+       .name           = "ttyS",
+       .write          = serial_m3110_con_write,
+       .device         = serial_m3110_con_device,
+       .setup          = serial_m3110_con_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_m3110_reg,
+};
+
+static unsigned int serial_m3110_tx_empty(struct uart_port *port)
+{
+       return 1;
+}
+
+static void serial_m3110_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* stop_rx will be called in spin_lock env */
+static void serial_m3110_stop_rx(struct uart_port *port)
+{
+       return;
+}
+
+#define WORDS_PER_XFER 128
+static void send_circ_buf(struct uart_max3110 *max,
+                               struct circ_buf *xmit)
+{
+       void *buf;
+       u16 *obuf, *ibuf;
+       u8 valid_str[WORDS_PER_XFER];
+       int i, j, len, blen, dma_size, left, ret = 0;
+
+
+       dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
+       buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return;
+       obuf = buf;
+       ibuf = buf + dma_size/2;
+
+       while (!uart_circ_empty(xmit)) {
+               left = uart_circ_chars_pending(xmit);
+               while (left) {
+                       len = min(left, WORDS_PER_XFER);
+                       blen = len * sizeof(u16);
+                       memset(ibuf, 0, blen);
+
+                       for (i = 0; i < len; i++) {
+                               obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
+                               xmit->tail = (xmit->tail + 1) &
+                                               (UART_XMIT_SIZE - 1);
+                       }
+
+                       /* Fail to send msg to console is not very critical */
+                       ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
+                       if (ret)
+                               pr_warning(PR_FMT "%s(): get err msg %d\n",
+                                               __func__, ret);
+
+                       for (i = 0, j = 0; i < len; i++) {
+                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
+                                       valid_str[j++] = ibuf[i] & 0xff;
+                       }
+
+                       if (j)
+                               receive_chars(max, valid_str, j);
+
+                       max->port.icount.tx += len;
+                       left -= len;
+               }
+       }
+
+       kfree(buf);
+}
+
+static void transmit_char(struct uart_max3110 *max)
+{
+       struct uart_port *port = &max->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       send_circ_buf(max, xmit);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               serial_m3110_stop_tx(port);
+}
+
+/*
+ * This will be called by uart_write() and tty_write, can't
+ * go to sleep
+ */
+static void serial_m3110_start_tx(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+
+       if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
+               wake_up_process(max->main_thread);
+}
+
+static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
+{
+       struct uart_port *port = &max->port;
+       struct tty_struct *tty;
+       int usable;
+
+       /* If uart is not opened, just return */
+       if (!port->state)
+               return;
+
+       tty = port->state->port.tty;
+       if (!tty)
+               return;
+
+       while (len) {
+               usable = tty_buffer_request_room(tty, len);
+               if (usable) {
+                       tty_insert_flip_string(tty, str, usable);
+                       str += usable;
+                       port->icount.rx += usable;
+               }
+               len -= usable;
+       }
+       tty_flip_buffer_push(tty);
+}
+
+/*
+ * This routine will be used in read_thread or RX IRQ handling,
+ * it will first do one round buffer read(8 words), if there is some
+ * valid RX data, will try to read 5 more rounds till all data
+ * is read out.
+ *
+ * Use stack space as data buffer to save some system load, and chose
+ * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
+ * receiving bulk data, a much bigger buffer may cause stack overflow
+ */
+static void max3110_con_receive(struct uart_max3110 *max)
+{
+       int loop = 1, num, total = 0;
+       u8 recv_buf[512], *pbuf;
+
+       pbuf = recv_buf;
+       do {
+               num = max3110_read_multi(max, pbuf);
+
+               if (num) {
+                       loop = 5;
+                       pbuf += num;
+                       total += num;
+
+                       if (total >= 504) {
+                               receive_chars(max, recv_buf, total);
+                               pbuf = recv_buf;
+                               total = 0;
+                       }
+               }
+       } while (--loop);
+
+       if (total)
+               receive_chars(max, recv_buf, total);
+}
+
+static int max3110_main_thread(void *_max)
+{
+       struct uart_max3110 *max = _max;
+       wait_queue_head_t *wq = &max->wq;
+       int ret = 0;
+       struct circ_buf *xmit = &max->con_xmit;
+
+       init_waitqueue_head(wq);
+       pr_info(PR_FMT "start main thread\n");
+
+       do {
+               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
+
+               mutex_lock(&max->thread_mutex);
+
+               if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
+                       max3110_con_receive(max);
+
+               /* first handle console output */
+               if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
+                       send_circ_buf(max, xmit);
+
+               /* handle uart output */
+               if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
+                       transmit_char(max);
+
+               mutex_unlock(&max->thread_mutex);
+
+       } while (!kthread_should_stop());
+
+       return ret;
+}
+
+static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
+{
+       struct uart_max3110 *max = dev_id;
+
+       /* max3110's irq is a falling edge, not level triggered,
+        * so no need to disable the irq */
+       if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
+               wake_up_process(max->main_thread);
+
+       return IRQ_HANDLED;
+}
+
+/* if don't use RX IRQ, then need a thread to polling read */
+static int max3110_read_thread(void *_max)
+{
+       struct uart_max3110 *max = _max;
+
+       pr_info(PR_FMT "start read thread\n");
+       do {
+               /*
+                * If can't acquire the mutex, it means the main thread
+                * is running which will also perform the rx job
+                */
+               if (mutex_trylock(&max->thread_mutex)) {
+                       max3110_con_receive(max);
+                       mutex_unlock(&max->thread_mutex);
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ / 20);
+       } while (!kthread_should_stop());
+
+       return 0;
+}
+
+static int serial_m3110_startup(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       u16 config = 0;
+       int ret = 0;
+
+       if (port->line != 0) {
+               pr_err(PR_FMT "uart port startup failed\n");
+               return -1;
+       }
+
+       /* Disable all IRQ and config it to 115200, 8n1 */
+       config = WC_TAG | WC_FIFO_ENABLE
+                       | WC_1_STOPBITS
+                       | WC_8BIT_WORD
+                       | WC_BAUD_DR2;
+
+       /* as we use thread to handle tx/rx, need set low latency */
+       port->state->port.tty->low_latency = 1;
+
+       if (max->irq) {
+               max->read_thread = NULL;
+               ret = request_irq(max->irq, serial_m3110_irq,
+                               IRQ_TYPE_EDGE_FALLING, "max3110", max);
+               if (ret) {
+                       max->irq = 0;
+                       pr_err(PR_FMT "unable to allocate IRQ, polling\n");
+               }  else {
+                       /* Enable RX IRQ only */
+                       config |= WC_RXA_IRQ_ENABLE;
+               }
+       }
+
+       if (max->irq == 0) {
+               /* If IRQ is disabled, start a read thread for input data */
+               max->read_thread =
+                       kthread_run(max3110_read_thread, max, "max3110_read");
+               if (IS_ERR(max->read_thread)) {
+                       ret = PTR_ERR(max->read_thread);
+                       max->read_thread = NULL;
+                       pr_err(PR_FMT "Can't create read thread!\n");
+                       return ret;
+               }
+       }
+
+       ret = max3110_out(max, config);
+       if (ret) {
+               if (max->irq)
+                       free_irq(max->irq, max);
+               if (max->read_thread)
+                       kthread_stop(max->read_thread);
+               max->read_thread = NULL;
+               return ret;
+       }
+
+       max->cur_conf = config;
+       return 0;
+}
+
+static void serial_m3110_shutdown(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       u16 config;
+
+       if (max->read_thread) {
+               kthread_stop(max->read_thread);
+               max->read_thread = NULL;
+       }
+
+       if (max->irq)
+               free_irq(max->irq, max);
+
+       /* Disable interrupts from this port */
+       config = WC_TAG | WC_SW_SHDI;
+       max3110_out(max, config);
+}
+
+static void serial_m3110_release_port(struct uart_port *port)
+{
+}
+
+static int serial_m3110_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_m3110_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_MAX3100;
+}
+
+static int
+serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+
+static const char *serial_m3110_type(struct uart_port *port)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       return max->name;
+}
+
+static void
+serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_max3110 *max =
+               container_of(port, struct uart_max3110, port);
+       unsigned char cval;
+       unsigned int baud, parity = 0;
+       int clk_div = -1;
+       u16 new_conf = max->cur_conf;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               new_conf |= WC_7BIT_WORD;
+               break;
+       default:
+               /* We only support CS7 & CS8 */
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= CS8;
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               new_conf |= WC_8BIT_WORD;
+               break;
+       }
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+
+       /* First calc the div for 1.8MHZ clock case */
+       switch (baud) {
+       case 300:
+               clk_div = WC_BAUD_DR384;
+               break;
+       case 600:
+               clk_div = WC_BAUD_DR192;
+               break;
+       case 1200:
+               clk_div = WC_BAUD_DR96;
+               break;
+       case 2400:
+               clk_div = WC_BAUD_DR48;
+               break;
+       case 4800:
+               clk_div = WC_BAUD_DR24;
+               break;
+       case 9600:
+               clk_div = WC_BAUD_DR12;
+               break;
+       case 19200:
+               clk_div = WC_BAUD_DR6;
+               break;
+       case 38400:
+               clk_div = WC_BAUD_DR3;
+               break;
+       case 57600:
+               clk_div = WC_BAUD_DR2;
+               break;
+       case 115200:
+               clk_div = WC_BAUD_DR1;
+               break;
+       case 230400:
+               if (max->clock & MAX3110_HIGH_CLK)
+                       break;
+       default:
+               /* Pick the previous baud rate */
+               baud = max->baud;
+               clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+
+       if (max->clock & MAX3110_HIGH_CLK) {
+               clk_div += 1;
+               /* High clk version max3110 doesn't support B300 */
+               if (baud == 300) {
+                       baud = 600;
+                       clk_div = WC_BAUD_DR384;
+               }
+               if (baud == 230400)
+                       clk_div = WC_BAUD_DR1;
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       }
+
+       new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
+
+       if (unlikely(termios->c_cflag & CMSPAR))
+               termios->c_cflag &= ~CMSPAR;
+
+       if (termios->c_cflag & CSTOPB)
+               new_conf |= WC_2_STOPBITS;
+       else
+               new_conf &= ~WC_2_STOPBITS;
+
+       if (termios->c_cflag & PARENB) {
+               new_conf |= WC_PARITY_ENABLE;
+               parity |= UART_LCR_PARITY;
+       } else
+               new_conf &= ~WC_PARITY_ENABLE;
+
+       if (!(termios->c_cflag & PARODD))
+               parity |= UART_LCR_EPAR;
+       max->parity = parity;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       new_conf |= WC_TAG;
+       if (new_conf != max->cur_conf) {
+               if (!max3110_out(max, new_conf)) {
+                       max->cur_conf = new_conf;
+                       max->baud = baud;
+               }
+       }
+}
+
+/* Don't handle hw handshaking */
+static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
+}
+
+static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void serial_m3110_pm(struct uart_port *port, unsigned int state,
+                       unsigned int oldstate)
+{
+}
+
+static void serial_m3110_enable_ms(struct uart_port *port)
+{
+}
+
+struct uart_ops serial_m3110_ops = {
+       .tx_empty       = serial_m3110_tx_empty,
+       .set_mctrl      = serial_m3110_set_mctrl,
+       .get_mctrl      = serial_m3110_get_mctrl,
+       .stop_tx        = serial_m3110_stop_tx,
+       .start_tx       = serial_m3110_start_tx,
+       .stop_rx        = serial_m3110_stop_rx,
+       .enable_ms      = serial_m3110_enable_ms,
+       .break_ctl      = serial_m3110_break_ctl,
+       .startup        = serial_m3110_startup,
+       .shutdown       = serial_m3110_shutdown,
+       .set_termios    = serial_m3110_set_termios,
+       .pm             = serial_m3110_pm,
+       .type           = serial_m3110_type,
+       .release_port   = serial_m3110_release_port,
+       .request_port   = serial_m3110_request_port,
+       .config_port    = serial_m3110_config_port,
+       .verify_port    = serial_m3110_verify_port,
+};
+
+static struct uart_driver serial_m3110_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "MRST serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = 1,
+       .cons           = &serial_m3110_console,
+};
+
+#ifdef CONFIG_PM
+static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct uart_max3110 *max = spi_get_drvdata(spi);
+
+       disable_irq(max->irq);
+       uart_suspend_port(&serial_m3110_reg, &max->port);
+       max3110_out(max, max->cur_conf | WC_SW_SHDI);
+       return 0;
+}
+
+static int serial_m3110_resume(struct spi_device *spi)
+{
+       struct uart_max3110 *max = spi_get_drvdata(spi);
+
+       max3110_out(max, max->cur_conf);
+       uart_resume_port(&serial_m3110_reg, &max->port);
+       enable_irq(max->irq);
+       return 0;
+}
+#else
+#define serial_m3110_suspend   NULL
+#define serial_m3110_resume    NULL
+#endif
+
+static int __devinit serial_m3110_probe(struct spi_device *spi)
+{
+       struct uart_max3110 *max;
+       void *buffer;
+       u16 res;
+       int ret = 0;
+
+       max = kzalloc(sizeof(*max), GFP_KERNEL);
+       if (!max)
+               return -ENOMEM;
+
+       /* Set spi info */
+       spi->bits_per_word = 16;
+       max->clock = MAX3110_HIGH_CLK;
+
+       spi_setup(spi);
+
+       max->port.type = PORT_MAX3100;
+       max->port.fifosize = 2;         /* Only have 16b buffer */
+       max->port.ops = &serial_m3110_ops;
+       max->port.line = 0;
+       max->port.dev = &spi->dev;
+       max->port.uartclk = 115200;
+
+       max->spi = spi;
+       strcpy(max->name, spi->modalias);
+       max->irq = (u16)spi->irq;
+
+       mutex_init(&max->thread_mutex);
+
+       max->word_7bits = 0;
+       max->parity = 0;
+       max->baud = 0;
+
+       max->cur_conf = 0;
+       max->uart_flags = 0;
+
+       /* Check if reading configuration register returns something sane */
+
+       res = RC_TAG;
+       ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
+       if (ret < 0 || res == 0 || res == 0xffff) {
+               printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
+                                                                       res);
+               ret = -ENODEV;
+               goto err_get_page;
+       }
+
+       buffer = (void *)__get_free_page(GFP_KERNEL);
+       if (!buffer) {
+               ret = -ENOMEM;
+               goto err_get_page;
+       }
+       max->con_xmit.buf = buffer;
+       max->con_xmit.head = 0;
+       max->con_xmit.tail = 0;
+
+       max->main_thread = kthread_run(max3110_main_thread,
+                                       max, "max3110_main");
+       if (IS_ERR(max->main_thread)) {
+               ret = PTR_ERR(max->main_thread);
+               goto err_kthread;
+       }
+
+       spi_set_drvdata(spi, max);
+       pmax = max;
+
+       /* Give membase a psudo value to pass serial_core's check */
+       max->port.membase = (void *)0xff110000;
+       uart_add_one_port(&serial_m3110_reg, &max->port);
+
+       return 0;
+
+err_kthread:
+       free_page((unsigned long)buffer);
+err_get_page:
+       kfree(max);
+       return ret;
+}
+
+static int __devexit serial_m3110_remove(struct spi_device *dev)
+{
+       struct uart_max3110 *max = spi_get_drvdata(dev);
+
+       if (!max)
+               return 0;
+
+       uart_remove_one_port(&serial_m3110_reg, &max->port);
+
+       free_page((unsigned long)max->con_xmit.buf);
+
+       if (max->main_thread)
+               kthread_stop(max->main_thread);
+
+       kfree(max);
+       return 0;
+}
+
+static struct spi_driver uart_max3110_driver = {
+       .driver = {
+                       .name   = "spi_max3111",
+                       .bus    = &spi_bus_type,
+                       .owner  = THIS_MODULE,
+       },
+       .probe          = serial_m3110_probe,
+       .remove         = __devexit_p(serial_m3110_remove),
+       .suspend        = serial_m3110_suspend,
+       .resume         = serial_m3110_resume,
+};
+
+static int __init serial_m3110_init(void)
+{
+       int ret = 0;
+
+       ret = uart_register_driver(&serial_m3110_reg);
+       if (ret)
+               return ret;
+
+       ret = spi_register_driver(&uart_max3110_driver);
+       if (ret)
+               uart_unregister_driver(&serial_m3110_reg);
+
+       return ret;
+}
+
+static void __exit serial_m3110_exit(void)
+{
+       spi_unregister_driver(&uart_max3110_driver);
+       uart_unregister_driver(&serial_m3110_reg);
+}
+
+module_init(serial_m3110_init);
+module_exit(serial_m3110_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("max3110-uart");
diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h
new file mode 100644 (file)
index 0000000..d1ef43a
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _MRST_MAX3110_H
+#define _MRST_MAX3110_H
+
+#define MAX3110_HIGH_CLK       0x1     /* 3.6864 MHZ */
+#define MAX3110_LOW_CLK                0x0     /* 1.8432 MHZ */
+
+/* status bits for all 4 MAX3110 operate modes */
+#define MAX3110_READ_DATA_AVAILABLE    (1 << 15)
+#define MAX3110_WRITE_BUF_EMPTY                (1 << 14)
+
+#define WC_TAG                 (3 << 14)
+#define RC_TAG                 (1 << 14)
+#define WD_TAG                 (2 << 14)
+#define RD_TAG                 (0 << 14)
+
+/* bits def for write configuration */
+#define WC_FIFO_ENABLE_MASK    (1 << 13)
+#define WC_FIFO_ENABLE         (0 << 13)
+
+#define WC_SW_SHDI             (1 << 12)
+
+#define WC_IRQ_MASK            (0xF << 8)
+#define WC_TXE_IRQ_ENABLE      (1 << 11)       /* TX empty irq */
+#define WC_RXA_IRQ_ENABLE      (1 << 10)       /* RX availabe irq */
+#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
+#define WC_REC_ACT_IRQ_ENABLE  (1 << 8)
+
+#define WC_IRDA_ENABLE         (1 << 7)
+
+#define WC_STOPBITS_MASK       (1 << 6)
+#define WC_2_STOPBITS          (1 << 6)
+#define WC_1_STOPBITS          (0 << 6)
+
+#define WC_PARITY_ENABLE_MASK  (1 << 5)
+#define WC_PARITY_ENABLE       (1 << 5)
+
+#define WC_WORDLEN_MASK                (1 << 4)
+#define WC_7BIT_WORD           (1 << 4)
+#define WC_8BIT_WORD           (0 << 4)
+
+#define WC_BAUD_DIV_MASK       (0xF)
+#define WC_BAUD_DR1            (0x0)
+#define WC_BAUD_DR2            (0x1)
+#define WC_BAUD_DR4            (0x2)
+#define WC_BAUD_DR8            (0x3)
+#define WC_BAUD_DR16           (0x4)
+#define WC_BAUD_DR32           (0x5)
+#define WC_BAUD_DR64           (0x6)
+#define WC_BAUD_DR128          (0x7)
+#define WC_BAUD_DR3            (0x8)
+#define WC_BAUD_DR6            (0x9)
+#define WC_BAUD_DR12           (0xA)
+#define WC_BAUD_DR24           (0xB)
+#define WC_BAUD_DR48           (0xC)
+#define WC_BAUD_DR96           (0xD)
+#define WC_BAUD_DR192          (0xE)
+#define WC_BAUD_DR384          (0xF)
+
+#define M3110_RX_FIFO_DEPTH    8
+#endif
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
new file mode 100644 (file)
index 0000000..8e43a7b
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_serial.h"
+
+struct msm_port {
+       struct uart_port        uart;
+       char                    name[16];
+       struct clk              *clk;
+       unsigned int            imr;
+};
+
+static void msm_stop_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr &= ~UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_start_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr |= UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_stop_rx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_enable_ms(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr |= UART_IMR_DELTA_CTS;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int sr;
+
+       /*
+        * Handle overrun. My understanding of the hardware is that overrun
+        * is not tied to the RX buffer, so we handle the case out of band.
+        */
+       if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       }
+
+       /* and now the main RX loop */
+       while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
+               unsigned int c;
+               char flag = TTY_NORMAL;
+
+               c = msm_read(port, UART_RF);
+
+               if (sr & UART_SR_RX_BREAK) {
+                       port->icount.brk++;
+                       if (uart_handle_break(port))
+                               continue;
+               } else if (sr & UART_SR_PAR_FRAME_ERR) {
+                       port->icount.frame++;
+               } else {
+                       port->icount.rx++;
+               }
+
+               /* Mask conditions we're ignorning. */
+               sr &= port->read_status_mask;
+
+               if (sr & UART_SR_RX_BREAK) {
+                       flag = TTY_BREAK;
+               } else if (sr & UART_SR_PAR_FRAME_ERR) {
+                       flag = TTY_FRAME;
+               }
+
+               if (!uart_handle_sysrq_char(port, c))
+                       tty_insert_flip_char(tty, c, flag);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       int sent_tx;
+
+       if (port->x_char) {
+               msm_write(port, port->x_char, UART_TF);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+
+       while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
+               if (uart_circ_empty(xmit)) {
+                       /* disable tx interrupts */
+                       msm_port->imr &= ~UART_IMR_TXLEV;
+                       msm_write(port, msm_port->imr, UART_IMR);
+                       break;
+               }
+
+               msm_write(port, xmit->buf[xmit->tail], UART_TF);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               sent_tx = 1;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+       port->icount.cts++;
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t msm_irq(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int misr;
+
+       spin_lock(&port->lock);
+       misr = msm_read(port, UART_MISR);
+       msm_write(port, 0, UART_IMR); /* disable interrupt */
+
+       if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
+               handle_rx(port);
+       if (misr & UART_IMR_TXLEV)
+               handle_tx(port);
+       if (misr & UART_IMR_DELTA_CTS)
+               handle_delta_cts(port);
+
+       msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int msm_tx_empty(struct uart_port *port)
+{
+       return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int msm_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
+}
+
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int mr;
+
+       mr = msm_read(port, UART_MR1);
+
+       if (!(mctrl & TIOCM_RTS)) {
+               mr &= ~UART_MR1_RX_RDY_CTL;
+               msm_write(port, mr, UART_MR1);
+               msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+       } else {
+               mr |= UART_MR1_RX_RDY_CTL;
+               msm_write(port, mr, UART_MR1);
+       }
+}
+
+static void msm_break_ctl(struct uart_port *port, int break_ctl)
+{
+       if (break_ctl)
+               msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
+       else
+               msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+}
+
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+       unsigned int baud_code, rxstale, watermark;
+
+       switch (baud) {
+       case 300:
+               baud_code = UART_CSR_300;
+               rxstale = 1;
+               break;
+       case 600:
+               baud_code = UART_CSR_600;
+               rxstale = 1;
+               break;
+       case 1200:
+               baud_code = UART_CSR_1200;
+               rxstale = 1;
+               break;
+       case 2400:
+               baud_code = UART_CSR_2400;
+               rxstale = 1;
+               break;
+       case 4800:
+               baud_code = UART_CSR_4800;
+               rxstale = 1;
+               break;
+       case 9600:
+               baud_code = UART_CSR_9600;
+               rxstale = 2;
+               break;
+       case 14400:
+               baud_code = UART_CSR_14400;
+               rxstale = 3;
+               break;
+       case 19200:
+               baud_code = UART_CSR_19200;
+               rxstale = 4;
+               break;
+       case 28800:
+               baud_code = UART_CSR_28800;
+               rxstale = 6;
+               break;
+       case 38400:
+               baud_code = UART_CSR_38400;
+               rxstale = 8;
+               break;
+       case 57600:
+               baud_code = UART_CSR_57600;
+               rxstale = 16;
+               break;
+       case 115200:
+       default:
+               baud_code = UART_CSR_115200;
+               baud = 115200;
+               rxstale = 31;
+               break;
+       }
+
+       msm_write(port, baud_code, UART_CSR);
+
+       /* RX stale watermark */
+       watermark = UART_IPR_STALE_LSB & rxstale;
+       watermark |= UART_IPR_RXSTALE_LAST;
+       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+       msm_write(port, watermark, UART_IPR);
+
+       /* set RX watermark */
+       watermark = (port->fifosize * 3) / 4;
+       msm_write(port, watermark, UART_RFWR);
+
+       /* set TX watermark */
+       msm_write(port, 10, UART_TFWR);
+
+       return baud;
+}
+
+static void msm_reset(struct uart_port *port)
+{
+       /* reset everything */
+       msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+       msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+       msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+
+static void msm_init_clock(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       clk_enable(msm_port->clk);
+       msm_serial_set_mnd_regs(port);
+}
+
+static int msm_startup(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int data, rfr_level;
+       int ret;
+
+       snprintf(msm_port->name, sizeof(msm_port->name),
+                "msm_serial%d", port->line);
+
+       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+                         msm_port->name, port);
+       if (unlikely(ret))
+               return ret;
+
+       msm_init_clock(port);
+
+       if (likely(port->fifosize > 12))
+               rfr_level = port->fifosize - 12;
+       else
+               rfr_level = port->fifosize;
+
+       /* set automatic RFR level */
+       data = msm_read(port, UART_MR1);
+       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+       data &= ~UART_MR1_AUTO_RFR_LEVEL0;
+       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+       data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
+       msm_write(port, data, UART_MR1);
+
+       /* make sure that RXSTALE count is non-zero */
+       data = msm_read(port, UART_IPR);
+       if (unlikely(!data)) {
+               data |= UART_IPR_RXSTALE_LAST;
+               data |= UART_IPR_STALE_LSB;
+               msm_write(port, data, UART_IPR);
+       }
+
+       msm_reset(port);
+
+       msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+
+       /* turn on RX and CTS interrupts */
+       msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
+                       UART_IMR_CURRENT_CTS;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       return 0;
+}
+
+static void msm_shutdown(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       msm_port->imr = 0;
+       msm_write(port, 0, UART_IMR); /* disable interrupts */
+
+       clk_disable(msm_port->clk);
+
+       free_irq(port->irq, port);
+}
+
+static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, mr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* calculate and set baud rate */
+       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
+       baud = msm_set_baud_rate(port, baud);
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+       
+       /* calculate parity */
+       mr = msm_read(port, UART_MR2);
+       mr &= ~UART_MR2_PARITY_MODE;
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       mr |= UART_MR2_PARITY_MODE_ODD;
+               else if (termios->c_cflag & CMSPAR)
+                       mr |= UART_MR2_PARITY_MODE_SPACE;
+               else
+                       mr |= UART_MR2_PARITY_MODE_EVEN;
+       }
+
+       /* calculate bits per char */
+       mr &= ~UART_MR2_BITS_PER_CHAR;
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               mr |= UART_MR2_BITS_PER_CHAR_5;
+               break;
+       case CS6:
+               mr |= UART_MR2_BITS_PER_CHAR_6;
+               break;
+       case CS7:
+               mr |= UART_MR2_BITS_PER_CHAR_7;
+               break;
+       case CS8:
+       default:
+               mr |= UART_MR2_BITS_PER_CHAR_8;
+               break;
+       }
+
+       /* calculate stop bits */
+       mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
+       if (termios->c_cflag & CSTOPB)
+               mr |= UART_MR2_STOP_BIT_LEN_TWO;
+       else
+               mr |= UART_MR2_STOP_BIT_LEN_ONE;
+
+       /* set parity, bits per char, and stop bit */
+       msm_write(port, mr, UART_MR2);
+
+       /* calculate and set hardware flow control */
+       mr = msm_read(port, UART_MR1);
+       mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
+       if (termios->c_cflag & CRTSCTS) {
+               mr |= UART_MR1_CTS_CTL;
+               mr |= UART_MR1_RX_RDY_CTL;
+       }
+       msm_write(port, mr, UART_MR1);
+
+       /* Configure status bits to ignore based on termio flags. */
+       port->read_status_mask = 0;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART_SR_RX_BREAK;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *msm_type(struct uart_port *port)
+{
+       return "MSM";
+}
+
+static void msm_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *resource;
+       resource_size_t size;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return;
+       size = resource->end - resource->start + 1;
+
+       release_mem_region(port->mapbase, size);
+       iounmap(port->membase);
+       port->membase = NULL;
+}
+
+static int msm_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       struct resource *resource;
+       resource_size_t size;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return -ENXIO;
+       size = resource->end - resource->start + 1;
+
+       if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+               return -EBUSY;
+
+       port->membase = ioremap(port->mapbase, size);
+       if (!port->membase) {
+               release_mem_region(port->mapbase, size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void msm_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_MSM;
+               msm_request_port(port);
+       }
+}
+
+static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
+               return -EINVAL;
+       if (unlikely(port->irq != ser->irq))
+               return -EINVAL;
+       return 0;
+}
+
+static void msm_power(struct uart_port *port, unsigned int state,
+                     unsigned int oldstate)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+
+       switch (state) {
+       case 0:
+               clk_enable(msm_port->clk);
+               break;
+       case 3:
+               clk_disable(msm_port->clk);
+               break;
+       default:
+               printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+       }
+}
+
+static struct uart_ops msm_uart_pops = {
+       .tx_empty = msm_tx_empty,
+       .set_mctrl = msm_set_mctrl,
+       .get_mctrl = msm_get_mctrl,
+       .stop_tx = msm_stop_tx,
+       .start_tx = msm_start_tx,
+       .stop_rx = msm_stop_rx,
+       .enable_ms = msm_enable_ms,
+       .break_ctl = msm_break_ctl,
+       .startup = msm_startup,
+       .shutdown = msm_shutdown,
+       .set_termios = msm_set_termios,
+       .type = msm_type,
+       .release_port = msm_release_port,
+       .request_port = msm_request_port,
+       .config_port = msm_config_port,
+       .verify_port = msm_verify_port,
+       .pm = msm_power,
+};
+
+static struct msm_port msm_uart_ports[] = {
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 512,
+                       .line = 0,
+               },
+       },
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 512,
+                       .line = 1,
+               },
+       },
+       {
+               .uart = {
+                       .iotype = UPIO_MEM,
+                       .ops = &msm_uart_pops,
+                       .flags = UPF_BOOT_AUTOCONF,
+                       .fifosize = 64,
+                       .line = 2,
+               },
+       },
+};
+
+#define UART_NR        ARRAY_SIZE(msm_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+       return &msm_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+
+static void msm_console_putchar(struct uart_port *port, int c)
+{
+       while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+               ;
+       msm_write(port, c, UART_TF);
+}
+
+static void msm_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct uart_port *port;
+       struct msm_port *msm_port;
+
+       BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+       port = get_port_from_line(co->index);
+       msm_port = UART_TO_MSM(port);
+
+       spin_lock(&port->lock);
+       uart_console_write(port, s, count, msm_console_putchar);
+       spin_unlock(&port->lock);
+}
+
+static int __init msm_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud, flow, bits, parity;
+
+       if (unlikely(co->index >= UART_NR || co->index < 0))
+               return -ENXIO;
+
+       port = get_port_from_line(co->index);
+
+       if (unlikely(!port->membase))
+               return -ENXIO;
+
+       port->cons = co;
+
+       msm_init_clock(port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       bits = 8;
+       parity = 'n';
+       flow = 'n';
+       msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
+                 UART_MR2);    /* 8N1 */
+
+       if (baud < 300 || baud > 115200)
+               baud = 115200;
+       msm_set_baud_rate(port, baud);
+
+       msm_reset(port);
+
+       printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver msm_uart_driver;
+
+static struct console msm_console = {
+       .name = "ttyMSM",
+       .write = msm_console_write,
+       .device = uart_console_device,
+       .setup = msm_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &msm_uart_driver,
+};
+
+#define MSM_CONSOLE    (&msm_console)
+
+#else
+#define MSM_CONSOLE    NULL
+#endif
+
+static struct uart_driver msm_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "msm_serial",
+       .dev_name = "ttyMSM",
+       .nr = UART_NR,
+       .cons = MSM_CONSOLE,
+};
+
+static int __init msm_serial_probe(struct platform_device *pdev)
+{
+       struct msm_port *msm_port;
+       struct resource *resource;
+       struct uart_port *port;
+       int irq;
+
+       if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+               return -ENXIO;
+
+       printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
+
+       port = get_port_from_line(pdev->id);
+       port->dev = &pdev->dev;
+       msm_port = UART_TO_MSM(port);
+
+       msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+       if (IS_ERR(msm_port->clk))
+               return PTR_ERR(msm_port->clk);
+       port->uartclk = clk_get_rate(msm_port->clk);
+       printk(KERN_INFO "uartclk = %d\n", port->uartclk);
+
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!resource))
+               return -ENXIO;
+       port->mapbase = resource->start;
+
+       irq = platform_get_irq(pdev, 0);
+       if (unlikely(irq < 0))
+               return -ENXIO;
+       port->irq = irq;
+
+       platform_set_drvdata(pdev, port);
+
+       return uart_add_one_port(&msm_uart_driver, port);
+}
+
+static int __devexit msm_serial_remove(struct platform_device *pdev)
+{
+       struct msm_port *msm_port = platform_get_drvdata(pdev);
+
+       clk_put(msm_port->clk);
+
+       return 0;
+}
+
+static struct platform_driver msm_platform_driver = {
+       .remove = msm_serial_remove,
+       .driver = {
+               .name = "msm_serial",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init msm_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&msm_uart_driver);
+       if (unlikely(ret))
+               return ret;
+
+       ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+       if (unlikely(ret))
+               uart_unregister_driver(&msm_uart_driver);
+
+       printk(KERN_INFO "msm_serial: driver initialized\n");
+
+       return ret;
+}
+
+static void __exit msm_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+       unregister_console(&msm_console);
+#endif
+       platform_driver_unregister(&msm_platform_driver);
+       uart_unregister_driver(&msm_uart_driver);
+}
+
+module_init(msm_serial_init);
+module_exit(msm_serial_exit);
+
+MODULE_AUTHOR("Robert Love <rlove@google.com>");
+MODULE_DESCRIPTION("Driver for msm7x serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
new file mode 100644 (file)
index 0000000..f6ca9ca
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * drivers/serial/msm_serial.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
+#define __DRIVERS_SERIAL_MSM_SERIAL_H
+
+#define UART_MR1                       0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0       0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
+#define UART_MR1_RX_RDY_CTL                    (1 << 7)
+#define UART_MR1_CTS_CTL                       (1 << 6)
+
+#define UART_MR2                       0x0004
+#define UART_MR2_ERROR_MODE            (1 << 6)
+#define UART_MR2_BITS_PER_CHAR         0x30
+#define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7       (0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8       (0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE      (0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO      (0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE      0x0
+#define UART_MR2_PARITY_MODE_ODD       0x1
+#define UART_MR2_PARITY_MODE_EVEN      0x2
+#define UART_MR2_PARITY_MODE_SPACE     0x3
+#define UART_MR2_PARITY_MODE           0x3
+
+#define UART_CSR       0x0008
+#define UART_CSR_115200        0xFF
+#define UART_CSR_57600 0xEE
+#define UART_CSR_38400 0xDD
+#define UART_CSR_28800 0xCC
+#define UART_CSR_19200 0xBB
+#define UART_CSR_14400 0xAA
+#define UART_CSR_9600  0x99
+#define UART_CSR_4800  0x77
+#define UART_CSR_2400  0x55
+#define UART_CSR_1200  0x44
+#define UART_CSR_600   0x33
+#define UART_CSR_300   0x22
+
+#define UART_TF                0x000C
+
+#define UART_CR                                0x0010
+#define UART_CR_CMD_NULL               (0 << 4)
+#define UART_CR_CMD_RESET_RX           (1 << 4)
+#define UART_CR_CMD_RESET_TX           (2 << 4)
+#define UART_CR_CMD_RESET_ERR          (3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT    (4 << 4)
+#define UART_CR_CMD_START_BREAK                (5 << 4)
+#define UART_CR_CMD_STOP_BREAK         (6 << 4)
+#define UART_CR_CMD_RESET_CTS          (7 << 4)
+#define UART_CR_CMD_PACKET_MODE                (9 << 4)
+#define UART_CR_CMD_MODE_RESET         (12 << 4)
+#define UART_CR_CMD_SET_RFR            (13 << 4)
+#define UART_CR_CMD_RESET_RFR          (14 << 4)
+#define UART_CR_TX_DISABLE             (1 << 3)
+#define UART_CR_TX_ENABLE              (1 << 3)
+#define UART_CR_RX_DISABLE             (1 << 3)
+#define UART_CR_RX_ENABLE              (1 << 3)
+
+#define UART_IMR               0x0014
+#define UART_IMR_TXLEV         (1 << 0)
+#define UART_IMR_RXSTALE       (1 << 3)
+#define UART_IMR_RXLEV         (1 << 4)
+#define UART_IMR_DELTA_CTS     (1 << 5)
+#define UART_IMR_CURRENT_CTS   (1 << 6)
+
+#define UART_IPR_RXSTALE_LAST          0x20
+#define UART_IPR_STALE_LSB             0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
+
+#define UART_IPR       0x0018
+#define UART_TFWR      0x001C
+#define UART_RFWR      0x0020
+#define UART_HCR       0x0024
+
+#define UART_MREG              0x0028
+#define UART_NREG              0x002C
+#define UART_DREG              0x0030
+#define UART_MNDREG            0x0034
+#define UART_IRDA              0x0038
+#define UART_MISR_MODE         0x0040
+#define UART_MISR_RESET                0x0044
+#define UART_MISR_EXPORT       0x0048
+#define UART_MISR_VAL          0x004C
+#define UART_TEST_CTRL         0x0050
+
+#define UART_SR                        0x0008
+#define UART_SR_HUNT_CHAR      (1 << 7)
+#define UART_SR_RX_BREAK       (1 << 6)
+#define UART_SR_PAR_FRAME_ERR  (1 << 5)
+#define UART_SR_OVERRUN                (1 << 4)
+#define UART_SR_TX_EMPTY       (1 << 3)
+#define UART_SR_TX_READY       (1 << 2)
+#define UART_SR_RX_FULL                (1 << 1)
+#define UART_SR_RX_READY       (1 << 0)
+
+#define UART_RF                0x000C
+#define UART_MISR      0x0010
+#define UART_ISR       0x0014
+
+#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
+
+static inline
+void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
+{
+       __raw_writel(val, port->membase + off);
+}
+
+static inline
+unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+       return __raw_readl(port->membase + off);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock.
+ */
+static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
+{
+       msm_write(port, 0x06, UART_MREG);
+       msm_write(port, 0xF1, UART_NREG);
+       msm_write(port, 0x0F, UART_DREG);
+       msm_write(port, 0x1A, UART_MNDREG);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock divided by 4.
+ */
+static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
+{
+       msm_write(port, 0x18, UART_MREG);
+       msm_write(port, 0xF6, UART_NREG);
+       msm_write(port, 0x0F, UART_DREG);
+       msm_write(port, 0x0A, UART_MNDREG);
+}
+
+static inline
+void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
+{
+       if (port->uartclk == 19200000)
+               msm_serial_set_mnd_regs_tcxo(port);
+       else
+               msm_serial_set_mnd_regs_tcxoby4(port);
+}
+
+/*
+ * TROUT has a specific defect that makes it report it's uartclk
+ * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
+ * cases TROUT to use the right clock.
+ */
+#ifdef CONFIG_MACH_TROUT
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
+#else
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
+#endif
+
+#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
new file mode 100644 (file)
index 0000000..9711e06
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+** mux.c:
+**     serial driver for the Mux console found in some PA-RISC servers.
+**
+**     (c) Copyright 2002 Ryan Bradetich
+**     (c) Copyright 2002 Hewlett-Packard Company
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/delay.h> /* for udelay */
+#include <linux/device.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/parisc-device.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_POLL_DELAY (30 * HZ / 1000)
+
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+
+#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
+
+#define MUX_NR 256
+static unsigned int port_cnt __read_mostly;
+struct mux_port {
+       struct uart_port port;
+       int enabled;
+};
+static struct mux_port mux_ports[MUX_NR];
+
+static struct uart_driver mux_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "ttyB",
+       .dev_name = "ttyB",
+       .major = MUX_MAJOR,
+       .minor = 0,
+       .nr = MUX_NR,
+};
+
+static struct timer_list mux_timer;
+
+#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
+#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
+
+/**
+ * get_mux_port_count - Get the number of available ports on the Mux.
+ * @dev: The parisc device.
+ *
+ * This function is used to determine the number of ports the Mux
+ * supports.  The IODC data reports the number of ports the Mux
+ * can support, but there are cases where not all the Mux ports
+ * are connected.  This function can override the IODC and
+ * return the true port count.
+ */
+static int __init get_mux_port_count(struct parisc_device *dev)
+{
+       int status;
+       u8 iodc_data[32];
+       unsigned long bytecnt;
+
+       /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
+        * we only need to allocate resources for 1 port since the
+        * other 7 ports are not connected.
+        */
+       if(dev->id.hversion == 0x15)
+               return 1;
+
+       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
+       BUG_ON(status != PDC_OK);
+
+       /* Return the number of ports specified in the iodc data. */
+       return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
+}
+
+/**
+ * mux_tx_empty - Check if the transmitter fifo is empty.
+ * @port: Ptr to the uart_port.
+ *
+ * This function test if the transmitter fifo for the port
+ * described by 'port' is empty.  If it is empty, this function
+ * should return TIOCSER_TEMT, otherwise return 0.
+ */
+static unsigned int mux_tx_empty(struct uart_port *port)
+{
+       return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT;
+} 
+
+/**
+ * mux_set_mctrl - Set the current state of the modem control inputs.
+ * @ports: Ptr to the uart_port.
+ * @mctrl: Modem control bits.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so this function
+ * is ignored.
+ */
+static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * mux_get_mctrl - Returns the current state of modem control inputs.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial MUX does not support CTS, DCD or DSR so these lines are
+ * treated as permanently active.
+ */
+static unsigned int mux_get_mctrl(struct uart_port *port)
+{ 
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/**
+ * mux_stop_tx - Stop transmitting characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial MUX does not support this function.
+ */
+static void mux_stop_tx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_start_tx - Start transmitting characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_start_tx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_stop_rx - Stop receiving characters.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_stop_rx(struct uart_port *port)
+{
+}
+
+/**
+ * mux_enable_ms - Enable modum status interrupts.
+ * @port: Ptr to the uart_port.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_enable_ms(struct uart_port *port)
+{
+}
+
+/**
+ * mux_break_ctl - Control the transmitssion of a break signal.
+ * @port: Ptr to the uart_port.
+ * @break_state: Raise/Lower the break signal.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void mux_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This function writes all the data from the uart buffer to
+ * the mux fifo.
+ */
+static void mux_write(struct uart_port *port)
+{
+       int count;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if(port->x_char) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               mux_stop_tx(port);
+               return;
+       }
+
+       count = (port->fifosize) - UART_GET_FIFO_CNT(port);
+       do {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if(uart_circ_empty(xmit))
+                       break;
+
+       } while(--count > 0);
+
+       while(UART_GET_FIFO_CNT(port)) 
+               udelay(1);
+
+       if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               mux_stop_tx(port);
+}
+
+/**
+ * mux_read - Read chars from the mux fifo.
+ * @port: Ptr to the uart_port.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void mux_read(struct uart_port *port)
+{
+       int data;
+       struct tty_struct *tty = port->state->port.tty;
+       __u32 start_count = port->icount.rx;
+
+       while(1) {
+               data = __raw_readl(port->membase + IO_DATA_REG_OFFSET);
+
+               if (MUX_STATUS(data))
+                       continue;
+
+               if (MUX_EOFIFO(data))
+                       break;
+
+               port->icount.rx++;
+
+               if (MUX_BREAK(data)) {
+                       port->icount.brk++;
+                       if(uart_handle_break(port))
+                               continue;
+               }
+
+               if (uart_handle_sysrq_char(port, data & 0xffu))
+                       continue;
+
+               tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+       }
+       
+       if (start_count != port->icount.rx) {
+               tty_flip_buffer_push(tty);
+       }
+}
+
+/**
+ * mux_startup - Initialize the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Grab any resources needed for this port and start the
+ * mux timer.
+ */
+static int mux_startup(struct uart_port *port)
+{
+       mux_ports[port->line].enabled = 1;
+       return 0;
+}
+
+/**
+ * mux_shutdown - Disable the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Release any resources needed for the port.
+ */
+static void mux_shutdown(struct uart_port *port)
+{
+       mux_ports[port->line].enabled = 0;
+}
+
+/**
+ * mux_set_termios - Chane port parameters.
+ * @port: Ptr to the uart_port.
+ * @termios: new termios settings.
+ * @old: old termios settings.
+ *
+ * The Serial Mux does not support this function.
+ */
+static void
+mux_set_termios(struct uart_port *port, struct ktermios *termios,
+               struct ktermios *old)
+{
+}
+
+/**
+ * mux_type - Describe the port.
+ * @port: Ptr to the uart_port.
+ *
+ * Return a pointer to a string constant describing the
+ * specified port.
+ */
+static const char *mux_type(struct uart_port *port)
+{
+       return "Mux";
+}
+
+/**
+ * mux_release_port - Release memory and IO regions.
+ * @port: Ptr to the uart_port.
+ * 
+ * Release any memory and IO region resources currently in use by
+ * the port.
+ */
+static void mux_release_port(struct uart_port *port)
+{
+}
+
+/**
+ * mux_request_port - Request memory and IO regions.
+ * @port: Ptr to the uart_port.
+ *
+ * Request any memory and IO region resources required by the port.
+ * If any fail, no resources should be registered when this function
+ * returns, and it should return -EBUSY on failure.
+ */
+static int mux_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * mux_config_port - Perform port autoconfiguration.
+ * @port: Ptr to the uart_port.
+ * @type: Bitmask of required configurations.
+ *
+ * Perform any autoconfiguration steps for the port.  This function is
+ * called if the UPF_BOOT_AUTOCONF flag is specified for the port.
+ * [Note: This is required for now because of a bug in the Serial core.
+ *  rmk has already submitted a patch to linus, should be available for
+ *  2.5.47.]
+ */
+static void mux_config_port(struct uart_port *port, int type)
+{
+       port->type = PORT_MUX;
+}
+
+/**
+ * mux_verify_port - Verify the port information.
+ * @port: Ptr to the uart_port.
+ * @ser: Ptr to the serial information.
+ *
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ */
+static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if(port->membase == NULL)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * mux_drv_poll - Mux poll function.
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Serial MUX to check for new data.
+ */
+static void mux_poll(unsigned long unused)
+{  
+       int i;
+
+       for(i = 0; i < port_cnt; ++i) {
+               if(!mux_ports[i].enabled)
+                       continue;
+
+               mux_read(&mux_ports[i].port);
+               mux_write(&mux_ports[i].port);
+       }
+
+       mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+}
+
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+static void mux_console_write(struct console *co, const char *s, unsigned count)
+{
+       /* Wait until the FIFO drains. */
+       while(UART_GET_FIFO_CNT(&mux_ports[0].port))
+               udelay(1);
+
+       while(count--) {
+               if(*s == '\n') {
+                       UART_PUT_CHAR(&mux_ports[0].port, '\r');
+               }
+               UART_PUT_CHAR(&mux_ports[0].port, *s++);
+       }
+
+}
+
+static int mux_console_setup(struct console *co, char *options)
+{
+        return 0;
+}
+
+struct tty_driver *mux_console_device(struct console *co, int *index)
+{
+        *index = co->index;
+       return mux_driver.tty_driver;
+}
+
+static struct console mux_console = {
+       .name =         "ttyB",
+       .write =        mux_console_write,
+       .device =       mux_console_device,
+       .setup =        mux_console_setup,
+       .flags =        CON_ENABLED | CON_PRINTBUFFER,
+       .index =        0,
+};
+
+#define MUX_CONSOLE    &mux_console
+#else
+#define MUX_CONSOLE    NULL
+#endif
+
+static struct uart_ops mux_pops = {
+       .tx_empty =             mux_tx_empty,
+       .set_mctrl =            mux_set_mctrl,
+       .get_mctrl =            mux_get_mctrl,
+       .stop_tx =              mux_stop_tx,
+       .start_tx =             mux_start_tx,
+       .stop_rx =              mux_stop_rx,
+       .enable_ms =            mux_enable_ms,
+       .break_ctl =            mux_break_ctl,
+       .startup =              mux_startup,
+       .shutdown =             mux_shutdown,
+       .set_termios =          mux_set_termios,
+       .type =                 mux_type,
+       .release_port =         mux_release_port,
+       .request_port =         mux_request_port,
+       .config_port =          mux_config_port,
+       .verify_port =          mux_verify_port,
+};
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Serial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init mux_probe(struct parisc_device *dev)
+{
+       int i, status;
+
+       int port_count = get_mux_port_count(dev);
+       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
+
+       dev_set_drvdata(&dev->dev, (void *)(long)port_count);
+       request_mem_region(dev->hpa.start + MUX_OFFSET,
+                           port_count * MUX_LINE_OFFSET, "Mux");
+
+       if(!port_cnt) {
+               mux_driver.cons = MUX_CONSOLE;
+
+               status = uart_register_driver(&mux_driver);
+               if(status) {
+                       printk(KERN_ERR "Serial mux: Unable to register driver.\n");
+                       return 1;
+               }
+       }
+
+       for(i = 0; i < port_count; ++i, ++port_cnt) {
+               struct uart_port *port = &mux_ports[port_cnt].port;
+               port->iobase    = 0;
+               port->mapbase   = dev->hpa.start + MUX_OFFSET +
+                                               (i * MUX_LINE_OFFSET);
+               port->membase   = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
+               port->iotype    = UPIO_MEM;
+               port->type      = PORT_MUX;
+               port->irq       = NO_IRQ;
+               port->uartclk   = 0;
+               port->fifosize  = MUX_FIFO_SIZE;
+               port->ops       = &mux_pops;
+               port->flags     = UPF_BOOT_AUTOCONF;
+               port->line      = port_cnt;
+
+               /* The port->timeout needs to match what is present in
+                * uart_wait_until_sent in serial_core.c.  Otherwise
+                * the time spent in msleep_interruptable will be very
+                * long, causing the appearance of a console hang.
+                */
+               port->timeout   = HZ / 50;
+               spin_lock_init(&port->lock);
+
+               status = uart_add_one_port(&mux_driver, port);
+               BUG_ON(status);
+       }
+
+       return 0;
+}
+
+static int __devexit mux_remove(struct parisc_device *dev)
+{
+       int i, j;
+       int port_count = (long)dev_get_drvdata(&dev->dev);
+
+       /* Find Port 0 for this card in the mux_ports list. */
+       for(i = 0; i < port_cnt; ++i) {
+               if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
+                       break;
+       }
+       BUG_ON(i + port_count > port_cnt);
+
+       /* Release the resources associated with each port on the device. */
+       for(j = 0; j < port_count; ++j, ++i) {
+               struct uart_port *port = &mux_ports[i].port;
+
+               uart_remove_one_port(&mux_driver, port);
+               if(port->membase)
+                       iounmap(port->membase);
+       }
+
+       release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
+       return 0;
+}
+
+/* Hack.  This idea was taken from the 8250_gsc.c on how to properly order
+ * the serial port detection in the proper order.   The idea is we always
+ * want the builtin mux to be detected before addin mux cards, so we
+ * specifically probe for the builtin mux cards first.
+ *
+ * This table only contains the parisc_device_id of known builtin mux
+ * devices.  All other mux cards will be detected by the generic mux_tbl.
+ */
+static struct parisc_device_id builtin_mux_tbl[] = {
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
+       { 0, }
+};
+
+static struct parisc_device_id mux_tbl[] = {
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver builtin_serial_mux_driver = {
+       .name =         "builtin_serial_mux",
+       .id_table =     builtin_mux_tbl,
+       .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
+};
+
+static struct parisc_driver serial_mux_driver = {
+       .name =         "serial_mux",
+       .id_table =     mux_tbl,
+       .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
+};
+
+/**
+ * mux_init - Serial MUX initialization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void)
+{
+       register_parisc_driver(&builtin_serial_mux_driver);
+       register_parisc_driver(&serial_mux_driver);
+
+       if(port_cnt > 0) {
+               /* Start the Mux timer */
+               init_timer(&mux_timer);
+               mux_timer.function = mux_poll;
+               mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               register_console(&mux_console);
+#endif
+       }
+
+       return 0;
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+       /* Delete the Mux timer. */
+       if(port_cnt > 0) {
+               del_timer(&mux_timer);
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               unregister_console(&mux_console);
+#endif
+       }
+
+       unregister_parisc_driver(&builtin_serial_mux_driver);
+       unregister_parisc_driver(&serial_mux_driver);
+       uart_unregister_driver(&mux_driver);
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
new file mode 100644 (file)
index 0000000..7735c9f
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * drivers/serial/netx-serial.c
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/netx-regs.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_NX_MAJOR        204
+#define MINOR_START    170
+
+enum uart_regs {
+       UART_DR              = 0x00,
+       UART_SR              = 0x04,
+       UART_LINE_CR         = 0x08,
+       UART_BAUDDIV_MSB     = 0x0c,
+       UART_BAUDDIV_LSB     = 0x10,
+       UART_CR              = 0x14,
+       UART_FR              = 0x18,
+       UART_IIR             = 0x1c,
+       UART_ILPR            = 0x20,
+       UART_RTS_CR          = 0x24,
+       UART_RTS_LEAD        = 0x28,
+       UART_RTS_TRAIL       = 0x2c,
+       UART_DRV_ENABLE      = 0x30,
+       UART_BRM_CR          = 0x34,
+       UART_RXFIFO_IRQLEVEL = 0x38,
+       UART_TXFIFO_IRQLEVEL = 0x3c,
+};
+
+#define SR_FE (1<<0)
+#define SR_PE (1<<1)
+#define SR_BE (1<<2)
+#define SR_OE (1<<3)
+
+#define LINE_CR_BRK       (1<<0)
+#define LINE_CR_PEN       (1<<1)
+#define LINE_CR_EPS       (1<<2)
+#define LINE_CR_STP2      (1<<3)
+#define LINE_CR_FEN       (1<<4)
+#define LINE_CR_5BIT      (0<<5)
+#define LINE_CR_6BIT      (1<<5)
+#define LINE_CR_7BIT      (2<<5)
+#define LINE_CR_8BIT      (3<<5)
+#define LINE_CR_BITS_MASK (3<<5)
+
+#define CR_UART_EN (1<<0)
+#define CR_SIREN   (1<<1)
+#define CR_SIRLP   (1<<2)
+#define CR_MSIE    (1<<3)
+#define CR_RIE     (1<<4)
+#define CR_TIE     (1<<5)
+#define CR_RTIE    (1<<6)
+#define CR_LBE     (1<<7)
+
+#define FR_CTS  (1<<0)
+#define FR_DSR  (1<<1)
+#define FR_DCD  (1<<2)
+#define FR_BUSY (1<<3)
+#define FR_RXFE (1<<4)
+#define FR_TXFF (1<<5)
+#define FR_RXFF (1<<6)
+#define FR_TXFE (1<<7)
+
+#define IIR_MIS (1<<0)
+#define IIR_RIS (1<<1)
+#define IIR_TIS (1<<2)
+#define IIR_RTIS (1<<3)
+#define IIR_MASK 0xf
+
+#define RTS_CR_AUTO (1<<0)
+#define RTS_CR_RTS  (1<<1)
+#define RTS_CR_COUNT (1<<2)
+#define RTS_CR_MOD2  (1<<3)
+#define RTS_CR_RTS_POL (1<<4)
+#define RTS_CR_CTS_CTR (1<<5)
+#define RTS_CR_CTS_POL (1<<6)
+#define RTS_CR_STICK   (1<<7)
+
+#define UART_PORT_SIZE 0x40
+#define DRIVER_NAME "netx-uart"
+
+struct netx_port {
+       struct uart_port        port;
+};
+
+static void netx_stop_tx(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val & ~CR_TIE,  port->membase + UART_CR);
+}
+
+static void netx_stop_rx(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val & ~CR_RIE,  port->membase + UART_CR);
+}
+
+static void netx_enable_ms(struct uart_port *port)
+{
+       unsigned int val;
+       val = readl(port->membase + UART_CR);
+       writel(val | CR_MSIE, port->membase + UART_CR);
+}
+
+static inline void netx_transmit_buffer(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               writel(port->x_char, port->membase + UART_DR);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+               netx_stop_tx(port);
+               return;
+       }
+
+       do {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+               writel(xmit->buf[xmit->tail], port->membase + UART_DR);
+               xmit->tail = (xmit->tail + 1) &
+                        (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (!(readl(port->membase + UART_FR) & FR_TXFF));
+
+       if (uart_circ_empty(xmit))
+               netx_stop_tx(port);
+}
+
+static void netx_start_tx(struct uart_port *port)
+{
+       writel(
+           readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR);
+
+       if (!(readl(port->membase + UART_FR) & FR_TXFF))
+               netx_transmit_buffer(port);
+}
+
+static unsigned int netx_tx_empty(struct uart_port *port)
+{
+       return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static void netx_txint(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               netx_stop_tx(port);
+               return;
+       }
+
+       netx_transmit_buffer(port);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static void netx_rxint(struct uart_port *port)
+{
+       unsigned char rx, flg, status;
+       struct tty_struct *tty = port->state->port.tty;
+
+       while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
+               rx = readl(port->membase + UART_DR);
+               flg = TTY_NORMAL;
+               port->icount.rx++;
+               status = readl(port->membase + UART_SR);
+               if (status & SR_BE) {
+                       writel(0, port->membase + UART_SR);
+                       if (uart_handle_break(port))
+                               continue;
+               }
+
+               if (unlikely(status & (SR_FE | SR_PE | SR_OE))) {
+
+                       if (status & SR_PE)
+                               port->icount.parity++;
+                       else if (status & SR_FE)
+                               port->icount.frame++;
+                       if (status & SR_OE)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+
+                       if (status & SR_BE)
+                               flg = TTY_BREAK;
+                       else if (status & SR_PE)
+                               flg = TTY_PARITY;
+                       else if (status & SR_FE)
+                               flg = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, rx))
+                       continue;
+
+               uart_insert_char(port, status, SR_OE, rx, flg);
+       }
+
+       tty_flip_buffer_push(tty);
+       return;
+}
+
+static irqreturn_t netx_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned long flags;
+       unsigned char status;
+
+       spin_lock_irqsave(&port->lock,flags);
+
+       status = readl(port->membase + UART_IIR) & IIR_MASK;
+       while (status) {
+               if (status & IIR_RIS)
+                       netx_rxint(port);
+               if (status & IIR_TIS)
+                       netx_txint(port);
+               if (status & IIR_MIS) {
+                       if (readl(port->membase + UART_FR) & FR_CTS)
+                               uart_handle_cts_change(port, 1);
+                       else
+                               uart_handle_cts_change(port, 0);
+               }
+               writel(0, port->membase + UART_IIR);
+               status = readl(port->membase + UART_IIR) & IIR_MASK;
+       }
+
+       spin_unlock_irqrestore(&port->lock,flags);
+       return IRQ_HANDLED;
+}
+
+static unsigned int netx_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = TIOCM_DSR | TIOCM_CAR;
+
+       if (readl(port->membase + UART_FR) & FR_CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned int val;
+
+       /* FIXME: Locking needed ? */
+       if (mctrl & TIOCM_RTS) {
+               val = readl(port->membase + UART_RTS_CR);
+               writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
+       }
+}
+
+static void netx_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned int line_cr;
+       spin_lock_irq(&port->lock);
+
+       line_cr = readl(port->membase + UART_LINE_CR);
+       if (break_state != 0)
+               line_cr |= LINE_CR_BRK;
+       else
+               line_cr &= ~LINE_CR_BRK;
+       writel(line_cr, port->membase + UART_LINE_CR);
+
+       spin_unlock_irq(&port->lock);
+}
+
+static int netx_startup(struct uart_port *port)
+{
+       int ret;
+
+       ret = request_irq(port->irq, netx_int, 0,
+                            DRIVER_NAME, port);
+       if (ret) {
+               dev_err(port->dev, "unable to grab irq%d\n",port->irq);
+               goto exit;
+       }
+
+       writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN,
+               port->membase + UART_LINE_CR);
+
+       writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN,
+               port->membase + UART_CR);
+
+exit:
+       return ret;
+}
+
+static void netx_shutdown(struct uart_port *port)
+{
+       writel(0, port->membase + UART_CR) ;
+
+       free_irq(port->irq, port);
+}
+
+static void
+netx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       unsigned int baud, quot;
+       unsigned char old_cr;
+       unsigned char line_cr = LINE_CR_FEN;
+       unsigned char rts_cr = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               line_cr |= LINE_CR_5BIT;
+               break;
+       case CS6:
+               line_cr |= LINE_CR_6BIT;
+               break;
+       case CS7:
+               line_cr |= LINE_CR_7BIT;
+               break;
+       case CS8:
+               line_cr |= LINE_CR_8BIT;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               line_cr |= LINE_CR_STP2;
+
+       if (termios->c_cflag & PARENB) {
+               line_cr |= LINE_CR_PEN;
+               if (!(termios->c_cflag & PARODD))
+                       line_cr |= LINE_CR_EPS;
+       }
+
+       if (termios->c_cflag & CRTSCTS)
+               rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = baud * 4096;
+       quot /= 1000;
+       quot *= 256;
+       quot /= 100000;
+
+       spin_lock_irq(&port->lock);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       old_cr = readl(port->membase + UART_CR);
+
+       /* disable interrupts */
+       writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE),
+               port->membase + UART_CR);
+
+       /* drain transmitter */
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+
+       /* disable UART */
+       writel(old_cr & ~CR_UART_EN, port->membase + UART_CR);
+
+       /* modem status interrupts */
+       old_cr &= ~CR_MSIE;
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               old_cr |= CR_MSIE;
+
+       writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB);
+       writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB);
+       writel(line_cr, port->membase + UART_LINE_CR);
+
+       writel(rts_cr, port->membase + UART_RTS_CR);
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= SR_PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= SR_BE;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= SR_PE;
+       }
+
+       port->read_status_mask = 0;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= SR_PE | SR_FE;
+
+       writel(old_cr, port->membase + UART_CR);
+
+       spin_unlock_irq(&port->lock);
+}
+
+static const char *netx_type(struct uart_port *port)
+{
+       return port->type == PORT_NETX ? "NETX" : NULL;
+}
+
+static void netx_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+static int netx_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE,
+                       DRIVER_NAME) != NULL ? 0 : -EBUSY;
+}
+
+static void netx_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0)
+               port->type = PORT_NETX;
+}
+
+static int
+netx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static struct uart_ops netx_pops = {
+       .tx_empty       = netx_tx_empty,
+       .set_mctrl      = netx_set_mctrl,
+       .get_mctrl      = netx_get_mctrl,
+       .stop_tx        = netx_stop_tx,
+       .start_tx       = netx_start_tx,
+       .stop_rx        = netx_stop_rx,
+       .enable_ms      = netx_enable_ms,
+       .break_ctl      = netx_break_ctl,
+       .startup        = netx_startup,
+       .shutdown       = netx_shutdown,
+       .set_termios    = netx_set_termios,
+       .type           = netx_type,
+       .release_port   = netx_release_port,
+       .request_port   = netx_request_port,
+       .config_port    = netx_config_port,
+       .verify_port    = netx_verify_port,
+};
+
+static struct netx_port netx_ports[] = {
+       {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART0),
+               .mapbase = NETX_PA_UART0,
+               .irq = NETX_IRQ_UART0,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 0,
+       },
+       }, {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART1),
+               .mapbase = NETX_PA_UART1,
+               .irq = NETX_IRQ_UART1,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 1,
+       },
+       }, {
+       .port = {
+               .type = PORT_NETX,
+               .iotype = UPIO_MEM,
+               .membase = (char __iomem *)io_p2v(NETX_PA_UART2),
+               .mapbase = NETX_PA_UART2,
+               .irq = NETX_IRQ_UART2,
+               .uartclk = 100000000,
+               .fifosize = 16,
+               .flags = UPF_BOOT_AUTOCONF,
+               .ops = &netx_pops,
+               .line = 2,
+       },
+       }
+};
+
+#ifdef CONFIG_SERIAL_NETX_CONSOLE
+
+static void netx_console_putchar(struct uart_port *port, int ch)
+{
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+       writel(ch, port->membase + UART_DR);
+}
+
+static void
+netx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &netx_ports[co->index].port;
+       unsigned char cr_save;
+
+       cr_save = readl(port->membase + UART_CR);
+       writel(cr_save | CR_UART_EN, port->membase + UART_CR);
+
+       uart_console_write(port, s, count, netx_console_putchar);
+
+       while (readl(port->membase + UART_FR) & FR_BUSY);
+       writel(cr_save, port->membase + UART_CR);
+}
+
+static void __init
+netx_console_get_options(struct uart_port *port, int *baud,
+                       int *parity, int *bits, int *flow)
+{
+       unsigned char line_cr;
+
+       *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) |
+               readl(port->membase + UART_BAUDDIV_LSB);
+       *baud *= 1000;
+       *baud /= 4096;
+       *baud *= 1000;
+       *baud /= 256;
+       *baud *= 100;
+
+       line_cr = readl(port->membase + UART_LINE_CR);
+       *parity = 'n';
+       if (line_cr & LINE_CR_PEN) {
+               if (line_cr & LINE_CR_EPS)
+                       *parity = 'e';
+               else
+                       *parity = 'o';
+       }
+
+       switch (line_cr & LINE_CR_BITS_MASK) {
+       case LINE_CR_8BIT:
+               *bits = 8;
+               break;
+       case LINE_CR_7BIT:
+               *bits = 7;
+               break;
+       case LINE_CR_6BIT:
+               *bits = 6;
+               break;
+       case LINE_CR_5BIT:
+               *bits = 5;
+               break;
+       }
+
+       if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO)
+               *flow = 'r';
+}
+
+static int __init
+netx_console_setup(struct console *co, char *options)
+{
+       struct netx_port *sport;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports))
+               co->index = 0;
+       sport = &netx_ports[co->index];
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       } else {
+               /* if the UART is enabled, assume it has been correctly setup
+                * by the bootloader and get the options
+                */
+               if (readl(sport->port.membase + UART_CR) & CR_UART_EN) {
+                       netx_console_get_options(&sport->port, &baud,
+                       &parity, &bits, &flow);
+               }
+
+       }
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver netx_reg;
+static struct console netx_console = {
+       .name           = "ttyNX",
+       .write          = netx_console_write,
+       .device         = uart_console_device,
+       .setup          = netx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &netx_reg,
+};
+
+static int __init netx_console_init(void)
+{
+       register_console(&netx_console);
+       return 0;
+}
+console_initcall(netx_console_init);
+
+#define NETX_CONSOLE   &netx_console
+#else
+#define NETX_CONSOLE   NULL
+#endif
+
+static struct uart_driver netx_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = "ttyNX",
+       .major          = SERIAL_NX_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ARRAY_SIZE(netx_ports),
+       .cons           = NETX_CONSOLE,
+};
+
+static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       if (sport)
+               uart_suspend_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_netx_resume(struct platform_device *pdev)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       if (sport)
+               uart_resume_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static int serial_netx_probe(struct platform_device *pdev)
+{
+       struct uart_port *port = &netx_ports[pdev->id].port;
+
+       dev_info(&pdev->dev, "initialising\n");
+
+       port->dev = &pdev->dev;
+
+       writel(1, port->membase + UART_RXFIFO_IRQLEVEL);
+       uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port);
+       platform_set_drvdata(pdev, &netx_ports[pdev->id]);
+
+       return 0;
+}
+
+static int serial_netx_remove(struct platform_device *pdev)
+{
+       struct netx_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&netx_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver serial_netx_driver = {
+       .probe          = serial_netx_probe,
+       .remove         = serial_netx_remove,
+
+       .suspend        = serial_netx_suspend,
+       .resume         = serial_netx_resume,
+
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init netx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: NetX driver\n");
+
+       ret = uart_register_driver(&netx_reg);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&serial_netx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&netx_reg);
+
+       return 0;
+}
+
+static void __exit netx_serial_exit(void)
+{
+       platform_driver_unregister(&serial_netx_driver);
+       uart_unregister_driver(&netx_reg);
+}
+
+module_init(netx_serial_init);
+module_exit(netx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("NetX serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
new file mode 100644 (file)
index 0000000..de17367
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ *  Serial Port driver for a NWP uart device
+ *
+ *    Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/nwpserial.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NWPSERIAL_NR               2
+
+#define NWPSERIAL_STATUS_RXVALID 0x1
+#define NWPSERIAL_STATUS_TXFULL  0x2
+
+struct nwpserial_port {
+       struct uart_port port;
+       dcr_host_t dcr_host;
+       unsigned int ier;
+       unsigned int mcr;
+};
+
+static DEFINE_MUTEX(nwpserial_mutex);
+static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
+
+static void wait_for_bits(struct nwpserial_port *up, int bits)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = dcr_read(up->dcr_host, UART_LSR);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & bits) != bits);
+}
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static void nwpserial_console_putchar(struct uart_port *port, int c)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+       /* check if tx buffer is full */
+       wait_for_bits(up, UART_LSR_THRE);
+       dcr_write(up->dcr_host, UART_TX, c);
+       up->port.icount.tx++;
+}
+
+static void
+nwpserial_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct nwpserial_port *up = &nwpserial_ports[co->index];
+       unsigned long flags;
+       int locked = 1;
+
+       if (oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
+
+       /* save and disable interrupt */
+       up->ier = dcr_read(up->dcr_host, UART_IER);
+       dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
+
+       uart_console_write(&up->port, s, count, nwpserial_console_putchar);
+
+       /* wait for transmitter to become empty */
+       while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
+               cpu_relax();
+
+       /* restore interrupt state */
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       if (locked)
+               spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver nwpserial_reg;
+static struct console nwpserial_console = {
+       .name           = "ttySQ",
+       .write          = nwpserial_console_write,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &nwpserial_reg,
+};
+#define NWPSERIAL_CONSOLE      (&nwpserial_console)
+#else
+#define NWPSERIAL_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
+
+/**************************************************************************/
+
+static int nwpserial_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void nwpserial_release_port(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void nwpserial_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_NWPSERIAL;
+}
+
+static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
+{
+       struct nwpserial_port *up = dev_id;
+       struct tty_struct *tty = up->port.state->port.tty;
+       irqreturn_t ret;
+       unsigned int iir;
+       unsigned char ch;
+
+       spin_lock(&up->port.lock);
+
+       /* check if the uart was the interrupt source. */
+       iir = dcr_read(up->dcr_host, UART_IIR);
+       if (!iir) {
+               ret = IRQ_NONE;
+               goto out;
+       }
+
+       do {
+               up->port.icount.rx++;
+               ch = dcr_read(up->dcr_host, UART_RX);
+               if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
+                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
+
+       tty_flip_buffer_push(tty);
+       ret = IRQ_HANDLED;
+
+       /* clear interrupt */
+       dcr_write(up->dcr_host, UART_IIR, 1);
+out:
+       spin_unlock(&up->port.lock);
+       return ret;
+}
+
+static int nwpserial_startup(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       int err;
+
+       up = container_of(port, struct nwpserial_port, port);
+
+       /* disable flow control by default */
+       up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
+       dcr_write(up->dcr_host, UART_MCR, up->mcr);
+
+       /* register interrupt handler */
+       err = request_irq(up->port.irq, nwpserial_interrupt,
+                       IRQF_SHARED, "nwpserial", up);
+       if (err)
+               return err;
+
+       /* enable interrupts */
+       up->ier = UART_IER_RDI;
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       /* enable receiving */
+       up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
+
+       return 0;
+}
+
+static void nwpserial_shutdown(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+
+       /* disable receiving */
+       up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+       /* disable interrupts from this port */
+       up->ier = 0;
+       dcr_write(up->dcr_host, UART_IER, up->ier);
+
+       /* free irq */
+       free_irq(up->port.irq, port);
+}
+
+static int nwpserial_verify_port(struct uart_port *port,
+                       struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static const char *nwpserial_type(struct uart_port *port)
+{
+       return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
+}
+
+static void nwpserial_set_termios(struct uart_port *port,
+                       struct ktermios *termios, struct ktermios *old)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+
+       up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
+                               | NWPSERIAL_STATUS_TXFULL;
+
+       up->port.ignore_status_mask = 0;
+       /* ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+       /* Copy back the old hardware settings */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+}
+
+static void nwpserial_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static void nwpserial_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void nwpserial_stop_rx(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       up = container_of(port, struct nwpserial_port, port);
+       /* don't forward any more data (like !CREAD) */
+       up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
+}
+
+static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
+{
+       /* check if tx buffer is full */
+       wait_for_bits(up, UART_LSR_THRE);
+       dcr_write(up->dcr_host, UART_TX, c);
+       up->port.icount.tx++;
+}
+
+static void nwpserial_start_tx(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       struct circ_buf *xmit;
+       up = container_of(port, struct nwpserial_port, port);
+       xmit  = &up->port.state->xmit;
+
+       if (port->x_char) {
+               nwpserial_putchar(up, up->port.x_char);
+               port->x_char = 0;
+       }
+
+       while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
+               nwpserial_putchar(up, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+       }
+}
+
+static unsigned int nwpserial_get_mctrl(struct uart_port *port)
+{
+       return 0;
+}
+
+static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+static void nwpserial_stop_tx(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static unsigned int nwpserial_tx_empty(struct uart_port *port)
+{
+       struct nwpserial_port *up;
+       unsigned long flags;
+       int ret;
+       up = container_of(port, struct nwpserial_port, port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = dcr_read(up->dcr_host, UART_LSR);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+}
+
+static struct uart_ops nwpserial_pops = {
+       .tx_empty     = nwpserial_tx_empty,
+       .set_mctrl    = nwpserial_set_mctrl,
+       .get_mctrl    = nwpserial_get_mctrl,
+       .stop_tx      = nwpserial_stop_tx,
+       .start_tx     = nwpserial_start_tx,
+       .stop_rx      = nwpserial_stop_rx,
+       .enable_ms    = nwpserial_enable_ms,
+       .break_ctl    = nwpserial_break_ctl,
+       .startup      = nwpserial_startup,
+       .shutdown     = nwpserial_shutdown,
+       .set_termios  = nwpserial_set_termios,
+       .type         = nwpserial_type,
+       .release_port = nwpserial_release_port,
+       .request_port = nwpserial_request_port,
+       .config_port  = nwpserial_config_port,
+       .verify_port  = nwpserial_verify_port,
+};
+
+static struct uart_driver nwpserial_reg = {
+       .owner       = THIS_MODULE,
+       .driver_name = "nwpserial",
+       .dev_name    = "ttySQ",
+       .major       = TTY_MAJOR,
+       .minor       = 68,
+       .nr          = NWPSERIAL_NR,
+       .cons        = NWPSERIAL_CONSOLE,
+};
+
+int nwpserial_register_port(struct uart_port *port)
+{
+       struct nwpserial_port *up = NULL;
+       int ret = -1;
+       int i;
+       static int first = 1;
+       int dcr_len;
+       int dcr_base;
+       struct device_node *dn;
+
+       mutex_lock(&nwpserial_mutex);
+
+       dn = port->dev->of_node;
+       if (dn == NULL)
+               goto out;
+
+       /* get dcr base. */
+       dcr_base = dcr_resource_start(dn, 0);
+
+       /* find matching entry */
+       for (i = 0; i < NWPSERIAL_NR; i++)
+               if (nwpserial_ports[i].port.iobase == dcr_base) {
+                       up = &nwpserial_ports[i];
+                       break;
+               }
+
+       /* we didn't find a mtching entry, search for a free port */
+       if (up == NULL)
+               for (i = 0; i < NWPSERIAL_NR; i++)
+                       if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
+                               nwpserial_ports[i].port.iobase == 0) {
+                               up = &nwpserial_ports[i];
+                               break;
+                       }
+
+       if (up == NULL) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       if (first)
+               uart_register_driver(&nwpserial_reg);
+       first = 0;
+
+       up->port.membase      = port->membase;
+       up->port.irq          = port->irq;
+       up->port.uartclk      = port->uartclk;
+       up->port.fifosize     = port->fifosize;
+       up->port.regshift     = port->regshift;
+       up->port.iotype       = port->iotype;
+       up->port.flags        = port->flags;
+       up->port.mapbase      = port->mapbase;
+       up->port.private_data = port->private_data;
+
+       if (port->dev)
+               up->port.dev = port->dev;
+
+       if (up->port.iobase != dcr_base) {
+               up->port.ops          = &nwpserial_pops;
+               up->port.fifosize     = 16;
+
+               spin_lock_init(&up->port.lock);
+
+               up->port.iobase = dcr_base;
+               dcr_len = dcr_resource_len(dn, 0);
+
+               up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+               if (!DCR_MAP_OK(up->dcr_host)) {
+                       printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
+                       goto out;
+               }
+       }
+
+       ret = uart_add_one_port(&nwpserial_reg, &up->port);
+       if (ret == 0)
+               ret = up->port.line;
+
+out:
+       mutex_unlock(&nwpserial_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(nwpserial_register_port);
+
+void nwpserial_unregister_port(int line)
+{
+       struct nwpserial_port *up = &nwpserial_ports[line];
+       mutex_lock(&nwpserial_mutex);
+       uart_remove_one_port(&nwpserial_reg, &up->port);
+
+       up->port.type = PORT_UNKNOWN;
+
+       mutex_unlock(&nwpserial_mutex);
+}
+EXPORT_SYMBOL(nwpserial_unregister_port);
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static int __init nwpserial_console_init(void)
+{
+       struct nwpserial_port *up = NULL;
+       struct device_node *dn;
+       const char *name;
+       int dcr_base;
+       int dcr_len;
+       int i;
+
+       /* search for a free port */
+       for (i = 0; i < NWPSERIAL_NR; i++)
+               if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
+                       up = &nwpserial_ports[i];
+                       break;
+               }
+
+       if (up == NULL)
+               return -1;
+
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+       if (name == NULL)
+               return -1;
+
+       dn = of_find_node_by_path(name);
+       if (!dn)
+               return -1;
+
+       spin_lock_init(&up->port.lock);
+       up->port.ops = &nwpserial_pops;
+       up->port.type = PORT_NWPSERIAL;
+       up->port.fifosize = 16;
+
+       dcr_base = dcr_resource_start(dn, 0);
+       dcr_len = dcr_resource_len(dn, 0);
+       up->port.iobase = dcr_base;
+
+       up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+       if (!DCR_MAP_OK(up->dcr_host)) {
+               printk("Cannot map DCR resources for SERIAL");
+               return -1;
+       }
+       register_console(&nwpserial_console);
+       return 0;
+}
+console_initcall(nwpserial_console_init);
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
new file mode 100644 (file)
index 0000000..5c7abe4
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  Serial Port driver for Open Firmware platform devices
+ *
+ *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM 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; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/nwpserial.h>
+
+struct of_serial_info {
+       int type;
+       int line;
+};
+
+/*
+ * Fill a struct uart_port for a given device node
+ */
+static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
+                                       int type, struct uart_port *port)
+{
+       struct resource resource;
+       struct device_node *np = ofdev->dev.of_node;
+       const __be32 *clk, *spd;
+       const __be32 *prop;
+       int ret, prop_size;
+
+       memset(port, 0, sizeof *port);
+       spd = of_get_property(np, "current-speed", NULL);
+       clk = of_get_property(np, "clock-frequency", NULL);
+       if (!clk) {
+               dev_warn(&ofdev->dev, "no clock-frequency property set\n");
+               return -ENODEV;
+       }
+
+       ret = of_address_to_resource(np, 0, &resource);
+       if (ret) {
+               dev_warn(&ofdev->dev, "invalid address\n");
+               return ret;
+       }
+
+       spin_lock_init(&port->lock);
+       port->mapbase = resource.start;
+
+       /* Check for shifted address mapping */
+       prop = of_get_property(np, "reg-offset", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               port->mapbase += be32_to_cpup(prop);
+
+       /* Check for registers offset within the devices address range */
+       prop = of_get_property(np, "reg-shift", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               port->regshift = be32_to_cpup(prop);
+
+       port->irq = irq_of_parse_and_map(np, 0);
+       port->iotype = UPIO_MEM;
+       port->type = type;
+       port->uartclk = be32_to_cpup(clk);
+       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
+               | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       port->dev = &ofdev->dev;
+       /* If current-speed was set, then try not to change it. */
+       if (spd)
+               port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
+
+       return 0;
+}
+
+/*
+ * Try to register a serial port
+ */
+static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
+                                               const struct of_device_id *id)
+{
+       struct of_serial_info *info;
+       struct uart_port port;
+       int port_type;
+       int ret;
+
+       if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+               return -EBUSY;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL)
+               return -ENOMEM;
+
+       port_type = (unsigned long)id->data;
+       ret = of_platform_serial_setup(ofdev, port_type, &port);
+       if (ret)
+               goto out;
+
+       switch (port_type) {
+#ifdef CONFIG_SERIAL_8250
+       case PORT_8250 ... PORT_MAX_8250:
+               ret = serial8250_register_port(&port);
+               break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       case PORT_NWPSERIAL:
+               ret = nwpserial_register_port(&port);
+               break;
+#endif
+       default:
+               /* need to add code for these */
+       case PORT_UNKNOWN:
+               dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
+               ret = -ENODEV;
+               break;
+       }
+       if (ret < 0)
+               goto out;
+
+       info->type = port_type;
+       info->line = ret;
+       dev_set_drvdata(&ofdev->dev, info);
+       return 0;
+out:
+       kfree(info);
+       irq_dispose_mapping(port.irq);
+       return ret;
+}
+
+/*
+ * Release a line
+ */
+static int of_platform_serial_remove(struct platform_device *ofdev)
+{
+       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
+       switch (info->type) {
+#ifdef CONFIG_SERIAL_8250
+       case PORT_8250 ... PORT_MAX_8250:
+               serial8250_unregister_port(info->line);
+               break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       case PORT_NWPSERIAL:
+               nwpserial_unregister_port(info->line);
+               break;
+#endif
+       default:
+               /* need to add code for these */
+               break;
+       }
+       kfree(info);
+       return 0;
+}
+
+/*
+ * A few common types, add more as needed.
+ */
+static struct of_device_id __devinitdata of_platform_serial_table[] = {
+       { .type = "serial", .compatible = "ns8250",   .data = (void *)PORT_8250, },
+       { .type = "serial", .compatible = "ns16450",  .data = (void *)PORT_16450, },
+       { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
+       { .type = "serial", .compatible = "ns16550",  .data = (void *)PORT_16550, },
+       { .type = "serial", .compatible = "ns16750",  .data = (void *)PORT_16750, },
+       { .type = "serial", .compatible = "ns16850",  .data = (void *)PORT_16850, },
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+       { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
+                                       .data = (void *)PORT_NWPSERIAL, },
+#endif
+       { .type = "serial",                           .data = (void *)PORT_UNKNOWN, },
+       { /* end of list */ },
+};
+
+static struct of_platform_driver of_platform_serial_driver = {
+       .driver = {
+               .name = "of_serial",
+               .owner = THIS_MODULE,
+               .of_match_table = of_platform_serial_table,
+       },
+       .probe = of_platform_serial_probe,
+       .remove = of_platform_serial_remove,
+};
+
+static int __init of_platform_serial_init(void)
+{
+       return of_register_platform_driver(&of_platform_serial_driver);
+}
+module_init(of_platform_serial_init);
+
+static void __exit of_platform_serial_exit(void)
+{
+       return of_unregister_platform_driver(&of_platform_serial_driver);
+};
+module_exit(of_platform_serial_exit);
+
+MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
new file mode 100644 (file)
index 0000000..7f2f010
--- /dev/null
@@ -0,0 +1,1359 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *     Govindraj R     <govindraj.raja@ti.com>
+ *     Thara Gopinath  <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Note: This driver is made seperate from 8250 driver as we cannot
+ * over load 8250 driver with omap platform specific configuration for
+ * features like DMA, it makes easier to implement features like DMA and
+ * hardware flow control and software flow control configuration with
+ * this driver as required for the omap-platform.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/omap-serial.h>
+
+static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
+
+/* Forward declaration of functions */
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
+static void serial_omap_rx_timeout(unsigned long uart_no);
+static int serial_omap_start_rxdma(struct uart_omap_port *up);
+
+static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
+{
+       offset <<= up->port.regshift;
+       return readw(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_omap_port *up, int offset, int value)
+{
+       offset <<= up->port.regshift;
+       writew(value, up->port.membase + offset);
+}
+
+static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
+{
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+/*
+ * serial_omap_get_divisor - calculate divisor value
+ * @port: uart port info
+ * @baud: baudrate for which divisor needs to be calculated.
+ *
+ * We have written our own function to get the divisor so as to support
+ * 13x mode. 3Mbps Baudrate as an different divisor.
+ * Reference OMAP TRM Chapter 17:
+ * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
+ * referring to oversampling - divisor value
+ * baudrate 460,800 to 3,686,400 all have divisor 13
+ * except 3,000,000 which has divisor value 16
+ */
+static unsigned int
+serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int divisor;
+
+       if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
+               divisor = 13;
+       else
+               divisor = 16;
+       return port->uartclk/(baud * divisor);
+}
+
+static void serial_omap_stop_rxdma(struct uart_omap_port *up)
+{
+       if (up->uart_dma.rx_dma_used) {
+               del_timer(&up->uart_dma.rx_timer);
+               omap_stop_dma(up->uart_dma.rx_dma_channel);
+               omap_free_dma(up->uart_dma.rx_dma_channel);
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_used = false;
+       }
+}
+
+static void serial_omap_enable_ms(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_omap_stop_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma &&
+               up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
+               /*
+                * Check if dma is still active. If yes do nothing,
+                * return. Else stop dma
+                */
+               if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
+                       return;
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               omap_free_dma(up->uart_dma.tx_dma_channel);
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_stop_rx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       if (up->use_dma)
+               serial_omap_stop_rxdma(up);
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_omap_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int flag;
+       unsigned char ch, lsr = *status;
+       int max_count = 256;
+
+       do {
+               if (likely(lsr & UART_LSR_DR))
+                       ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (lsr & UART_LSR_PE) {
+                               up->port.icount.parity++;
+                       } else if (lsr & UART_LSR_FE) {
+                               up->port.icount.frame++;
+                       }
+
+                       if (lsr & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       lsr &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               lsr |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (lsr & UART_LSR_BI)
+                               flag = TTY_BREAK;
+                       else if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ignore_char:
+               lsr = serial_in(up, UART_LSR);
+       } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+}
+
+static void transmit_chars(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_omap_stop_tx(&up->port);
+               return;
+       }
+       count = up->port.fifosize / 4;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_omap_stop_tx(&up->port);
+}
+
+static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
+{
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_omap_start_tx(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       struct circ_buf *xmit;
+       unsigned int start;
+       int ret = 0;
+
+       if (!up->use_dma) {
+               serial_omap_enable_ier_thri(up);
+               return;
+       }
+
+       if (up->uart_dma.tx_dma_used)
+               return;
+
+       xmit = &up->port.state->xmit;
+
+       if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_tx,
+                               "UART Tx DMA",
+                               (void *)uart_tx_dma_callback, up,
+                               &(up->uart_dma.tx_dma_channel));
+
+               if (ret < 0) {
+                       serial_omap_enable_ier_thri(up);
+                       return;
+               }
+       }
+       spin_lock(&(up->uart_dma.tx_lock));
+       up->uart_dma.tx_dma_used = true;
+       spin_unlock(&(up->uart_dma.tx_lock));
+
+       start = up->uart_dma.tx_buf_dma_phys +
+                               (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys +
+                       UART_XMIT_SIZE) - start;
+
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static unsigned int check_modem_status(struct uart_omap_port *up)
+{
+       unsigned int status;
+
+       status = serial_in(up, UART_MSR);
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return status;
+
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.state != NULL) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change
+                               (&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change
+                               (&up->port, status & UART_MSR_CTS);
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       return status;
+}
+
+/**
+ * serial_omap_irq() - This handles the interrupt from one port
+ * @irq: uart port irq number
+ * @dev_id: uart port info
+ */
+static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+{
+       struct uart_omap_port *up = dev_id;
+       unsigned int iir, lsr;
+       unsigned long flags;
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       if (iir & UART_IIR_RLSI) {
+               if (!up->use_dma) {
+                       if (lsr & UART_LSR_DR)
+                               receive_chars(up, &lsr);
+               } else {
+                       up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+                       if ((serial_omap_start_rxdma(up) != 0) &&
+                                       (lsr & UART_LSR_DR))
+                               receive_chars(up, &lsr);
+               }
+       }
+
+       check_modem_status(up);
+       if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
+               transmit_chars(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       up->port_activity = jiffies;
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_omap_tx_empty(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       unsigned int ret = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_omap_get_mctrl(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char status;
+       unsigned int ret = 0;
+
+       status = check_modem_status(up);
+       dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
+
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char mcr = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_omap_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial_omap_startup(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
+                               up->name, up);
+       if (retval)
+               return retval;
+
+       dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_omap_clear_fifos(up);
+       /* For Hardware flow control */
+       serial_out(up, UART_MCR, UART_MCR_RTS);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_in(up, UART_LSR);
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+       spin_lock_irqsave(&up->port.lock, flags);
+       /*
+        * Most PC uarts need OUT2 raised to enable interrupts.
+        */
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       up->msr_saved_flags = 0;
+       if (up->use_dma) {
+               free_page((unsigned long)up->port.state->xmit.buf);
+               up->port.state->xmit.buf = dma_alloc_coherent(NULL,
+                       UART_XMIT_SIZE,
+                       (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+                       0);
+               init_timer(&(up->uart_dma.rx_timer));
+               up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+               up->uart_dma.rx_timer.data = up->pdev->id;
+               /* Currently the buffer size is 4KB. Can increase it */
+               up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
+                       up->uart_dma.rx_buf_size,
+                       (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
+       }
+       /*
+        * Finally, enable interrupts. Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_out(up, UART_IER, up->ier);
+
+       up->port_activity = jiffies;
+       return 0;
+}
+
+static void serial_omap_shutdown(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned long flags = 0;
+
+       dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_omap_clear_fifos(up);
+
+       /*
+        * Read data port to reset things, and then free the irq
+        */
+       if (serial_in(up, UART_LSR) & UART_LSR_DR)
+               (void) serial_in(up, UART_RX);
+       if (up->use_dma) {
+               dma_free_coherent(up->port.dev,
+                       UART_XMIT_SIZE, up->port.state->xmit.buf,
+                       up->uart_dma.tx_buf_dma_phys);
+               up->port.state->xmit.buf = NULL;
+               serial_omap_stop_rx(port);
+               dma_free_coherent(up->port.dev,
+                       up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
+                       up->uart_dma.rx_buf_dma_phys);
+               up->uart_dma.rx_buf = NULL;
+       }
+       free_irq(up->port.irq, up);
+}
+
+static inline void
+serial_omap_configure_xonxoff
+               (struct uart_omap_port *up, struct ktermios *termios)
+{
+       unsigned char efr = 0;
+
+       up->lcr = serial_in(up, UART_LCR);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+       serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+       serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+       /* clear SW control mode bits */
+       efr = up->efr;
+       efr &= OMAP_UART_SW_CLR;
+
+       /*
+        * IXON Flag:
+        * Enable XON/XOFF flow control on output.
+        * Transmit XON1, XOFF1
+        */
+       if (termios->c_iflag & IXON)
+               efr |= OMAP_UART_SW_TX;
+
+       /*
+        * IXOFF Flag:
+        * Enable XON/XOFF flow control on input.
+        * Receiver compares XON1, XOFF1.
+        */
+       if (termios->c_iflag & IXOFF)
+               efr |= OMAP_UART_SW_RX;
+
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       up->mcr = serial_in(up, UART_MCR);
+
+       /*
+        * IXANY Flag:
+        * Enable any character to restart output.
+        * Operation resumes after receiving any
+        * character after recognition of the XOFF character
+        */
+       if (termios->c_iflag & IXANY)
+               up->mcr |= UART_MCR_XONANY;
+
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+       /* Enable special char function UARTi.EFR_REG[5] and
+        * load the new software flow control mode IXON or IXOFF
+        * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+        */
+       serial_out(up, UART_EFR, efr | UART_EFR_SCD);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+       serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+       serial_out(up, UART_LCR, up->lcr);
+}
+
+static void
+serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
+                       struct ktermios *old)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char cval = 0;
+       unsigned char efr = 0;
+       unsigned long flags = 0;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
+       quot = serial_omap_get_divisor(port, baud);
+
+       up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
+                       UART_FCR_ENABLE_FIFO;
+       if (up->use_dma)
+               up->fcr |= UART_FCR_DMA_SELECT;
+
+       /*
+        * Ok, we're now changing the port state. Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * Modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, cval);         /* reset DLAB */
+
+       /* FIFOs and DMA Settings */
+
+       /* FCR can be changed only when the
+        * baud clock is not running
+        * DLL_REG and DLH_REG set to 0.
+        */
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_out(up, UART_DLL, 0);
+       serial_out(up, UART_DLM, 0);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       up->mcr = serial_in(up, UART_MCR);
+       serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+       /* FIFO ENABLE, DMA MODE */
+       serial_out(up, UART_FCR, up->fcr);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       if (up->use_dma) {
+               serial_out(up, UART_TI752_TLR, 0);
+               serial_out(up, UART_OMAP_SCR,
+                       (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
+       }
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+       serial_out(up, UART_MCR, up->mcr);
+
+       /* Protocol, Baud Rate, and Interrupt Settings */
+
+       serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       up->efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, 0);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+
+       serial_out(up, UART_LCR, 0);
+       serial_out(up, UART_IER, up->ier);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+       serial_out(up, UART_EFR, up->efr);
+       serial_out(up, UART_LCR, cval);
+
+       if (baud > 230400 && baud != 3000000)
+               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
+       else
+               serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+
+       /* Hardware Flow Control Configuration */
+
+       if (termios->c_cflag & CRTSCTS) {
+               efr |= (UART_EFR_CTS | UART_EFR_RTS);
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+               up->mcr = serial_in(up, UART_MCR);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+               up->efr = serial_in(up, UART_EFR);
+               serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+               serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+               serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+               serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+               serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+               serial_out(up, UART_LCR, cval);
+       }
+
+       serial_omap_set_mctrl(&up->port, up->port.mctrl);
+       /* Software Flow Control Configuration */
+       if (termios->c_iflag & (IXON | IXOFF))
+               serial_omap_configure_xonxoff(up, termios);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
+}
+
+static void
+serial_omap_pm(struct uart_port *port, unsigned int state,
+              unsigned int oldstate)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned char efr;
+
+       dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
+       serial_out(up, UART_LCR, 0);
+
+       serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       serial_out(up, UART_EFR, efr);
+       serial_out(up, UART_LCR, 0);
+       /* Enable module level wake up */
+       serial_out(up, UART_OMAP_WER,
+               (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
+}
+
+static void serial_omap_release_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_release_port+\n");
+}
+
+static int serial_omap_request_port(struct uart_port *port)
+{
+       dev_dbg(port->dev, "serial_omap_request_port+\n");
+       return 0;
+}
+
+static void serial_omap_config_port(struct uart_port *port, int flags)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
+                                                       up->pdev->id);
+       up->port.type = PORT_OMAP;
+}
+
+static int
+serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       dev_dbg(port->dev, "serial_omap_verify_port+\n");
+       return -EINVAL;
+}
+
+static const char *
+serial_omap_type(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
+       return up->name;
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void wait_for_xmitr(struct uart_omap_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
+
+                       udelay(1);
+               }
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+static int serial_omap_poll_get_char(struct uart_port *port)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+       unsigned int status = serial_in(up, UART_LSR);
+
+       if (!(status & UART_LSR_DR))
+               return NO_POLL_CHAR;
+
+       return serial_in(up, UART_RX);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
+static void serial_omap_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+static void
+serial_omap_console_write(struct console *co, const char *s,
+               unsigned int count)
+{
+       struct uart_omap_port *up = serial_omap_console_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock(&up->port.lock);
+       else
+               spin_lock(&up->port.lock);
+
+       /*
+        * First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, serial_omap_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+       /*
+        * The receive handling will happen properly because the
+        * receive ready bit will still be set; it is not cleared
+        * on read.  However, modem control will not, we must
+        * call it if we have saved something in the saved flags
+        * while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init
+serial_omap_console_setup(struct console *co, char *options)
+{
+       struct uart_omap_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (serial_omap_console_ports[co->index] == NULL)
+               return -ENODEV;
+       up = serial_omap_console_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_omap_console = {
+       .name           = OMAP_SERIAL_NAME,
+       .write          = serial_omap_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_omap_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_omap_reg,
+};
+
+static void serial_omap_add_console_port(struct uart_omap_port *up)
+{
+       serial_omap_console_ports[up->pdev->id] = up;
+}
+
+#define OMAP_CONSOLE   (&serial_omap_console)
+
+#else
+
+#define OMAP_CONSOLE   NULL
+
+static inline void serial_omap_add_console_port(struct uart_omap_port *up)
+{}
+
+#endif
+
+static struct uart_ops serial_omap_pops = {
+       .tx_empty       = serial_omap_tx_empty,
+       .set_mctrl      = serial_omap_set_mctrl,
+       .get_mctrl      = serial_omap_get_mctrl,
+       .stop_tx        = serial_omap_stop_tx,
+       .start_tx       = serial_omap_start_tx,
+       .stop_rx        = serial_omap_stop_rx,
+       .enable_ms      = serial_omap_enable_ms,
+       .break_ctl      = serial_omap_break_ctl,
+       .startup        = serial_omap_startup,
+       .shutdown       = serial_omap_shutdown,
+       .set_termios    = serial_omap_set_termios,
+       .pm             = serial_omap_pm,
+       .type           = serial_omap_type,
+       .release_port   = serial_omap_release_port,
+       .request_port   = serial_omap_request_port,
+       .config_port    = serial_omap_config_port,
+       .verify_port    = serial_omap_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = serial_omap_poll_put_char,
+       .poll_get_char  = serial_omap_poll_get_char,
+#endif
+};
+
+static struct uart_driver serial_omap_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "OMAP-SERIAL",
+       .dev_name       = OMAP_SERIAL_NAME,
+       .nr             = OMAP_MAX_HSUART_PORTS,
+       .cons           = OMAP_CONSOLE,
+};
+
+static int
+serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct uart_omap_port *up = platform_get_drvdata(pdev);
+
+       if (up)
+               uart_suspend_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static int serial_omap_resume(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       if (up)
+               uart_resume_port(&serial_omap_reg, &up->port);
+       return 0;
+}
+
+static void serial_omap_rx_timeout(unsigned long uart_no)
+{
+       struct uart_omap_port *up = ui[uart_no];
+       unsigned int curr_dma_pos, curr_transmitted_size;
+       int ret = 0;
+
+       curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
+       if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+                            (curr_dma_pos == 0)) {
+               if (jiffies_to_msecs(jiffies - up->port_activity) <
+                                                       RX_TIMEOUT) {
+                       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+               } else {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+               return;
+       }
+
+       curr_transmitted_size = curr_dma_pos -
+                                       up->uart_dma.prev_rx_dma_pos;
+       up->port.icount.rx += curr_transmitted_size;
+       tty_insert_flip_string(up->port.state->port.tty,
+                       up->uart_dma.rx_buf +
+                       (up->uart_dma.prev_rx_dma_pos -
+                       up->uart_dma.rx_buf_dma_phys),
+                       curr_transmitted_size);
+       tty_flip_buffer_push(up->port.state->port.tty);
+       up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
+       if (up->uart_dma.rx_buf_size +
+                       up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+               ret = serial_omap_start_rxdma(up);
+               if (ret < 0) {
+                       serial_omap_stop_rxdma(up);
+                       up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+                       serial_out(up, UART_IER, up->ier);
+               }
+       } else  {
+               mod_timer(&up->uart_dma.rx_timer, jiffies +
+                       usecs_to_jiffies(up->uart_dma.rx_timeout));
+       }
+       up->port_activity = jiffies;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       return;
+}
+
+static int serial_omap_start_rxdma(struct uart_omap_port *up)
+{
+       int ret = 0;
+
+       if (up->uart_dma.rx_dma_channel == -1) {
+               ret = omap_request_dma(up->uart_dma.uart_dma_rx,
+                               "UART Rx DMA",
+                               (void *)uart_rx_dma_callback, up,
+                               &(up->uart_dma.rx_dma_channel));
+               if (ret < 0)
+                       return ret;
+
+               omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+               omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC,
+                               up->uart_dma.rx_buf_dma_phys, 0, 0);
+               omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.rx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_rx, 0);
+       }
+       up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.rx_dma_channel);
+       mod_timer(&up->uart_dma.rx_timer, jiffies +
+                               usecs_to_jiffies(up->uart_dma.rx_timeout));
+       up->uart_dma.rx_dma_used = true;
+       return ret;
+}
+
+static void serial_omap_continue_tx(struct uart_omap_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       unsigned int start = up->uart_dma.tx_buf_dma_phys
+                       + (xmit->tail & (UART_XMIT_SIZE - 1));
+
+       if (uart_circ_empty(xmit))
+               return;
+
+       up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+       /*
+        * It is a circular buffer. See if the buffer has wounded back.
+        * If yes it will have to be transferred in two separate dma
+        * transfers
+        */
+       if (start + up->uart_dma.tx_buf_size >=
+                       up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+               up->uart_dma.tx_buf_size =
+                       (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+       omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               up->uart_dma.uart_base, 0, 0);
+       omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+                               OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+       omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+                               OMAP_DMA_DATA_TYPE_S8,
+                               up->uart_dma.tx_buf_size, 1,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               up->uart_dma.uart_dma_tx, 0);
+       /* FIXME: Cache maintenance needed here? */
+       omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct uart_omap_port *up = (struct uart_omap_port *)data;
+       struct circ_buf *xmit = &up->port.state->xmit;
+
+       xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+                       (UART_XMIT_SIZE - 1);
+       up->port.icount.tx += up->uart_dma.tx_buf_size;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit)) {
+               spin_lock(&(up->uart_dma.tx_lock));
+               serial_omap_stop_tx(&up->port);
+               up->uart_dma.tx_dma_used = false;
+               spin_unlock(&(up->uart_dma.tx_lock));
+       } else {
+               omap_stop_dma(up->uart_dma.tx_dma_channel);
+               serial_omap_continue_tx(up);
+       }
+       up->port_activity = jiffies;
+       return;
+}
+
+static int serial_omap_probe(struct platform_device *pdev)
+{
+       struct uart_omap_port   *up;
+       struct resource         *mem, *irq, *dma_tx, *dma_rx;
+       struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+       int ret = -ENOSPC;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                                    pdev->dev.driver->name)) {
+               dev_err(&pdev->dev, "memory region already claimed\n");
+               return -EBUSY;
+       }
+
+       dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+       if (!dma_rx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+       if (!dma_tx) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       up = kzalloc(sizeof(*up), GFP_KERNEL);
+       if (up == NULL) {
+               ret = -ENOMEM;
+               goto do_release_region;
+       }
+       sprintf(up->name, "OMAP UART%d", pdev->id);
+       up->pdev = pdev;
+       up->port.dev = &pdev->dev;
+       up->port.type = PORT_OMAP;
+       up->port.iotype = UPIO_MEM;
+       up->port.irq = irq->start;
+
+       up->port.regshift = 2;
+       up->port.fifosize = 64;
+       up->port.ops = &serial_omap_pops;
+       up->port.line = pdev->id;
+
+       up->port.membase = omap_up_info->membase;
+       up->port.mapbase = omap_up_info->mapbase;
+       up->port.flags = omap_up_info->flags;
+       up->port.irqflags = omap_up_info->irqflags;
+       up->port.uartclk = omap_up_info->uartclk;
+       up->uart_dma.uart_base = mem->start;
+
+       if (omap_up_info->dma_enabled) {
+               up->uart_dma.uart_dma_tx = dma_tx->start;
+               up->uart_dma.uart_dma_rx = dma_rx->start;
+               up->use_dma = 1;
+               up->uart_dma.rx_buf_size = 4096;
+               up->uart_dma.rx_timeout = 2;
+               spin_lock_init(&(up->uart_dma.tx_lock));
+               spin_lock_init(&(up->uart_dma.rx_lock));
+               up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+               up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+       }
+
+       ui[pdev->id] = up;
+       serial_omap_add_console_port(up);
+
+       ret = uart_add_one_port(&serial_omap_reg, &up->port);
+       if (ret != 0)
+               goto do_release_region;
+
+       platform_set_drvdata(pdev, up);
+       return 0;
+err:
+       dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
+                               pdev->id, __func__, ret);
+do_release_region:
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+       return ret;
+}
+
+static int serial_omap_remove(struct platform_device *dev)
+{
+       struct uart_omap_port *up = platform_get_drvdata(dev);
+
+       platform_set_drvdata(dev, NULL);
+       if (up) {
+               uart_remove_one_port(&serial_omap_reg, &up->port);
+               kfree(up);
+       }
+       return 0;
+}
+
+static struct platform_driver serial_omap_driver = {
+       .probe          = serial_omap_probe,
+       .remove         = serial_omap_remove,
+
+       .suspend        = serial_omap_suspend,
+       .resume         = serial_omap_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init serial_omap_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&serial_omap_reg);
+       if (ret != 0)
+               return ret;
+       ret = platform_driver_register(&serial_omap_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_omap_reg);
+       return ret;
+}
+
+static void __exit serial_omap_exit(void)
+{
+       platform_driver_unregister(&serial_omap_driver);
+       uart_unregister_driver(&serial_omap_reg);
+}
+
+module_init(serial_omap_init);
+module_exit(serial_omap_exit);
+
+MODULE_DESCRIPTION("OMAP High Speed UART driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
new file mode 100644 (file)
index 0000000..70a6145
--- /dev/null
@@ -0,0 +1,1451 @@
+/*
+ *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *
+ *This program is free software; you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation; 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; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/dmaengine.h>
+#include <linux/pch_dma.h>
+
+enum {
+       PCH_UART_HANDLED_RX_INT_SHIFT,
+       PCH_UART_HANDLED_TX_INT_SHIFT,
+       PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
+       PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
+       PCH_UART_HANDLED_MS_INT_SHIFT,
+};
+
+enum {
+       PCH_UART_8LINE,
+       PCH_UART_2LINE,
+};
+
+#define PCH_UART_DRIVER_DEVICE "ttyPCH"
+
+#define PCH_UART_NR_GE_256FIFO         1
+#define PCH_UART_NR_GE_64FIFO          3
+#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
+#define PCH_UART_NR    PCH_UART_NR_GE
+
+#define PCH_UART_HANDLED_RX_INT        (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_TX_INT        (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_ERR_INT    (1<<((\
+                                       PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_TRG_INT    (1<<((\
+                                       PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_MS_INT        (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+
+#define PCH_UART_RBR           0x00
+#define PCH_UART_THR           0x00
+
+#define PCH_UART_IER_MASK      (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
+                               PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
+#define PCH_UART_IER_ERBFI     0x00000001
+#define PCH_UART_IER_ETBEI     0x00000002
+#define PCH_UART_IER_ELSI      0x00000004
+#define PCH_UART_IER_EDSSI     0x00000008
+
+#define PCH_UART_IIR_IP                        0x00000001
+#define PCH_UART_IIR_IID               0x00000006
+#define PCH_UART_IIR_MSI               0x00000000
+#define PCH_UART_IIR_TRI               0x00000002
+#define PCH_UART_IIR_RRI               0x00000004
+#define PCH_UART_IIR_REI               0x00000006
+#define PCH_UART_IIR_TOI               0x00000008
+#define PCH_UART_IIR_FIFO256           0x00000020
+#define PCH_UART_IIR_FIFO64            PCH_UART_IIR_FIFO256
+#define PCH_UART_IIR_FE                        0x000000C0
+
+#define PCH_UART_FCR_FIFOE             0x00000001
+#define PCH_UART_FCR_RFR               0x00000002
+#define PCH_UART_FCR_TFR               0x00000004
+#define PCH_UART_FCR_DMS               0x00000008
+#define PCH_UART_FCR_FIFO256           0x00000020
+#define PCH_UART_FCR_RFTL              0x000000C0
+
+#define PCH_UART_FCR_RFTL1             0x00000000
+#define PCH_UART_FCR_RFTL64            0x00000040
+#define PCH_UART_FCR_RFTL128           0x00000080
+#define PCH_UART_FCR_RFTL224           0x000000C0
+#define PCH_UART_FCR_RFTL16            PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL32            PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL56            PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL4             PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL8             PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL14            PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL_SHIFT                6
+
+#define PCH_UART_LCR_WLS       0x00000003
+#define PCH_UART_LCR_STB       0x00000004
+#define PCH_UART_LCR_PEN       0x00000008
+#define PCH_UART_LCR_EPS       0x00000010
+#define PCH_UART_LCR_SP                0x00000020
+#define PCH_UART_LCR_SB                0x00000040
+#define PCH_UART_LCR_DLAB      0x00000080
+#define PCH_UART_LCR_NP                0x00000000
+#define PCH_UART_LCR_OP                PCH_UART_LCR_PEN
+#define PCH_UART_LCR_EP                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
+#define PCH_UART_LCR_1P                (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
+#define PCH_UART_LCR_0P                (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
+                               PCH_UART_LCR_SP)
+
+#define PCH_UART_LCR_5BIT      0x00000000
+#define PCH_UART_LCR_6BIT      0x00000001
+#define PCH_UART_LCR_7BIT      0x00000002
+#define PCH_UART_LCR_8BIT      0x00000003
+
+#define PCH_UART_MCR_DTR       0x00000001
+#define PCH_UART_MCR_RTS       0x00000002
+#define PCH_UART_MCR_OUT       0x0000000C
+#define PCH_UART_MCR_LOOP      0x00000010
+#define PCH_UART_MCR_AFE       0x00000020
+
+#define PCH_UART_LSR_DR                0x00000001
+#define PCH_UART_LSR_ERR       (1<<7)
+
+#define PCH_UART_MSR_DCTS      0x00000001
+#define PCH_UART_MSR_DDSR      0x00000002
+#define PCH_UART_MSR_TERI      0x00000004
+#define PCH_UART_MSR_DDCD      0x00000008
+#define PCH_UART_MSR_CTS       0x00000010
+#define PCH_UART_MSR_DSR       0x00000020
+#define PCH_UART_MSR_RI                0x00000040
+#define PCH_UART_MSR_DCD       0x00000080
+#define PCH_UART_MSR_DELTA     (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
+                               PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
+
+#define PCH_UART_DLL           0x00
+#define PCH_UART_DLM           0x01
+
+#define DIV_ROUND(a, b)        (((a) + ((b)/2)) / (b))
+
+#define PCH_UART_IID_RLS       (PCH_UART_IIR_REI)
+#define PCH_UART_IID_RDR       (PCH_UART_IIR_RRI)
+#define PCH_UART_IID_RDR_TO    (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
+#define PCH_UART_IID_THRE      (PCH_UART_IIR_TRI)
+#define PCH_UART_IID_MS                (PCH_UART_IIR_MSI)
+
+#define PCH_UART_HAL_PARITY_NONE       (PCH_UART_LCR_NP)
+#define PCH_UART_HAL_PARITY_ODD                (PCH_UART_LCR_OP)
+#define PCH_UART_HAL_PARITY_EVEN       (PCH_UART_LCR_EP)
+#define PCH_UART_HAL_PARITY_FIX1       (PCH_UART_LCR_1P)
+#define PCH_UART_HAL_PARITY_FIX0       (PCH_UART_LCR_0P)
+#define PCH_UART_HAL_5BIT              (PCH_UART_LCR_5BIT)
+#define PCH_UART_HAL_6BIT              (PCH_UART_LCR_6BIT)
+#define PCH_UART_HAL_7BIT              (PCH_UART_LCR_7BIT)
+#define PCH_UART_HAL_8BIT              (PCH_UART_LCR_8BIT)
+#define PCH_UART_HAL_STB1              0
+#define PCH_UART_HAL_STB2              (PCH_UART_LCR_STB)
+
+#define PCH_UART_HAL_CLR_TX_FIFO       (PCH_UART_FCR_TFR)
+#define PCH_UART_HAL_CLR_RX_FIFO       (PCH_UART_FCR_RFR)
+#define PCH_UART_HAL_CLR_ALL_FIFO      (PCH_UART_HAL_CLR_TX_FIFO | \
+                                       PCH_UART_HAL_CLR_RX_FIFO)
+
+#define PCH_UART_HAL_DMA_MODE0         0
+#define PCH_UART_HAL_FIFO_DIS          0
+#define PCH_UART_HAL_FIFO16            (PCH_UART_FCR_FIFOE)
+#define PCH_UART_HAL_FIFO256           (PCH_UART_FCR_FIFOE | \
+                                       PCH_UART_FCR_FIFO256)
+#define PCH_UART_HAL_FIFO64            (PCH_UART_HAL_FIFO256)
+#define PCH_UART_HAL_TRIGGER1          (PCH_UART_FCR_RFTL1)
+#define PCH_UART_HAL_TRIGGER64         (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER128                (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER224                (PCH_UART_FCR_RFTL224)
+#define PCH_UART_HAL_TRIGGER16         (PCH_UART_FCR_RFTL16)
+#define PCH_UART_HAL_TRIGGER32         (PCH_UART_FCR_RFTL32)
+#define PCH_UART_HAL_TRIGGER56         (PCH_UART_FCR_RFTL56)
+#define PCH_UART_HAL_TRIGGER4          (PCH_UART_FCR_RFTL4)
+#define PCH_UART_HAL_TRIGGER8          (PCH_UART_FCR_RFTL8)
+#define PCH_UART_HAL_TRIGGER14         (PCH_UART_FCR_RFTL14)
+#define PCH_UART_HAL_TRIGGER_L         (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER_M         (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER_H         (PCH_UART_FCR_RFTL224)
+
+#define PCH_UART_HAL_RX_INT            (PCH_UART_IER_ERBFI)
+#define PCH_UART_HAL_TX_INT            (PCH_UART_IER_ETBEI)
+#define PCH_UART_HAL_RX_ERR_INT                (PCH_UART_IER_ELSI)
+#define PCH_UART_HAL_MS_INT            (PCH_UART_IER_EDSSI)
+#define PCH_UART_HAL_ALL_INT           (PCH_UART_IER_MASK)
+
+#define PCH_UART_HAL_DTR               (PCH_UART_MCR_DTR)
+#define PCH_UART_HAL_RTS               (PCH_UART_MCR_RTS)
+#define PCH_UART_HAL_OUT               (PCH_UART_MCR_OUT)
+#define PCH_UART_HAL_LOOP              (PCH_UART_MCR_LOOP)
+#define PCH_UART_HAL_AFE               (PCH_UART_MCR_AFE)
+
+struct pch_uart_buffer {
+       unsigned char *buf;
+       int size;
+};
+
+struct eg20t_port {
+       struct uart_port port;
+       int port_type;
+       void __iomem *membase;
+       resource_size_t mapbase;
+       unsigned int iobase;
+       struct pci_dev *pdev;
+       int fifo_size;
+       int base_baud;
+       int start_tx;
+       int start_rx;
+       int tx_empty;
+       int int_dis_flag;
+       int trigger;
+       int trigger_level;
+       struct pch_uart_buffer rxbuf;
+       unsigned int dmsr;
+       unsigned int fcr;
+       unsigned int use_dma;
+       unsigned int use_dma_flag;
+       struct dma_async_tx_descriptor  *desc_tx;
+       struct dma_async_tx_descriptor  *desc_rx;
+       struct pch_dma_slave            param_tx;
+       struct pch_dma_slave            param_rx;
+       struct dma_chan                 *chan_tx;
+       struct dma_chan                 *chan_rx;
+       struct scatterlist              sg_tx;
+       struct scatterlist              sg_rx;
+       int                             tx_dma_use;
+       void                            *rx_buf_virt;
+       dma_addr_t                      rx_buf_dma;
+};
+
+static unsigned int default_baud = 9600;
+static const int trigger_level_256[4] = { 1, 64, 128, 224 };
+static const int trigger_level_64[4] = { 1, 16, 32, 56 };
+static const int trigger_level_16[4] = { 1, 4, 8, 14 };
+static const int trigger_level_1[4] = { 1, 1, 1, 1 };
+
+static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
+                                int base_baud)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+       priv->trigger_level = 1;
+       priv->fcr = 0;
+}
+
+static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+{
+       unsigned int msr = ioread8(base + UART_MSR);
+       priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+
+       return msr;
+}
+
+static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
+                                         unsigned int flag)
+{
+       u8 ier = ioread8(priv->membase + UART_IER);
+       ier |= flag & PCH_UART_IER_MASK;
+       iowrite8(ier, priv->membase + UART_IER);
+}
+
+static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
+                                          unsigned int flag)
+{
+       u8 ier = ioread8(priv->membase + UART_IER);
+       ier &= ~(flag & PCH_UART_IER_MASK);
+       iowrite8(ier, priv->membase + UART_IER);
+}
+
+static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+                                unsigned int parity, unsigned int bits,
+                                unsigned int stb)
+{
+       unsigned int dll, dlm, lcr;
+       int div;
+
+       div = DIV_ROUND(priv->base_baud / 16, baud);
+       if (div < 0 || USHRT_MAX <= div) {
+               pr_err("Invalid Baud(div=0x%x)\n", div);
+               return -EINVAL;
+       }
+
+       dll = (unsigned int)div & 0x00FFU;
+       dlm = ((unsigned int)div >> 8) & 0x00FFU;
+
+       if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
+               pr_err("Invalid parity(0x%x)\n", parity);
+               return -EINVAL;
+       }
+
+       if (bits & ~PCH_UART_LCR_WLS) {
+               pr_err("Invalid bits(0x%x)\n", bits);
+               return -EINVAL;
+       }
+
+       if (stb & ~PCH_UART_LCR_STB) {
+               pr_err("Invalid STB(0x%x)\n", stb);
+               return -EINVAL;
+       }
+
+       lcr = parity;
+       lcr |= bits;
+       lcr |= stb;
+
+       pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+                __func__, baud, div, lcr, jiffies);
+       iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+       iowrite8(dll, priv->membase + PCH_UART_DLL);
+       iowrite8(dlm, priv->membase + PCH_UART_DLM);
+       iowrite8(lcr, priv->membase + UART_LCR);
+
+       return 0;
+}
+
+static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
+                                   unsigned int flag)
+{
+       if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
+               pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
+               return -EINVAL;
+       }
+
+       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
+       iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
+                priv->membase + UART_FCR);
+       iowrite8(priv->fcr, priv->membase + UART_FCR);
+
+       return 0;
+}
+
+static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
+                                unsigned int dmamode,
+                                unsigned int fifo_size, unsigned int trigger)
+{
+       u8 fcr;
+
+       if (dmamode & ~PCH_UART_FCR_DMS) {
+               pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
+               return -EINVAL;
+       }
+
+       if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
+               pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
+               return -EINVAL;
+       }
+
+       if (trigger & ~PCH_UART_FCR_RFTL) {
+               pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
+               return -EINVAL;
+       }
+
+       switch (priv->fifo_size) {
+       case 256:
+               priv->trigger_level =
+                   trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       case 64:
+               priv->trigger_level =
+                   trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       case 16:
+               priv->trigger_level =
+                   trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       default:
+               priv->trigger_level =
+                   trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+               break;
+       }
+       fcr =
+           dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
+       iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
+       iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
+                priv->membase + UART_FCR);
+       iowrite8(fcr, priv->membase + UART_FCR);
+       priv->fcr = fcr;
+
+       return 0;
+}
+
+static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
+{
+       priv->dmsr = 0;
+       return get_msr(priv, priv->membase);
+}
+
+static int pch_uart_hal_write(struct eg20t_port *priv,
+                             const unsigned char *buf, int tx_size)
+{
+       int i;
+       unsigned int thr;
+
+       for (i = 0; i < tx_size;) {
+               thr = buf[i++];
+               iowrite8(thr, priv->membase + PCH_UART_THR);
+       }
+       return i;
+}
+
+static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
+                            int rx_size)
+{
+       int i;
+       u8 rbr, lsr;
+
+       lsr = ioread8(priv->membase + UART_LSR);
+       for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
+            i < rx_size && lsr & UART_LSR_DR;
+            lsr = ioread8(priv->membase + UART_LSR)) {
+               rbr = ioread8(priv->membase + PCH_UART_RBR);
+               buf[i++] = rbr;
+       }
+       return i;
+}
+
+static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+{
+       unsigned int iir;
+       int ret;
+
+       iir = ioread8(priv->membase + UART_IIR);
+       ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
+       return ret;
+}
+
+static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
+{
+       return ioread8(priv->membase + UART_LSR);
+}
+
+static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
+{
+       unsigned int lcr;
+
+       lcr = ioread8(priv->membase + UART_LCR);
+       if (on)
+               lcr |= PCH_UART_LCR_SB;
+       else
+               lcr &= ~PCH_UART_LCR_SB;
+
+       iowrite8(lcr, priv->membase + UART_LCR);
+}
+
+static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
+                  int size)
+{
+       struct uart_port *port;
+       struct tty_struct *tty;
+
+       port = &priv->port;
+       tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return -EBUSY;
+       }
+
+       tty_insert_flip_string(tty, buf, size);
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+
+       return 0;
+}
+
+static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
+{
+       int ret;
+       struct uart_port *port = &priv->port;
+
+       if (port->x_char) {
+               pr_debug("%s:X character send %02x (%lu)\n", __func__,
+                       port->x_char, jiffies);
+               buf[0] = port->x_char;
+               port->x_char = 0;
+               ret = 1;
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int dma_push_rx(struct eg20t_port *priv, int size)
+{
+       struct tty_struct *tty;
+       int room;
+       struct uart_port *port = &priv->port;
+
+       port = &priv->port;
+       tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return 0;
+       }
+
+       room = tty_buffer_request_room(tty, size);
+
+       if (room < size)
+               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+                        size - room);
+       if (!room)
+               return room;
+
+       tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
+
+       port->icount.rx += room;
+       tty_kref_put(tty);
+
+       return room;
+}
+
+static void pch_free_dma(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+
+       if (priv->chan_tx) {
+               dma_release_channel(priv->chan_tx);
+               priv->chan_tx = NULL;
+       }
+       if (priv->chan_rx) {
+               dma_release_channel(priv->chan_rx);
+               priv->chan_rx = NULL;
+       }
+       if (sg_dma_address(&priv->sg_rx))
+               dma_free_coherent(port->dev, port->fifosize,
+                                 sg_virt(&priv->sg_rx),
+                                 sg_dma_address(&priv->sg_rx));
+
+       return;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct pch_dma_slave *param = slave;
+
+       if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
+                                                 chan->device->dev)) {
+               chan->private = param;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static void pch_request_dma(struct uart_port *port)
+{
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct pci_dev *dma_dev;
+       struct pch_dma_slave *param;
+       struct eg20t_port *priv =
+                               container_of(port, struct eg20t_port, port);
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+                                                               information */
+       /* Set Tx DMA */
+       param = &priv->param_tx;
+       param->dma_dev = &dma_dev->dev;
+       param->chan_id = priv->port.line;
+       param->tx_reg = port->mapbase + UART_TX;
+       chan = dma_request_channel(mask, filter, param);
+       if (!chan) {
+               pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
+               return;
+       }
+       priv->chan_tx = chan;
+
+       /* Set Rx DMA */
+       param = &priv->param_rx;
+       param->dma_dev = &dma_dev->dev;
+       param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
+       param->rx_reg = port->mapbase + UART_RX;
+       chan = dma_request_channel(mask, filter, param);
+       if (!chan) {
+               pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
+               dma_release_channel(priv->chan_tx);
+               return;
+       }
+
+       /* Get Consistent memory for DMA */
+       priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
+                                   &priv->rx_buf_dma, GFP_KERNEL);
+       priv->chan_rx = chan;
+}
+
+static void pch_dma_rx_complete(void *arg)
+{
+       struct eg20t_port *priv = arg;
+       struct uart_port *port = &priv->port;
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+       if (!tty) {
+               pr_debug("%s:tty is busy now", __func__);
+               return;
+       }
+
+       if (dma_push_rx(priv, priv->trigger_level))
+               tty_flip_buffer_push(tty);
+
+       tty_kref_put(tty);
+}
+
+static void pch_dma_tx_complete(void *arg)
+{
+       struct eg20t_port *priv = arg;
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       xmit->tail += sg_dma_len(&priv->sg_tx);
+       xmit->tail &= UART_XMIT_SIZE - 1;
+       port->icount.tx += sg_dma_len(&priv->sg_tx);
+
+       async_tx_ack(priv->desc_tx);
+       priv->tx_dma_use = 0;
+}
+
+static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
+{
+       int count = 0;
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
+               goto pop_tx_end;
+
+       do {
+               int cnt_to_end =
+                   CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               int sz = min(size - count, cnt_to_end);
+               memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
+               xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
+               count += sz;
+       } while (!uart_circ_empty(xmit) && count < size);
+
+pop_tx_end:
+       pr_debug("%d characters. Remained %d characters. (%lu)\n",
+                count, size - count, jiffies);
+
+       return count;
+}
+
+static int handle_rx_to(struct eg20t_port *priv)
+{
+       struct pch_uart_buffer *buf;
+       int rx_size;
+       int ret;
+       if (!priv->start_rx) {
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+               return 0;
+       }
+       buf = &priv->rxbuf;
+       do {
+               rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
+               ret = push_rx(priv, buf->buf, rx_size);
+               if (ret)
+                       return 0;
+       } while (rx_size == buf->size);
+
+       return PCH_UART_HANDLED_RX_INT;
+}
+
+static int handle_rx(struct eg20t_port *priv)
+{
+       return handle_rx_to(priv);
+}
+
+static int dma_handle_rx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist *sg;
+
+       priv = container_of(port, struct eg20t_port, port);
+       sg = &priv->sg_rx;
+
+       sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
+
+       sg_dma_len(sg) = priv->fifo_size;
+
+       sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
+                    sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
+                    ~PAGE_MASK);
+
+       sg_dma_address(sg) = priv->rx_buf_dma;
+
+       desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+                       sg, 1, DMA_FROM_DEVICE,
+                       DMA_PREP_INTERRUPT);
+       if (!desc)
+               return 0;
+
+       priv->desc_rx = desc;
+       desc->callback = pch_dma_rx_complete;
+       desc->callback_param = priv;
+       desc->tx_submit(desc);
+       dma_async_issue_pending(priv->chan_rx);
+
+       return PCH_UART_HANDLED_RX_INT;
+}
+
+static unsigned int handle_tx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       int ret;
+       int fifo_size;
+       int tx_size;
+       int size;
+       int tx_empty;
+
+       if (!priv->start_tx) {
+               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+               priv->tx_empty = 1;
+               return 0;
+       }
+
+       fifo_size = max(priv->fifo_size, 1);
+       tx_empty = 1;
+       if (pop_tx_x(priv, xmit->buf)) {
+               pch_uart_hal_write(priv, xmit->buf, 1);
+               port->icount.tx++;
+               tx_empty = 0;
+               fifo_size--;
+       }
+       size = min(xmit->head - xmit->tail, fifo_size);
+       tx_size = pop_tx(priv, xmit->buf, size);
+       if (tx_size > 0) {
+               ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
+               port->icount.tx += ret;
+               tx_empty = 0;
+       }
+
+       priv->tx_empty = tx_empty;
+
+       if (tx_empty)
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+       return PCH_UART_HANDLED_TX_INT;
+}
+
+static unsigned int dma_handle_tx(struct eg20t_port *priv)
+{
+       struct uart_port *port = &priv->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct scatterlist *sg = &priv->sg_tx;
+       int nent;
+       int fifo_size;
+       int tx_empty;
+       struct dma_async_tx_descriptor *desc;
+
+       if (!priv->start_tx) {
+               pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+               pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+               priv->tx_empty = 1;
+               return 0;
+       }
+
+       fifo_size = max(priv->fifo_size, 1);
+       tx_empty = 1;
+       if (pop_tx_x(priv, xmit->buf)) {
+               pch_uart_hal_write(priv, xmit->buf, 1);
+               port->icount.tx++;
+               tx_empty = 0;
+               fifo_size--;
+       }
+
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+       priv->tx_dma_use = 1;
+
+       sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
+
+       sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
+                   UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
+
+       nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
+       if (!nent) {
+               pr_err("%s:dma_map_sg Failed\n", __func__);
+               return 0;
+       }
+
+       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+                             sg->offset;
+       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
+                            UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+                            xmit->tail, UART_XMIT_SIZE));
+
+       desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+               sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               pr_err("%s:device_prep_slave_sg Failed\n", __func__);
+               return 0;
+       }
+
+       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+       priv->desc_tx = desc;
+       desc->callback = pch_dma_tx_complete;
+       desc->callback_param = priv;
+
+       desc->tx_submit(desc);
+
+       dma_async_issue_pending(priv->chan_tx);
+
+       return PCH_UART_HANDLED_TX_INT;
+}
+
+static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
+{
+       u8 fcr = ioread8(priv->membase + UART_FCR);
+
+       /* Reset FIFO */
+       fcr |= UART_FCR_CLEAR_RCVR;
+       iowrite8(fcr, priv->membase + UART_FCR);
+
+       if (lsr & PCH_UART_LSR_ERR)
+               dev_err(&priv->pdev->dev, "Error data in FIFO\n");
+
+       if (lsr & UART_LSR_FE)
+               dev_err(&priv->pdev->dev, "Framing Error\n");
+
+       if (lsr & UART_LSR_PE)
+               dev_err(&priv->pdev->dev, "Parity Error\n");
+
+       if (lsr & UART_LSR_OE)
+               dev_err(&priv->pdev->dev, "Overrun Error\n");
+}
+
+static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
+{
+       struct eg20t_port *priv = dev_id;
+       unsigned int handled;
+       u8 lsr;
+       int ret = 0;
+       unsigned int iid;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->port.lock, flags);
+       handled = 0;
+       while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+               switch (iid) {
+               case PCH_UART_IID_RLS:  /* Receiver Line Status */
+                       lsr = pch_uart_hal_get_line_status(priv);
+                       if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
+                                               UART_LSR_PE | UART_LSR_OE)) {
+                               pch_uart_err_ir(priv, lsr);
+                               ret = PCH_UART_HANDLED_RX_ERR_INT;
+                       }
+                       break;
+               case PCH_UART_IID_RDR:  /* Received Data Ready */
+                       if (priv->use_dma)
+                               ret = dma_handle_rx(priv);
+                       else
+                               ret = handle_rx(priv);
+                       break;
+               case PCH_UART_IID_RDR_TO:       /* Received Data Ready
+                                                  (FIFO Timeout) */
+                       ret = handle_rx_to(priv);
+                       break;
+               case PCH_UART_IID_THRE: /* Transmitter Holding Register
+                                                  Empty */
+                       if (priv->use_dma)
+                               ret = dma_handle_tx(priv);
+                       else
+                               ret = handle_tx(priv);
+                       break;
+               case PCH_UART_IID_MS:   /* Modem Status */
+                       ret = PCH_UART_HANDLED_MS_INT;
+                       break;
+               default:        /* Never junp to this label */
+                       pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
+                       ret = -1;
+                       break;
+               }
+               handled |= (unsigned int)ret;
+       }
+       if (handled == 0 && iid <= 1) {
+               if (priv->int_dis_flag)
+                       priv->int_dis_flag = 0;
+       }
+
+       spin_unlock_irqrestore(&priv->port.lock, flags);
+       return IRQ_RETVAL(handled);
+}
+
+/* This function tests whether the transmitter fifo and shifter for the port
+                                               described by 'port' is empty. */
+static unsigned int pch_uart_tx_empty(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       priv = container_of(port, struct eg20t_port, port);
+       if (priv->tx_empty)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* Returns the current state of modem control inputs. */
+static unsigned int pch_uart_get_mctrl(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       u8 modem;
+       unsigned int ret = 0;
+
+       priv = container_of(port, struct eg20t_port, port);
+       modem = pch_uart_hal_get_modem(priv);
+
+       if (modem & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+
+       if (modem & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+
+       if (modem & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+
+       if (modem & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       u32 mcr = 0;
+       unsigned int dat;
+       struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       if (mctrl) {
+               dat = pch_uart_get_mctrl(port);
+               dat |= mcr;
+               iowrite8(dat, priv->membase + UART_MCR);
+       }
+}
+
+static void pch_uart_stop_tx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       priv->start_tx = 0;
+       priv->tx_dma_use = 0;
+}
+
+static void pch_uart_start_tx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+
+       if (priv->use_dma)
+               if (priv->tx_dma_use)
+                       return;
+
+       priv->start_tx = 1;
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+}
+
+static void pch_uart_stop_rx(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       priv->start_rx = 0;
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+       priv->int_dis_flag = 1;
+}
+
+/* Enable the modem status interrupts. */
+static void pch_uart_enable_ms(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       priv = container_of(port, struct eg20t_port, port);
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
+}
+
+/* Control the transmission of a break signal. */
+static void pch_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       struct eg20t_port *priv;
+       unsigned long flags;
+
+       priv = container_of(port, struct eg20t_port, port);
+       spin_lock_irqsave(&port->lock, flags);
+       pch_uart_hal_set_break(priv, ctl);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Grab any interrupt resources and initialise any low level driver state. */
+static int pch_uart_startup(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       int fifo_size;
+       int trigger_level;
+
+       priv = container_of(port, struct eg20t_port, port);
+       priv->tx_empty = 1;
+       port->uartclk = priv->base_baud;
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+       ret = pch_uart_hal_set_line(priv, default_baud,
+                             PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
+                             PCH_UART_HAL_STB1);
+       if (ret)
+               return ret;
+
+       switch (priv->fifo_size) {
+       case 256:
+               fifo_size = PCH_UART_HAL_FIFO256;
+               break;
+       case 64:
+               fifo_size = PCH_UART_HAL_FIFO64;
+               break;
+       case 16:
+               fifo_size = PCH_UART_HAL_FIFO16;
+       case 1:
+       default:
+               fifo_size = PCH_UART_HAL_FIFO_DIS;
+               break;
+       }
+
+       switch (priv->trigger) {
+       case PCH_UART_HAL_TRIGGER1:
+               trigger_level = 1;
+               break;
+       case PCH_UART_HAL_TRIGGER_L:
+               trigger_level = priv->fifo_size / 4;
+               break;
+       case PCH_UART_HAL_TRIGGER_M:
+               trigger_level = priv->fifo_size / 2;
+               break;
+       case PCH_UART_HAL_TRIGGER_H:
+       default:
+               trigger_level = priv->fifo_size - (priv->fifo_size / 8);
+               break;
+       }
+
+       priv->trigger_level = trigger_level;
+       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+                                   fifo_size, priv->trigger);
+       if (ret < 0)
+               return ret;
+
+       ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
+                       KBUILD_MODNAME, priv);
+       if (ret < 0)
+               return ret;
+
+       if (priv->use_dma)
+               pch_request_dma(port);
+
+       priv->start_rx = 1;
+       pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
+       uart_update_timeout(port, CS8, default_baud);
+
+       return 0;
+}
+
+static void pch_uart_shutdown(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+
+       priv = container_of(port, struct eg20t_port, port);
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+       pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
+       ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+                             PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
+       if (ret)
+               pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
+
+       if (priv->use_dma_flag)
+               pch_free_dma(port);
+
+       free_irq(priv->port.irq, priv);
+}
+
+/* Change the port parameters, including word length, parity, stop
+ *bits.  Update read_status_mask and ignore_status_mask to indicate
+ *the types of events we are interested in receiving.  */
+static void pch_uart_set_termios(struct uart_port *port,
+                                struct ktermios *termios, struct ktermios *old)
+{
+       int baud;
+       int rtn;
+       unsigned int parity, bits, stb;
+       struct eg20t_port *priv;
+       unsigned long flags;
+
+       priv = container_of(port, struct eg20t_port, port);
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               bits = PCH_UART_HAL_5BIT;
+               break;
+       case CS6:
+               bits = PCH_UART_HAL_6BIT;
+               break;
+       case CS7:
+               bits = PCH_UART_HAL_7BIT;
+               break;
+       default:                /* CS8 */
+               bits = PCH_UART_HAL_8BIT;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               stb = PCH_UART_HAL_STB2;
+       else
+               stb = PCH_UART_HAL_STB1;
+
+       if (termios->c_cflag & PARENB) {
+               if (!(termios->c_cflag & PARODD))
+                       parity = PCH_UART_HAL_PARITY_ODD;
+               else
+                       parity = PCH_UART_HAL_PARITY_EVEN;
+
+       } else {
+               parity = PCH_UART_HAL_PARITY_NONE;
+       }
+       termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+       rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
+       if (rtn)
+               goto out;
+
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+
+out:
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pch_uart_type(struct uart_port *port)
+{
+       return KBUILD_MODNAME;
+}
+
+static void pch_uart_release_port(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       pci_iounmap(priv->pdev, priv->membase);
+       pci_release_regions(priv->pdev);
+}
+
+static int pch_uart_request_port(struct uart_port *port)
+{
+       struct eg20t_port *priv;
+       int ret;
+       void __iomem *membase;
+
+       priv = container_of(port, struct eg20t_port, port);
+       ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
+       if (ret < 0)
+               return -EBUSY;
+
+       membase = pci_iomap(priv->pdev, 1, 0);
+       if (!membase) {
+               pci_release_regions(priv->pdev);
+               return -EBUSY;
+       }
+       priv->membase = port->membase = membase;
+
+       return 0;
+}
+
+static void pch_uart_config_port(struct uart_port *port, int type)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       if (type & UART_CONFIG_TYPE) {
+               port->type = priv->port_type;
+               pch_uart_request_port(port);
+       }
+}
+
+static int pch_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *serinfo)
+{
+       struct eg20t_port *priv;
+
+       priv = container_of(port, struct eg20t_port, port);
+       if (serinfo->flags & UPF_LOW_LATENCY) {
+               pr_info("PCH UART : Use PIO Mode (without DMA)\n");
+               priv->use_dma = 0;
+               serinfo->flags &= ~UPF_LOW_LATENCY;
+       } else {
+#ifndef CONFIG_PCH_DMA
+               pr_err("%s : PCH DMA is not Loaded.\n", __func__);
+               return -EOPNOTSUPP;
+#endif
+               priv->use_dma = 1;
+               priv->use_dma_flag = 1;
+               pr_info("PCH UART : Use DMA Mode\n");
+       }
+
+       return 0;
+}
+
+static struct uart_ops pch_uart_ops = {
+       .tx_empty = pch_uart_tx_empty,
+       .set_mctrl = pch_uart_set_mctrl,
+       .get_mctrl = pch_uart_get_mctrl,
+       .stop_tx = pch_uart_stop_tx,
+       .start_tx = pch_uart_start_tx,
+       .stop_rx = pch_uart_stop_rx,
+       .enable_ms = pch_uart_enable_ms,
+       .break_ctl = pch_uart_break_ctl,
+       .startup = pch_uart_startup,
+       .shutdown = pch_uart_shutdown,
+       .set_termios = pch_uart_set_termios,
+/*     .pm             = pch_uart_pm,          Not supported yet */
+/*     .set_wake       = pch_uart_set_wake,    Not supported yet */
+       .type = pch_uart_type,
+       .release_port = pch_uart_release_port,
+       .request_port = pch_uart_request_port,
+       .config_port = pch_uart_config_port,
+       .verify_port = pch_uart_verify_port
+};
+
+static struct uart_driver pch_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = KBUILD_MODNAME,
+       .dev_name = PCH_UART_DRIVER_DEVICE,
+       .major = 0,
+       .minor = 0,
+       .nr = PCH_UART_NR,
+};
+
+static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
+                                               int port_type)
+{
+       struct eg20t_port *priv;
+       int ret;
+       unsigned int iobase;
+       unsigned int mapbase;
+       unsigned char *rxbuf;
+       int fifosize, base_baud;
+       static int num;
+
+       priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
+       if (priv == NULL)
+               goto init_port_alloc_err;
+
+       rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+       if (!rxbuf)
+               goto init_port_free_txbuf;
+
+       switch (port_type) {
+       case PORT_UNKNOWN:
+               fifosize = 256; /* UART0 */
+               base_baud = 1843200; /* 1.8432MHz */
+               break;
+       case PORT_8250:
+               fifosize = 64; /* UART1~3 */
+               base_baud = 1843200; /* 1.8432MHz */
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
+               goto init_port_hal_free;
+       }
+
+       iobase = pci_resource_start(pdev, 0);
+       mapbase = pci_resource_start(pdev, 1);
+       priv->mapbase = mapbase;
+       priv->iobase = iobase;
+       priv->pdev = pdev;
+       priv->tx_empty = 1;
+       priv->rxbuf.buf = rxbuf;
+       priv->rxbuf.size = PAGE_SIZE;
+
+       priv->fifo_size = fifosize;
+       priv->base_baud = base_baud;
+       priv->port_type = PORT_MAX_8250 + port_type + 1;
+       priv->port.dev = &pdev->dev;
+       priv->port.iobase = iobase;
+       priv->port.membase = NULL;
+       priv->port.mapbase = mapbase;
+       priv->port.irq = pdev->irq;
+       priv->port.iotype = UPIO_PORT;
+       priv->port.ops = &pch_uart_ops;
+       priv->port.flags = UPF_BOOT_AUTOCONF;
+       priv->port.fifosize = fifosize;
+       priv->port.line = num++;
+       priv->trigger = PCH_UART_HAL_TRIGGER_M;
+
+       pci_set_drvdata(pdev, priv);
+       pch_uart_hal_request(pdev, fifosize, base_baud);
+       ret = uart_add_one_port(&pch_uart_driver, &priv->port);
+       if (ret < 0)
+               goto init_port_hal_free;
+
+       return priv;
+
+init_port_hal_free:
+       free_page((unsigned long)rxbuf);
+init_port_free_txbuf:
+       kfree(priv);
+init_port_alloc_err:
+
+       return NULL;
+}
+
+static void pch_uart_exit_port(struct eg20t_port *priv)
+{
+       uart_remove_one_port(&pch_uart_driver, &priv->port);
+       pci_set_drvdata(priv->pdev, NULL);
+       free_page((unsigned long)priv->rxbuf.buf);
+}
+
+static void pch_uart_pci_remove(struct pci_dev *pdev)
+{
+       struct eg20t_port *priv;
+
+       priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+       pch_uart_exit_port(priv);
+       pci_disable_device(pdev);
+       kfree(priv);
+       return;
+}
+#ifdef CONFIG_PM
+static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+       uart_suspend_port(&pch_uart_driver, &priv->port);
+
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return 0;
+}
+
+static int pch_uart_pci_resume(struct pci_dev *pdev)
+{
+       struct eg20t_port *priv = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev,
+               "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
+               return ret;
+       }
+
+       uart_resume_port(&pch_uart_driver, &priv->port);
+
+       return 0;
+}
+#else
+#define pch_uart_pci_suspend NULL
+#define pch_uart_pci_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
+        .driver_data = PCH_UART_8LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
+        .driver_data = PCH_UART_2LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
+        .driver_data = PCH_UART_2LINE},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
+        .driver_data = PCH_UART_2LINE},
+       {0,},
+};
+
+static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *id)
+{
+       int ret;
+       struct eg20t_port *priv;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               goto probe_error;
+
+       priv = pch_uart_init_port(pdev, id->driver_data);
+       if (!priv) {
+               ret = -EBUSY;
+               goto probe_disable_device;
+       }
+       pci_set_drvdata(pdev, priv);
+
+       return ret;
+
+probe_disable_device:
+       pci_disable_device(pdev);
+probe_error:
+       return ret;
+}
+
+static struct pci_driver pch_uart_pci_driver = {
+       .name = "pch_uart",
+       .id_table = pch_uart_pci_id,
+       .probe = pch_uart_pci_probe,
+       .remove = __devexit_p(pch_uart_pci_remove),
+       .suspend = pch_uart_pci_suspend,
+       .resume = pch_uart_pci_resume,
+};
+
+static int __init pch_uart_module_init(void)
+{
+       int ret;
+
+       /* register as UART driver */
+       ret = uart_register_driver(&pch_uart_driver);
+       if (ret < 0)
+               return ret;
+
+       /* register as PCI driver */
+       ret = pci_register_driver(&pch_uart_pci_driver);
+       if (ret < 0)
+               uart_unregister_driver(&pch_uart_driver);
+
+       return ret;
+}
+module_init(pch_uart_module_init);
+
+static void __exit pch_uart_module_exit(void)
+{
+       pci_unregister_driver(&pch_uart_pci_driver);
+       uart_unregister_driver(&pch_uart_driver);
+}
+module_exit(pch_uart_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
+module_param(default_baud, uint, S_IRUGO);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
new file mode 100644 (file)
index 0000000..5b9cde7
--- /dev/null
@@ -0,0 +1,2208 @@
+/*
+ * linux/drivers/serial/pmac_zilog.c
+ * 
+ * Driver for PowerMac Z85c30 based ESCC cell found in the
+ * "macio" ASICs of various PowerMac models
+ * 
+ * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * Derived from drivers/macintosh/macserial.c by Paul Mackerras
+ * and drivers/serial/sunzilog.c by David S. Miller
+ *
+ * Hrm... actually, I ripped most of sunzilog (Thanks David !) and
+ * adapted special tweaks needed for us. I don't think it's worth
+ * merging back those though. The DMA code still has to get in
+ * and once done, I expect that driver to remain fairly stable in
+ * the long term, unless we change the driver model again...
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 2004-08-06 Harald Welte <laforge@gnumonks.org>
+ *     - Enable BREAK interrupt
+ *     - Add support for sysreq
+ *
+ * TODO:   - Add DMA support
+ *         - Defer port shutdown to a few seconds after close
+ *         - maybe put something right into uap->clk_divisor
+ */
+
+#undef DEBUG
+#undef DEBUG_HARD
+#undef USE_CTRL_O_SYSRQ
+
+#include <linux/module.h>
+#include <linux/tty.h>
+
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/bitops.h>
+#include <linux/sysrq.h>
+#include <linux/mutex.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/macio.h>
+#else
+#include <linux/platform_device.h>
+#define of_machine_is_compatible(x) (0)
+#endif
+
+#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include "pmac_zilog.h"
+
+/* Not yet implemented */
+#undef HAS_DBDMA
+
+static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR                TTY_MAJOR
+#define PMACZILOG_MINOR                64
+#define PMACZILOG_NAME         "ttyS"
+#else
+#define PMACZILOG_MAJOR                204
+#define PMACZILOG_MINOR                192
+#define PMACZILOG_NAME         "ttyPZ"
+#endif
+
+
+/*
+ * For the sake of early serial console, we can do a pre-probe
+ * (optional) of the ports at rather early boot time.
+ */
+static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
+static int                     pmz_ports_count;
+static DEFINE_MUTEX(pmz_irq_mutex);
+
+static struct uart_driver pmz_uart_reg = {
+       .owner          =       THIS_MODULE,
+       .driver_name    =       PMACZILOG_NAME,
+       .dev_name       =       PMACZILOG_NAME,
+       .major          =       PMACZILOG_MAJOR,
+       .minor          =       PMACZILOG_MINOR,
+};
+
+
+/* 
+ * Load all registers to reprogram the port
+ * This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
+{
+       int i;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(uap, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       ZS_CLEARERR(uap);
+       zssync(uap);
+       ZS_CLEARFIFO(uap);
+       zssync(uap);
+       ZS_CLEARERR(uap);
+
+       /* Disable all interrupts.  */
+       write_zsreg(uap, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(uap, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(uap, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
+
+       /* now set R7 "prime" on ESCC */
+       write_zsreg(uap, R15, regs[R15] | EN85C30);
+       write_zsreg(uap, R7, regs[R7P]);
+
+       /* make sure we use R7 "non-prime" on ESCC */
+       write_zsreg(uap, R15, regs[R15] & ~EN85C30);
+
+       /* Synchronous mode config.  */
+       write_zsreg(uap, R6, regs[R6]);
+       write_zsreg(uap, R7, regs[R7]);
+
+       /* Disable baud generator.  */
+       write_zsreg(uap, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(uap, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(uap, R12, regs[R12]);
+       write_zsreg(uap, R13, regs[R13]);
+       
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(uap, R14, regs[R14]);
+
+       /* Reset external status interrupts.  */
+       write_zsreg(uap, R0, RES_EXT_INT);
+       write_zsreg(uap, R0, RES_EXT_INT);
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(uap, R3, regs[R3]);
+       write_zsreg(uap, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(uap, R1, regs[R1]);
+
+       /* Enable interrupts */
+       write_zsreg(uap, R9, regs[R9]);
+}
+
+/* 
+ * We do like sunzilog to avoid disrupting pending Tx
+ * Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
+{
+       if (!ZS_REGS_HELD(uap)) {
+               if (ZS_TX_ACTIVE(uap)) {
+                       uap->flags |= PMACZILOG_FLAG_REGS_HELD;
+               } else {
+                       pmz_debug("pmz: maybe_update_regs: updating\n");
+                       pmz_load_zsregs(uap, uap->curregs);
+               }
+       }
+}
+
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
+{
+       struct tty_struct *tty = NULL;
+       unsigned char ch, r1, drop, error, flag;
+       int loops = 0;
+
+       /* The interrupt can be enabled when the port isn't open, typically
+        * that happens when using one port is open and the other closed (stale
+        * interrupt) or when one port is used as a console.
+        */
+       if (!ZS_IS_OPEN(uap)) {
+               pmz_debug("pmz: draining input\n");
+               /* Port is closed, drain input data */
+               for (;;) {
+                       if ((++loops) > 1000)
+                               goto flood;
+                       (void)read_zsreg(uap, R1);
+                       write_zsreg(uap, R0, ERR_RES);
+                       (void)read_zsdata(uap);
+                       ch = read_zsreg(uap, R0);
+                       if (!(ch & Rx_CH_AV))
+                               break;
+               }
+               return NULL;
+       }
+
+       /* Sanity check, make sure the old bug is no longer happening */
+       if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
+               WARN_ON(1);
+               (void)read_zsdata(uap);
+               return NULL;
+       }
+       tty = uap->port.state->port.tty;
+
+       while (1) {
+               error = 0;
+               drop = 0;
+
+               r1 = read_zsreg(uap, R1);
+               ch = read_zsdata(uap);
+
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       write_zsreg(uap, R0, ERR_RES);
+                       zssync(uap);
+               }
+
+               ch &= uap->parity_mask;
+               if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
+                       uap->flags &= ~PMACZILOG_FLAG_BREAK;
+               }
+
+#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
+#ifdef USE_CTRL_O_SYSRQ
+               /* Handle the SysRq ^O Hack */
+               if (ch == '\x0f') {
+                       uap->port.sysrq = jiffies + HZ*5;
+                       goto next_char;
+               }
+#endif /* USE_CTRL_O_SYSRQ */
+               if (uap->port.sysrq) {
+                       int swallow;
+                       spin_unlock(&uap->port.lock);
+                       swallow = uart_handle_sysrq_char(&uap->port, ch);
+                       spin_lock(&uap->port.lock);
+                       if (swallow)
+                               goto next_char;
+               }
+#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
+
+               /* A real serial line, record the character and status.  */
+               if (drop)
+                       goto next_char;
+
+               flag = TTY_NORMAL;
+               uap->port.icount.rx++;
+
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
+                       error = 1;
+                       if (r1 & BRK_ABRT) {
+                               pmz_debug("pmz: got break !\n");
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                               uap->port.icount.brk++;
+                               if (uart_handle_break(&uap->port))
+                                       goto next_char;
+                       }
+                       else if (r1 & PAR_ERR)
+                               uap->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               uap->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               uap->port.icount.overrun++;
+                       r1 &= uap->port.read_status_mask;
+                       if (r1 & BRK_ABRT)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uap->port.ignore_status_mask == 0xff ||
+                   (r1 & uap->port.ignore_status_mask) == 0) {
+                       tty_insert_flip_char(tty, ch, flag);
+               }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       next_char:
+               /* We can get stuck in an infinite loop getting char 0 when the
+                * line is in a wrong HW state, we break that here.
+                * When that happens, I disable the receive side of the driver.
+                * Note that what I've been experiencing is a real irq loop where
+                * I'm getting flooded regardless of the actual port speed.
+                * Something stange is going on with the HW
+                */
+               if ((++loops) > 1000)
+                       goto flood;
+               ch = read_zsreg(uap, R0);
+               if (!(ch & Rx_CH_AV))
+                       break;
+       }
+
+       return tty;
+ flood:
+       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       write_zsreg(uap, R1, uap->curregs[R1]);
+       zssync(uap);
+       pmz_error("pmz: rx irq flood !\n");
+       return tty;
+}
+
+static void pmz_status_handle(struct uart_pmac_port *uap)
+{
+       unsigned char status;
+
+       status = read_zsreg(uap, R0);
+       write_zsreg(uap, R0, RES_EXT_INT);
+       zssync(uap);
+
+       if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) {
+               if (status & SYNC_HUNT)
+                       uap->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                * The CTS input is inverted for some reason.  -- paulus
+                */
+               if ((status ^ uap->prev_status) & DCD)
+                       uart_handle_dcd_change(&uap->port,
+                                              (status & DCD));
+               if ((status ^ uap->prev_status) & CTS)
+                       uart_handle_cts_change(&uap->port,
+                                              !(status & CTS));
+
+               wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
+       }
+
+       if (status & BRK_ABRT)
+               uap->flags |= PMACZILOG_FLAG_BREAK;
+
+       uap->prev_status = status;
+}
+
+static void pmz_transmit_chars(struct uart_pmac_port *uap)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       if (ZS_IS_CONS(uap)) {
+               unsigned char status = read_zsreg(uap, R0);
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(uap)) {
+               pmz_load_zsregs(uap, uap->curregs);
+               uap->flags &= ~PMACZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(uap)) {
+               uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       /* Under some circumstances, we see interrupts reported for
+        * a closed channel. The interrupt mask in R1 is clear, but
+        * R3 still signals the interrupts and we see them when taking
+        * an interrupt for the other channel (this could be a qemu
+        * bug but since the ESCC doc doesn't specify precsiely whether
+        * R3 interrup status bits are masked by R1 interrupt enable
+        * bits, better safe than sorry). --BenH.
+        */
+       if (!ZS_IS_OPEN(uap))
+               goto ack_tx_int;
+
+       if (uap->port.x_char) {
+               uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+               write_zsdata(uap, uap->port.x_char);
+               zssync(uap);
+               uap->port.icount.tx++;
+               uap->port.x_char = 0;
+               return;
+       }
+
+       if (uap->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &uap->port.state->xmit;
+       if (uart_circ_empty(xmit)) {
+               uart_write_wakeup(&uap->port);
+               goto ack_tx_int;
+       }
+       if (uart_tx_stopped(&uap->port))
+               goto ack_tx_int;
+
+       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+       write_zsdata(uap, xmit->buf[xmit->tail]);
+       zssync(uap);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       uap->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uap->port);
+
+       return;
+
+ack_tx_int:
+       write_zsreg(uap, R0, RES_Tx_P);
+       zssync(uap);
+}
+
+/* Hrm... we register that twice, fixme later.... */
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
+{
+       struct uart_pmac_port *uap = dev_id;
+       struct uart_pmac_port *uap_a;
+       struct uart_pmac_port *uap_b;
+       int rc = IRQ_NONE;
+       struct tty_struct *tty;
+       u8 r3;
+
+       uap_a = pmz_get_port_A(uap);
+       uap_b = uap_a->mate;
+
+       spin_lock(&uap_a->port.lock);
+       r3 = read_zsreg(uap_a, R3);
+
+#ifdef DEBUG_HARD
+       pmz_debug("irq, r3: %x\n", r3);
+#endif
+       /* Channel A */
+       tty = NULL;
+       if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+               write_zsreg(uap_a, R0, RES_H_IUS);
+               zssync(uap_a);          
+               if (r3 & CHAEXT)
+                       pmz_status_handle(uap_a);
+               if (r3 & CHARxIP)
+                       tty = pmz_receive_chars(uap_a);
+               if (r3 & CHATxIP)
+                       pmz_transmit_chars(uap_a);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_a->port.lock);
+       if (tty != NULL)
+               tty_flip_buffer_push(tty);
+
+       if (uap_b->node == NULL)
+               goto out;
+
+       spin_lock(&uap_b->port.lock);
+       tty = NULL;
+       if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+               write_zsreg(uap_b, R0, RES_H_IUS);
+               zssync(uap_b);
+               if (r3 & CHBEXT)
+                       pmz_status_handle(uap_b);
+               if (r3 & CHBRxIP)
+                       tty = pmz_receive_chars(uap_b);
+               if (r3 & CHBTxIP)
+                       pmz_transmit_chars(uap_b);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_b->port.lock);
+       if (tty != NULL)
+               tty_flip_buffer_push(tty);
+
+ out:
+#ifdef DEBUG_HARD
+       pmz_debug("irq done.\n");
+#endif
+       return rc;
+}
+
+/*
+ * Peek the status register, lock not held by caller
+ */
+static inline u8 pmz_peek_status(struct uart_pmac_port *uap)
+{
+       unsigned long flags;
+       u8 status;
+       
+       spin_lock_irqsave(&uap->port.lock, flags);
+       status = read_zsreg(uap, R0);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       return status;
+}
+
+/* 
+ * Check if transmitter is empty
+ * The port lock is not held.
+ */
+static unsigned int pmz_tx_empty(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return TIOCSER_TEMT;
+
+       status = pmz_peek_status(to_pmz(port));
+       if (status & Tx_BUF_EMP)
+               return TIOCSER_TEMT;
+       return 0;
+}
+
+/* 
+ * Set Modem Control (RTS & DTR) bits
+ * The port lock is held and interrupts are disabled.
+ * Note: Shall we really filter out RTS on external ports or
+ * should that be dealt at higher level only ?
+ */
+static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char set_bits, clear_bits;
+
+        /* Do nothing for irda for now... */
+       if (ZS_IS_IRDA(uap))
+               return;
+       /* We get called during boot with a port not up yet */
+       if (ZS_IS_ASLEEP(uap) ||
+           !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
+               return;
+
+       set_bits = clear_bits = 0;
+
+       if (ZS_IS_INTMODEM(uap)) {
+               if (mctrl & TIOCM_RTS)
+                       set_bits |= RTS;
+               else
+                       clear_bits |= RTS;
+       }
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */ 
+       uap->curregs[R5] |= set_bits;
+       uap->curregs[R5] &= ~clear_bits;
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
+                 set_bits, clear_bits, uap->curregs[R5]);
+       zssync(uap);
+}
+
+/* 
+ * Get Modem Control bits (only the input ones, the core will
+ * or that with a cached value of the control ones)
+ * The port lock is held and interrupts are disabled.
+ */
+static unsigned int pmz_get_mctrl(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+       unsigned int ret;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return 0;
+
+       status = read_zsreg(uap, R0);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC_HUNT)
+               ret |= TIOCM_DSR;
+       if (!(status & CTS))
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* 
+ * Stop TX side. Dealt like sunzilog at next Tx interrupt,
+ * though for DMA, we will have to do a bit more.
+ * The port lock is held and interrupts are disabled.
+ */
+static void pmz_stop_tx(struct uart_port *port)
+{
+       to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
+}
+
+/* 
+ * Kick the Tx side.
+ * The port lock is held and interrupts are disabled.
+ */
+static void pmz_start_tx(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char status;
+
+       pmz_debug("pmz: start_tx()\n");
+
+       uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
+       uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return;
+
+       status = read_zsreg(uap, R0);
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               write_zsdata(uap, port->x_char);
+               zssync(uap);
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               write_zsdata(uap, xmit->buf[xmit->tail]);
+               zssync(uap);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&uap->port);
+       }
+       pmz_debug("pmz: start_tx() done.\n");
+}
+
+/* 
+ * Stop Rx side, basically disable emitting of
+ * Rx interrupts on the port. We don't disable the rx
+ * side of the chip proper though
+ * The port lock is held.
+ */
+static void pmz_stop_rx(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+
+       if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
+               return;
+
+       pmz_debug("pmz: stop_rx()()\n");
+
+       /* Disable all RX interrupts.  */
+       uap->curregs[R1] &= ~RxINT_MASK;
+       pmz_maybe_update_regs(uap);
+
+       pmz_debug("pmz: stop_rx() done.\n");
+}
+
+/* 
+ * Enable modem status change interrupts
+ * The port lock is held.
+ */
+static void pmz_enable_ms(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char new_reg;
+
+       if (ZS_IS_IRDA(uap) || uap->node == NULL)
+               return;
+       new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != uap->curregs[R15]) {
+               uap->curregs[R15] = new_reg;
+
+               if (ZS_IS_ASLEEP(uap))
+                       return;
+               /* NOTE: Not subject to 'transmitter active' rule. */
+               write_zsreg(uap, R15, uap->curregs[R15]);
+       }
+}
+
+/* 
+ * Control break state emission
+ * The port lock is not held.
+ */
+static void pmz_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       if (uap->node == NULL)
+               return;
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != uap->curregs[R5]) {
+               uap->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule. */
+               if (ZS_IS_ASLEEP(uap)) {
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       return;
+               }
+               write_zsreg(uap, R5, uap->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#ifdef CONFIG_PPC_PMAC
+
+/*
+ * Turn power on or off to the SCC and associated stuff
+ * (port drivers, modem, IR port, etc.)
+ * Returns the number of milliseconds we should wait before
+ * trying to use the port.
+ */
+static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
+{
+       int delay = 0;
+       int rc;
+
+       if (state) {
+               rc = pmac_call_feature(
+                       PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1);
+               pmz_debug("port power on result: %d\n", rc);
+               if (ZS_IS_INTMODEM(uap)) {
+                       rc = pmac_call_feature(
+                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1);
+                       delay = 2500;   /* wait for 2.5s before using */
+                       pmz_debug("modem power result: %d\n", rc);
+               }
+       } else {
+               /* TODO: Make that depend on a timer, don't power down
+                * immediately
+                */
+               if (ZS_IS_INTMODEM(uap)) {
+                       rc = pmac_call_feature(
+                               PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0);
+                       pmz_debug("port power off result: %d\n", rc);
+               }
+               pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0);
+       }
+       return delay;
+}
+
+#else
+
+static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
+/*
+ * FixZeroBug....Works around a bug in the SCC receving channel.
+ * Inspired from Darwin code, 15 Sept. 2000  -DanM
+ *
+ * The following sequence prevents a problem that is seen with O'Hare ASICs
+ * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
+ * at the input to the receiver becomes 'stuck' and locks up the receiver.
+ * This problem can occur as a result of a zero bit at the receiver input
+ * coincident with any of the following events:
+ *
+ *     The SCC is initialized (hardware or software).
+ *     A framing error is detected.
+ *     The clocking option changes from synchronous or X1 asynchronous
+ *             clocking to X16, X32, or X64 asynchronous clocking.
+ *     The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
+ *
+ * This workaround attempts to recover from the lockup condition by placing
+ * the SCC in synchronous loopback mode with a fast clock before programming
+ * any of the asynchronous modes.
+ */
+static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap)
+{
+       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
+       zssync(uap);
+       udelay(10);
+       write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV);
+       zssync(uap);
+
+       write_zsreg(uap, 4, X1CLK | MONSYNC);
+       write_zsreg(uap, 3, Rx8);
+       write_zsreg(uap, 5, Tx8 | RTS);
+       write_zsreg(uap, 9, NV);        /* Didn't we already do this? */
+       write_zsreg(uap, 11, RCBR | TCBR);
+       write_zsreg(uap, 12, 0);
+       write_zsreg(uap, 13, 0);
+       write_zsreg(uap, 14, (LOOPBAK | BRSRC));
+       write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB));
+       write_zsreg(uap, 3, Rx8 | RxENABLE);
+       write_zsreg(uap, 0, RES_EXT_INT);
+       write_zsreg(uap, 0, RES_EXT_INT);
+       write_zsreg(uap, 0, RES_EXT_INT);       /* to kill some time */
+
+       /* The channel should be OK now, but it is probably receiving
+        * loopback garbage.
+        * Switch to asynchronous mode, disable the receiver,
+        * and discard everything in the receive buffer.
+        */
+       write_zsreg(uap, 9, NV);
+       write_zsreg(uap, 4, X16CLK | SB_MASK);
+       write_zsreg(uap, 3, Rx8);
+
+       while (read_zsreg(uap, 0) & Rx_CH_AV) {
+               (void)read_zsreg(uap, 8);
+               write_zsreg(uap, 0, RES_EXT_INT);
+               write_zsreg(uap, 0, ERR_RES);
+       }
+}
+
+/*
+ * Real startup routine, powers up the hardware and sets up
+ * the SCC. Returns a delay in ms where you need to wait before
+ * actually using the port, this is typically the internal modem
+ * powerup delay. This routine expect the lock to be taken.
+ */
+static int __pmz_startup(struct uart_pmac_port *uap)
+{
+       int pwr_delay = 0;
+
+       memset(&uap->curregs, 0, sizeof(uap->curregs));
+
+       /* Power up the SCC & underlying hardware (modem/irda) */
+       pwr_delay = pmz_set_scc_power(uap, 1);
+
+       /* Nice buggy HW ... */
+       pmz_fix_zero_bug_scc(uap);
+
+       /* Reset the channel */
+       uap->curregs[R9] = 0;
+       write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB);
+       zssync(uap);
+       udelay(10);
+       write_zsreg(uap, 9, 0);
+       zssync(uap);
+
+       /* Clear the interrupt registers */
+       write_zsreg(uap, R1, 0);
+       write_zsreg(uap, R0, ERR_RES);
+       write_zsreg(uap, R0, ERR_RES);
+       write_zsreg(uap, R0, RES_H_IUS);
+       write_zsreg(uap, R0, RES_H_IUS);
+
+       /* Setup some valid baud rate */
+       uap->curregs[R4] = X16CLK | SB1;
+       uap->curregs[R3] = Rx8;
+       uap->curregs[R5] = Tx8 | RTS;
+       if (!ZS_IS_IRDA(uap))
+               uap->curregs[R5] |= DTR;
+       uap->curregs[R12] = 0;
+       uap->curregs[R13] = 0;
+       uap->curregs[R14] = BRENAB;
+
+       /* Clear handshaking, enable BREAK interrupts */
+       uap->curregs[R15] = BRKIE;
+
+       /* Master interrupt enable */
+       uap->curregs[R9] |= NV | MIE;
+
+       pmz_load_zsregs(uap, uap->curregs);
+
+       /* Enable receiver and transmitter.  */
+       write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE);
+       write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE);
+
+       /* Remember status for DCD/CTS changes */
+       uap->prev_status = read_zsreg(uap, R0);
+
+       return pwr_delay;
+}
+
+static void pmz_irda_reset(struct uart_pmac_port *uap)
+{
+       uap->curregs[R5] |= DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(110);
+       uap->curregs[R5] &= ~DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(10);
+}
+
+/*
+ * This is the "normal" startup routine, using the above one
+ * wrapped with the lock and doing a schedule delay
+ */
+static int pmz_startup(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+       int pwr_delay = 0;
+
+       pmz_debug("pmz: startup()\n");
+
+       if (ZS_IS_ASLEEP(uap))
+               return -EAGAIN;
+       if (uap->node == NULL)
+               return -ENODEV;
+
+       mutex_lock(&pmz_irq_mutex);
+
+       uap->flags |= PMACZILOG_FLAG_IS_OPEN;
+
+       /* A console is never powered down. Else, power up and
+        * initialize the chip
+        */
+       if (!ZS_IS_CONS(uap)) {
+               spin_lock_irqsave(&port->lock, flags);
+               pwr_delay = __pmz_startup(uap);
+               spin_unlock_irqrestore(&port->lock, flags);
+       }       
+
+       pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
+       if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
+                       "SCC", uap)) {
+               pmz_error("Unable to register zs interrupt handler.\n");
+               pmz_set_scc_power(uap, 0);
+               mutex_unlock(&pmz_irq_mutex);
+               return -ENXIO;
+       }
+
+       mutex_unlock(&pmz_irq_mutex);
+
+       /* Right now, we deal with delay by blocking here, I'll be
+        * smarter later on
+        */
+       if (pwr_delay != 0) {
+               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
+               msleep(pwr_delay);
+       }
+
+       /* IrDA reset is done now */
+       if (ZS_IS_IRDA(uap))
+               pmz_irda_reset(uap);
+
+       /* Enable interrupts emission from the chip */
+       spin_lock_irqsave(&port->lock, flags);
+       uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+       if (!ZS_IS_EXTCLK(uap))
+               uap->curregs[R1] |= EXT_INT_ENAB;
+       write_zsreg(uap, R1, uap->curregs[R1]);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       pmz_debug("pmz: startup() done.\n");
+
+       return 0;
+}
+
+static void pmz_shutdown(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+
+       pmz_debug("pmz: shutdown()\n");
+
+       if (uap->node == NULL)
+               return;
+
+       mutex_lock(&pmz_irq_mutex);
+
+       /* Release interrupt handler */
+       free_irq(uap->port.irq, uap);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;
+
+       if (!ZS_IS_OPEN(uap->mate))
+               pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
+
+       /* Disable interrupts */
+       if (!ZS_IS_ASLEEP(uap)) {
+               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+               write_zsreg(uap, R1, uap->curregs[R1]);
+               zssync(uap);
+       }
+
+       if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               mutex_unlock(&pmz_irq_mutex);
+               return;
+       }
+
+       /* Disable receiver and transmitter.  */
+       uap->curregs[R3] &= ~RxENABLE;
+       uap->curregs[R5] &= ~TxENABLE;
+
+       /* Disable all interrupts and BRK assertion.  */
+       uap->curregs[R5] &= ~SND_BRK;
+       pmz_maybe_update_regs(uap);
+
+       /* Shut the chip down */
+       pmz_set_scc_power(uap, 0);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       mutex_unlock(&pmz_irq_mutex);
+
+       pmz_debug("pmz: shutdown() done.\n");
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
+                             unsigned int iflag, unsigned long baud)
+{
+       int brg;
+
+       /* Switch to external clocking for IrDA high clock rates. That
+        * code could be re-used for Midi interfaces with different
+        * multipliers
+        */
+       if (baud >= 115200 && ZS_IS_IRDA(uap)) {
+               uap->curregs[R4] = X1CLK;
+               uap->curregs[R11] = RCTRxCP | TCTRxCP;
+               uap->curregs[R14] = 0; /* BRG off */
+               uap->curregs[R12] = 0;
+               uap->curregs[R13] = 0;
+               uap->flags |= PMACZILOG_FLAG_IS_EXTCLK;
+       } else {
+               switch (baud) {
+               case ZS_CLOCK/16:       /* 230400 */
+                       uap->curregs[R4] = X16CLK;
+                       uap->curregs[R11] = 0;
+                       uap->curregs[R14] = 0;
+                       break;
+               case ZS_CLOCK/32:       /* 115200 */
+                       uap->curregs[R4] = X32CLK;
+                       uap->curregs[R11] = 0;
+                       uap->curregs[R14] = 0;
+                       break;
+               default:
+                       uap->curregs[R4] = X16CLK;
+                       uap->curregs[R11] = TCBR | RCBR;
+                       brg = BPS_TO_BRG(baud, ZS_CLOCK / 16);
+                       uap->curregs[R12] = (brg & 255);
+                       uap->curregs[R13] = ((brg >> 8) & 255);
+                       uap->curregs[R14] = BRENAB;
+               }
+               uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK;
+       }
+
+       /* Character size, stop bits, and parity. */
+       uap->curregs[3] &= ~RxN_MASK;
+       uap->curregs[5] &= ~TxN_MASK;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               uap->curregs[3] |= Rx5;
+               uap->curregs[5] |= Tx5;
+               uap->parity_mask = 0x1f;
+               break;
+       case CS6:
+               uap->curregs[3] |= Rx6;
+               uap->curregs[5] |= Tx6;
+               uap->parity_mask = 0x3f;
+               break;
+       case CS7:
+               uap->curregs[3] |= Rx7;
+               uap->curregs[5] |= Tx7;
+               uap->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               uap->curregs[3] |= Rx8;
+               uap->curregs[5] |= Tx8;
+               uap->parity_mask = 0xff;
+               break;
+       };
+       uap->curregs[4] &= ~(SB_MASK);
+       if (cflag & CSTOPB)
+               uap->curregs[4] |= SB2;
+       else
+               uap->curregs[4] |= SB1;
+       if (cflag & PARENB)
+               uap->curregs[4] |= PAR_ENAB;
+       else
+               uap->curregs[4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               uap->curregs[4] |= PAR_EVEN;
+       else
+               uap->curregs[4] &= ~PAR_EVEN;
+
+       uap->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               uap->port.read_status_mask |= BRK_ABRT;
+
+       uap->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               uap->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       uap->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               uap->port.ignore_status_mask = 0xff;
+}
+
+
+/*
+ * Set the irda codec on the imac to the specified baud rate.
+ */
+static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
+{
+       u8 cmdbyte;
+       int t, version;
+
+       switch (*baud) {
+       /* SIR modes */
+       case 2400:
+               cmdbyte = 0x53;
+               break;
+       case 4800:
+               cmdbyte = 0x52;
+               break;
+       case 9600:
+               cmdbyte = 0x51;
+               break;
+       case 19200:
+               cmdbyte = 0x50;
+               break;
+       case 38400:
+               cmdbyte = 0x4f;
+               break;
+       case 57600:
+               cmdbyte = 0x4e;
+               break;
+       case 115200:
+               cmdbyte = 0x4d;
+               break;
+       /* The FIR modes aren't really supported at this point, how
+        * do we select the speed ? via the FCR on KeyLargo ?
+        */
+       case 1152000:
+               cmdbyte = 0;
+               break;
+       case 4000000:
+               cmdbyte = 0;
+               break;
+       default: /* 9600 */
+               cmdbyte = 0x51;
+               *baud = 9600;
+               break;
+       }
+
+       /* Wait for transmitter to drain */
+       t = 10000;
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
+              || (read_zsreg(uap, R1) & ALL_SNT) == 0) {
+               if (--t <= 0) {
+                       pmz_error("transmitter didn't drain\n");
+                       return;
+               }
+               udelay(10);
+       }
+
+       /* Drain the receiver too */
+       t = 100;
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       mdelay(10);
+       while (read_zsreg(uap, R0) & Rx_CH_AV) {
+               read_zsdata(uap);
+               mdelay(10);
+               if (--t <= 0) {
+                       pmz_error("receiver didn't drain\n");
+                       return;
+               }
+       }
+
+       /* Switch to command mode */
+       uap->curregs[R5] |= DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+       mdelay(1);
+
+       /* Switch SCC to 19200 */
+       pmz_convert_to_zs(uap, CS8, 0, 19200);          
+       pmz_load_zsregs(uap, uap->curregs);
+       mdelay(1);
+
+       /* Write get_version command byte */
+       write_zsdata(uap, 1);
+       t = 5000;
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       pmz_error("irda_setup timed out on get_version byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       version = read_zsdata(uap);
+
+       if (version < 4) {
+               pmz_info("IrDA: dongle version %d not supported\n", version);
+               goto out;
+       }
+
+       /* Send speed mode */
+       write_zsdata(uap, cmdbyte);
+       t = 5000;
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       pmz_error("irda_setup timed out on speed mode byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       t = read_zsdata(uap);
+       if (t != cmdbyte)
+               pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
+
+       pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
+                *baud, version);
+
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+
+ out:
+       /* Switch back to data mode */
+       uap->curregs[R5] &= ~DTR;
+       write_zsreg(uap, R5, uap->curregs[R5]);
+       zssync(uap);
+
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+       (void)read_zsdata(uap);
+}
+
+
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long baud;
+
+       pmz_debug("pmz: set_termios()\n");
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+
+       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
+
+       /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
+        * on the IR dongle. Note that the IRTTY driver currently doesn't know
+        * about the FIR mode and high speed modes. So these are unused. For
+        * implementing proper support for these, we should probably add some
+        * DMA as well, at least on the Rx side, which isn't a simple thing
+        * at this point.
+        */
+       if (ZS_IS_IRDA(uap)) {
+               /* Calc baud rate */
+               baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);
+               pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);
+               /* Cet the irda codec to the right rate */
+               pmz_irda_setup(uap, &baud);
+               /* Set final baud rate */
+               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
+               pmz_load_zsregs(uap, uap->curregs);
+               zssync(uap);
+       } else {
+               baud = uart_get_baud_rate(port, termios, old, 1200, 230400);
+               pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
+               /* Make sure modem status interrupts are correctly configured */
+               if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {
+                       uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
+                       uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;
+               } else {
+                       uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
+                       uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
+               }
+
+               /* Load registers to the chip */
+               pmz_maybe_update_regs(uap);
+       }
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       pmz_debug("pmz: set_termios() done.\n");
+}
+
+/* The port lock is not held.  */
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);  
+
+       /* Disable IRQs on the port */
+       uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       write_zsreg(uap, R1, uap->curregs[R1]);
+
+       /* Setup new port configuration */
+       __pmz_set_termios(port, termios, old);
+
+       /* Re-enable IRQs on the port */
+       if (ZS_IS_OPEN(uap)) {
+               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+               if (!ZS_IS_EXTCLK(uap))
+                       uap->curregs[R1] |= EXT_INT_ENAB;
+               write_zsreg(uap, R1, uap->curregs[R1]);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pmz_type(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = to_pmz(port);
+
+       if (ZS_IS_IRDA(uap))
+               return "Z85c30 ESCC - Infrared port";
+       else if (ZS_IS_INTMODEM(uap))
+               return "Z85c30 ESCC - Internal modem";
+       return "Z85c30 ESCC - Serial port";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void pmz_release_port(struct uart_port *port)
+{
+}
+
+static int pmz_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void pmz_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+               udelay(5);
+       return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops pmz_pops = {
+       .tx_empty       =       pmz_tx_empty,
+       .set_mctrl      =       pmz_set_mctrl,
+       .get_mctrl      =       pmz_get_mctrl,
+       .stop_tx        =       pmz_stop_tx,
+       .start_tx       =       pmz_start_tx,
+       .stop_rx        =       pmz_stop_rx,
+       .enable_ms      =       pmz_enable_ms,
+       .break_ctl      =       pmz_break_ctl,
+       .startup        =       pmz_startup,
+       .shutdown       =       pmz_shutdown,
+       .set_termios    =       pmz_set_termios,
+       .type           =       pmz_type,
+       .release_port   =       pmz_release_port,
+       .request_port   =       pmz_request_port,
+       .config_port    =       pmz_config_port,
+       .verify_port    =       pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  =       pmz_poll_get_char,
+       .poll_put_char  =       pmz_poll_put_char,
+#endif
+};
+
+#ifdef CONFIG_PPC_PMAC
+
+/*
+ * Setup one port structure after probing, HW is down at this point,
+ * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
+ * register our console before uart_add_one_port() is called
+ */
+static int __init pmz_init_port(struct uart_pmac_port *uap)
+{
+       struct device_node *np = uap->node;
+       const char *conn;
+       const struct slot_names_prop {
+               int     count;
+               char    name[1];
+       } *slots;
+       int len;
+       struct resource r_ports, r_rxdma, r_txdma;
+
+       /*
+        * Request & map chip registers
+        */
+       if (of_address_to_resource(np, 0, &r_ports))
+               return -ENODEV;
+       uap->port.mapbase = r_ports.start;
+       uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
+
+       uap->control_reg = uap->port.membase;
+       uap->data_reg = uap->control_reg + 0x10;
+       
+       /*
+        * Request & map DBDMA registers
+        */
+#ifdef HAS_DBDMA
+       if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+           of_address_to_resource(np, 2, &r_rxdma) == 0)
+               uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+       memset(&r_txdma, 0, sizeof(struct resource));
+       memset(&r_rxdma, 0, sizeof(struct resource));
+#endif 
+       if (ZS_HAS_DMA(uap)) {
+               uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
+               if (uap->tx_dma_regs == NULL) { 
+                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
+                       goto no_dma;
+               }
+               uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
+               if (uap->rx_dma_regs == NULL) { 
+                       iounmap(uap->tx_dma_regs);
+                       uap->tx_dma_regs = NULL;
+                       uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
+                       goto no_dma;
+               }
+               uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
+               uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
+       }
+no_dma:
+
+       /*
+        * Detect port type
+        */
+       if (of_device_is_compatible(np, "cobalt"))
+               uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
+       conn = of_get_property(np, "AAPL,connector", &len);
+       if (conn && (strcmp(conn, "infrared") == 0))
+               uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+       uap->port_type = PMAC_SCC_ASYNC;
+       /* 1999 Powerbook G3 has slot-names property instead */
+       slots = of_get_property(np, "slot-names", &len);
+       if (slots && slots->count > 0) {
+               if (strcmp(slots->name, "IrDA") == 0)
+                       uap->flags |= PMACZILOG_FLAG_IS_IRDA;
+               else if (strcmp(slots->name, "Modem") == 0)
+                       uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
+       }
+       if (ZS_IS_IRDA(uap))
+               uap->port_type = PMAC_SCC_IRDA;
+       if (ZS_IS_INTMODEM(uap)) {
+               struct device_node* i2c_modem =
+                       of_find_node_by_name(NULL, "i2c-modem");
+               if (i2c_modem) {
+                       const char* mid =
+                               of_get_property(i2c_modem, "modem-id", NULL);
+                       if (mid) switch(*mid) {
+                       case 0x04 :
+                       case 0x05 :
+                       case 0x07 :
+                       case 0x08 :
+                       case 0x0b :
+                       case 0x0c :
+                               uap->port_type = PMAC_SCC_I2S1;
+                       }
+                       printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
+                               mid ? (*mid) : 0);
+                       of_node_put(i2c_modem);
+               } else {
+                       printk(KERN_INFO "pmac_zilog: serial modem detected\n");
+               }
+       }
+
+       /*
+        * Init remaining bits of "port" structure
+        */
+       uap->port.iotype = UPIO_MEM;
+       uap->port.irq = irq_of_parse_and_map(np, 0);
+       uap->port.uartclk = ZS_CLOCK;
+       uap->port.fifosize = 1;
+       uap->port.ops = &pmz_pops;
+       uap->port.type = PORT_PMAC_ZILOG;
+       uap->port.flags = 0;
+
+       /*
+        * Fixup for the port on Gatwick for which the device-tree has
+        * missing interrupts. Normally, the macio_dev would contain
+        * fixed up interrupt info, but we use the device-tree directly
+        * here due to early probing so we need the fixup too.
+        */
+       if (uap->port.irq == NO_IRQ &&
+           np->parent && np->parent->parent &&
+           of_device_is_compatible(np->parent->parent, "gatwick")) {
+               /* IRQs on gatwick are offset by 64 */
+               uap->port.irq = irq_create_mapping(NULL, 64 + 15);
+               uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
+               uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
+       }
+
+       /* Setup some valid baud rate information in the register
+        * shadows so we don't write crap there before baud rate is
+        * first initialized.
+        */
+       pmz_convert_to_zs(uap, CS8, 0, 9600);
+
+       return 0;
+}
+
+/*
+ * Get rid of a port on module removal
+ */
+static void pmz_dispose_port(struct uart_pmac_port *uap)
+{
+       struct device_node *np;
+
+       np = uap->node;
+       iounmap(uap->rx_dma_regs);
+       iounmap(uap->tx_dma_regs);
+       iounmap(uap->control_reg);
+       uap->node = NULL;
+       of_node_put(np);
+       memset(uap, 0, sizeof(struct uart_pmac_port));
+}
+
+/*
+ * Called upon match with an escc node in the device-tree.
+ */
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+       int i;
+       
+       /* Iterate the pmz_ports array to find a matching entry
+        */
+       for (i = 0; i < MAX_ZS_PORTS; i++)
+               if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
+                       struct uart_pmac_port *uap = &pmz_ports[i];
+
+                       uap->dev = mdev;
+                       dev_set_drvdata(&mdev->ofdev.dev, uap);
+                       if (macio_request_resources(uap->dev, "pmac_zilog"))
+                               printk(KERN_WARNING "%s: Failed to request resource"
+                                      ", port still active\n",
+                                      uap->node->name);
+                       else
+                               uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;                            
+                       return 0;
+               }
+       return -ENODEV;
+}
+
+/*
+ * That one should not be called, macio isn't really a hotswap device,
+ * we don't expect one of those serial ports to go away...
+ */
+static int pmz_detach(struct macio_dev *mdev)
+{
+       struct uart_pmac_port   *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       
+       if (!uap)
+               return -ENODEV;
+
+       if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
+               macio_release_resources(uap->dev);
+               uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;
+       }
+       dev_set_drvdata(&mdev->ofdev.dev, NULL);
+       uap->dev = NULL;
+       
+       return 0;
+}
+
+
+static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
+{
+       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       struct uart_state *state;
+       unsigned long flags;
+
+       if (uap == NULL) {
+               printk("HRM... pmz_suspend with NULL uap\n");
+               return 0;
+       }
+
+       if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
+               return 0;
+
+       pmz_debug("suspend, switching to state %d\n", pm_state.event);
+
+       state = pmz_uart_reg.state + uap->port.line;
+
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->port.mutex);
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
+               /* Disable receiver and transmitter.  */
+               uap->curregs[R3] &= ~RxENABLE;
+               uap->curregs[R5] &= ~TxENABLE;
+
+               /* Disable all interrupts and BRK assertion.  */
+               uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+               uap->curregs[R5] &= ~SND_BRK;
+               pmz_load_zsregs(uap, uap->curregs);
+               uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
+               mb();
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))
+               if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
+                       pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
+                       disable_irq(uap->port.irq);
+               }
+
+       if (ZS_IS_CONS(uap))
+               uap->port.cons->flags &= ~CON_ENABLED;
+
+       /* Shut the chip down */
+       pmz_set_scc_power(uap, 0);
+
+       mutex_unlock(&state->port.mutex);
+       mutex_unlock(&pmz_irq_mutex);
+
+       pmz_debug("suspend, switching complete\n");
+
+       mdev->ofdev.dev.power.power_state = pm_state;
+
+       return 0;
+}
+
+
+static int pmz_resume(struct macio_dev *mdev)
+{
+       struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
+       struct uart_state *state;
+       unsigned long flags;
+       int pwr_delay = 0;
+
+       if (uap == NULL)
+               return 0;
+
+       if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
+               return 0;
+       
+       pmz_debug("resume, switching to state 0\n");
+
+       state = pmz_uart_reg.state + uap->port.line;
+
+       mutex_lock(&pmz_irq_mutex);
+       mutex_lock(&state->port.mutex);
+
+       spin_lock_irqsave(&uap->port.lock, flags);
+       if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
+               spin_unlock_irqrestore(&uap->port.lock, flags);
+               goto bail;
+       }
+       pwr_delay = __pmz_startup(uap);
+
+       /* Take care of config that may have changed while asleep */
+       __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
+
+       if (ZS_IS_OPEN(uap)) {
+               /* Enable interrupts */         
+               uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
+               if (!ZS_IS_EXTCLK(uap))
+                       uap->curregs[R1] |= EXT_INT_ENAB;
+               write_zsreg(uap, R1, uap->curregs[R1]);
+       }
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+
+       if (ZS_IS_CONS(uap))
+               uap->port.cons->flags |= CON_ENABLED;
+
+       /* Re-enable IRQ on the controller */
+       if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
+               pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
+               enable_irq(uap->port.irq);
+       }
+
+ bail:
+       mutex_unlock(&state->port.mutex);
+       mutex_unlock(&pmz_irq_mutex);
+
+       /* Right now, we deal with delay by blocking here, I'll be
+        * smarter later on
+        */
+       if (pwr_delay != 0) {
+               pmz_debug("pmz: delaying %d ms\n", pwr_delay);
+               msleep(pwr_delay);
+       }
+
+       pmz_debug("resume, switching complete\n");
+
+       mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
+
+       return 0;
+}
+
+/*
+ * Probe all ports in the system and build the ports array, we register
+ * with the serial layer at this point, the macio-type probing is only
+ * used later to "attach" to the sysfs tree so we get power management
+ * events
+ */
+static int __init pmz_probe(void)
+{
+       struct device_node      *node_p, *node_a, *node_b, *np;
+       int                     count = 0;
+       int                     rc;
+
+       /*
+        * Find all escc chips in the system
+        */
+       node_p = of_find_node_by_name(NULL, "escc");
+       while (node_p) {
+               /*
+                * First get channel A/B node pointers
+                * 
+                * TODO: Add routines with proper locking to do that...
+                */
+               node_a = node_b = NULL;
+               for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
+                       if (strncmp(np->name, "ch-a", 4) == 0)
+                               node_a = of_node_get(np);
+                       else if (strncmp(np->name, "ch-b", 4) == 0)
+                               node_b = of_node_get(np);
+               }
+               if (!node_a && !node_b) {
+                       of_node_put(node_a);
+                       of_node_put(node_b);
+                       printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",
+                               (!node_a) ? 'a' : 'b', node_p->full_name);
+                       goto next;
+               }
+
+               /*
+                * Fill basic fields in the port structures
+                */
+               pmz_ports[count].mate           = &pmz_ports[count+1];
+               pmz_ports[count+1].mate         = &pmz_ports[count];
+               pmz_ports[count].flags          = PMACZILOG_FLAG_IS_CHANNEL_A;
+               pmz_ports[count].node           = node_a;
+               pmz_ports[count+1].node         = node_b;
+               pmz_ports[count].port.line      = count;
+               pmz_ports[count+1].port.line    = count+1;
+
+               /*
+                * Setup the ports for real
+                */
+               rc = pmz_init_port(&pmz_ports[count]);
+               if (rc == 0 && node_b != NULL)
+                       rc = pmz_init_port(&pmz_ports[count+1]);
+               if (rc != 0) {
+                       of_node_put(node_a);
+                       of_node_put(node_b);
+                       memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));
+                       memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));
+                       goto next;
+               }
+               count += 2;
+next:
+               node_p = of_find_node_by_name(node_p, "escc");
+       }
+       pmz_ports_count = count;
+
+       return 0;
+}
+
+#else
+
+extern struct platform_device scc_a_pdev, scc_b_pdev;
+
+static int __init pmz_init_port(struct uart_pmac_port *uap)
+{
+       struct resource *r_ports;
+       int irq;
+
+       r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(uap->node, 0);
+       if (!r_ports || !irq)
+               return -ENODEV;
+
+       uap->port.mapbase  = r_ports->start;
+       uap->port.membase  = (unsigned char __iomem *) r_ports->start;
+       uap->port.iotype   = UPIO_MEM;
+       uap->port.irq      = irq;
+       uap->port.uartclk  = ZS_CLOCK;
+       uap->port.fifosize = 1;
+       uap->port.ops      = &pmz_pops;
+       uap->port.type     = PORT_PMAC_ZILOG;
+       uap->port.flags    = 0;
+
+       uap->control_reg   = uap->port.membase;
+       uap->data_reg      = uap->control_reg + 4;
+       uap->port_type     = 0;
+
+       pmz_convert_to_zs(uap, CS8, 0, 9600);
+
+       return 0;
+}
+
+static int __init pmz_probe(void)
+{
+       int err;
+
+       pmz_ports_count = 0;
+
+       pmz_ports[0].mate      = &pmz_ports[1];
+       pmz_ports[0].port.line = 0;
+       pmz_ports[0].flags     = PMACZILOG_FLAG_IS_CHANNEL_A;
+       pmz_ports[0].node      = &scc_a_pdev;
+       err = pmz_init_port(&pmz_ports[0]);
+       if (err)
+               return err;
+       pmz_ports_count++;
+
+       pmz_ports[1].mate      = &pmz_ports[0];
+       pmz_ports[1].port.line = 1;
+       pmz_ports[1].flags     = 0;
+       pmz_ports[1].node      = &scc_b_pdev;
+       err = pmz_init_port(&pmz_ports[1]);
+       if (err)
+               return err;
+       pmz_ports_count++;
+
+       return 0;
+}
+
+static void pmz_dispose_port(struct uart_pmac_port *uap)
+{
+       memset(uap, 0, sizeof(struct uart_pmac_port));
+}
+
+static int __init pmz_attach(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < pmz_ports_count; i++)
+               if (pmz_ports[i].node == pdev)
+                       return 0;
+       return -ENODEV;
+}
+
+static int __exit pmz_detach(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+
+static void pmz_console_write(struct console *con, const char *s, unsigned int count);
+static int __init pmz_console_setup(struct console *co, char *options);
+
+static struct console pmz_console = {
+       .name   =       PMACZILOG_NAME,
+       .write  =       pmz_console_write,
+       .device =       uart_console_device,
+       .setup  =       pmz_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &pmz_uart_reg,
+};
+
+#define PMACZILOG_CONSOLE      &pmz_console
+#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+#define PMACZILOG_CONSOLE      (NULL)
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+
+/*
+ * Register the driver, console driver and ports with the serial
+ * core
+ */
+static int __init pmz_register(void)
+{
+       int i, rc;
+       
+       pmz_uart_reg.nr = pmz_ports_count;
+       pmz_uart_reg.cons = PMACZILOG_CONSOLE;
+
+       /*
+        * Register this driver with the serial core
+        */
+       rc = uart_register_driver(&pmz_uart_reg);
+       if (rc)
+               return rc;
+
+       /*
+        * Register each port with the serial core
+        */
+       for (i = 0; i < pmz_ports_count; i++) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               /* NULL node may happen on wallstreet */
+               if (uport->node != NULL)
+                       rc = uart_add_one_port(&pmz_uart_reg, &uport->port);
+               if (rc)
+                       goto err_out;
+       }
+
+       return 0;
+err_out:
+       while (i-- > 0) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               uart_remove_one_port(&pmz_uart_reg, &uport->port);
+       }
+       uart_unregister_driver(&pmz_uart_reg);
+       return rc;
+}
+
+#ifdef CONFIG_PPC_PMAC
+
+static struct of_device_id pmz_match[] = 
+{
+       {
+       .name           = "ch-a",
+       },
+       {
+       .name           = "ch-b",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE (of, pmz_match);
+
+static struct macio_driver pmz_driver = {
+       .driver = {
+               .name           = "pmac_zilog",
+               .owner          = THIS_MODULE,
+               .of_match_table = pmz_match,
+       },
+       .probe          = pmz_attach,
+       .remove         = pmz_detach,
+       .suspend        = pmz_suspend,
+       .resume         = pmz_resume,
+};
+
+#else
+
+static struct platform_driver pmz_driver = {
+       .remove         = __exit_p(pmz_detach),
+       .driver         = {
+               .name           = "scc",
+               .owner          = THIS_MODULE,
+       },
+};
+
+#endif /* !CONFIG_PPC_PMAC */
+
+static int __init init_pmz(void)
+{
+       int rc, i;
+       printk(KERN_INFO "%s\n", version);
+
+       /* 
+        * First, we need to do a direct OF-based probe pass. We
+        * do that because we want serial console up before the
+        * macio stuffs calls us back, and since that makes it
+        * easier to pass the proper number of channels to
+        * uart_register_driver()
+        */
+       if (pmz_ports_count == 0)
+               pmz_probe();
+
+       /*
+        * Bail early if no port found
+        */
+       if (pmz_ports_count == 0)
+               return -ENODEV;
+
+       /*
+        * Now we register with the serial layer
+        */
+       rc = pmz_register();
+       if (rc) {
+               printk(KERN_ERR 
+                       "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n"
+                       "pmac_zilog: Did another serial driver already claim the minors?\n"); 
+               /* effectively "pmz_unprobe()" */
+               for (i=0; i < pmz_ports_count; i++)
+                       pmz_dispose_port(&pmz_ports[i]);
+               return rc;
+       }
+
+       /*
+        * Then we register the macio driver itself
+        */
+#ifdef CONFIG_PPC_PMAC
+       return macio_register_driver(&pmz_driver);
+#else
+       return platform_driver_probe(&pmz_driver, pmz_attach);
+#endif
+}
+
+static void __exit exit_pmz(void)
+{
+       int i;
+
+#ifdef CONFIG_PPC_PMAC
+       /* Get rid of macio-driver (detach from macio) */
+       macio_unregister_driver(&pmz_driver);
+#else
+       platform_driver_unregister(&pmz_driver);
+#endif
+
+       for (i = 0; i < pmz_ports_count; i++) {
+               struct uart_pmac_port *uport = &pmz_ports[i];
+               if (uport->node != NULL) {
+                       uart_remove_one_port(&pmz_uart_reg, &uport->port);
+                       pmz_dispose_port(uport);
+               }
+       }
+       /* Unregister UART driver */
+       uart_unregister_driver(&pmz_uart_reg);
+}
+
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+
+static void pmz_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void pmz_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_pmac_port *uap = &pmz_ports[con->index];
+       unsigned long flags;
+
+       if (ZS_IS_ASLEEP(uap))
+               return;
+       spin_lock_irqsave(&uap->port.lock, flags);
+
+       /* Turn of interrupts and enable the transmitter. */
+       write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
+       write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
+
+       uart_console_write(&uap->port, s, count, pmz_console_putchar);
+
+       /* Restore the values in the registers. */
+       write_zsreg(uap, R1, uap->curregs[1]);
+       /* Don't disable the transmitter. */
+
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Setup the serial console
+ */
+static int __init pmz_console_setup(struct console *co, char *options)
+{
+       struct uart_pmac_port *uap;
+       struct uart_port *port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       unsigned long pwr_delay;
+
+       /*
+        * XServe's default to 57600 bps
+        */
+       if (of_machine_is_compatible("RackMac1,1")
+           || of_machine_is_compatible("RackMac1,2")
+           || of_machine_is_compatible("MacRISC4"))
+               baud = 57600;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= pmz_ports_count)
+               co->index = 0;
+       uap = &pmz_ports[co->index];
+       if (uap->node == NULL)
+               return -ENODEV;
+       port = &uap->port;
+
+       /*
+        * Mark port as beeing a console
+        */
+       uap->flags |= PMACZILOG_FLAG_IS_CONS;
+
+       /*
+        * Temporary fix for uart layer who didn't setup the spinlock yet
+        */
+       spin_lock_init(&port->lock);
+
+       /*
+        * Enable the hardware
+        */
+       pwr_delay = __pmz_startup(uap);
+       if (pwr_delay)
+               mdelay(pwr_delay);
+       
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static int __init pmz_console_init(void)
+{
+       /* Probe ports */
+       pmz_probe();
+
+       /* TODO: Autoprobe console based on OF */
+       /* pmz_console.index = i; */
+       register_console(&pmz_console);
+
+       return 0;
+
+}
+console_initcall(pmz_console_init);
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+
+module_init(init_pmz);
+module_exit(exit_pmz);
diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h
new file mode 100644 (file)
index 0000000..cbc34fb
--- /dev/null
@@ -0,0 +1,396 @@
+#ifndef __PMAC_ZILOG_H__
+#define __PMAC_ZILOG_H__
+
+#ifdef CONFIG_PPC_PMAC
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_info(fmt, arg...)  dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
+#else
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
+#define pmz_info(fmt, arg...)  dev_info(&uap->node->dev, fmt, ## arg)
+#endif
+
+/*
+ * At most 2 ESCCs with 2 ports each
+ */
+#define MAX_ZS_PORTS   4
+
+/* 
+ * We wrap our port structure around the generic uart_port.
+ */
+#define NUM_ZSREGS    17
+
+struct uart_pmac_port {
+       struct uart_port                port;
+       struct uart_pmac_port           *mate;
+
+#ifdef CONFIG_PPC_PMAC
+       /* macio_dev for the escc holding this port (maybe be null on
+        * early inited port)
+        */
+       struct macio_dev                *dev;
+       /* device node to this port, this points to one of 2 childs
+        * of "escc" node (ie. ch-a or ch-b)
+        */
+       struct device_node              *node;
+#else
+       struct platform_device          *node;
+#endif
+
+       /* Port type as obtained from device tree (IRDA, modem, ...) */
+       int                             port_type;
+       u8                              curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define PMACZILOG_FLAG_IS_CONS         0x00000001
+#define PMACZILOG_FLAG_IS_KGDB         0x00000002
+#define PMACZILOG_FLAG_MODEM_STATUS    0x00000004
+#define PMACZILOG_FLAG_IS_CHANNEL_A    0x00000008
+#define PMACZILOG_FLAG_REGS_HELD       0x00000010
+#define PMACZILOG_FLAG_TX_STOPPED      0x00000020
+#define PMACZILOG_FLAG_TX_ACTIVE       0x00000040
+#define PMACZILOG_FLAG_ENABLED          0x00000080
+#define PMACZILOG_FLAG_IS_IRDA         0x00000100
+#define PMACZILOG_FLAG_IS_INTMODEM     0x00000200
+#define PMACZILOG_FLAG_HAS_DMA         0x00000400
+#define PMACZILOG_FLAG_RSRC_REQUESTED  0x00000800
+#define PMACZILOG_FLAG_IS_ASLEEP       0x00001000
+#define PMACZILOG_FLAG_IS_OPEN         0x00002000
+#define PMACZILOG_FLAG_IS_IRQ_ON       0x00004000
+#define PMACZILOG_FLAG_IS_EXTCLK       0x00008000
+#define PMACZILOG_FLAG_BREAK           0x00010000
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+
+       volatile u8                     __iomem *control_reg;
+       volatile u8                     __iomem *data_reg;
+
+#ifdef CONFIG_PPC_PMAC
+       unsigned int                    tx_dma_irq;
+       unsigned int                    rx_dma_irq;
+       volatile struct dbdma_regs      __iomem *tx_dma_regs;
+       volatile struct dbdma_regs      __iomem *rx_dma_regs;
+#endif
+
+       struct ktermios                 termios_cache;
+};
+
+#define to_pmz(p) ((struct uart_pmac_port *)(p))
+
+static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
+{
+       if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
+               return uap;
+       return uap->mate;
+}
+
+/*
+ * Register accessors. Note that we don't need to enforce a recovery
+ * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
+ * though if we try to use this driver on older machines, we might have
+ * to add it back
+ */
+static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg)
+{
+       if (reg != 0)
+               writeb(reg, port->control_reg);
+       return readb(port->control_reg);
+}
+
+static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value)
+{
+       if (reg != 0)
+               writeb(reg, port->control_reg);
+       writeb(value, port->control_reg);
+}
+
+static inline u8 read_zsdata(struct uart_pmac_port *port)
+{
+       return readb(port->data_reg);
+}
+
+static inline void write_zsdata(struct uart_pmac_port *port, u8 data)
+{
+       writeb(data, port->data_reg);
+}
+
+static inline void zssync(struct uart_pmac_port *port)
+{
+       (void)readb(port->control_reg);
+}
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+#define        R7P     16
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
+#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
+#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENABLE        0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENABLE        0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 7' (Some enhanced feature control) */
+#define        ENEXREAD        0x40    /* Enable read of some write registers */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
+#define        ZCIE    2       /* Zero count IE */
+#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC_HUNT       0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define        CHB_Tx_EMPTY    0x00
+#define        CHB_EXT_STAT    0x02
+#define        CHB_Rx_AVAIL    0x04
+#define        CHB_SPECIAL     0x06
+#define        CHA_Tx_EMPTY    0x08
+#define        CHA_EXT_STAT    0x0a
+#define        CHA_Rx_AVAIL    0x0c
+#define        CHA_SPECIAL     0x0e
+#define        STATUS_MASK     0x06
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(port)    (write_zsreg(port, 0, ERR_RES))
+#define ZS_CLEARFIFO(port)   do { volatile unsigned char garbage; \
+                                    garbage = read_zsdata(port); \
+                                    garbage = read_zsdata(port); \
+                                    garbage = read_zsdata(port); \
+                               } while(0)
+
+#define ZS_IS_CONS(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_KGDB)
+#define ZS_IS_CHANNEL_A(UP)            ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)               ((UP)->flags & PMACZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)              ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)               ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_IRDA(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
+#define ZS_IS_INTMODEM(UP)             ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
+#define ZS_HAS_DMA(UP)                 ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
+#define ZS_IS_ASLEEP(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
+#define ZS_IS_OPEN(UP)                 ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
+#define ZS_IS_IRQ_ON(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
+#define ZS_IS_EXTCLK(UP)               ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
+
+#endif /* __PMAC_ZILOG_H__ */
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
new file mode 100644 (file)
index 0000000..0aa75a9
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * UART driver for PNX8XXX SoCs
+ *
+ * Author: Per Hallsmark per.hallsmark@mvista.com
+ * Ported to 2.6 kernel by EmbeddedAlley
+ * Reworked by Vitaly Wool <vitalywool@gmail.com>
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_pnx8xxx.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* We'll be using StrongARM sa1100 serial port major/minor */
+#define SERIAL_PNX8XXX_MAJOR   204
+#define MINOR_START            5
+
+#define NR_PORTS               2
+
+#define PNX8XXX_ISR_PASS_LIMIT 256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to FIFO
+ * and interrupt status bits
+ */
+#define SM_TO_FIFO(x)  ((x) >> 10)
+#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
+#define FIFO_TO_SM(x)  ((x) << 10)
+#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x1000
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+extern struct pnx8xxx_port pnx8xxx_ports[];
+
+static inline int serial_in(struct pnx8xxx_port *sport, int offset)
+{
+       return (__raw_readl(sport->port.membase + offset));
+}
+
+static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
+{
+       __raw_writel(value, sport->port.membase + offset);
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void pnx8xxx_timeout(unsigned long data)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               pnx8xxx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void pnx8xxx_stop_tx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Disable TX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
+
+       /* Clear all pending TX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * interrupts may not be disabled on entry
+ */
+static void pnx8xxx_start_tx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Clear all pending TX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+
+       /* Enable TX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void pnx8xxx_stop_rx(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       u32 ien;
+
+       /* Disable RX intr */
+       ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
+
+       /* Clear all pending RX intr */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void pnx8xxx_enable_ms(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
+{
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+                ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+       while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
+               ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
+
+               sport->port.icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
+                                       PNX8XXX_UART_FIFO_RXPAR |
+                                       PNX8XXX_UART_FIFO_RXBRK) |
+                             ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
+                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
+                               status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
+                               sport->port.icount.brk++;
+                               if (uart_handle_break(&sport->port))
+                                       goto ignore_char;
+                       } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+                               sport->port.icount.parity++;
+                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+                               sport->port.icount.frame++;
+                       if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
+                               sport->port.icount.overrun++;
+
+                       status &= sport->port.read_status_mask;
+
+                       if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+                               flg = TTY_PARITY;
+                       else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&sport->port, status,
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
+
+       ignore_char:
+               serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
+                               PNX8XXX_UART_LCR_RX_NEXT);
+               status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+                        ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+       }
+       tty_flip_buffer_push(tty);
+}
+
+static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       if (sport->port.x_char) {
+               serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /*
+        * Check the modem control lines before
+        * transmitting anything.
+        */
+       pnx8xxx_mctrl_check(sport);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               pnx8xxx_stop_tx(&sport->port);
+               return;
+       }
+
+       /*
+        * TX while bytes available
+        */
+       while (((serial_in(sport, PNX8XXX_FIFO) &
+                                       PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
+               serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               pnx8xxx_stop_tx(&sport->port);
+}
+
+static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
+{
+       struct pnx8xxx_port *sport = dev_id;
+       unsigned int status;
+
+       spin_lock(&sport->port.lock);
+       /* Get the interrupts */
+       status  = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
+
+       /* Byte or break signal received */
+       if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
+               pnx8xxx_rx_chars(sport);
+
+       /* TX holding register empty - transmit a byte */
+       if (status & PNX8XXX_UART_INT_TX)
+               pnx8xxx_tx_chars(sport);
+
+       /* Clear the ISTAT register */
+       serial_out(sport, PNX8XXX_ICLR, status);
+
+       spin_unlock(&sport->port.lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned int mctrl = TIOCM_DSR;
+       unsigned int msr;
+
+       /* REVISIT */
+
+       msr = serial_in(sport, PNX8XXX_MCR);
+
+       mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
+       mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
+
+       return mctrl;
+}
+
+static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+#if    0       /* FIXME */
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned int msr;
+#endif
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned long flags;
+       unsigned int lcr;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       lcr = serial_in(sport, PNX8XXX_LCR);
+       if (break_state == -1)
+               lcr |= PNX8XXX_UART_LCR_TXBREAK;
+       else
+               lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+       serial_out(sport, PNX8XXX_LCR, lcr);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int pnx8xxx_startup(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
+                            "pnx8xxx-uart", sport);
+       if (retval)
+               return retval;
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+                            PNX8XXX_UART_INT_ALLTX);
+
+       serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
+                           PNX8XXX_UART_INT_ALLRX |
+                           PNX8XXX_UART_INT_ALLTX);
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irq(&sport->port.lock);
+       pnx8xxx_enable_ms(&sport->port);
+       spin_unlock_irq(&sport->port.lock);
+
+       return 0;
+}
+
+static void pnx8xxx_shutdown(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int lcr;
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Disable all interrupts
+        */
+       serial_out(sport, PNX8XXX_IEN, 0);
+
+       /*
+        * Reset the Tx and Rx FIFOS, disable the break condition
+        */
+       lcr = serial_in(sport, PNX8XXX_LCR);
+       lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+       lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
+       serial_out(sport, PNX8XXX_LCR, lcr);
+
+       /*
+        * Clear all interrupts
+        */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+                            PNX8XXX_UART_INT_ALLTX);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(sport->port.irq, sport);
+}
+
+static void
+pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       unsigned long flags;
+       unsigned int lcr_fcr, old_ien, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               lcr_fcr = PNX8XXX_UART_LCR_8BIT;
+       else
+               lcr_fcr = 0;
+
+       if (termios->c_cflag & CSTOPB)
+               lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
+       if (termios->c_cflag & PARENB) {
+               lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
+               if (!(termios->c_cflag & PARODD))
+                       lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |=
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |=
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+                       FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |=
+                               ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               sport->port.ignore_status_mask |=
+                       ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+                                       PNX8XXX_UART_INT_ALLRX));
+
+       while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
+               barrier();
+
+       /* then, disable everything */
+       serial_out(sport, PNX8XXX_IEN, 0);
+
+       /* Reset the Rx and Tx FIFOs too */
+       lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
+       lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
+
+       /* set the parity, stop bits and data size */
+       serial_out(sport, PNX8XXX_LCR, lcr_fcr);
+
+       /* set the baud rate */
+       quot -= 1;
+       serial_out(sport, PNX8XXX_BAUD, quot);
+
+       serial_out(sport, PNX8XXX_ICLR, -1);
+
+       serial_out(sport, PNX8XXX_IEN, old_ien);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               pnx8xxx_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *pnx8xxx_type(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void pnx8xxx_release_port(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int pnx8xxx_request_port(struct uart_port *port)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+                       "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pnx8xxx_config_port(struct uart_port *port, int flags)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           pnx8xxx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_PNX8XXX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_PNX8XXX and PORT_UNKNOWN
+ */
+static int
+pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops pnx8xxx_pops = {
+       .tx_empty       = pnx8xxx_tx_empty,
+       .set_mctrl      = pnx8xxx_set_mctrl,
+       .get_mctrl      = pnx8xxx_get_mctrl,
+       .stop_tx        = pnx8xxx_stop_tx,
+       .start_tx       = pnx8xxx_start_tx,
+       .stop_rx        = pnx8xxx_stop_rx,
+       .enable_ms      = pnx8xxx_enable_ms,
+       .break_ctl      = pnx8xxx_break_ctl,
+       .startup        = pnx8xxx_startup,
+       .shutdown       = pnx8xxx_shutdown,
+       .set_termios    = pnx8xxx_set_termios,
+       .type           = pnx8xxx_type,
+       .release_port   = pnx8xxx_release_port,
+       .request_port   = pnx8xxx_request_port,
+       .config_port    = pnx8xxx_config_port,
+       .verify_port    = pnx8xxx_verify_port,
+};
+
+
+/*
+ * Setup the PNX8XXX serial ports.
+ *
+ * Note also that we support "console=ttySx" where "x" is either 0 or 1.
+ */
+static void __init pnx8xxx_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               init_timer(&pnx8xxx_ports[i].timer);
+               pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
+               pnx8xxx_ports[i].timer.data     = (unsigned long)&pnx8xxx_ports[i];
+               pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
+       }
+}
+
+#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
+
+static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
+{
+       struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+       int status;
+
+       do {
+               /* Wait for UART_TX register to empty */
+               status = serial_in(sport, PNX8XXX_FIFO);
+       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+       serial_out(sport, PNX8XXX_FIFO, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */static void
+pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
+       unsigned int old_ien, status;
+
+       /*
+        *      First, save IEN and then disable interrupts
+        */
+       old_ien = serial_in(sport, PNX8XXX_IEN);
+       serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+                                       PNX8XXX_UART_INT_ALLRX));
+
+       uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore IEN
+        */
+       do {
+               /* Wait for UART_TX register to empty */
+               status = serial_in(sport, PNX8XXX_FIFO);
+       } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+
+       /* Clear TX and EMPTY interrupt */
+       serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
+                            PNX8XXX_UART_INT_EMPTY);
+
+       serial_out(sport, PNX8XXX_IEN, old_ien);
+}
+
+static int __init
+pnx8xxx_console_setup(struct console *co, char *options)
+{
+       struct pnx8xxx_port *sport;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       sport = &pnx8xxx_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver pnx8xxx_reg;
+static struct console pnx8xxx_console = {
+       .name           = "ttyS",
+       .write          = pnx8xxx_console_write,
+       .device         = uart_console_device,
+       .setup          = pnx8xxx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &pnx8xxx_reg,
+};
+
+static int __init pnx8xxx_rs_console_init(void)
+{
+       pnx8xxx_init_ports();
+       register_console(&pnx8xxx_console);
+       return 0;
+}
+console_initcall(pnx8xxx_rs_console_init);
+
+#define PNX8XXX_CONSOLE        &pnx8xxx_console
+#else
+#define PNX8XXX_CONSOLE        NULL
+#endif
+
+static struct uart_driver pnx8xxx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyS",
+       .dev_name               = "ttyS",
+       .major                  = SERIAL_PNX8XXX_MAJOR,
+       .minor                  = MINOR_START,
+       .nr                     = NR_PORTS,
+       .cons                   = PNX8XXX_CONSOLE,
+};
+
+static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       return uart_suspend_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_resume(struct platform_device *pdev)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       return uart_resume_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_probe(struct platform_device *pdev)
+{
+       struct resource *res = pdev->resource;
+       int i;
+
+       for (i = 0; i < pdev->num_resources; i++, res++) {
+               if (!(res->flags & IORESOURCE_MEM))
+                       continue;
+
+               for (i = 0; i < NR_PORTS; i++) {
+                       if (pnx8xxx_ports[i].port.mapbase != res->start)
+                               continue;
+
+                       pnx8xxx_ports[i].port.dev = &pdev->dev;
+                       uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
+                       platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int pnx8xxx_serial_remove(struct platform_device *pdev)
+{
+       struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&pnx8xxx_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver pnx8xxx_serial_driver = {
+       .driver         = {
+               .name   = "pnx8xxx-uart",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pnx8xxx_serial_probe,
+       .remove         = pnx8xxx_serial_remove,
+       .suspend        = pnx8xxx_serial_suspend,
+       .resume         = pnx8xxx_serial_resume,
+};
+
+static int __init pnx8xxx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: PNX8XXX driver\n");
+
+       pnx8xxx_init_ports();
+
+       ret = uart_register_driver(&pnx8xxx_reg);
+       if (ret == 0) {
+               ret = platform_driver_register(&pnx8xxx_serial_driver);
+               if (ret)
+                       uart_unregister_driver(&pnx8xxx_reg);
+       }
+       return ret;
+}
+
+static void __exit pnx8xxx_serial_exit(void)
+{
+       platform_driver_unregister(&pnx8xxx_serial_driver);
+       uart_unregister_driver(&pnx8xxx_reg);
+}
+
+module_init(pnx8xxx_serial_init);
+module_exit(pnx8xxx_serial_exit);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
+MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
+MODULE_ALIAS("platform:pnx8xxx-uart");
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
new file mode 100644 (file)
index 0000000..1102a39
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ *  linux/drivers/serial/pxa.c
+ *
+ *  Based on drivers/serial/8250.c by Russell King.
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Feb 20, 2003
+ *  Copyright: (C) 2003 Monta Vista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Note 1: This driver is made separate from the already too overloaded
+ * 8250.c because it needs some kirks of its own and that'll make it
+ * easier to add DMA support.
+ *
+ * Note 2: I'm too sick of device allocation policies for serial ports.
+ * If someone else wants to request an "official" allocation of major/minor
+ * for this driver please be my guest.  And don't forget that new hardware
+ * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
+ * hope for a better port registration and dynamic device allocation scheme
+ * with the serial core maintainer satisfaction to appear soon.
+ */
+
+
+#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+struct uart_pxa_port {
+       struct uart_port        port;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned int            lsr_break_flag;
+       struct clk              *clk;
+       char                    *name;
+};
+
+static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
+{
+       offset <<= 2;
+       return readl(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
+{
+       offset <<= 2;
+       writel(value, up->port.membase + offset);
+}
+
+static void serial_pxa_enable_ms(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_pxa_stop_tx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void serial_pxa_stop_rx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_pxa_port *up, int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned int ch, flag;
+       int max_count = 256;
+
+       do {
+               ch = serial_in(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ignored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_PXA_CONSOLE
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+#endif
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+       tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct uart_pxa_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_out(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_pxa_stop_tx(&up->port);
+               return;
+       }
+
+       count = up->port.fifosize / 2;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+
+       if (uart_circ_empty(xmit))
+               serial_pxa_stop_tx(&up->port);
+}
+
+static void serial_pxa_start_tx(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static inline void check_modem_status(struct uart_pxa_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
+{
+       struct uart_pxa_port *up = dev_id;
+       unsigned int iir, lsr;
+
+       iir = serial_in(up, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+       lsr = serial_in(up, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(up, &lsr);
+       check_modem_status(up);
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(up);
+       return IRQ_HANDLED;
+}
+
+static unsigned int serial_pxa_tx_empty(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       mcr |= up->mcr;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+#if 0
+static void serial_pxa_dma_init(struct pxa_uart *up)
+{
+       up->rxdma =
+               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
+       if (up->rxdma < 0)
+               goto out;
+       up->txdma =
+               pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
+       if (up->txdma < 0)
+               goto err_txdma;
+       up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
+       if (!up->dmadesc)
+               goto err_alloc;
+
+       /* ... */
+err_alloc:
+       pxa_free_dma(up->txdma);
+err_rxdma:
+       pxa_free_dma(up->rxdma);
+out:
+       return;
+}
+#endif
+
+static int serial_pxa_startup(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+       int retval;
+
+       if (port->line == 3) /* HWUART */
+               up->mcr |= UART_MCR_AFE;
+       else
+               up->mcr = 0;
+
+       up->port.uartclk = clk_get_rate(up->clk);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
+       if (retval)
+               return retval;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_out(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl |= TIOCM_OUT2;
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+       serial_out(up, UART_IER, up->ier);
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void) serial_in(up, UART_LSR);
+       (void) serial_in(up, UART_RX);
+       (void) serial_in(up, UART_IIR);
+       (void) serial_in(up, UART_MSR);
+
+       return 0;
+}
+
+static void serial_pxa_shutdown(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned long flags;
+
+       free_irq(up->port.irq, up);
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_out(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->port.mctrl &= ~TIOCM_OUT2;
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_out(up, UART_FCR, 0);
+}
+
+static void
+serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned int dll;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               cval = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               cval = UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               cval = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= UART_LCR_STOP;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       if ((up->port.uartclk / quot) < (2400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
+       else if ((up->port.uartclk / quot) < (230400 * 16))
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
+       else
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Ensure the port will be enabled.
+        * This is required especially for serial console.
+        */
+       up->ier |= UART_IER_UUE;
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE;
+       else
+               up->mcr &= ~UART_MCR_AFE;
+
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+       serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+
+       /*
+        * work around Errata #75 according to Intel(R) PXA27x Processor Family
+        * Specification Update (Nov 2005)
+        */
+       dll = serial_in(up, UART_DLL);
+       WARN_ON(dll != (quot & 0xff));
+
+       serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       serial_pxa_set_mctrl(&up->port, up->port.mctrl);
+       serial_out(up, UART_FCR, fcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_pxa_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       if (!state)
+               clk_enable(up->clk);
+       else
+               clk_disable(up->clk);
+}
+
+static void serial_pxa_release_port(struct uart_port *port)
+{
+}
+
+static int serial_pxa_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void serial_pxa_config_port(struct uart_port *port, int flags)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       up->port.type = PORT_PXA;
+}
+
+static int
+serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static const char *
+serial_pxa_type(struct uart_port *port)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       return up->name;
+}
+
+static struct uart_pxa_port *serial_pxa_ports[4];
+static struct uart_driver serial_pxa_reg;
+
+#ifdef CONFIG_SERIAL_PXA_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_pxa_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void serial_pxa_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void
+serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_pxa_port *up = serial_pxa_ports[co->index];
+       unsigned int ier;
+
+       clk_enable(up->clk);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, UART_IER_UUE);
+
+       uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       clk_disable(up->clk);
+}
+
+static int __init
+serial_pxa_console_setup(struct console *co, char *options)
+{
+       struct uart_pxa_port *up;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index == -1 || co->index >= serial_pxa_reg.nr)
+               co->index = 0;
+       up = serial_pxa_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_pxa_console = {
+       .name           = "ttyS",
+       .write          = serial_pxa_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_pxa_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_pxa_reg,
+};
+
+#define PXA_CONSOLE    &serial_pxa_console
+#else
+#define PXA_CONSOLE    NULL
+#endif
+
+struct uart_ops serial_pxa_pops = {
+       .tx_empty       = serial_pxa_tx_empty,
+       .set_mctrl      = serial_pxa_set_mctrl,
+       .get_mctrl      = serial_pxa_get_mctrl,
+       .stop_tx        = serial_pxa_stop_tx,
+       .start_tx       = serial_pxa_start_tx,
+       .stop_rx        = serial_pxa_stop_rx,
+       .enable_ms      = serial_pxa_enable_ms,
+       .break_ctl      = serial_pxa_break_ctl,
+       .startup        = serial_pxa_startup,
+       .shutdown       = serial_pxa_shutdown,
+       .set_termios    = serial_pxa_set_termios,
+       .pm             = serial_pxa_pm,
+       .type           = serial_pxa_type,
+       .release_port   = serial_pxa_release_port,
+       .request_port   = serial_pxa_request_port,
+       .config_port    = serial_pxa_config_port,
+       .verify_port    = serial_pxa_verify_port,
+};
+
+static struct uart_driver serial_pxa_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "PXA serial",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = 4,
+       .cons           = PXA_CONSOLE,
+};
+
+#ifdef CONFIG_PM
+static int serial_pxa_suspend(struct device *dev)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
+
+        if (sport)
+                uart_suspend_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_pxa_resume(struct device *dev)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
+
+        if (sport)
+                uart_resume_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static const struct dev_pm_ops serial_pxa_pm_ops = {
+       .suspend        = serial_pxa_suspend,
+       .resume         = serial_pxa_resume,
+};
+#endif
+
+static int serial_pxa_probe(struct platform_device *dev)
+{
+       struct uart_pxa_port *sport;
+       struct resource *mmres, *irqres;
+       int ret;
+
+       mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
+       if (!sport)
+               return -ENOMEM;
+
+       sport->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(sport->clk)) {
+               ret = PTR_ERR(sport->clk);
+               goto err_free;
+       }
+
+       sport->port.type = PORT_PXA;
+       sport->port.iotype = UPIO_MEM;
+       sport->port.mapbase = mmres->start;
+       sport->port.irq = irqres->start;
+       sport->port.fifosize = 64;
+       sport->port.ops = &serial_pxa_pops;
+       sport->port.line = dev->id;
+       sport->port.dev = &dev->dev;
+       sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       sport->port.uartclk = clk_get_rate(sport->clk);
+
+       switch (dev->id) {
+       case 0: sport->name = "FFUART"; break;
+       case 1: sport->name = "BTUART"; break;
+       case 2: sport->name = "STUART"; break;
+       case 3: sport->name = "HWUART"; break;
+       default:
+               sport->name = "???";
+               break;
+       }
+
+       sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
+       if (!sport->port.membase) {
+               ret = -ENOMEM;
+               goto err_clk;
+       }
+
+       serial_pxa_ports[dev->id] = sport;
+
+       uart_add_one_port(&serial_pxa_reg, &sport->port);
+       platform_set_drvdata(dev, sport);
+
+       return 0;
+
+ err_clk:
+       clk_put(sport->clk);
+ err_free:
+       kfree(sport);
+       return ret;
+}
+
+static int serial_pxa_remove(struct platform_device *dev)
+{
+       struct uart_pxa_port *sport = platform_get_drvdata(dev);
+
+       platform_set_drvdata(dev, NULL);
+
+       uart_remove_one_port(&serial_pxa_reg, &sport->port);
+       clk_put(sport->clk);
+       kfree(sport);
+
+       return 0;
+}
+
+static struct platform_driver serial_pxa_driver = {
+        .probe          = serial_pxa_probe,
+        .remove         = serial_pxa_remove,
+
+       .driver         = {
+               .name   = "pxa2xx-uart",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &serial_pxa_pm_ops,
+#endif
+       },
+};
+
+int __init serial_pxa_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&serial_pxa_reg);
+       if (ret != 0)
+               return ret;
+
+       ret = platform_driver_register(&serial_pxa_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_pxa_reg);
+
+       return ret;
+}
+
+void __exit serial_pxa_exit(void)
+{
+       platform_driver_unregister(&serial_pxa_driver);
+       uart_unregister_driver(&serial_pxa_reg);
+}
+
+module_init(serial_pxa_init);
+module_exit(serial_pxa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/tty/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c
new file mode 100644 (file)
index 0000000..fed1a9a
--- /dev/null
@@ -0,0 +1,106 @@
+/* linux/drivers/serial/s3c240.c
+ *
+ * Driver for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2400_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       clk->divisor = 1;
+       clk->name = "pclk";
+
+       return 0;
+}
+
+static int s3c2400_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       return 0;
+}
+
+static int s3c2400_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2400_uart_inf = {
+       .name           = "Samsung S3C2400 UART",
+       .type           = PORT_S3C2400,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2400_serial_getsource,
+       .set_clksrc     = s3c2400_serial_setsource,
+       .reset_port     = s3c2400_serial_resetport,
+};
+
+static int s3c2400_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
+}
+
+static struct platform_driver s3c2400_serial_driver = {
+       .probe          = s3c2400_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2400-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
+
+static inline int s3c2400_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
+}
+
+static inline void s3c2400_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2400_serial_driver);
+}
+
+module_init(s3c2400_serial_init);
+module_exit(s3c2400_serial_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver");
+MODULE_ALIAS("platform:s3c2400-uart");
diff --git a/drivers/tty/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c
new file mode 100644 (file)
index 0000000..73f089d
--- /dev/null
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c2410.c
+ *
+ * Driver for Samsung S3C2410 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2410_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c2410_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static int s3c2410_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2410_uart_inf = {
+       .name           = "Samsung S3C2410 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2410_serial_getsource,
+       .set_clksrc     = s3c2410_serial_setsource,
+       .reset_port     = s3c2410_serial_resetport,
+};
+
+static int s3c2410_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
+}
+
+static struct platform_driver s3c2410_serial_driver = {
+       .probe          = s3c2410_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2410-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
+
+static int __init s3c2410_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
+}
+
+static void __exit s3c2410_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2410_serial_driver);
+}
+
+module_init(s3c2410_serial_init);
+module_exit(s3c2410_serial_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver");
+MODULE_ALIAS("platform:s3c2410-uart");
diff --git a/drivers/tty/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c
new file mode 100644 (file)
index 0000000..1700b1a
--- /dev/null
@@ -0,0 +1,152 @@
+/* linux/drivers/serial/s3c2412.c
+ *
+ * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c2412_serial_setsource(struct uart_port *port,
+                                    struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       ucon &= ~S3C2412_UCON_CLKMASK;
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2440_UCON_UCLK;
+       else if (strcmp(clk->name, "pclk") == 0)
+               ucon |= S3C2440_UCON_PCLK;
+       else if (strcmp(clk->name, "usysclk") == 0)
+               ucon |= S3C2412_UCON_USYSCLK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c2412_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       switch (ucon & S3C2412_UCON_CLKMASK) {
+       case S3C2412_UCON_UCLK:
+               clk->divisor = 1;
+               clk->name = "uclk";
+               break;
+
+       case S3C2412_UCON_PCLK:
+       case S3C2412_UCON_PCLK2:
+               clk->divisor = 1;
+               clk->name = "pclk";
+               break;
+
+       case S3C2412_UCON_USYSCLK:
+               clk->divisor = 1;
+               clk->name = "usysclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c2412_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("%s: port=%p (%08lx), cfg=%p\n",
+           __func__, port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= S3C2412_UCON_CLKMASK;
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2412_uart_inf = {
+       .name           = "Samsung S3C2412 UART",
+       .type           = PORT_S3C2412,
+       .fifosize       = 64,
+       .has_divslot    = 1,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2412_serial_getsource,
+       .set_clksrc     = s3c2412_serial_setsource,
+       .reset_port     = s3c2412_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2412_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c2440_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
+}
+
+static struct platform_driver s3c2412_serial_driver = {
+       .probe          = s3c2412_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2412-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
+
+static inline int s3c2412_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2412_serial_driver);
+}
+
+module_init(s3c2412_serial_init);
+module_exit(s3c2412_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c2412-uart");
diff --git a/drivers/tty/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c
new file mode 100644 (file)
index 0000000..094cc39
--- /dev/null
@@ -0,0 +1,181 @@
+/* linux/drivers/serial/s3c2440.c
+ *
+ * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+
+static int s3c2440_serial_setsource(struct uart_port *port,
+                                    struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       /* todo - proper fclk<>nonfclk switch. */
+
+       ucon &= ~S3C2440_UCON_CLKMASK;
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2440_UCON_UCLK;
+       else if (strcmp(clk->name, "pclk") == 0)
+               ucon |= S3C2440_UCON_PCLK;
+       else if (strcmp(clk->name, "fclk") == 0)
+               ucon |= S3C2440_UCON_FCLK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c2440_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+       unsigned long ucon0, ucon1, ucon2;
+
+       switch (ucon & S3C2440_UCON_CLKMASK) {
+       case S3C2440_UCON_UCLK:
+               clk->divisor = 1;
+               clk->name = "uclk";
+               break;
+
+       case S3C2440_UCON_PCLK:
+       case S3C2440_UCON_PCLK2:
+               clk->divisor = 1;
+               clk->name = "pclk";
+               break;
+
+       case S3C2440_UCON_FCLK:
+               /* the fun of calculating the uart divisors on
+                * the s3c2440 */
+
+               ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
+               ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
+               ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
+
+               printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
+
+               ucon0 &= S3C2440_UCON0_DIVMASK;
+               ucon1 &= S3C2440_UCON1_DIVMASK;
+               ucon2 &= S3C2440_UCON2_DIVMASK;
+
+               if (ucon0 != 0) {
+                       clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 6;
+               } else if (ucon1 != 0) {
+                       clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 21;
+               } else if (ucon2 != 0) {
+                       clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
+                       clk->divisor += 36;
+               } else {
+                       /* manual calims 44, seems to be 9 */
+                       clk->divisor = 9;
+               }
+
+               clk->name = "fclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c2440_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c2440_uart_inf = {
+       .name           = "Samsung S3C2440 UART",
+       .type           = PORT_S3C2440,
+       .fifosize       = 64,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c2440_serial_getsource,
+       .set_clksrc     = s3c2440_serial_setsource,
+       .reset_port     = s3c2440_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2440_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c2440_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
+}
+
+static struct platform_driver s3c2440_serial_driver = {
+       .probe          = s3c2440_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c2440-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
+
+static int __init s3c2440_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
+}
+
+static void __exit s3c2440_serial_exit(void)
+{
+       platform_driver_unregister(&s3c2440_serial_driver);
+}
+
+module_init(s3c2440_serial_init);
+module_exit(s3c2440_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c2440-uart");
diff --git a/drivers/tty/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c
new file mode 100644 (file)
index 0000000..fad6083
--- /dev/null
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c24a0.c
+ *
+ * Driver for Samsung S3C24A0 SoC onboard UARTs.
+ *
+ * Based on drivers/serial/s3c2410.c
+ *
+ * Author: Sandeep Patil <sandeep.patil@azingo.com>
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c24a0_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c24a0_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static int s3c24a0_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c24a0_uart_inf = {
+       .name           = "Samsung S3C24A0 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C24A0_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C24A0_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C24A0_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C24A0_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C24A0_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C24A0_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c24a0_serial_getsource,
+       .set_clksrc     = s3c24a0_serial_setsource,
+       .reset_port     = s3c24a0_serial_resetport,
+};
+
+static int s3c24a0_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
+}
+
+static struct platform_driver s3c24a0_serial_driver = {
+       .probe          = s3c24a0_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c24a0-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
+
+static int __init s3c24a0_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
+}
+
+static void __exit s3c24a0_serial_exit(void)
+{
+       platform_driver_unregister(&s3c24a0_serial_driver);
+}
+
+module_init(s3c24a0_serial_init);
+module_exit(s3c24a0_serial_exit);
+
diff --git a/drivers/tty/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c
new file mode 100644 (file)
index 0000000..4be92ab
--- /dev/null
@@ -0,0 +1,152 @@
+/* linux/drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
+ *
+ * Copyright 2008 Openmoko,  Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+static int s3c6400_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk0") == 0) {
+               ucon &= ~S3C6400_UCON_CLKMASK;
+               ucon |= S3C6400_UCON_UCLK0;
+       } else if (strcmp(clk->name, "uclk1") == 0)
+               ucon |= S3C6400_UCON_UCLK1;
+       else if (strcmp(clk->name, "pclk") == 0) {
+               /* See notes about transitioning from UCLK to PCLK */
+               ucon &= ~S3C6400_UCON_UCLK0;
+       } else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c6400_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       u32 ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+
+       switch (ucon & S3C6400_UCON_CLKMASK) {
+       case S3C6400_UCON_UCLK0:
+               clk->name = "uclk0";
+               break;
+
+       case S3C6400_UCON_UCLK1:
+               clk->name = "uclk1";
+               break;
+
+       case S3C6400_UCON_PCLK:
+       case S3C6400_UCON_PCLK2:
+               clk->name = "pclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c6400_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= S3C6400_UCON_CLKMASK;
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c6400_uart_inf = {
+       .name           = "Samsung S3C6400 UART",
+       .type           = PORT_S3C6400,
+       .fifosize       = 64,
+       .has_divslot    = 1,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c6400_serial_getsource,
+       .set_clksrc     = s3c6400_serial_setsource,
+       .reset_port     = s3c6400_serial_resetport,
+};
+
+/* device management */
+
+static int s3c6400_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c6400_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
+}
+
+static struct platform_driver s3c6400_serial_driver = {
+       .probe          = s3c6400_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s3c6400-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
+
+static int __init s3c6400_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
+}
+
+static void __exit s3c6400_serial_exit(void)
+{
+       platform_driver_unregister(&s3c6400_serial_driver);
+}
+
+module_init(s3c6400_serial_init);
+module_exit(s3c6400_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c
new file mode 100644 (file)
index 0000000..6ebccd7
--- /dev/null
@@ -0,0 +1,162 @@
+/* linux/drivers/serial/s5pv210.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Based on drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S5PV210 SoC UARTs.
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <plat/regs-serial.h>
+#include "samsung.h"
+
+static int s5pv210_serial_setsource(struct uart_port *port,
+                                       struct s3c24xx_uart_clksrc *clk)
+{
+       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if ((cfg->clocks_size) == 1)
+               return 0;
+
+       if (strcmp(clk->name, "pclk") == 0)
+               ucon &= ~S5PV210_UCON_CLKMASK;
+       else if (strcmp(clk->name, "uclk1") == 0)
+               ucon |= S5PV210_UCON_CLKMASK;
+       else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s5pv210_serial_getsource(struct uart_port *port,
+                                       struct s3c24xx_uart_clksrc *clk)
+{
+       struct s3c2410_uartcfg *cfg = port->dev->platform_data;
+       u32 ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+
+       if ((cfg->clocks_size) == 1)
+               return 0;
+
+       switch (ucon & S5PV210_UCON_CLKMASK) {
+       case S5PV210_UCON_PCLK:
+               clk->name = "pclk";
+               break;
+       case S5PV210_UCON_UCLK:
+               clk->name = "uclk1";
+               break;
+       }
+
+       return 0;
+}
+
+static int s5pv210_serial_resetport(struct uart_port *port,
+                                       struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       ucon &= S5PV210_UCON_CLKMASK;
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+#define S5PV210_UART_DEFAULT_INFO(fifo_size)                   \
+               .name           = "Samsung S5PV210 UART0",      \
+               .type           = PORT_S3C6400,                 \
+               .fifosize       = fifo_size,                    \
+               .has_divslot    = 1,                            \
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
+               .get_clksrc     = s5pv210_serial_getsource,     \
+               .set_clksrc     = s5pv210_serial_setsource,     \
+               .reset_port     = s5pv210_serial_resetport
+
+static struct s3c24xx_uart_info s5p_port_fifo256 = {
+       S5PV210_UART_DEFAULT_INFO(256),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo64 = {
+       S5PV210_UART_DEFAULT_INFO(64),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo16 = {
+       S5PV210_UART_DEFAULT_INFO(16),
+};
+
+static struct s3c24xx_uart_info *s5p_uart_inf[] = {
+       [0] = &s5p_port_fifo256,
+       [1] = &s5p_port_fifo64,
+       [2] = &s5p_port_fifo16,
+       [3] = &s5p_port_fifo16,
+};
+
+/* device management */
+static int s5p_serial_probe(struct platform_device *pdev)
+{
+       return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
+}
+
+static struct platform_driver s5p_serial_driver = {
+       .probe          = s5p_serial_probe,
+       .remove         = __devexit_p(s3c24xx_serial_remove),
+       .driver         = {
+               .name   = "s5pv210-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init s5pv210_serial_console_init(void)
+{
+       return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf);
+}
+
+console_initcall(s5pv210_serial_console_init);
+
+static int __init s5p_serial_init(void)
+{
+       return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf);
+}
+
+static void __exit s5p_serial_exit(void)
+{
+       platform_driver_unregister(&s5p_serial_driver);
+}
+
+module_init(s5p_serial_init);
+module_exit(s5p_serial_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s5pv210-uart");
+MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
new file mode 100644 (file)
index 0000000..2199d81
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ *  linux/drivers/char/sa1100.c
+ *
+ *  Driver for SA11x0 serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/serial_sa1100.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_SA1100_MAJOR    204
+#define MINOR_START            5
+
+#define NR_PORTS               3
+
+#define SA1100_ISR_PASS_LIMIT  256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to UTSR[01]
+ */
+#define SM_TO_UTSR0(x) ((x) & 0xff)
+#define SM_TO_UTSR1(x) ((x) >> 8)
+#define UTSR0_TO_SM(x) ((x))
+#define UTSR1_TO_SM(x) ((x) << 8)
+
+#define UART_GET_UTCR0(sport)  __raw_readl((sport)->port.membase + UTCR0)
+#define UART_GET_UTCR1(sport)  __raw_readl((sport)->port.membase + UTCR1)
+#define UART_GET_UTCR2(sport)  __raw_readl((sport)->port.membase + UTCR2)
+#define UART_GET_UTCR3(sport)  __raw_readl((sport)->port.membase + UTCR3)
+#define UART_GET_UTSR0(sport)  __raw_readl((sport)->port.membase + UTSR0)
+#define UART_GET_UTSR1(sport)  __raw_readl((sport)->port.membase + UTSR1)
+#define UART_GET_CHAR(sport)   __raw_readl((sport)->port.membase + UTDR)
+
+#define UART_PUT_UTCR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR0)
+#define UART_PUT_UTCR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR1)
+#define UART_PUT_UTCR2(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR2)
+#define UART_PUT_UTCR3(sport,v)        __raw_writel((v),(sport)->port.membase + UTCR3)
+#define UART_PUT_UTSR0(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR0)
+#define UART_PUT_UTSR1(sport,v)        __raw_writel((v),(sport)->port.membase + UTSR1)
+#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x24
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+struct sa1100_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+};
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void sa1100_mctrl_check(struct sa1100_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void sa1100_timeout(unsigned long data)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)data;
+       unsigned long flags;
+
+       if (sport->port.state) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               sa1100_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void sa1100_stop_tx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
+       sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
+}
+
+/*
+ * port locked and interrupts disabled
+ */
+static void sa1100_start_tx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
+       UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void sa1100_stop_rx(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       u32 utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void sa1100_enable_ms(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static void
+sa1100_rx_chars(struct sa1100_port *sport)
+{
+       struct tty_struct *tty = sport->port.state->port.tty;
+       unsigned int status, ch, flg;
+
+       status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+                UTSR0_TO_SM(UART_GET_UTSR0(sport));
+       while (status & UTSR1_TO_SM(UTSR1_RNE)) {
+               ch = UART_GET_CHAR(sport);
+
+               sport->port.icount.rx++;
+
+               flg = TTY_NORMAL;
+
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) {
+                       if (status & UTSR1_TO_SM(UTSR1_PRE))
+                               sport->port.icount.parity++;
+                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
+                               sport->port.icount.frame++;
+                       if (status & UTSR1_TO_SM(UTSR1_ROR))
+                               sport->port.icount.overrun++;
+
+                       status &= sport->port.read_status_mask;
+
+                       if (status & UTSR1_TO_SM(UTSR1_PRE))
+                               flg = TTY_PARITY;
+                       else if (status & UTSR1_TO_SM(UTSR1_FRE))
+                               flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+                       sport->port.sysrq = 0;
+#endif
+               }
+
+               if (uart_handle_sysrq_char(&sport->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
+
+       ignore_char:
+               status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+                        UTSR0_TO_SM(UART_GET_UTSR0(sport));
+       }
+       tty_flip_buffer_push(tty);
+}
+
+static void sa1100_tx_chars(struct sa1100_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.state->xmit;
+
+       if (sport->port.x_char) {
+               UART_PUT_CHAR(sport, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /*
+        * Check the modem control lines before
+        * transmitting anything.
+        */
+       sa1100_mctrl_check(sport);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               sa1100_stop_tx(&sport->port);
+               return;
+       }
+
+       /*
+        * Tried using FIFO (not checking TNF) for fifo fill:
+        * still had the '4 bytes repeated' problem.
+        */
+       while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
+               UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+       if (uart_circ_empty(xmit))
+               sa1100_stop_tx(&sport->port);
+}
+
+static irqreturn_t sa1100_int(int irq, void *dev_id)
+{
+       struct sa1100_port *sport = dev_id;
+       unsigned int status, pass_counter = 0;
+
+       spin_lock(&sport->port.lock);
+       status = UART_GET_UTSR0(sport);
+       status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
+       do {
+               if (status & (UTSR0_RFS | UTSR0_RID)) {
+                       /* Clear the receiver idle bit, if set */
+                       if (status & UTSR0_RID)
+                               UART_PUT_UTSR0(sport, UTSR0_RID);
+                       sa1100_rx_chars(sport);
+               }
+
+               /* Clear the relevant break bits */
+               if (status & (UTSR0_RBB | UTSR0_REB))
+                       UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
+
+               if (status & UTSR0_RBB)
+                       sport->port.icount.brk++;
+
+               if (status & UTSR0_REB)
+                       uart_handle_break(&sport->port);
+
+               if (status & UTSR0_TFS)
+                       sa1100_tx_chars(sport);
+               if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
+                       break;
+               status = UART_GET_UTSR0(sport);
+               status &= SM_TO_UTSR0(sport->port.read_status_mask) |
+                         ~UTSR0_TFS;
+       } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
+       spin_unlock(&sport->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int sa1100_tx_empty(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int sa1100_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void sa1100_break_ctl(struct uart_port *port, int break_state)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       unsigned long flags;
+       unsigned int utcr3;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       utcr3 = UART_GET_UTCR3(sport);
+       if (break_state == -1)
+               utcr3 |= UTCR3_BRK;
+       else
+               utcr3 &= ~UTCR3_BRK;
+       UART_PUT_UTCR3(sport, utcr3);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int sa1100_startup(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       int retval;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(sport->port.irq, sa1100_int, 0,
+                            "sa11x0-uart", sport);
+       if (retval)
+               return retval;
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+       UART_PUT_UTSR0(sport, -1);
+       UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
+
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irq(&sport->port.lock);
+       sa1100_enable_ms(&sport->port);
+       spin_unlock_irq(&sport->port.lock);
+
+       return 0;
+}
+
+static void sa1100_shutdown(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Free the interrupt
+        */
+       free_irq(sport->port.irq, sport);
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+       UART_PUT_UTCR3(sport, 0);
+}
+
+static void
+sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       unsigned long flags;
+       unsigned int utcr0, old_utcr3, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               utcr0 = UTCR0_DSS;
+       else
+               utcr0 = 0;
+
+       if (termios->c_cflag & CSTOPB)
+               utcr0 |= UTCR0_SBS;
+       if (termios->c_cflag & PARENB) {
+               utcr0 |= UTCR0_PE;
+               if (!(termios->c_cflag & PARODD))
+                       utcr0 |= UTCR0_OES;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
+       sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |=
+                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |=
+                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |=
+                               UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |=
+                               UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |=
+                               UTSR1_TO_SM(UTSR1_ROR);
+       }
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
+
+       while (UART_GET_UTSR1(sport) & UTSR1_TBY)
+               barrier();
+
+       /* then, disable everything */
+       UART_PUT_UTCR3(sport, 0);
+
+       /* set the parity, stop bits and data size */
+       UART_PUT_UTCR0(sport, utcr0);
+
+       /* set the baud rate */
+       quot -= 1;
+       UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
+       UART_PUT_UTCR2(sport, (quot & 0xff));
+
+       UART_PUT_UTSR0(sport, -1);
+
+       UART_PUT_UTCR3(sport, old_utcr3);
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               sa1100_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *sa1100_type(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void sa1100_release_port(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int sa1100_request_port(struct uart_port *port)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+                       "sa11x0-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void sa1100_config_port(struct uart_port *port, int flags)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           sa1100_request_port(&sport->port) == 0)
+               sport->port.type = PORT_SA1100;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_SA1100 and PORT_UNKNOWN
+ */
+static int
+sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops sa1100_pops = {
+       .tx_empty       = sa1100_tx_empty,
+       .set_mctrl      = sa1100_set_mctrl,
+       .get_mctrl      = sa1100_get_mctrl,
+       .stop_tx        = sa1100_stop_tx,
+       .start_tx       = sa1100_start_tx,
+       .stop_rx        = sa1100_stop_rx,
+       .enable_ms      = sa1100_enable_ms,
+       .break_ctl      = sa1100_break_ctl,
+       .startup        = sa1100_startup,
+       .shutdown       = sa1100_shutdown,
+       .set_termios    = sa1100_set_termios,
+       .type           = sa1100_type,
+       .release_port   = sa1100_release_port,
+       .request_port   = sa1100_request_port,
+       .config_port    = sa1100_config_port,
+       .verify_port    = sa1100_verify_port,
+};
+
+static struct sa1100_port sa1100_ports[NR_PORTS];
+
+/*
+ * Setup the SA1100 serial ports.  Note that we don't include the IrDA
+ * port here since we have our own SIR/FIR driver (see drivers/net/irda)
+ *
+ * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
+ * Which serial port this ends up being depends on the machine you're
+ * running this kernel on.  I'm not convinced that this is a good idea,
+ * but that's the way it traditionally works.
+ *
+ * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
+ * used here.
+ */
+static void __init sa1100_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               sa1100_ports[i].port.uartclk   = 3686400;
+               sa1100_ports[i].port.ops       = &sa1100_pops;
+               sa1100_ports[i].port.fifosize  = 8;
+               sa1100_ports[i].port.line      = i;
+               sa1100_ports[i].port.iotype    = UPIO_MEM;
+               init_timer(&sa1100_ports[i].timer);
+               sa1100_ports[i].timer.function = sa1100_timeout;
+               sa1100_ports[i].timer.data     = (unsigned long)&sa1100_ports[i];
+       }
+
+       /*
+        * make transmit lines outputs, so that when the port
+        * is closed, the output is in the MARK state.
+        */
+       PPDR |= PPC_TXD1 | PPC_TXD3;
+       PPSR |= PPC_TXD1 | PPC_TXD3;
+}
+
+void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns)
+{
+       if (fns->get_mctrl)
+               sa1100_pops.get_mctrl = fns->get_mctrl;
+       if (fns->set_mctrl)
+               sa1100_pops.set_mctrl = fns->set_mctrl;
+
+       sa1100_pops.pm       = fns->pm;
+       sa1100_pops.set_wake = fns->set_wake;
+}
+
+void __init sa1100_register_uart(int idx, int port)
+{
+       if (idx >= NR_PORTS) {
+               printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
+               return;
+       }
+
+       switch (port) {
+       case 1:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       case 2:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       case 3:
+               sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
+               sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
+               sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
+               break;
+
+       default:
+               printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
+       }
+}
+
+
+#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+static void sa1100_console_putchar(struct uart_port *port, int ch)
+{
+       struct sa1100_port *sport = (struct sa1100_port *)port;
+
+       while (!(UART_GET_UTSR1(sport) & UTSR1_TNF))
+               barrier();
+       UART_PUT_CHAR(sport, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sa1100_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct sa1100_port *sport = &sa1100_ports[co->index];
+       unsigned int old_utcr3, status;
+
+       /*
+        *      First, save UTCR3 and then disable interrupts
+        */
+       old_utcr3 = UART_GET_UTCR3(sport);
+       UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
+                               UTCR3_TXE);
+
+       uart_console_write(&sport->port, s, count, sa1100_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore UTCR3
+        */
+       do {
+               status = UART_GET_UTSR1(sport);
+       } while (status & UTSR1_TBY);
+       UART_PUT_UTCR3(sport, old_utcr3);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+sa1100_console_get_options(struct sa1100_port *sport, int *baud,
+                          int *parity, int *bits)
+{
+       unsigned int utcr3;
+
+       utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
+       if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
+               /* ok, the port was enabled */
+               unsigned int utcr0, quot;
+
+               utcr0 = UART_GET_UTCR0(sport);
+
+               *parity = 'n';
+               if (utcr0 & UTCR0_PE) {
+                       if (utcr0 & UTCR0_OES)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+
+               if (utcr0 & UTCR0_DSS)
+                       *bits = 8;
+               else
+                       *bits = 7;
+
+               quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
+               quot &= 0xfff;
+               *baud = sport->port.uartclk / (16 * (quot + 1));
+       }
+}
+
+static int __init
+sa1100_console_setup(struct console *co, char *options)
+{
+       struct sa1100_port *sport;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       sport = &sa1100_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               sa1100_console_get_options(sport, &baud, &parity, &bits);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sa1100_reg;
+static struct console sa1100_console = {
+       .name           = "ttySA",
+       .write          = sa1100_console_write,
+       .device         = uart_console_device,
+       .setup          = sa1100_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &sa1100_reg,
+};
+
+static int __init sa1100_rs_console_init(void)
+{
+       sa1100_init_ports();
+       register_console(&sa1100_console);
+       return 0;
+}
+console_initcall(sa1100_rs_console_init);
+
+#define SA1100_CONSOLE &sa1100_console
+#else
+#define SA1100_CONSOLE NULL
+#endif
+
+static struct uart_driver sa1100_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttySA",
+       .dev_name               = "ttySA",
+       .major                  = SERIAL_SA1100_MAJOR,
+       .minor                  = MINOR_START,
+       .nr                     = NR_PORTS,
+       .cons                   = SA1100_CONSOLE,
+};
+
+static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sa1100_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_suspend_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static int sa1100_serial_resume(struct platform_device *dev)
+{
+       struct sa1100_port *sport = platform_get_drvdata(dev);
+
+       if (sport)
+               uart_resume_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static int sa1100_serial_probe(struct platform_device *dev)
+{
+       struct resource *res = dev->resource;
+       int i;
+
+       for (i = 0; i < dev->num_resources; i++, res++)
+               if (res->flags & IORESOURCE_MEM)
+                       break;
+
+       if (i < dev->num_resources) {
+               for (i = 0; i < NR_PORTS; i++) {
+                       if (sa1100_ports[i].port.mapbase != res->start)
+                               continue;
+
+                       sa1100_ports[i].port.dev = &dev->dev;
+                       uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
+                       platform_set_drvdata(dev, &sa1100_ports[i]);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int sa1100_serial_remove(struct platform_device *pdev)
+{
+       struct sa1100_port *sport = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&sa1100_reg, &sport->port);
+
+       return 0;
+}
+
+static struct platform_driver sa11x0_serial_driver = {
+       .probe          = sa1100_serial_probe,
+       .remove         = sa1100_serial_remove,
+       .suspend        = sa1100_serial_suspend,
+       .resume         = sa1100_serial_resume,
+       .driver         = {
+               .name   = "sa11x0-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sa1100_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: SA11x0 driver\n");
+
+       sa1100_init_ports();
+
+       ret = uart_register_driver(&sa1100_reg);
+       if (ret == 0) {
+               ret = platform_driver_register(&sa11x0_serial_driver);
+               if (ret)
+                       uart_unregister_driver(&sa1100_reg);
+       }
+       return ret;
+}
+
+static void __exit sa1100_serial_exit(void)
+{
+       platform_driver_unregister(&sa11x0_serial_driver);
+       uart_unregister_driver(&sa1100_reg);
+}
+
+module_init(sa1100_serial_init);
+module_exit(sa1100_serial_exit);
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("SA1100 generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
+MODULE_ALIAS("platform:sa11x0-uart");
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
new file mode 100644 (file)
index 0000000..2335eda
--- /dev/null
@@ -0,0 +1,1487 @@
+/* linux/drivers/serial/samsuing.c
+ *
+ * Driver core for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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.
+*/
+
+/* Hote on 2410 error handling
+ *
+ * The s3c2410 manual has a love/hate affair with the contents of the
+ * UERSTAT register in the UART blocks, and keeps marking some of the
+ * error bits as reserved. Having checked with the s3c2410x01,
+ * it copes with BREAKs properly, so I am happy to ignore the RESERVED
+ * feature from the latter versions of the manual.
+ *
+ * If it becomes aparrent that latter versions of the 2410 remove these
+ * bits, then action will have to be taken to differentiate the versions
+ * and change the policy on BREAK
+ *
+ * BJD, 04-Nov-2004
+*/
+
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+/* UART name and device definitions */
+
+#define S3C24XX_SERIAL_NAME    "ttySAC"
+#define S3C24XX_SERIAL_MAJOR   204
+#define S3C24XX_SERIAL_MINOR   64
+
+/* macros to change one thing to another */
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+/* flag to ignore all characters comming in */
+#define RXSTAT_DUMMY_READ (0x10000000)
+
+static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
+{
+       return container_of(port, struct s3c24xx_uart_port, port);
+}
+
+/* translate a port to the device name */
+
+static inline const char *s3c24xx_serial_portname(struct uart_port *port)
+{
+       return to_platform_device(port->dev)->name;
+}
+
+static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
+{
+       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+}
+
+static void s3c24xx_serial_rx_enable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon, ufcon;
+       int count = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon |= S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_rx_disable(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       rx_enabled(port) = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_stop_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (tx_enabled(port)) {
+               disable_irq_nosync(ourport->tx_irq);
+               tx_enabled(port) = 0;
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_enable(port);
+       }
+}
+
+static void s3c24xx_serial_start_tx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (!tx_enabled(port)) {
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_disable(port);
+
+               enable_irq(ourport->tx_irq);
+               tx_enabled(port) = 1;
+       }
+}
+
+
+static void s3c24xx_serial_stop_rx(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (rx_enabled(port)) {
+               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
+               disable_irq_nosync(ourport->rx_irq);
+               rx_enabled(port) = 0;
+       }
+}
+
+static void s3c24xx_serial_enable_ms(struct uart_port *port)
+{
+}
+
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+       return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+       if (port->dev == NULL)
+               return NULL;
+
+       return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat)
+{
+       struct s3c24xx_uart_info *info = ourport->info;
+
+       if (ufstat & info->rx_fifofull)
+               return info->fifosize;
+
+       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
+}
+
+
+/* ? - where has parity gone?? */
+#define S3C2410_UERSTAT_PARITY (0x1000)
+
+static irqreturn_t
+s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int ufcon, ch, flag, ufstat, uerstat;
+       int max_count = 64;
+
+       while (max_count-- > 0) {
+               ufcon = rd_regl(port, S3C2410_UFCON);
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+                       break;
+
+               uerstat = rd_regl(port, S3C2410_UERSTAT);
+               ch = rd_regb(port, S3C2410_URXH);
+
+               if (port->flags & UPF_CONS_FLOW) {
+                       int txe = s3c24xx_serial_txempty_nofifo(port);
+
+                       if (rx_enabled(port)) {
+                               if (!txe) {
+                                       rx_enabled(port) = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (txe) {
+                                       ufcon |= S3C2410_UFCON_RESETRX;
+                                       wr_regl(port, S3C2410_UFCON, ufcon);
+                                       rx_enabled(port) = 1;
+                                       goto out;
+                               }
+                               continue;
+                       }
+               }
+
+               /* insert the character into the buffer */
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
+                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+                           ch, uerstat);
+
+                       /* check for break */
+                       if (uerstat & S3C2410_UERSTAT_BREAK) {
+                               dbg("break!\n");
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                   goto ignore_char;
+                       }
+
+                       if (uerstat & S3C2410_UERSTAT_FRAME)
+                               port->icount.frame++;
+                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
+                               port->icount.overrun++;
+
+                       uerstat &= port->read_status_mask;
+
+                       if (uerstat & S3C2410_UERSTAT_BREAK)
+                               flag = TTY_BREAK;
+                       else if (uerstat & S3C2410_UERSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
+                                           S3C2410_UERSTAT_OVERRUN))
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
+                                ch, flag);
+
+ ignore_char:
+               continue;
+       }
+       tty_flip_buffer_push(tty);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
+{
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count = 256;
+
+       if (port->x_char) {
+               wr_regb(port, S3C2410_UTXH, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+
+       /* if there isnt anything more to transmit, or the uart is now
+        * stopped, disable the uart and exit
+       */
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               s3c24xx_serial_stop_tx(port);
+               goto out;
+       }
+
+       /* try and drain the buffer... */
+
+       while (!uart_circ_empty(xmit) && count-- > 0) {
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+                       break;
+
+               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               s3c24xx_serial_stop_tx(port);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
+       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               if ((ufstat & info->tx_fifomask) != 0 ||
+                   (ufstat & info->tx_fifofull))
+                       return 0;
+
+               return 1;
+       }
+
+       return s3c24xx_serial_txempty_nofifo(port);
+}
+
+/* no modem control lines */
+static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
+{
+       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
+
+       if (umstat & S3C2410_UMSTAT_CTS)
+               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+       else
+               return TIOCM_CAR | TIOCM_DSR;
+}
+
+static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* todo - possibly remove AFC and do manual CTS */
+}
+
+static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+       unsigned int ucon;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ucon = rd_regl(port, S3C2410_UCON);
+
+       if (break_state)
+               ucon |= S3C2410_UCON_SBREAK;
+       else
+               ucon &= ~S3C2410_UCON_SBREAK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c24xx_serial_shutdown(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (ourport->tx_claimed) {
+               free_irq(ourport->tx_irq, ourport);
+               tx_enabled(port) = 0;
+               ourport->tx_claimed = 0;
+       }
+
+       if (ourport->rx_claimed) {
+               free_irq(ourport->rx_irq, ourport);
+               ourport->rx_claimed = 0;
+               rx_enabled(port) = 0;
+       }
+}
+
+
+static int s3c24xx_serial_startup(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+
+       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
+
+       rx_enabled(port) = 1;
+
+       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret != 0) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
+               return ret;
+       }
+
+       ourport->rx_claimed = 1;
+
+       dbg("requesting tx irq...\n");
+
+       tx_enabled(port) = 1;
+
+       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+
+       if (ret) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
+               goto err;
+       }
+
+       ourport->tx_claimed = 1;
+
+       dbg("s3c24xx_serial_startup ok\n");
+
+       /* the port reset code should have done the correct
+        * register setup for the port controls */
+
+       return ret;
+
+ err:
+       s3c24xx_serial_shutdown(port);
+       return ret;
+}
+
+/* power power management control */
+
+static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
+                             unsigned int old)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       ourport->pm_level = level;
+
+       switch (level) {
+       case 3:
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_disable(ourport->baudclk);
+
+               clk_disable(ourport->clk);
+               break;
+
+       case 0:
+               clk_enable(ourport->clk);
+
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_enable(ourport->baudclk);
+
+               break;
+       default:
+               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+       }
+}
+
+/* baud rate calculation
+ *
+ * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
+ * of different sources, including the peripheral clock ("pclk") and an
+ * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
+ * with a programmable extra divisor.
+ *
+ * The following code goes through the clock sources, and calculates the
+ * baud clocks (and the resultant actual baud rates) and then tries to
+ * pick the closest one and select that.
+ *
+*/
+
+
+#define MAX_CLKS (8)
+
+static struct s3c24xx_uart_clksrc tmp_clksrc = {
+       .name           = "pclk",
+       .min_baud       = 0,
+       .max_baud       = 0,
+       .divisor        = 1,
+};
+
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->set_clksrc)(port, c);
+}
+
+struct baud_calc {
+       struct s3c24xx_uart_clksrc      *clksrc;
+       unsigned int                     calc;
+       unsigned int                     divslot;
+       unsigned int                     quot;
+       struct clk                      *src;
+};
+
+static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
+                                  struct uart_port *port,
+                                  struct s3c24xx_uart_clksrc *clksrc,
+                                  unsigned int baud)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long rate;
+
+       calc->src = clk_get(port->dev, clksrc->name);
+       if (calc->src == NULL || IS_ERR(calc->src))
+               return 0;
+
+       rate = clk_get_rate(calc->src);
+       rate /= clksrc->divisor;
+
+       calc->clksrc = clksrc;
+
+       if (ourport->info->has_divslot) {
+               unsigned long div = rate / baud;
+
+               /* The UDIVSLOT register on the newer UARTs allows us to
+                * get a divisor adjustment of 1/16th on the baud clock.
+                *
+                * We don't keep the UDIVSLOT value (the 16ths we calculated
+                * by not multiplying the baud by 16) as it is easy enough
+                * to recalculate.
+                */
+
+               calc->quot = div / 16;
+               calc->calc = rate / div;
+       } else {
+               calc->quot = (rate + (8 * baud)) / (16 * baud);
+               calc->calc = (rate / (calc->quot * 16));
+       }
+
+       calc->quot--;
+       return 1;
+}
+
+static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
+                                         struct s3c24xx_uart_clksrc **clksrc,
+                                         struct clk **clk,
+                                         unsigned int baud)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_clksrc *clkp;
+       struct baud_calc res[MAX_CLKS];
+       struct baud_calc *resptr, *best, *sptr;
+       int i;
+
+       clkp = cfg->clocks;
+       best = NULL;
+
+       if (cfg->clocks_size < 2) {
+               if (cfg->clocks_size == 0)
+                       clkp = &tmp_clksrc;
+
+               /* check to see if we're sourcing fclk, and if so we're
+                * going to have to update the clock source
+                */
+
+               if (strcmp(clkp->name, "fclk") == 0) {
+                       struct s3c24xx_uart_clksrc src;
+
+                       s3c24xx_serial_getsource(port, &src);
+
+                       /* check that the port already using fclk, and if
+                        * not, then re-select fclk
+                        */
+
+                       if (strcmp(src.name, clkp->name) == 0) {
+                               s3c24xx_serial_setsource(port, clkp);
+                               s3c24xx_serial_getsource(port, &src);
+                       }
+
+                       clkp->divisor = src.divisor;
+               }
+
+               s3c24xx_serial_calcbaud(res, port, clkp, baud);
+               best = res;
+               resptr = best + 1;
+       } else {
+               resptr = res;
+
+               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
+                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
+                               resptr++;
+               }
+       }
+
+       /* ok, we now need to select the best clock we found */
+
+       if (!best) {
+               unsigned int deviation = (1<<30)|((1<<30)-1);
+               int calc_deviation;
+
+               for (sptr = res; sptr < resptr; sptr++) {
+                       calc_deviation = baud - sptr->calc;
+                       if (calc_deviation < 0)
+                               calc_deviation = -calc_deviation;
+
+                       if (calc_deviation < deviation) {
+                               best = sptr;
+                               deviation = calc_deviation;
+                       }
+               }
+       }
+
+       /* store results to pass back */
+
+       *clksrc = best->clksrc;
+       *clk    = best->src;
+
+       return best->quot;
+}
+
+/* udivslot_table[]
+ *
+ * This table takes the fractional value of the baud divisor and gives
+ * the recommended setting for the UDIVSLOT register.
+ */
+static u16 udivslot_table[16] = {
+       [0] = 0x0000,
+       [1] = 0x0080,
+       [2] = 0x0808,
+       [3] = 0x0888,
+       [4] = 0x2222,
+       [5] = 0x4924,
+       [6] = 0x4A52,
+       [7] = 0x54AA,
+       [8] = 0x5555,
+       [9] = 0xD555,
+       [10] = 0xD5D5,
+       [11] = 0xDDD5,
+       [12] = 0xDDDD,
+       [13] = 0xDFDD,
+       [14] = 0xDFDF,
+       [15] = 0xFFDF,
+};
+
+static void s3c24xx_serial_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_clksrc *clksrc = NULL;
+       struct clk *clk = NULL;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned int ulcon;
+       unsigned int umcon;
+       unsigned int udivslot = 0;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
+
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
+
+       /* check to see if we need  to change clock source */
+
+       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
+               dbg("selecting clock %p\n", clk);
+               s3c24xx_serial_setsource(port, clksrc);
+
+               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+                       clk_disable(ourport->baudclk);
+                       ourport->baudclk  = NULL;
+               }
+
+               clk_enable(clk);
+
+               ourport->clksrc = clksrc;
+               ourport->baudclk = clk;
+               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
+       }
+
+       if (ourport->info->has_divslot) {
+               unsigned int div = ourport->baudclk_rate / baud;
+
+               if (cfg->has_fracval) {
+                       udivslot = (div & 15);
+                       dbg("fracval = %04x\n", udivslot);
+               } else {
+                       udivslot = udivslot_table[div & 15];
+                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
+               }
+       }
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               dbg("config: 5bits/char\n");
+               ulcon = S3C2410_LCON_CS5;
+               break;
+       case CS6:
+               dbg("config: 6bits/char\n");
+               ulcon = S3C2410_LCON_CS6;
+               break;
+       case CS7:
+               dbg("config: 7bits/char\n");
+               ulcon = S3C2410_LCON_CS7;
+               break;
+       case CS8:
+       default:
+               dbg("config: 8bits/char\n");
+               ulcon = S3C2410_LCON_CS8;
+               break;
+       }
+
+       /* preserve original lcon IR settings */
+       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
+
+       if (termios->c_cflag & CSTOPB)
+               ulcon |= S3C2410_LCON_STOPB;
+
+       umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       ulcon |= S3C2410_LCON_PODD;
+               else
+                       ulcon |= S3C2410_LCON_PEVEN;
+       } else {
+               ulcon |= S3C2410_LCON_PNONE;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
+           ulcon, quot, udivslot);
+
+       wr_regl(port, S3C2410_ULCON, ulcon);
+       wr_regl(port, S3C2410_UBRDIV, quot);
+       wr_regl(port, S3C2410_UMCON, umcon);
+
+       if (ourport->info->has_divslot)
+               wr_regl(port, S3C2443_DIVSLOT, udivslot);
+
+       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
+           rd_regl(port, S3C2410_ULCON),
+           rd_regl(port, S3C2410_UCON),
+           rd_regl(port, S3C2410_UFCON));
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
+
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *s3c24xx_serial_type(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_S3C2410:
+               return "S3C2410";
+       case PORT_S3C2440:
+               return "S3C2440";
+       case PORT_S3C2412:
+               return "S3C2412";
+       case PORT_S3C6400:
+               return "S3C6400/10";
+       default:
+               return NULL;
+       }
+}
+
+#define MAP_SIZE (0x100)
+
+static void s3c24xx_serial_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, MAP_SIZE);
+}
+
+static int s3c24xx_serial_request_port(struct uart_port *port)
+{
+       const char *name = s3c24xx_serial_portname(port);
+       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
+}
+
+static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (flags & UART_CONFIG_TYPE &&
+           s3c24xx_serial_request_port(port) == 0)
+               port->type = info->type;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct console s3c24xx_serial_console;
+
+#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
+#else
+#define S3C24XX_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_ops s3c24xx_serial_ops = {
+       .pm             = s3c24xx_serial_pm,
+       .tx_empty       = s3c24xx_serial_tx_empty,
+       .get_mctrl      = s3c24xx_serial_get_mctrl,
+       .set_mctrl      = s3c24xx_serial_set_mctrl,
+       .stop_tx        = s3c24xx_serial_stop_tx,
+       .start_tx       = s3c24xx_serial_start_tx,
+       .stop_rx        = s3c24xx_serial_stop_rx,
+       .enable_ms      = s3c24xx_serial_enable_ms,
+       .break_ctl      = s3c24xx_serial_break_ctl,
+       .startup        = s3c24xx_serial_startup,
+       .shutdown       = s3c24xx_serial_shutdown,
+       .set_termios    = s3c24xx_serial_set_termios,
+       .type           = s3c24xx_serial_type,
+       .release_port   = s3c24xx_serial_release_port,
+       .request_port   = s3c24xx_serial_request_port,
+       .config_port    = s3c24xx_serial_config_port,
+       .verify_port    = s3c24xx_serial_verify_port,
+};
+
+
+static struct uart_driver s3c24xx_uart_drv = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "s3c2410_serial",
+       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
+       .cons           = S3C24XX_SERIAL_CONSOLE,
+       .dev_name       = S3C24XX_SERIAL_NAME,
+       .major          = S3C24XX_SERIAL_MAJOR,
+       .minor          = S3C24XX_SERIAL_MINOR,
+};
+
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
+       [0] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX0,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               }
+       },
+       [1] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX1,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               }
+       },
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+
+       [2] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX2,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               }
+       },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+       [3] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX3,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 3,
+               }
+       }
+#endif
+};
+
+/* s3c24xx_serial_resetport
+ *
+ * wrapper to call the specific reset for this port (reset the fifos
+ * and the settings)
+*/
+
+static inline int s3c24xx_serial_resetport(struct uart_port *port,
+                                          struct s3c2410_uartcfg *cfg)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+       return (info->reset_port)(port, cfg);
+}
+
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+                                            unsigned long val, void *data)
+{
+       struct s3c24xx_uart_port *port;
+       struct uart_port *uport;
+
+       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+       uport = &port->port;
+
+       /* check to see if port is enabled */
+
+       if (port->pm_level != 0)
+               return 0;
+
+       /* try and work out if the baudrate is changing, we can detect
+        * a change in rate, but we do not have support for detecting
+        * a disturbance in the clock-rate over the change.
+        */
+
+       if (IS_ERR(port->clk))
+               goto exit;
+
+       if (port->baudclk_rate == clk_get_rate(port->clk))
+               goto exit;
+
+       if (val == CPUFREQ_PRECHANGE) {
+               /* we should really shut the port down whilst the
+                * frequency change is in progress. */
+
+       } else if (val == CPUFREQ_POSTCHANGE) {
+               struct ktermios *termios;
+               struct tty_struct *tty;
+
+               if (uport->state == NULL)
+                       goto exit;
+
+               tty = uport->state->port.tty;
+
+               if (tty == NULL)
+                       goto exit;
+
+               termios = tty->termios;
+
+               if (termios == NULL) {
+                       printk(KERN_WARNING "%s: no termios?\n", __func__);
+                       goto exit;
+               }
+
+               s3c24xx_serial_set_termios(uport, termios, NULL);
+       }
+
+ exit:
+       return 0;
+}
+
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+       return cpufreq_register_notifier(&port->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+       cpufreq_unregister_notifier(&port->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       return 0;
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
+/* s3c24xx_serial_init_port
+ *
+ * initialise a single serial port from the platform device given
+ */
+
+static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
+                                   struct s3c24xx_uart_info *info,
+                                   struct platform_device *platdev)
+{
+       struct uart_port *port = &ourport->port;
+       struct s3c2410_uartcfg *cfg;
+       struct resource *res;
+       int ret;
+
+       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
+
+       if (platdev == NULL)
+               return -ENODEV;
+
+       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
+
+       if (port->mapbase != 0)
+               return 0;
+
+       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
+               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
+                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
+               return -ERANGE;
+       }
+
+       /* setup info for port */
+       port->dev       = &platdev->dev;
+       ourport->info   = info;
+
+       /* copy the info in from provided structure */
+       ourport->port.fifosize = info->fifosize;
+
+       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
+
+       port->uartclk = 1;
+
+       if (cfg->uart_flags & UPF_CONS_FLOW) {
+               dbg("s3c24xx_serial_init_port: enabling flow control\n");
+               port->flags |= UPF_CONS_FLOW;
+       }
+
+       /* sort our the physical and virtual addresses for each UART */
+
+       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               printk(KERN_ERR "failed to find memory resource for uart\n");
+               return -EINVAL;
+       }
+
+       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
+
+       port->mapbase = res->start;
+       port->membase = S3C_VA_UART + (res->start & 0xfffff);
+       ret = platform_get_irq(platdev, 0);
+       if (ret < 0)
+               port->irq = 0;
+       else {
+               port->irq = ret;
+               ourport->rx_irq = ret;
+               ourport->tx_irq = ret + 1;
+       }
+       
+       ret = platform_get_irq(platdev, 1);
+       if (ret > 0)
+               ourport->tx_irq = ret;
+
+       ourport->clk    = clk_get(&platdev->dev, "uart");
+
+       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
+           port->mapbase, port->membase, port->irq,
+           ourport->rx_irq, ourport->tx_irq, port->uartclk);
+
+       /* reset the fifos (and setup the uart) */
+       s3c24xx_serial_resetport(port, cfg);
+       return 0;
+}
+
+static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
+}
+
+static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+
+/* Device driver serial port probe */
+
+static int probe_index;
+
+int s3c24xx_serial_probe(struct platform_device *dev,
+                        struct s3c24xx_uart_info *info)
+{
+       struct s3c24xx_uart_port *ourport;
+       int ret;
+
+       dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
+
+       ourport = &s3c24xx_serial_ports[probe_index];
+       probe_index++;
+
+       dbg("%s: initialising port %p...\n", __func__, ourport);
+
+       ret = s3c24xx_serial_init_port(ourport, info, dev);
+       if (ret < 0)
+               goto probe_err;
+
+       dbg("%s: adding port\n", __func__);
+       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
+       platform_set_drvdata(dev, &ourport->port);
+
+       ret = device_create_file(&dev->dev, &dev_attr_clock_source);
+       if (ret < 0)
+               printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
+
+       ret = s3c24xx_serial_cpufreq_register(ourport);
+       if (ret < 0)
+               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+
+       return 0;
+
+ probe_err:
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
+
+int __devexit s3c24xx_serial_remove(struct platform_device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+
+       if (port) {
+               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
+               device_remove_file(&dev->dev, &dev_attr_clock_source);
+               uart_remove_one_port(&s3c24xx_uart_drv, port);
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
+
+/* UART power management code */
+
+#ifdef CONFIG_PM
+
+static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+
+       if (port)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
+
+       return 0;
+}
+
+static int s3c24xx_serial_resume(struct platform_device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+       if (port) {
+               clk_enable(ourport->clk);
+               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               clk_disable(ourport->clk);
+
+               uart_resume_port(&s3c24xx_uart_drv, port);
+       }
+
+       return 0;
+}
+#endif
+
+int s3c24xx_serial_init(struct platform_driver *drv,
+                       struct s3c24xx_uart_info *info)
+{
+       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
+
+#ifdef CONFIG_PM
+       drv->suspend = s3c24xx_serial_suspend;
+       drv->resume = s3c24xx_serial_resume;
+#endif
+
+       return platform_driver_register(drv);
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
+
+/* module initialisation code */
+
+static int __init s3c24xx_serial_modinit(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&s3c24xx_uart_drv);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to register UART driver\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void __exit s3c24xx_serial_modexit(void)
+{
+       uart_unregister_driver(&s3c24xx_uart_drv);
+}
+
+module_init(s3c24xx_serial_modinit);
+module_exit(s3c24xx_serial_modexit);
+
+/* Console code */
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+static struct uart_port *cons_uart;
+
+static int
+s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+{
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat, utrstat;
+
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               /* fifo mode - check amount of data in fifo registers... */
+
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+               return (ufstat & info->tx_fifofull) ? 0 : 1;
+       }
+
+       /* in non-fifo mode, we go and use the tx buffer empty */
+
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
+}
+
+static void
+s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+{
+       unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               barrier();
+       wr_regb(cons_uart, S3C2410_UTXH, ch);
+}
+
+static void
+s3c24xx_serial_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
+}
+
+static void __init
+s3c24xx_serial_get_options(struct uart_port *port, int *baud,
+                          int *parity, int *bits)
+{
+       struct s3c24xx_uart_clksrc clksrc;
+       struct clk *clk;
+       unsigned int ulcon;
+       unsigned int ucon;
+       unsigned int ubrdiv;
+       unsigned long rate;
+
+       ulcon  = rd_regl(port, S3C2410_ULCON);
+       ucon   = rd_regl(port, S3C2410_UCON);
+       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+       dbg("s3c24xx_serial_get_options: port=%p\n"
+           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+           port, ulcon, ucon, ubrdiv);
+
+       if ((ucon & 0xf) != 0) {
+               /* consider the serial port configured if the tx/rx mode set */
+
+               switch (ulcon & S3C2410_LCON_CSMASK) {
+               case S3C2410_LCON_CS5:
+                       *bits = 5;
+                       break;
+               case S3C2410_LCON_CS6:
+                       *bits = 6;
+                       break;
+               case S3C2410_LCON_CS7:
+                       *bits = 7;
+                       break;
+               default:
+               case S3C2410_LCON_CS8:
+                       *bits = 8;
+                       break;
+               }
+
+               switch (ulcon & S3C2410_LCON_PMASK) {
+               case S3C2410_LCON_PEVEN:
+                       *parity = 'e';
+                       break;
+
+               case S3C2410_LCON_PODD:
+                       *parity = 'o';
+                       break;
+
+               case S3C2410_LCON_PNONE:
+               default:
+                       *parity = 'n';
+               }
+
+               /* now calculate the baud rate */
+
+               s3c24xx_serial_getsource(port, &clksrc);
+
+               clk = clk_get(port->dev, clksrc.name);
+               if (!IS_ERR(clk) && clk != NULL)
+                       rate = clk_get_rate(clk) / clksrc.divisor;
+               else
+                       rate = 1;
+
+
+               *baud = rate / (16 * (ubrdiv + 1));
+               dbg("calculated baud %d\n", *baud);
+       }
+
+}
+
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+{
+       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+       struct platform_device **platdev_ptr;
+       int i;
+
+       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+       platdev_ptr = s3c24xx_uart_devs;
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+               s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+       }
+
+       return 0;
+}
+
+static int __init
+s3c24xx_serial_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
+           co, co->index, options);
+
+       /* is this a valid port */
+
+       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
+               co->index = 0;
+
+       port = &s3c24xx_serial_ports[co->index].port;
+
+       /* is the port configured? */
+
+       if (port->mapbase == 0x0) {
+               co->index = 0;
+               port = &s3c24xx_serial_ports[co->index].port;
+       }
+
+       cons_uart = port;
+
+       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+
+       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/* s3c24xx_serial_initconsole
+ *
+ * initialise the console from one of the uart drivers
+*/
+
+static struct console s3c24xx_serial_console = {
+       .name           = S3C24XX_SERIAL_NAME,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .write          = s3c24xx_serial_console_write,
+       .setup          = s3c24xx_serial_console_setup
+};
+
+int s3c24xx_serial_initconsole(struct platform_driver *drv,
+                              struct s3c24xx_uart_info **info)
+
+{
+       struct platform_device *dev = s3c24xx_uart_devs[0];
+
+       dbg("s3c24xx_serial_initconsole\n");
+
+       /* select driver based on the cpu */
+
+       if (dev == NULL) {
+               printk(KERN_ERR "s3c24xx: no devices for console init\n");
+               return 0;
+       }
+
+       if (strcmp(dev->name, drv->driver.name) != 0)
+               return 0;
+
+       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
+       s3c24xx_serial_init_ports(info);
+
+       register_console(&s3c24xx_serial_console);
+       return 0;
+}
+
+#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
+
+MODULE_DESCRIPTION("Samsung SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
new file mode 100644 (file)
index 0000000..0ac06a0
--- /dev/null
@@ -0,0 +1,120 @@
+/* linux/drivers/serial/samsung.h
+ *
+ * Driver for Samsung SoC onboard UARTs.
+ *
+ * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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.
+*/
+
+struct s3c24xx_uart_info {
+       char                    *name;
+       unsigned int            type;
+       unsigned int            fifosize;
+       unsigned long           rx_fifomask;
+       unsigned long           rx_fifoshift;
+       unsigned long           rx_fifofull;
+       unsigned long           tx_fifomask;
+       unsigned long           tx_fifoshift;
+       unsigned long           tx_fifofull;
+
+       /* uart port features */
+
+       unsigned int            has_divslot:1;
+
+       /* clock source control */
+
+       int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+       int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
+
+       /* uart controls */
+       int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
+};
+
+struct s3c24xx_uart_port {
+       unsigned char                   rx_claimed;
+       unsigned char                   tx_claimed;
+       unsigned int                    pm_level;
+       unsigned long                   baudclk_rate;
+
+       unsigned int                    rx_irq;
+       unsigned int                    tx_irq;
+
+       struct s3c24xx_uart_info        *info;
+       struct s3c24xx_uart_clksrc      *clksrc;
+       struct clk                      *clk;
+       struct clk                      *baudclk;
+       struct uart_port                port;
+
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block           freq_transition;
+#endif
+};
+
+/* conversion functions */
+
+#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
+#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
+
+/* register access controls */
+
+#define portaddr(port, reg) ((port)->membase + (reg))
+
+#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
+#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
+
+#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
+#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
+
+extern int s3c24xx_serial_probe(struct platform_device *dev,
+                               struct s3c24xx_uart_info *uart);
+
+extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
+
+extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
+                                     struct s3c24xx_uart_info **uart);
+
+extern int s3c24xx_serial_init(struct platform_driver *drv,
+                              struct s3c24xx_uart_info *info);
+
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+#define s3c24xx_console_init(__drv, __inf)                             \
+static int __init s3c_serial_console_init(void)                                \
+{                                                                      \
+       struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS];   \
+       int i;                                                          \
+                                                                       \
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)               \
+               uinfo[i] = __inf;                                       \
+       return s3c24xx_serial_initconsole(__drv, uinfo);                \
+}                                                                      \
+                                                                       \
+console_initcall(s3c_serial_console_init)
+
+#else
+#define s3c24xx_console_init(drv, inf) extern void no_console(void)
+#endif
+
+#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
+
+extern void printascii(const char *);
+
+static void dbg(const char *fmt, ...)
+{
+       va_list va;
+       char buff[256];
+
+       va_start(va, fmt);
+       vsprintf(buff, fmt, va);
+       va_end(va);
+
+       printascii(buff);
+}
+
+#else
+#define dbg(x...) do { } while (0)
+#endif
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
new file mode 100644 (file)
index 0000000..602d984
--- /dev/null
@@ -0,0 +1,976 @@
+/*
+ *     drivers/serial/sb1250-duart.c
+ *
+ *     Support for the asynchronous serial interface (DUART) included
+ *     in the BCM1250 and derived System-On-a-Chip (SOC) devices.
+ *
+ *     Copyright (c) 2007  Maciej W. Rozycki
+ *
+ *     Derived from drivers/char/sb1250_duart.c for which the following
+ *     copyright applies:
+ *
+ *     Copyright (c) 2000, 2001, 2002, 2003, 2004  Broadcom Corporation
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     References:
+ *
+ *     "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation
+ */
+
+#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/compiler.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/war.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/swarm.h>
+
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_int.h>
+
+#define SBD_CHANREGS(line)     A_BCM1480_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line)     A_BCM1480_DUART_CTRLREG((line), 0)
+#define SBD_INT(line)          (K_BCM1480_INT_UART_0 + (line))
+
+#define DUART_CHANREG_SPACING  BCM1480_DUART_CHANREG_SPACING
+
+#define R_DUART_IMRREG(line)   R_BCM1480_DUART_IMRREG(line)
+#define R_DUART_INCHREG(line)  R_BCM1480_DUART_INCHREG(line)
+#define R_DUART_ISRREG(line)   R_BCM1480_DUART_ISRREG(line)
+
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define SBD_CHANREGS(line)     A_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line)     A_DUART_CTRLREG(0)
+#define SBD_INT(line)          (K_INT_UART_0 + (line))
+
+#else
+#error invalid SB1250 UART configuration
+
+#endif
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver");
+MODULE_LICENSE("GPL");
+
+
+#define DUART_MAX_CHIP 2
+#define DUART_MAX_SIDE 2
+
+/*
+ * Per-port state.
+ */
+struct sbd_port {
+       struct sbd_duart        *duart;
+       struct uart_port        port;
+       unsigned char __iomem   *memctrl;
+       int                     tx_stopped;
+       int                     initialised;
+};
+
+/*
+ * Per-DUART state for the shared register space.
+ */
+struct sbd_duart {
+       struct sbd_port         sport[2];
+       unsigned long           mapctrl;
+       atomic_t                map_guard;
+};
+
+#define to_sport(uport) container_of(uport, struct sbd_port, port)
+
+static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
+
+
+/*
+ * Reading and writing SB1250 DUART registers.
+ *
+ * There are three register spaces: two per-channel ones and
+ * a shared one.  We have to define accessors appropriately.
+ * All registers are 64-bit and all but the Baud Rate Clock
+ * registers only define 8 least significant bits.  There is
+ * also a workaround to take into account.  Raw accessors use
+ * the full register width, but cooked ones truncate it
+ * intentionally so that the rest of the driver does not care.
+ */
+static u64 __read_sbdchn(struct sbd_port *sport, int reg)
+{
+       void __iomem *csr = sport->port.membase + reg;
+
+       return __raw_readq(csr);
+}
+
+static u64 __read_sbdshr(struct sbd_port *sport, int reg)
+{
+       void __iomem *csr = sport->memctrl + reg;
+
+       return __raw_readq(csr);
+}
+
+static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value)
+{
+       void __iomem *csr = sport->port.membase + reg;
+
+       __raw_writeq(value, csr);
+}
+
+static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value)
+{
+       void __iomem *csr = sport->memctrl + reg;
+
+       __raw_writeq(value, csr);
+}
+
+/*
+ * In bug 1956, we get glitches that can mess up uart registers.  This
+ * "read-mode-reg after any register access" is an accepted workaround.
+ */
+static void __war_sbd1956(struct sbd_port *sport)
+{
+       __read_sbdchn(sport, R_DUART_MODE_REG_1);
+       __read_sbdchn(sport, R_DUART_MODE_REG_2);
+}
+
+static unsigned char read_sbdchn(struct sbd_port *sport, int reg)
+{
+       unsigned char retval;
+
+       retval = __read_sbdchn(sport, reg);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+       return retval;
+}
+
+static unsigned char read_sbdshr(struct sbd_port *sport, int reg)
+{
+       unsigned char retval;
+
+       retval = __read_sbdshr(sport, reg);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+       return retval;
+}
+
+static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value)
+{
+       __write_sbdchn(sport, reg, value);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+}
+
+static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value)
+{
+       __write_sbdshr(sport, reg, value);
+       if (SIBYTE_1956_WAR)
+               __war_sbd1956(sport);
+}
+
+
+static int sbd_receive_ready(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY;
+}
+
+static int sbd_receive_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (sbd_receive_ready(sport) && --loops)
+               read_sbdchn(sport, R_DUART_RX_HOLD);
+       return loops;
+}
+
+static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
+}
+
+static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (!sbd_transmit_ready(sport) && --loops)
+               udelay(2);
+       return loops;
+}
+
+static int sbd_transmit_empty(struct sbd_port *sport)
+{
+       return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT;
+}
+
+static int sbd_line_drain(struct sbd_port *sport)
+{
+       int loops = 10000;
+
+       while (!sbd_transmit_empty(sport) && --loops)
+               udelay(2);
+       return loops;
+}
+
+
+static unsigned int sbd_tx_empty(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int sbd_get_mctrl(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mctrl, status;
+
+       status = read_sbdshr(sport, R_DUART_IN_PORT);
+       status >>= (uport->line) % 2;
+       mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) |
+               (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) |
+               (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) |
+               (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0);
+       return mctrl;
+}
+
+static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int clr = 0, set = 0, mode2;
+
+       if (mctrl & TIOCM_DTR)
+               set |= M_DUART_SET_OPR2;
+       else
+               clr |= M_DUART_CLR_OPR2;
+       if (mctrl & TIOCM_RTS)
+               set |= M_DUART_SET_OPR0;
+       else
+               clr |= M_DUART_CLR_OPR0;
+       clr <<= (uport->line) % 2;
+       set <<= (uport->line) % 2;
+
+       mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2);
+       mode2 &= ~M_DUART_CHAN_MODE;
+       if (mctrl & TIOCM_LOOP)
+               mode2 |= V_DUART_CHAN_MODE_LCL_LOOP;
+       else
+               mode2 |= V_DUART_CHAN_MODE_NORMAL;
+
+       write_sbdshr(sport, R_DUART_CLEAR_OPR, clr);
+       write_sbdshr(sport, R_DUART_SET_OPR, set);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2);
+}
+
+static void sbd_stop_tx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+       sport->tx_stopped = 1;
+};
+
+static void sbd_start_tx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mask;
+
+       /* Enable tx interrupts.  */
+       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+       mask |= M_DUART_IMR_TX;
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+
+       /* Go!, go!, go!...  */
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+       sport->tx_stopped = 0;
+};
+
+static void sbd_stop_rx(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+};
+
+static void sbd_enable_ms(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_AUXCTL_X,
+                    M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA);
+}
+
+static void sbd_break_ctl(struct uart_port *uport, int break_state)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       if (break_state == -1)
+               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK);
+       else
+               write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK);
+}
+
+
+static void sbd_receive_chars(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       struct uart_icount *icount;
+       unsigned int status, ch, flag;
+       int count;
+
+       for (count = 16; count; count--) {
+               status = read_sbdchn(sport, R_DUART_STATUS);
+               if (!(status & M_DUART_RX_RDY))
+                       break;
+
+               ch = read_sbdchn(sport, R_DUART_RX_HOLD);
+
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               if (unlikely(status &
+                            (M_DUART_RCVD_BRK | M_DUART_FRM_ERR |
+                             M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) {
+                       if (status & M_DUART_RCVD_BRK) {
+                               icount->brk++;
+                               if (uart_handle_break(uport))
+                                       continue;
+                       } else if (status & M_DUART_FRM_ERR)
+                               icount->frame++;
+                       else if (status & M_DUART_PARITY_ERR)
+                               icount->parity++;
+                       if (status & M_DUART_OVRUN_ERR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & M_DUART_RCVD_BRK)
+                               flag = TTY_BREAK;
+                       else if (status & M_DUART_FRM_ERR)
+                               flag = TTY_FRAME;
+                       else if (status & M_DUART_PARITY_ERR)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
+       }
+
+       tty_flip_buffer_push(uport->state->port.tty);
+}
+
+static void sbd_transmit_chars(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned int mask;
+       int stop_tx;
+
+       /* XON/XOFF chars.  */
+       if (sport->port.x_char) {
+               write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
+               return;
+       }
+
+       /* If nothing to do or stopped or hardware stopped.  */
+       stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
+
+       /* Send char.  */
+       if (!stop_tx) {
+               write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&sport->port);
+       }
+
+       /* Are we are done?  */
+       if (stop_tx || uart_circ_empty(xmit)) {
+               /* Disable tx interrupts.  */
+               mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+               mask &= ~M_DUART_IMR_TX;
+               write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+       }
+}
+
+static void sbd_status_handle(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+       unsigned int delta;
+
+       delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+       delta >>= (uport->line) % 2;
+
+       if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
+               uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));
+
+       if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
+               uport->icount.dsr++;
+
+       if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
+                    S_DUART_IN_PIN_CHNG))
+               wake_up_interruptible(&uport->state->port.delta_msr_wait);
+}
+
+static irqreturn_t sbd_interrupt(int irq, void *dev_id)
+{
+       struct sbd_port *sport = dev_id;
+       struct uart_port *uport = &sport->port;
+       irqreturn_t status = IRQ_NONE;
+       unsigned int intstat;
+       int count;
+
+       for (count = 16; count; count--) {
+               intstat = read_sbdshr(sport,
+                                     R_DUART_ISRREG((uport->line) % 2));
+               intstat &= read_sbdshr(sport,
+                                      R_DUART_IMRREG((uport->line) % 2));
+               intstat &= M_DUART_ISR_ALL;
+               if (!intstat)
+                       break;
+
+               if (intstat & M_DUART_ISR_RX)
+                       sbd_receive_chars(sport);
+               if (intstat & M_DUART_ISR_IN)
+                       sbd_status_handle(sport);
+               if (intstat & M_DUART_ISR_TX)
+                       sbd_transmit_chars(sport);
+
+               status = IRQ_HANDLED;
+       }
+
+       return status;
+}
+
+
+static int sbd_startup(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mode1;
+       int ret;
+
+       ret = request_irq(sport->port.irq, sbd_interrupt,
+                         IRQF_SHARED, "sb1250-duart", sport);
+       if (ret)
+               return ret;
+
+       /* Clear the receive FIFO.  */
+       sbd_receive_drain(sport);
+
+       /* Clear the interrupt registers.  */
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);
+       read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+
+       /* Set rx/tx interrupt to FIFO available.  */
+       mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);
+       mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);
+       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);
+
+       /* Disable tx, enable rx.  */
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);
+       sport->tx_stopped = 1;
+
+       /* Enable interrupts.  */
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+                    M_DUART_IMR_IN | M_DUART_IMR_RX);
+
+       return 0;
+}
+
+static void sbd_shutdown(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+       sport->tx_stopped = 1;
+       free_irq(sport->port.irq, sport);
+}
+
+
+static void sbd_init_port(struct sbd_port *sport)
+{
+       struct uart_port *uport = &sport->port;
+
+       if (sport->initialised)
+               return;
+
+       /* There is no DUART reset feature, so just set some sane defaults.  */
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);
+       write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);
+       write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, 0);
+       write_sbdchn(sport, R_DUART_FULL_CTL,
+                    V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));
+       write_sbdchn(sport, R_DUART_OPCR_X, 0);
+       write_sbdchn(sport, R_DUART_AUXCTL_X, 0);
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+
+       sport->initialised = 1;
+}
+
+static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
+                           struct ktermios *old_termios)
+{
+       struct sbd_port *sport = to_sport(uport);
+       unsigned int mode1 = 0, mode2 = 0, aux = 0;
+       unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;
+       unsigned int oldmode1, oldmode2, oldaux;
+       unsigned int baud, brg;
+       unsigned int command;
+
+       mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |
+                      M_DUART_BITS_PER_CHAR);
+       mode2mask |= ~M_DUART_STOP_BIT_LEN_2;
+       auxmask |= ~M_DUART_CTS_CHNG_ENA;
+
+       /* Byte size.  */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+       case CS6:
+               /* Unsupported, leave unchanged.  */
+               mode1mask |= M_DUART_PARITY_MODE;
+               break;
+       case CS7:
+               mode1 |= V_DUART_BITS_PER_CHAR_7;
+               break;
+       case CS8:
+       default:
+               mode1 |= V_DUART_BITS_PER_CHAR_8;
+               break;
+       }
+
+       /* Parity and stop bits.  */
+       if (termios->c_cflag & CSTOPB)
+               mode2 |= M_DUART_STOP_BIT_LEN_2;
+       else
+               mode2 |= M_DUART_STOP_BIT_LEN_1;
+       if (termios->c_cflag & PARENB)
+               mode1 |= V_DUART_PARITY_MODE_ADD;
+       else
+               mode1 |= V_DUART_PARITY_MODE_NONE;
+       if (termios->c_cflag & PARODD)
+               mode1 |= M_DUART_PARITY_TYPE_ODD;
+       else
+               mode1 |= M_DUART_PARITY_TYPE_EVEN;
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);
+       brg = V_DUART_BAUD_RATE(baud);
+       /* The actual lower bound is 1221bps, so compensate.  */
+       if (brg > M_DUART_CLK_COUNTER)
+               brg = M_DUART_CLK_COUNTER;
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       uport->read_status_mask = M_DUART_OVRUN_ERR;
+       if (termios->c_iflag & INPCK)
+               uport->read_status_mask |= M_DUART_FRM_ERR |
+                                          M_DUART_PARITY_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uport->read_status_mask |= M_DUART_RCVD_BRK;
+
+       uport->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uport->ignore_status_mask |= M_DUART_FRM_ERR |
+                                            M_DUART_PARITY_ERR;
+       if (termios->c_iflag & IGNBRK) {
+               uport->ignore_status_mask |= M_DUART_RCVD_BRK;
+               if (termios->c_iflag & IGNPAR)
+                       uport->ignore_status_mask |= M_DUART_OVRUN_ERR;
+       }
+
+       if (termios->c_cflag & CREAD)
+               command = M_DUART_RX_EN;
+       else
+               command = M_DUART_RX_DIS;
+
+       if (termios->c_cflag & CRTSCTS)
+               aux |= M_DUART_CTS_CHNG_ENA;
+       else
+               aux &= ~M_DUART_CTS_CHNG_ENA;
+
+       spin_lock(&uport->lock);
+
+       if (sport->tx_stopped)
+               command |= M_DUART_TX_DIS;
+       else
+               command |= M_DUART_TX_EN;
+
+       oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;
+       oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;
+       oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;
+
+       if (!sport->tx_stopped)
+               sbd_line_drain(sport);
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+
+       write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);
+       write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);
+       write_sbdchn(sport, R_DUART_CLK_SEL, brg);
+       write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);
+
+       write_sbdchn(sport, R_DUART_CMD, command);
+
+       spin_unlock(&uport->lock);
+}
+
+
+static const char *sbd_type(struct uart_port *uport)
+{
+       return "SB1250 DUART";
+}
+
+static void sbd_release_port(struct uart_port *uport)
+{
+       struct sbd_port *sport = to_sport(uport);
+       struct sbd_duart *duart = sport->duart;
+       int map_guard;
+
+       iounmap(sport->memctrl);
+       sport->memctrl = NULL;
+       iounmap(uport->membase);
+       uport->membase = NULL;
+
+       map_guard = atomic_add_return(-1, &duart->map_guard);
+       if (!map_guard)
+               release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
+       release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+}
+
+static int sbd_map_port(struct uart_port *uport)
+{
+       const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
+       struct sbd_port *sport = to_sport(uport);
+       struct sbd_duart *duart = sport->duart;
+
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                DUART_CHANREG_SPACING);
+       if (!uport->membase) {
+               printk(err);
+               return -ENOMEM;
+       }
+
+       if (!sport->memctrl)
+               sport->memctrl = ioremap_nocache(duart->mapctrl,
+                                                DUART_CHANREG_SPACING);
+       if (!sport->memctrl) {
+               printk(err);
+               iounmap(uport->membase);
+               uport->membase = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int sbd_request_port(struct uart_port *uport)
+{
+       const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
+       struct sbd_duart *duart = to_sport(uport)->duart;
+       int map_guard;
+       int ret = 0;
+
+       if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
+                               "sb1250-duart")) {
+               printk(err);
+               return -EBUSY;
+       }
+       map_guard = atomic_add_return(1, &duart->map_guard);
+       if (map_guard == 1) {
+               if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
+                                       "sb1250-duart")) {
+                       atomic_add(-1, &duart->map_guard);
+                       printk(err);
+                       ret = -EBUSY;
+               }
+       }
+       if (!ret) {
+               ret = sbd_map_port(uport);
+               if (ret) {
+                       map_guard = atomic_add_return(-1, &duart->map_guard);
+                       if (!map_guard)
+                               release_mem_region(duart->mapctrl,
+                                                  DUART_CHANREG_SPACING);
+               }
+       }
+       if (ret) {
+               release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+               return ret;
+       }
+       return 0;
+}
+
+static void sbd_config_port(struct uart_port *uport, int flags)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (sbd_request_port(uport))
+                       return;
+
+               uport->type = PORT_SB1250_DUART;
+
+               sbd_init_port(sport);
+       }
+}
+
+static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       if (ser->baud_base != uport->uartclk / 16)
+               ret = -EINVAL;
+       return ret;
+}
+
+
+static const struct uart_ops sbd_ops = {
+       .tx_empty       = sbd_tx_empty,
+       .set_mctrl      = sbd_set_mctrl,
+       .get_mctrl      = sbd_get_mctrl,
+       .stop_tx        = sbd_stop_tx,
+       .start_tx       = sbd_start_tx,
+       .stop_rx        = sbd_stop_rx,
+       .enable_ms      = sbd_enable_ms,
+       .break_ctl      = sbd_break_ctl,
+       .startup        = sbd_startup,
+       .shutdown       = sbd_shutdown,
+       .set_termios    = sbd_set_termios,
+       .type           = sbd_type,
+       .release_port   = sbd_release_port,
+       .request_port   = sbd_request_port,
+       .config_port    = sbd_config_port,
+       .verify_port    = sbd_verify_port,
+};
+
+/* Initialize SB1250 DUART port structures.  */
+static void __init sbd_probe_duarts(void)
+{
+       static int probed;
+       int chip, side;
+       int max_lines, line;
+
+       if (probed)
+               return;
+
+       /* Set the number of available units based on the SOC type.  */
+       switch (soc_type) {
+       case K_SYS_SOC_TYPE_BCM1x55:
+       case K_SYS_SOC_TYPE_BCM1x80:
+               max_lines = 4;
+               break;
+       default:
+               /* Assume at least two serial ports at the normal address.  */
+               max_lines = 2;
+               break;
+       }
+
+       probed = 1;
+
+       for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;
+            chip++) {
+               sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);
+
+               for (side = 0; side < DUART_MAX_SIDE && line < max_lines;
+                    side++, line++) {
+                       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+                       struct uart_port *uport = &sport->port;
+
+                       sport->duart    = &sbd_duarts[chip];
+
+                       uport->irq      = SBD_INT(line);
+                       uport->uartclk  = 100000000 / 20 * 16;
+                       uport->fifosize = 16;
+                       uport->iotype   = UPIO_MEM;
+                       uport->flags    = UPF_BOOT_AUTOCONF;
+                       uport->ops      = &sbd_ops;
+                       uport->line     = line;
+                       uport->mapbase  = SBD_CHANREGS(line);
+               }
+       }
+}
+
+
+#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
+/*
+ * Serial console stuff.  Very basic, polling driver for doing serial
+ * console output.  The console_lock is held by the caller, so we
+ * shouldn't be interrupted for more console activity.
+ */
+static void sbd_console_putchar(struct uart_port *uport, int ch)
+{
+       struct sbd_port *sport = to_sport(uport);
+
+       sbd_transmit_drain(sport);
+       write_sbdchn(sport, R_DUART_TX_HOLD, ch);
+}
+
+static void sbd_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       int chip = co->index / DUART_MAX_SIDE;
+       int side = co->index % DUART_MAX_SIDE;
+       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+       struct uart_port *uport = &sport->port;
+       unsigned long flags;
+       unsigned int mask;
+
+       /* Disable transmit interrupts and enable the transmitter. */
+       spin_lock_irqsave(&uport->lock, flags);
+       mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+                    mask & ~M_DUART_IMR_TX);
+       write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+       spin_unlock_irqrestore(&uport->lock, flags);
+
+       uart_console_write(&sport->port, s, count, sbd_console_putchar);
+
+       /* Restore transmit interrupts and the transmitter enable. */
+       spin_lock_irqsave(&uport->lock, flags);
+       sbd_line_drain(sport);
+       if (sport->tx_stopped)
+               write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+       write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+       spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int __init sbd_console_setup(struct console *co, char *options)
+{
+       int chip = co->index / DUART_MAX_SIDE;
+       int side = co->index % DUART_MAX_SIDE;
+       struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+       struct uart_port *uport = &sport->port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       if (!sport->duart)
+               return -ENXIO;
+
+       ret = sbd_map_port(uport);
+       if (ret)
+               return ret;
+
+       sbd_init_port(sport);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sbd_reg;
+static struct console sbd_console = {
+       .name   = "duart",
+       .write  = sbd_console_write,
+       .device = uart_console_device,
+       .setup  = sbd_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &sbd_reg
+};
+
+static int __init sbd_serial_console_init(void)
+{
+       sbd_probe_duarts();
+       register_console(&sbd_console);
+
+       return 0;
+}
+
+console_initcall(sbd_serial_console_init);
+
+#define SERIAL_SB1250_DUART_CONSOLE    &sbd_console
+#else
+#define SERIAL_SB1250_DUART_CONSOLE    NULL
+#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */
+
+
+static struct uart_driver sbd_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "sb1250_duart",
+       .dev_name       = "duart",
+       .major          = TTY_MAJOR,
+       .minor          = SB1250_DUART_MINOR_BASE,
+       .nr             = DUART_MAX_CHIP * DUART_MAX_SIDE,
+       .cons           = SERIAL_SB1250_DUART_CONSOLE,
+};
+
+/* Set up the driver and register it.  */
+static int __init sbd_init(void)
+{
+       int i, ret;
+
+       sbd_probe_duarts();
+
+       ret = uart_register_driver(&sbd_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {
+               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+               struct uart_port *uport = &sport->port;
+
+               if (sport->duart)
+                       uart_add_one_port(&sbd_reg, uport);
+       }
+
+       return 0;
+}
+
+/* Unload the driver.  Unregister stuff, get ready to go away.  */
+static void __exit sbd_exit(void)
+{
+       int i;
+
+       for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {
+               struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+               struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+               struct uart_port *uport = &sport->port;
+
+               if (sport->duart)
+                       uart_remove_one_port(&sbd_reg, uport);
+       }
+
+       uart_unregister_driver(&sbd_reg);
+}
+
+module_init(sbd_init);
+module_exit(sbd_exit);
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
new file mode 100644 (file)
index 0000000..75038ad
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR         204
+#define SC26XX_MINOR_START   205
+#define SC26XX_NR            2
+
+struct uart_sc26xx_port {
+       struct uart_port      port[2];
+       u8     dsr_mask[2];
+       u8     cts_mask[2];
+       u8     dcd_mask[2];
+       u8     ri_mask[2];
+       u8     dtr_mask[2];
+       u8     rts_mask[2];
+       u8     imr;
+};
+
+/* register common to both ports */
+#define RD_ISR      0x14
+#define RD_IPR      0x34
+
+#define WR_ACR      0x10
+#define WR_IMR      0x14
+#define WR_OPCR     0x34
+#define WR_OPR_SET  0x38
+#define WR_OPR_CLR  0x3C
+
+/* access common register */
+#define READ_SC(p, r)        readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR  0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR  0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK    (1 << 7)
+#define SR_FRAME    (1 << 6)
+#define SR_PARITY   (1 << 5)
+#define SR_OVERRUN  (1 << 4)
+#define SR_TXRDY    (1 << 2)
+#define SR_RXRDY    (1 << 0)
+
+#define CR_RES_MR   (1 << 4)
+#define CR_RES_RX   (2 << 4)
+#define CR_RES_TX   (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX   (1 << 3)
+#define CR_ENA_TX   (1 << 2)
+#define CR_DIS_RX   (1 << 1)
+#define CR_ENA_RX   (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB  (1 << 5)
+#define ISR_TXRDYB  (1 << 4)
+#define ISR_RXRDYA  (1 << 1)
+#define ISR_TXRDYA  (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY   (1 << 1)
+#define IMR_TXRDY   (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+       return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+       writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr |= mask << (line * 4);
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr &= ~(mask << (line * 4));
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+       int limit = 10000;
+       unsigned char ch;
+       char flag;
+       u8 status;
+
+       if (port->state != NULL)                /* Unopened serial console */
+               tty = port->state->port.tty;
+
+       while (limit-- > 0) {
+               status = READ_SC_PORT(port, SR);
+               if (!(status & SR_RXRDY))
+                       break;
+               ch = READ_SC_PORT(port, RHR);
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(status & (SR_BREAK | SR_FRAME |
+                                      SR_PARITY | SR_OVERRUN))) {
+                       if (status & SR_BREAK) {
+                               status &= ~(SR_PARITY | SR_FRAME);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & SR_PARITY)
+                               port->icount.parity++;
+                       else if (status & SR_FRAME)
+                               port->icount.frame++;
+                       if (status & SR_OVERRUN)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+                       if (status & SR_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & SR_PARITY)
+                               flag = TTY_PARITY;
+                       else if (status & SR_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+
+               if (status & port->ignore_status_mask)
+                       continue;
+
+               tty_insert_flip_char(tty, ch, flag);
+       }
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->state)
+               return;
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               sc26xx_disable_irq(port, IMR_TXRDY);
+               return;
+       }
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+                       break;
+
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+       struct uart_sc26xx_port *up = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+       u8 isr;
+
+       spin_lock_irqsave(&up->port[0].lock, flags);
+
+       tty = NULL;
+       isr = READ_SC(&up->port[0], ISR);
+       if (isr & ISR_TXRDYA)
+           transmit_chars(&up->port[0]);
+       if (isr & ISR_RXRDYA)
+           tty = receive_chars(&up->port[0]);
+
+       spin_unlock(&up->port[0].lock);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       spin_lock(&up->port[1].lock);
+
+       tty = NULL;
+       if (isr & ISR_TXRDYB)
+           transmit_chars(&up->port[1]);
+       if (isr & ISR_RXRDYB)
+           tty = receive_chars(&up->port[1]);
+
+       spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       if (up->dtr_mask[line]) {
+               if (mctrl & TIOCM_DTR)
+                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+       }
+       if (up->rts_mask[line]) {
+               if (mctrl & TIOCM_RTS)
+                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+       }
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+       u8 ipr;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+       ipr = READ_SC(port, IPR) ^ 0xff;
+
+       if (up->dsr_mask[line]) {
+               mctrl &= ~TIOCM_DSR;
+               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+       }
+       if (up->cts_mask[line]) {
+               mctrl &= ~TIOCM_CTS;
+               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+       }
+       if (up->dcd_mask[line]) {
+               mctrl &= ~TIOCM_CAR;
+               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+       }
+       if (up->ri_mask[line]) {
+               mctrl &= ~TIOCM_RNG;
+               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+       }
+       return mctrl;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+                       sc26xx_enable_irq(port, IMR_TXRDY);
+                       break;
+               }
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state == -1)
+               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+       else
+               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held.  */
+static int sc26xx_startup(struct uart_port *port)
+{
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+       WRITE_SC(port, OPCR, 0);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       /* start rx/tx */
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+       /* enable irqs */
+       sc26xx_enable_irq(port, IMR_RXRDY);
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+       /* disable interrupst */
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+       /* stop tx/rx */
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held.  */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+       u8 mr1, mr2, csr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->read_status_mask = SR_OVERRUN;
+       if (iflag & INPCK)
+               port->read_status_mask |= SR_PARITY | SR_FRAME;
+       if (iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BREAK;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= SR_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+                                           SR_PARITY | SR_OVERRUN;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               mr1 = 0x00;
+               break;
+       case CS6:
+               mr1 = 0x01;
+               break;
+       case CS7:
+               mr1 = 0x02;
+               break;
+       default:
+       case CS8:
+               mr1 = 0x03;
+               break;
+       }
+       mr2 = 0x07;
+       if (cflag & CSTOPB)
+               mr2 = 0x0f;
+       if (cflag & PARENB) {
+               if (cflag & PARODD)
+                       mr1 |= (1 << 2);
+       } else
+               mr1 |= (2 << 3);
+
+       switch (baud) {
+       case 50:
+               csr = 0x00;
+               break;
+       case 110:
+               csr = 0x11;
+               break;
+       case 134:
+               csr = 0x22;
+               break;
+       case 200:
+               csr = 0x33;
+               break;
+       case 300:
+               csr = 0x44;
+               break;
+       case 600:
+               csr = 0x55;
+               break;
+       case 1200:
+               csr = 0x66;
+               break;
+       case 2400:
+               csr = 0x88;
+               break;
+       case 4800:
+               csr = 0x99;
+               break;
+       default:
+       case 9600:
+               csr = 0xbb;
+               break;
+       case 19200:
+               csr = 0xcc;
+               break;
+       }
+
+       WRITE_SC_PORT(port, CR, CR_RES_MR);
+       WRITE_SC_PORT(port, MRx, mr1);
+       WRITE_SC_PORT(port, MRx, mr2);
+
+       WRITE_SC(port, ACR, 0x80);
+       WRITE_SC_PORT(port, CSR, csr);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+       return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+       .tx_empty       = sc26xx_tx_empty,
+       .set_mctrl      = sc26xx_set_mctrl,
+       .get_mctrl      = sc26xx_get_mctrl,
+       .stop_tx        = sc26xx_stop_tx,
+       .start_tx       = sc26xx_start_tx,
+       .stop_rx        = sc26xx_stop_rx,
+       .enable_ms      = sc26xx_enable_ms,
+       .break_ctl      = sc26xx_break_ctl,
+       .startup        = sc26xx_startup,
+       .shutdown       = sc26xx_shutdown,
+       .set_termios    = sc26xx_set_termios,
+       .type           = sc26xx_type,
+       .release_port   = sc26xx_release_port,
+       .request_port   = sc26xx_request_port,
+       .config_port    = sc26xx_config_port,
+       .verify_port    = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+       unsigned long flags;
+       int limit = 1000000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+                       WRITE_SC_PORT(port, THR, c);
+                       break;
+               }
+               udelay(2);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sc26xx_port;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sc26xx_console_putchar(port, '\r');
+               sc26xx_console_putchar(port, *s++);
+       }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port = sc26xx_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->type != PORT_SC26XX)
+               return -1;
+
+       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+       .name   =       "ttySC",
+       .write  =       sc26xx_console_write,
+       .device =       uart_console_device,
+       .setup  =       sc26xx_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sc26xx_reg,
+};
+#define SC26XX_CONSOLE   &sc26xx_console
+#else
+#define SC26XX_CONSOLE   NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "SC26xx",
+       .dev_name               = "ttySC",
+       .major                  = SC26XX_MAJOR,
+       .minor                  = SC26XX_MINOR_START,
+       .nr                     = SC26XX_NR,
+       .cons                   = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+       unsigned int bit = (flags >> bitpos) & 15;
+
+       return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+                                       int line, unsigned int data)
+{
+       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
+       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
+       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
+       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct uart_sc26xx_port *up;
+       unsigned int *sc26xx_data = dev->dev.platform_data;
+       int err;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       up = kzalloc(sizeof *up, GFP_KERNEL);
+       if (unlikely(!up))
+               return -ENOMEM;
+
+       up->port[0].line = 0;
+       up->port[0].ops = &sc26xx_ops;
+       up->port[0].type = PORT_SC26XX;
+       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[0].mapbase = res->start;
+       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+       up->port[0].iotype = UPIO_MEM;
+       up->port[0].irq = platform_get_irq(dev, 0);
+
+       up->port[0].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+       sc26xx_port = &up->port[0];
+
+       up->port[1].line = 1;
+       up->port[1].ops = &sc26xx_ops;
+       up->port[1].type = PORT_SC26XX;
+       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[1].mapbase = up->port[0].mapbase;
+       up->port[1].membase = up->port[0].membase;
+       up->port[1].iotype = UPIO_MEM;
+       up->port[1].irq = up->port[0].irq;
+
+       up->port[1].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+       err = uart_register_driver(&sc26xx_reg);
+       if (err)
+               goto out_free_port;
+
+       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+       if (err)
+               goto out_unregister_driver;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+       if (err)
+               goto out_remove_port0;
+
+       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+       if (err)
+               goto out_remove_ports;
+
+       dev_set_drvdata(&dev->dev, up);
+       return 0;
+
+out_remove_ports:
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+       uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+       kfree(up);
+       sc26xx_port = NULL;
+       return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+       free_irq(up->port[0].irq, up);
+
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+       uart_unregister_driver(&sc26xx_reg);
+
+       kfree(up);
+       sc26xx_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+       .probe  = sc26xx_probe,
+       .remove = __devexit_p(sc26xx_driver_remove),
+       .driver = {
+               .name   = "SC26xx",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sc26xx_init(void)
+{
+       return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+       platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:SC26xx");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
new file mode 100644 (file)
index 0000000..460a72d
--- /dev/null
@@ -0,0 +1,2578 @@
+/*
+ *  linux/drivers/char/core.c
+ *
+ *  Driver core for serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/*
+ * This is used to lock changes in serial line configuration.
+ */
+static DEFINE_MUTEX(port_mutex);
+
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ *          want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
+#define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port)     (0)
+#endif
+
+static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
+                                       struct ktermios *old_termios);
+static void __uart_wait_until_sent(struct uart_port *port, int timeout);
+static void uart_change_pm(struct uart_state *state, int pm_state);
+
+/*
+ * This routine is used by the interrupt handler to schedule processing in
+ * the software interrupt portion of the driver.
+ */
+void uart_write_wakeup(struct uart_port *port)
+{
+       struct uart_state *state = port->state;
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       BUG_ON(!state);
+       tasklet_schedule(&state->tlet);
+}
+
+static void uart_stop(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->ops->stop_tx(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __uart_start(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
+           !tty->stopped && !tty->hw_stopped)
+               port->ops->start_tx(port);
+}
+
+static void uart_start(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __uart_start(tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void uart_tasklet_action(unsigned long data)
+{
+       struct uart_state *state = (struct uart_state *)data;
+       tty_wakeup(state->port.tty);
+}
+
+static inline void
+uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
+{
+       unsigned long flags;
+       unsigned int old;
+
+       spin_lock_irqsave(&port->lock, flags);
+       old = port->mctrl;
+       port->mctrl = (old & ~clear) | set;
+       if (old != port->mctrl)
+               port->ops->set_mctrl(port, port->mctrl);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#define uart_set_mctrl(port, set)      uart_update_mctrl(port, set, 0)
+#define uart_clear_mctrl(port, clear)  uart_update_mctrl(port, 0, clear)
+
+/*
+ * Startup the port.  This will be called once per open.  All calls
+ * will be serialised by the per-port mutex.
+ */
+static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       unsigned long page;
+       int retval = 0;
+
+       if (port->flags & ASYNC_INITIALIZED)
+               return 0;
+
+       /*
+        * Set the TTY IO error marker - we will only clear this
+        * once we have successfully opened the port.  Also set
+        * up the tty->alt_speed kludge
+        */
+       set_bit(TTY_IO_ERROR, &tty->flags);
+
+       if (uport->type == PORT_UNKNOWN)
+               return 0;
+
+       /*
+        * Initialise and allocate the transmit and temporary
+        * buffer.
+        */
+       if (!state->xmit.buf) {
+               /* This is protected by the per port mutex */
+               page = get_zeroed_page(GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
+
+               state->xmit.buf = (unsigned char *) page;
+               uart_circ_clear(&state->xmit);
+       }
+
+       retval = uport->ops->startup(uport);
+       if (retval == 0) {
+               if (init_hw) {
+                       /*
+                        * Initialise the hardware port settings.
+                        */
+                       uart_change_speed(tty, state, NULL);
+
+                       /*
+                        * Setup the RTS and DTR signals once the
+                        * port is open and ready to respond.
+                        */
+                       if (tty->termios->c_cflag & CBAUD)
+                               uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
+               }
+
+               if (port->flags & ASYNC_CTS_FLOW) {
+                       spin_lock_irq(&uport->lock);
+                       if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
+                               tty->hw_stopped = 1;
+                       spin_unlock_irq(&uport->lock);
+               }
+
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+       }
+
+       if (retval && capable(CAP_SYS_ADMIN))
+               retval = 0;
+
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.  Calls to
+ * uart_shutdown are serialised by the per-port semaphore.
+ */
+static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+
+       /*
+        * Set the TTY IO error marker
+        */
+       if (tty)
+               set_bit(TTY_IO_ERROR, &tty->flags);
+
+       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               /*
+                * Turn off DTR and RTS early.
+                */
+               if (!tty || (tty->termios->c_cflag & HUPCL))
+                       uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * clear delta_msr_wait queue to avoid mem leaks: we may free
+                * the irq here so the queue might never be woken up.  Note
+                * that we won't end up waiting on delta_msr_wait again since
+                * any outstanding file descriptors should be pointing at
+                * hung_up_tty_fops now.
+                */
+               wake_up_interruptible(&port->delta_msr_wait);
+
+               /*
+                * Free the IRQ and disable the port.
+                */
+               uport->ops->shutdown(uport);
+
+               /*
+                * Ensure that the IRQ handler isn't running on another CPU.
+                */
+               synchronize_irq(uport->irq);
+       }
+
+       /*
+        * kill off our tasklet
+        */
+       tasklet_kill(&state->tlet);
+
+       /*
+        * Free the transmit buffer page.
+        */
+       if (state->xmit.buf) {
+               free_page((unsigned long)state->xmit.buf);
+               state->xmit.buf = NULL;
+       }
+}
+
+/**
+ *     uart_update_timeout - update per-port FIFO timeout.
+ *     @port:  uart_port structure describing the port
+ *     @cflag: termios cflag value
+ *     @baud:  speed of the port
+ *
+ *     Set the port FIFO timeout value.  The @cflag value should
+ *     reflect the actual hardware settings.
+ */
+void
+uart_update_timeout(struct uart_port *port, unsigned int cflag,
+                   unsigned int baud)
+{
+       unsigned int bits;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:
+               bits = 7;
+               break;
+       case CS6:
+               bits = 8;
+               break;
+       case CS7:
+               bits = 9;
+               break;
+       default:
+               bits = 10;
+               break; /* CS8 */
+       }
+
+       if (cflag & CSTOPB)
+               bits++;
+       if (cflag & PARENB)
+               bits++;
+
+       /*
+        * The total number of bits to be transmitted in the fifo.
+        */
+       bits = bits * port->fifosize;
+
+       /*
+        * Figure the timeout to send the above number of bits.
+        * Add .02 seconds of slop
+        */
+       port->timeout = (HZ * bits) / baud + HZ/50;
+}
+
+EXPORT_SYMBOL(uart_update_timeout);
+
+/**
+ *     uart_get_baud_rate - return baud rate for a particular port
+ *     @port: uart_port structure describing the port in question.
+ *     @termios: desired termios settings.
+ *     @old: old termios (or NULL)
+ *     @min: minimum acceptable baud rate
+ *     @max: maximum acceptable baud rate
+ *
+ *     Decode the termios structure into a numeric baud rate,
+ *     taking account of the magic 38400 baud rate (with spd_*
+ *     flags), and mapping the %B0 rate to 9600 baud.
+ *
+ *     If the new baud rate is invalid, try the old termios setting.
+ *     If it's still invalid, we try 9600 baud.
+ *
+ *     Update the @termios structure to reflect the baud rate
+ *     we're actually going to be using. Don't do this for the case
+ *     where B0 is requested ("hang up").
+ */
+unsigned int
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old, unsigned int min, unsigned int max)
+{
+       unsigned int try, baud, altbaud = 38400;
+       int hung_up = 0;
+       upf_t flags = port->flags & UPF_SPD_MASK;
+
+       if (flags == UPF_SPD_HI)
+               altbaud = 57600;
+       else if (flags == UPF_SPD_VHI)
+               altbaud = 115200;
+       else if (flags == UPF_SPD_SHI)
+               altbaud = 230400;
+       else if (flags == UPF_SPD_WARP)
+               altbaud = 460800;
+
+       for (try = 0; try < 2; try++) {
+               baud = tty_termios_baud_rate(termios);
+
+               /*
+                * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
+                * Die! Die! Die!
+                */
+               if (baud == 38400)
+                       baud = altbaud;
+
+               /*
+                * Special case: B0 rate.
+                */
+               if (baud == 0) {
+                       hung_up = 1;
+                       baud = 9600;
+               }
+
+               if (baud >= min && baud <= max)
+                       return baud;
+
+               /*
+                * Oops, the quotient was zero.  Try again with
+                * the old baud rate if possible.
+                */
+               termios->c_cflag &= ~CBAUD;
+               if (old) {
+                       baud = tty_termios_baud_rate(old);
+                       if (!hung_up)
+                               tty_termios_encode_baud_rate(termios,
+                                                               baud, baud);
+                       old = NULL;
+                       continue;
+               }
+
+               /*
+                * As a last resort, if the range cannot be met then clip to
+                * the nearest chip supported rate.
+                */
+               if (!hung_up) {
+                       if (baud <= min)
+                               tty_termios_encode_baud_rate(termios,
+                                                       min + 1, min + 1);
+                       else
+                               tty_termios_encode_baud_rate(termios,
+                                                       max - 1, max - 1);
+               }
+       }
+       /* Should never happen */
+       WARN_ON(1);
+       return 0;
+}
+
+EXPORT_SYMBOL(uart_get_baud_rate);
+
+/**
+ *     uart_get_divisor - return uart clock divisor
+ *     @port: uart_port structure describing the port.
+ *     @baud: desired baud rate
+ *
+ *     Calculate the uart clock divisor for the port.
+ */
+unsigned int
+uart_get_divisor(struct uart_port *port, unsigned int baud)
+{
+       unsigned int quot;
+
+       /*
+        * Old custom speed handling.
+        */
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = (port->uartclk + (8 * baud)) / (16 * baud);
+
+       return quot;
+}
+
+EXPORT_SYMBOL(uart_get_divisor);
+
+/* FIXME: Consistent locking policy */
+static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
+                                       struct ktermios *old_termios)
+{
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+       struct ktermios *termios;
+
+       /*
+        * If we have no tty, termios, or the port does not exist,
+        * then we can't set the parameters for this port.
+        */
+       if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
+               return;
+
+       termios = tty->termios;
+
+       /*
+        * Set flags based on termios cflag
+        */
+       if (termios->c_cflag & CRTSCTS)
+               set_bit(ASYNCB_CTS_FLOW, &port->flags);
+       else
+               clear_bit(ASYNCB_CTS_FLOW, &port->flags);
+
+       if (termios->c_cflag & CLOCAL)
+               clear_bit(ASYNCB_CHECK_CD, &port->flags);
+       else
+               set_bit(ASYNCB_CHECK_CD, &port->flags);
+
+       uport->ops->set_termios(uport, termios, old_termios);
+}
+
+static inline int __uart_put_char(struct uart_port *port,
+                               struct circ_buf *circ, unsigned char c)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (!circ->buf)
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (uart_circ_chars_free(circ) != 0) {
+               circ->buf[circ->head] = c;
+               circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
+static int uart_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct uart_state *state = tty->driver_data;
+
+       return __uart_put_char(state->uart_port, &state->xmit, ch);
+}
+
+static void uart_flush_chars(struct tty_struct *tty)
+{
+       uart_start(tty);
+}
+
+static int uart_write(struct tty_struct *tty,
+                                       const unsigned char *buf, int count)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
+       struct circ_buf *circ;
+       unsigned long flags;
+       int c, ret = 0;
+
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       if (!state) {
+               WARN_ON(1);
+               return -EL3HLT;
+       }
+
+       port = state->uart_port;
+       circ = &state->xmit;
+
+       if (!circ->buf)
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       while (1) {
+               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+               if (count < c)
+                       c = count;
+               if (c <= 0)
+                       break;
+               memcpy(circ->buf + circ->head, buf, c);
+               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+               buf += c;
+               count -= c;
+               ret += c;
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       uart_start(tty);
+       return ret;
+}
+
+static int uart_write_room(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&state->uart_port->lock, flags);
+       ret = uart_circ_chars_free(&state->xmit);
+       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       return ret;
+}
+
+static int uart_chars_in_buffer(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&state->uart_port->lock, flags);
+       ret = uart_circ_chars_pending(&state->xmit);
+       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       return ret;
+}
+
+static void uart_flush_buffer(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
+       unsigned long flags;
+
+       /*
+        * This means you called this function _after_ the port was
+        * closed.  No cookie for you.
+        */
+       if (!state) {
+               WARN_ON(1);
+               return;
+       }
+
+       port = state->uart_port;
+       pr_debug("uart_flush_buffer(%d) called\n", tty->index);
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_circ_clear(&state->xmit);
+       if (port->ops->flush_buffer)
+               port->ops->flush_buffer(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+       tty_wakeup(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void uart_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+       unsigned long flags;
+
+       if (port->ops->send_xchar)
+               port->ops->send_xchar(port, ch);
+       else {
+               port->x_char = ch;
+               if (ch) {
+                       spin_lock_irqsave(&port->lock, flags);
+                       port->ops->start_tx(port);
+                       spin_unlock_irqrestore(&port->lock, flags);
+               }
+       }
+}
+
+static void uart_throttle(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+
+       if (I_IXOFF(tty))
+               uart_send_xchar(tty, STOP_CHAR(tty));
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               uart_clear_mctrl(state->uart_port, TIOCM_RTS);
+}
+
+static void uart_unthrottle(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       if (I_IXOFF(tty)) {
+               if (port->x_char)
+                       port->x_char = 0;
+               else
+                       uart_send_xchar(tty, START_CHAR(tty));
+       }
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               uart_set_mctrl(port, TIOCM_RTS);
+}
+
+static int uart_get_info(struct uart_state *state,
+                        struct serial_struct __user *retinfo)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       struct serial_struct tmp;
+
+       memset(&tmp, 0, sizeof(tmp));
+
+       /* Ensure the state we copy is consistent and no hardware changes
+          occur as we go */
+       mutex_lock(&port->mutex);
+
+       tmp.type            = uport->type;
+       tmp.line            = uport->line;
+       tmp.port            = uport->iobase;
+       if (HIGH_BITS_OFFSET)
+               tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
+       tmp.irq             = uport->irq;
+       tmp.flags           = uport->flags;
+       tmp.xmit_fifo_size  = uport->fifosize;
+       tmp.baud_base       = uport->uartclk / 16;
+       tmp.close_delay     = port->close_delay / 10;
+       tmp.closing_wait    = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                               ASYNC_CLOSING_WAIT_NONE :
+                               port->closing_wait / 10;
+       tmp.custom_divisor  = uport->custom_divisor;
+       tmp.hub6            = uport->hub6;
+       tmp.io_type         = uport->iotype;
+       tmp.iomem_reg_shift = uport->regshift;
+       tmp.iomem_base      = (void *)(unsigned long)uport->mapbase;
+
+       mutex_unlock(&port->mutex);
+
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
+                        struct serial_struct __user *newinfo)
+{
+       struct serial_struct new_serial;
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       unsigned long new_port;
+       unsigned int change_irq, change_port, closing_wait;
+       unsigned int old_custom_divisor, close_delay;
+       upf_t old_flags, new_flags;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+               return -EFAULT;
+
+       new_port = new_serial.port;
+       if (HIGH_BITS_OFFSET)
+               new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+       new_serial.irq = irq_canonicalize(new_serial.irq);
+       close_delay = new_serial.close_delay * 10;
+       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+       /*
+        * This semaphore protects port->count.  It is also
+        * very useful to prevent opens.  Also, take the
+        * port configuration semaphore to make sure that a
+        * module insertion/removal doesn't change anything
+        * under us.
+        */
+       mutex_lock(&port->mutex);
+
+       change_irq  = !(uport->flags & UPF_FIXED_PORT)
+               && new_serial.irq != uport->irq;
+
+       /*
+        * Since changing the 'type' of the port changes its resource
+        * allocations, we should treat type changes the same as
+        * IO port changes.
+        */
+       change_port = !(uport->flags & UPF_FIXED_PORT)
+               && (new_port != uport->iobase ||
+                   (unsigned long)new_serial.iomem_base != uport->mapbase ||
+                   new_serial.hub6 != uport->hub6 ||
+                   new_serial.io_type != uport->iotype ||
+                   new_serial.iomem_reg_shift != uport->regshift ||
+                   new_serial.type != uport->type);
+
+       old_flags = uport->flags;
+       new_flags = new_serial.flags;
+       old_custom_divisor = uport->custom_divisor;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               retval = -EPERM;
+               if (change_irq || change_port ||
+                   (new_serial.baud_base != uport->uartclk / 16) ||
+                   (close_delay != port->close_delay) ||
+                   (closing_wait != port->closing_wait) ||
+                   (new_serial.xmit_fifo_size &&
+                    new_serial.xmit_fifo_size != uport->fifosize) ||
+                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+                       goto exit;
+               uport->flags = ((uport->flags & ~UPF_USR_MASK) |
+                              (new_flags & UPF_USR_MASK));
+               uport->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       /*
+        * Ask the low level driver to verify the settings.
+        */
+       if (uport->ops->verify_port)
+               retval = uport->ops->verify_port(uport, &new_serial);
+
+       if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
+           (new_serial.baud_base < 9600))
+               retval = -EINVAL;
+
+       if (retval)
+               goto exit;
+
+       if (change_port || change_irq) {
+               retval = -EBUSY;
+
+               /*
+                * Make sure that we are the sole user of this port.
+                */
+               if (tty_port_users(port) > 1)
+                       goto exit;
+
+               /*
+                * We need to shutdown the serial port at the old
+                * port/type/irq combination.
+                */
+               uart_shutdown(tty, state);
+       }
+
+       if (change_port) {
+               unsigned long old_iobase, old_mapbase;
+               unsigned int old_type, old_iotype, old_hub6, old_shift;
+
+               old_iobase = uport->iobase;
+               old_mapbase = uport->mapbase;
+               old_type = uport->type;
+               old_hub6 = uport->hub6;
+               old_iotype = uport->iotype;
+               old_shift = uport->regshift;
+
+               /*
+                * Free and release old regions
+                */
+               if (old_type != PORT_UNKNOWN)
+                       uport->ops->release_port(uport);
+
+               uport->iobase = new_port;
+               uport->type = new_serial.type;
+               uport->hub6 = new_serial.hub6;
+               uport->iotype = new_serial.io_type;
+               uport->regshift = new_serial.iomem_reg_shift;
+               uport->mapbase = (unsigned long)new_serial.iomem_base;
+
+               /*
+                * Claim and map the new regions
+                */
+               if (uport->type != PORT_UNKNOWN) {
+                       retval = uport->ops->request_port(uport);
+               } else {
+                       /* Always success - Jean II */
+                       retval = 0;
+               }
+
+               /*
+                * If we fail to request resources for the
+                * new port, try to restore the old settings.
+                */
+               if (retval && old_type != PORT_UNKNOWN) {
+                       uport->iobase = old_iobase;
+                       uport->type = old_type;
+                       uport->hub6 = old_hub6;
+                       uport->iotype = old_iotype;
+                       uport->regshift = old_shift;
+                       uport->mapbase = old_mapbase;
+                       retval = uport->ops->request_port(uport);
+                       /*
+                        * If we failed to restore the old settings,
+                        * we fail like this.
+                        */
+                       if (retval)
+                               uport->type = PORT_UNKNOWN;
+
+                       /*
+                        * We failed anyway.
+                        */
+                       retval = -EBUSY;
+                       /* Added to return the correct error -Ram Gupta */
+                       goto exit;
+               }
+       }
+
+       if (change_irq)
+               uport->irq      = new_serial.irq;
+       if (!(uport->flags & UPF_FIXED_PORT))
+               uport->uartclk  = new_serial.baud_base * 16;
+       uport->flags            = (uport->flags & ~UPF_CHANGE_MASK) |
+                                (new_flags & UPF_CHANGE_MASK);
+       uport->custom_divisor   = new_serial.custom_divisor;
+       port->close_delay     = close_delay;
+       port->closing_wait    = closing_wait;
+       if (new_serial.xmit_fifo_size)
+               uport->fifosize = new_serial.xmit_fifo_size;
+       if (port->tty)
+               port->tty->low_latency =
+                       (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+       retval = 0;
+       if (uport->type == PORT_UNKNOWN)
+               goto exit;
+       if (port->flags & ASYNC_INITIALIZED) {
+               if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
+                   old_custom_divisor != uport->custom_divisor) {
+                       /*
+                        * If they're setting up a custom divisor or speed,
+                        * instead of clearing it, then bitch about it. No
+                        * need to rate-limit; it's CAP_SYS_ADMIN only.
+                        */
+                       if (uport->flags & UPF_SPD_MASK) {
+                               char buf[64];
+                               printk(KERN_NOTICE
+                                      "%s sets custom speed on %s. This "
+                                      "is deprecated.\n", current->comm,
+                                      tty_name(port->tty, buf));
+                       }
+                       uart_change_speed(tty, state, NULL);
+               }
+       } else
+               retval = uart_startup(tty, state, 1);
+ exit:
+       mutex_unlock(&port->mutex);
+       return retval;
+}
+
+/**
+ *     uart_get_lsr_info       -       get line status register info
+ *     @tty: tty associated with the UART
+ *     @state: UART being queried
+ *     @value: returned modem value
+ *
+ *     Note: uart_ioctl protects us against hangups.
+ */
+static int uart_get_lsr_info(struct tty_struct *tty,
+                       struct uart_state *state, unsigned int __user *value)
+{
+       struct uart_port *uport = state->uart_port;
+       unsigned int result;
+
+       result = uport->ops->tx_empty(uport);
+
+       /*
+        * If we're about to load something into the transmit
+        * register, we'll pretend the transmitter isn't empty to
+        * avoid a race condition (depending on when the transmit
+        * interrupt happens).
+        */
+       if (uport->x_char ||
+           ((uart_circ_chars_pending(&state->xmit) > 0) &&
+            !tty->stopped && !tty->hw_stopped))
+               result &= ~TIOCSER_TEMT;
+
+       return put_user(result, value);
+}
+
+static int uart_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+       int result = -EIO;
+
+       mutex_lock(&port->mutex);
+       if ((!file || !tty_hung_up_p(file)) &&
+           !(tty->flags & (1 << TTY_IO_ERROR))) {
+               result = uport->mctrl;
+
+               spin_lock_irq(&uport->lock);
+               result |= uport->ops->get_mctrl(uport);
+               spin_unlock_irq(&uport->lock);
+       }
+       mutex_unlock(&port->mutex);
+
+       return result;
+}
+
+static int
+uart_tiocmset(struct tty_struct *tty, struct file *file,
+             unsigned int set, unsigned int clear)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       int ret = -EIO;
+
+       mutex_lock(&port->mutex);
+       if ((!file || !tty_hung_up_p(file)) &&
+           !(tty->flags & (1 << TTY_IO_ERROR))) {
+               uart_update_mctrl(uport, set, clear);
+               ret = 0;
+       }
+       mutex_unlock(&port->mutex);
+       return ret;
+}
+
+static int uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       struct uart_port *uport = state->uart_port;
+
+       mutex_lock(&port->mutex);
+
+       if (uport->type != PORT_UNKNOWN)
+               uport->ops->break_ctl(uport, break_state);
+
+       mutex_unlock(&port->mutex);
+       return 0;
+}
+
+static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       int flags, ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /*
+        * Take the per-port semaphore.  This prevents count from
+        * changing, and hence any extra opens of the port while
+        * we're auto-configuring.
+        */
+       if (mutex_lock_interruptible(&port->mutex))
+               return -ERESTARTSYS;
+
+       ret = -EBUSY;
+       if (tty_port_users(port) == 1) {
+               uart_shutdown(tty, state);
+
+               /*
+                * If we already have a port type configured,
+                * we must release its resources.
+                */
+               if (uport->type != PORT_UNKNOWN)
+                       uport->ops->release_port(uport);
+
+               flags = UART_CONFIG_TYPE;
+               if (uport->flags & UPF_AUTO_IRQ)
+                       flags |= UART_CONFIG_IRQ;
+
+               /*
+                * This will claim the ports resources if
+                * a port is found.
+                */
+               uport->ops->config_port(uport, flags);
+
+               ret = uart_startup(tty, state, 1);
+       }
+       mutex_unlock(&port->mutex);
+       return ret;
+}
+
+/*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ *
+ * FIXME: This wants extracting into a common all driver implementation
+ * of TIOCMWAIT using tty_port.
+ */
+static int
+uart_wait_modem_status(struct uart_state *state, unsigned long arg)
+{
+       struct uart_port *uport = state->uart_port;
+       struct tty_port *port = &state->port;
+       DECLARE_WAITQUEUE(wait, current);
+       struct uart_icount cprev, cnow;
+       int ret;
+
+       /*
+        * note the counters on entry
+        */
+       spin_lock_irq(&uport->lock);
+       memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
+
+       /*
+        * Force modem status interrupts on
+        */
+       uport->ops->enable_ms(uport);
+       spin_unlock_irq(&uport->lock);
+
+       add_wait_queue(&port->delta_msr_wait, &wait);
+       for (;;) {
+               spin_lock_irq(&uport->lock);
+               memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+               spin_unlock_irq(&uport->lock);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                   ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                   ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                   ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+                       ret = 0;
+                       break;
+               }
+
+               schedule();
+
+               /* see if a signal did it */
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               cprev = cnow;
+       }
+
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&port->delta_msr_wait, &wait);
+
+       return ret;
+}
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int uart_get_icount(struct tty_struct *tty,
+                         struct serial_icounter_struct *icount)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_icount cnow;
+       struct uart_port *uport = state->uart_port;
+
+       spin_lock_irq(&uport->lock);
+       memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+       spin_unlock_irq(&uport->lock);
+
+       icount->cts         = cnow.cts;
+       icount->dsr         = cnow.dsr;
+       icount->rng         = cnow.rng;
+       icount->dcd         = cnow.dcd;
+       icount->rx          = cnow.rx;
+       icount->tx          = cnow.tx;
+       icount->frame       = cnow.frame;
+       icount->overrun     = cnow.overrun;
+       icount->parity      = cnow.parity;
+       icount->brk         = cnow.brk;
+       icount->buf_overrun = cnow.buf_overrun;
+
+       return 0;
+}
+
+/*
+ * Called via sys_ioctl.  We can use spin_lock_irq() here.
+ */
+static int
+uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
+          unsigned long arg)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       void __user *uarg = (void __user *)arg;
+       int ret = -ENOIOCTLCMD;
+
+
+       /*
+        * These ioctls don't rely on the hardware to be present.
+        */
+       switch (cmd) {
+       case TIOCGSERIAL:
+               ret = uart_get_info(state, uarg);
+               break;
+
+       case TIOCSSERIAL:
+               ret = uart_set_info(tty, state, uarg);
+               break;
+
+       case TIOCSERCONFIG:
+               ret = uart_do_autoconfig(tty, state);
+               break;
+
+       case TIOCSERGWILD: /* obsolete */
+       case TIOCSERSWILD: /* obsolete */
+               ret = 0;
+               break;
+       }
+
+       if (ret != -ENOIOCTLCMD)
+               goto out;
+
+       if (tty->flags & (1 << TTY_IO_ERROR)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /*
+        * The following should only be used when hardware is present.
+        */
+       switch (cmd) {
+       case TIOCMIWAIT:
+               ret = uart_wait_modem_status(state, arg);
+               break;
+       }
+
+       if (ret != -ENOIOCTLCMD)
+               goto out;
+
+       mutex_lock(&port->mutex);
+
+       if (tty_hung_up_p(filp)) {
+               ret = -EIO;
+               goto out_up;
+       }
+
+       /*
+        * All these rely on hardware being present and need to be
+        * protected against the tty being hung up.
+        */
+       switch (cmd) {
+       case TIOCSERGETLSR: /* Get line status register */
+               ret = uart_get_lsr_info(tty, state, uarg);
+               break;
+
+       default: {
+               struct uart_port *uport = state->uart_port;
+               if (uport->ops->ioctl)
+                       ret = uport->ops->ioctl(uport, cmd, arg);
+               break;
+       }
+       }
+out_up:
+       mutex_unlock(&port->mutex);
+out:
+       return ret;
+}
+
+static void uart_set_ldisc(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *uport = state->uart_port;
+
+       if (uport->ops->set_ldisc)
+               uport->ops->set_ldisc(uport, tty->termios->c_line);
+}
+
+static void uart_set_termios(struct tty_struct *tty,
+                                               struct ktermios *old_termios)
+{
+       struct uart_state *state = tty->driver_data;
+       unsigned long flags;
+       unsigned int cflag = tty->termios->c_cflag;
+
+
+       /*
+        * These are the bits that are used to setup various
+        * flags in the low level driver. We can ignore the Bfoo
+        * bits in c_cflag; c_[io]speed will always be set
+        * appropriately by set_termios() in tty_ioctl.c
+        */
+#define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+       if ((cflag ^ old_termios->c_cflag) == 0 &&
+           tty->termios->c_ospeed == old_termios->c_ospeed &&
+           tty->termios->c_ispeed == old_termios->c_ispeed &&
+           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
+               return;
+       }
+
+       uart_change_speed(tty, state, old_termios);
+
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+               uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
+       /* Handle transition away from B0 status */
+       else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+               unsigned int mask = TIOCM_DTR;
+               if (!(cflag & CRTSCTS) ||
+                   !test_bit(TTY_THROTTLED, &tty->flags))
+                       mask |= TIOCM_RTS;
+               uart_set_mctrl(state->uart_port, mask);
+       }
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+               spin_lock_irqsave(&state->uart_port->lock, flags);
+               tty->hw_stopped = 0;
+               __uart_start(tty);
+               spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       }
+       /* Handle turning on CRTSCTS */
+       else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+               spin_lock_irqsave(&state->uart_port->lock, flags);
+               if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
+                       tty->hw_stopped = 1;
+                       state->uart_port->ops->stop_tx(state->uart_port);
+               }
+               spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       }
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&state->uart_port.open_wait);
+#endif
+}
+
+/*
+ * In 2.4.5, calls to this will be serialized via the BKL in
+ *  linux/drivers/char/tty_io.c:tty_release()
+ *  linux/drivers/char/tty_io.c:do_tty_handup()
+ */
+static void uart_close(struct tty_struct *tty, struct file *filp)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port;
+       struct uart_port *uport;
+       unsigned long flags;
+
+       BUG_ON(!tty_locked());
+
+       if (!state)
+               return;
+
+       uport = state->uart_port;
+       port = &state->port;
+
+       pr_debug("uart_close(%d) called\n", uport->line);
+
+       mutex_lock(&port->mutex);
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               goto done;
+       }
+
+       if ((tty->count == 1) && (port->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  port->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
+                      "port->count is %d\n", port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
+                      tty->name, port->count);
+               port->count = 0;
+       }
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               goto done;
+       }
+
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify
+        * the line discipline to only process XON/XOFF characters by
+        * setting tty->closing.
+        */
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+               /*
+                * hack: open-coded tty_wait_until_sent to avoid
+                * recursive tty_lock
+                */
+               long timeout = msecs_to_jiffies(port->closing_wait);
+               if (wait_event_interruptible_timeout(tty->write_wait,
+                               !tty_chars_in_buffer(tty), timeout) >= 0)
+                       __uart_wait_until_sent(uport, timeout);
+       }
+
+       /*
+        * At this point, we stop accepting input.  To do this, we
+        * disable the receive line status interrupts.
+        */
+       if (port->flags & ASYNC_INITIALIZED) {
+               unsigned long flags;
+               spin_lock_irqsave(&uport->lock, flags);
+               uport->ops->stop_rx(uport);
+               spin_unlock_irqrestore(&uport->lock, flags);
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               __uart_wait_until_sent(uport, uport->timeout);
+       }
+
+       uart_shutdown(tty, state);
+       uart_flush_buffer(tty);
+
+       tty_ldisc_flush(tty);
+
+       tty_port_tty_set(port, NULL);
+       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(port->close_delay);
+               spin_lock_irqsave(&port->lock, flags);
+       } else if (!uart_console(uport)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               uart_change_pm(state, 3);
+               spin_lock_irqsave(&port->lock, flags);
+       }
+
+       /*
+        * Wake up anyone trying to open this port.
+        */
+       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+
+done:
+       mutex_unlock(&port->mutex);
+}
+
+static void __uart_wait_until_sent(struct uart_port *port, int timeout)
+{
+       unsigned long char_time, expire;
+
+       if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+               return;
+
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        *
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = (port->timeout - HZ/50) / port->fifosize;
+       char_time = char_time / 5;
+       if (char_time == 0)
+               char_time = 1;
+       if (timeout && timeout < char_time)
+               char_time = timeout;
+
+       /*
+        * If the transmitter hasn't cleared in twice the approximate
+        * amount of time to send the entire FIFO, it probably won't
+        * ever clear.  This assumes the UART isn't doing flow
+        * control, which is currently the case.  Hence, if it ever
+        * takes longer than port->timeout, this is probably due to a
+        * UART bug of some kind.  So, we clamp the timeout parameter at
+        * 2*port->timeout.
+        */
+       if (timeout == 0 || timeout > 2 * port->timeout)
+               timeout = 2 * port->timeout;
+
+       expire = jiffies + timeout;
+
+       pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+               port->line, jiffies, expire);
+
+       /*
+        * Check whether the transmitter is empty every 'char_time'.
+        * 'timeout' / 'expire' give us the maximum amount of time
+        * we wait.
+        */
+       while (!port->ops->tx_empty(port)) {
+               msleep_interruptible(jiffies_to_msecs(char_time));
+               if (signal_pending(current))
+                       break;
+               if (time_after(jiffies, expire))
+                       break;
+       }
+       set_current_state(TASK_RUNNING); /* might not be needed */
+}
+
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
+
+       tty_lock();
+       __uart_wait_until_sent(port, timeout);
+       tty_unlock();
+}
+
+/*
+ * This is called with the BKL held in
+ *  linux/drivers/char/tty_io.c:do_tty_hangup()
+ * We're called from the eventd thread, so we can sleep for
+ * a _short_ time only.
+ */
+static void uart_hangup(struct tty_struct *tty)
+{
+       struct uart_state *state = tty->driver_data;
+       struct tty_port *port = &state->port;
+       unsigned long flags;
+
+       BUG_ON(!tty_locked());
+       pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+
+       mutex_lock(&port->mutex);
+       if (port->flags & ASYNC_NORMAL_ACTIVE) {
+               uart_flush_buffer(tty);
+               uart_shutdown(tty, state);
+               spin_lock_irqsave(&port->lock, flags);
+               port->count = 0;
+               clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+               spin_unlock_irqrestore(&port->lock, flags);
+               tty_port_tty_set(port, NULL);
+               wake_up_interruptible(&port->open_wait);
+               wake_up_interruptible(&port->delta_msr_wait);
+       }
+       mutex_unlock(&port->mutex);
+}
+
+/**
+ *     uart_update_termios     -       update the terminal hw settings
+ *     @tty: tty associated with UART
+ *     @state: UART to update
+ *
+ *     Copy across the serial console cflag setting into the termios settings
+ *     for the initial open of the port.  This allows continuity between the
+ *     kernel settings, and the settings init adopts when it opens the port
+ *     for the first time.
+ */
+static void uart_update_termios(struct tty_struct *tty,
+                                               struct uart_state *state)
+{
+       struct uart_port *port = state->uart_port;
+
+       if (uart_console(port) && port->cons->cflag) {
+               tty->termios->c_cflag = port->cons->cflag;
+               port->cons->cflag = 0;
+       }
+
+       /*
+        * If the device failed to grab its irq resources,
+        * or some other error occurred, don't try to talk
+        * to the port hardware.
+        */
+       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+               /*
+                * Make termios settings take effect.
+                */
+               uart_change_speed(tty, state, NULL);
+
+               /*
+                * And finally enable the RTS and DTR signals.
+                */
+               if (tty->termios->c_cflag & CBAUD)
+                       uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       }
+}
+
+static int uart_carrier_raised(struct tty_port *port)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = state->uart_port;
+       int mctrl;
+       spin_lock_irq(&uport->lock);
+       uport->ops->enable_ms(uport);
+       mctrl = uport->ops->get_mctrl(uport);
+       spin_unlock_irq(&uport->lock);
+       if (mctrl & TIOCM_CAR)
+               return 1;
+       return 0;
+}
+
+static void uart_dtr_rts(struct tty_port *port, int onoff)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = state->uart_port;
+
+       if (onoff) {
+               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * If this is the first open to succeed,
+                * adjust things to suit.
+                */
+               if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags))
+                       uart_update_termios(port->tty, state);
+       }
+       else
+               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+}
+
+static struct uart_state *uart_get(struct uart_driver *drv, int line)
+{
+       struct uart_state *state;
+       struct tty_port *port;
+       int ret = 0;
+
+       state = drv->state + line;
+       port = &state->port;
+       if (mutex_lock_interruptible(&port->mutex)) {
+               ret = -ERESTARTSYS;
+               goto err;
+       }
+
+       port->count++;
+       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
+               ret = -ENXIO;
+               goto err_unlock;
+       }
+       return state;
+
+ err_unlock:
+       port->count--;
+       mutex_unlock(&port->mutex);
+ err:
+       return ERR_PTR(ret);
+}
+
+/*
+ * calls to uart_open are serialised by the BKL in
+ *   fs/char_dev.c:chrdev_open()
+ * Note that if this fails, then uart_close() _will_ be called.
+ *
+ * In time, we want to scrap the "opening nonpresent ports"
+ * behaviour and implement an alternative way for setserial
+ * to set base addresses/ports/types.  This will allow us to
+ * get rid of a certain amount of extra tests.
+ */
+static int uart_open(struct tty_struct *tty, struct file *filp)
+{
+       struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+       struct uart_state *state;
+       struct tty_port *port;
+       int retval, line = tty->index;
+
+       BUG_ON(!tty_locked());
+       pr_debug("uart_open(%d) called\n", line);
+
+       /*
+        * tty->driver->num won't change, so we won't fail here with
+        * tty->driver_data set to something non-NULL (and therefore
+        * we won't get caught by uart_close()).
+        */
+       retval = -ENODEV;
+       if (line >= tty->driver->num)
+               goto fail;
+
+       /*
+        * We take the semaphore inside uart_get to guarantee that we won't
+        * be re-entered while allocating the state structure, or while we
+        * request any IRQs that the driver may need.  This also has the nice
+        * side-effect that it delays the action of uart_hangup, so we can
+        * guarantee that state->port.tty will always contain something
+        * reasonable.
+        */
+       state = uart_get(drv, line);
+       if (IS_ERR(state)) {
+               retval = PTR_ERR(state);
+               goto fail;
+       }
+       port = &state->port;
+
+       /*
+        * Once we set tty->driver_data here, we are guaranteed that
+        * uart_close() will decrement the driver module use count.
+        * Any failures from here onwards should not touch the count.
+        */
+       tty->driver_data = state;
+       state->uart_port->state = state;
+       tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+       tty->alt_speed = 0;
+       tty_port_tty_set(port, tty);
+
+       /*
+        * If the port is in the middle of closing, bail out now.
+        */
+       if (tty_hung_up_p(filp)) {
+               retval = -EAGAIN;
+               port->count--;
+               mutex_unlock(&port->mutex);
+               goto fail;
+       }
+
+       /*
+        * Make sure the device is in D0 state.
+        */
+       if (port->count == 1)
+               uart_change_pm(state, 0);
+
+       /*
+        * Start up the serial port.
+        */
+       retval = uart_startup(tty, state, 0);
+
+       /*
+        * If we succeeded, wait until the port is ready.
+        */
+       mutex_unlock(&port->mutex);
+       if (retval == 0)
+               retval = tty_port_block_til_ready(port, tty, filp);
+
+fail:
+       return retval;
+}
+
+static const char *uart_type(struct uart_port *port)
+{
+       const char *str = NULL;
+
+       if (port->ops->type)
+               str = port->ops->type(port);
+
+       if (!str)
+               str = "unknown";
+
+       return str;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
+{
+       struct uart_state *state = drv->state + i;
+       struct tty_port *port = &state->port;
+       int pm_state;
+       struct uart_port *uport = state->uart_port;
+       char stat_buf[32];
+       unsigned int status;
+       int mmio;
+
+       if (!uport)
+               return;
+
+       mmio = uport->iotype >= UPIO_MEM;
+       seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
+                       uport->line, uart_type(uport),
+                       mmio ? "mmio:0x" : "port:",
+                       mmio ? (unsigned long long)uport->mapbase
+                            : (unsigned long long)uport->iobase,
+                       uport->irq);
+
+       if (uport->type == PORT_UNKNOWN) {
+               seq_putc(m, '\n');
+               return;
+       }
+
+       if (capable(CAP_SYS_ADMIN)) {
+               mutex_lock(&port->mutex);
+               pm_state = state->pm_state;
+               if (pm_state)
+                       uart_change_pm(state, 0);
+               spin_lock_irq(&uport->lock);
+               status = uport->ops->get_mctrl(uport);
+               spin_unlock_irq(&uport->lock);
+               if (pm_state)
+                       uart_change_pm(state, pm_state);
+               mutex_unlock(&port->mutex);
+
+               seq_printf(m, " tx:%d rx:%d",
+                               uport->icount.tx, uport->icount.rx);
+               if (uport->icount.frame)
+                       seq_printf(m, " fe:%d",
+                               uport->icount.frame);
+               if (uport->icount.parity)
+                       seq_printf(m, " pe:%d",
+                               uport->icount.parity);
+               if (uport->icount.brk)
+                       seq_printf(m, " brk:%d",
+                               uport->icount.brk);
+               if (uport->icount.overrun)
+                       seq_printf(m, " oe:%d",
+                               uport->icount.overrun);
+
+#define INFOBIT(bit, str) \
+       if (uport->mctrl & (bit)) \
+               strncat(stat_buf, (str), sizeof(stat_buf) - \
+                       strlen(stat_buf) - 2)
+#define STATBIT(bit, str) \
+       if (status & (bit)) \
+               strncat(stat_buf, (str), sizeof(stat_buf) - \
+                      strlen(stat_buf) - 2)
+
+               stat_buf[0] = '\0';
+               stat_buf[1] = '\0';
+               INFOBIT(TIOCM_RTS, "|RTS");
+               STATBIT(TIOCM_CTS, "|CTS");
+               INFOBIT(TIOCM_DTR, "|DTR");
+               STATBIT(TIOCM_DSR, "|DSR");
+               STATBIT(TIOCM_CAR, "|CD");
+               STATBIT(TIOCM_RNG, "|RI");
+               if (stat_buf[0])
+                       stat_buf[0] = ' ';
+
+               seq_puts(m, stat_buf);
+       }
+       seq_putc(m, '\n');
+#undef STATBIT
+#undef INFOBIT
+}
+
+static int uart_proc_show(struct seq_file *m, void *v)
+{
+       struct tty_driver *ttydrv = m->private;
+       struct uart_driver *drv = ttydrv->driver_state;
+       int i;
+
+       seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
+                       "", "", "");
+       for (i = 0; i < drv->nr; i++)
+               uart_line_info(m, drv, i);
+       return 0;
+}
+
+static int uart_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, uart_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations uart_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = uart_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
+/*
+ *     uart_console_write - write a console message to a serial port
+ *     @port: the port to write the message
+ *     @s: array of characters
+ *     @count: number of characters in string to write
+ *     @write: function to write character to port
+ */
+void uart_console_write(struct uart_port *port, const char *s,
+                       unsigned int count,
+                       void (*putchar)(struct uart_port *, int))
+{
+       unsigned int i;
+
+       for (i = 0; i < count; i++, s++) {
+               if (*s == '\n')
+                       putchar(port, '\r');
+               putchar(port, *s);
+       }
+}
+EXPORT_SYMBOL_GPL(uart_console_write);
+
+/*
+ *     Check whether an invalid uart number has been specified, and
+ *     if so, search for the first available port that does have
+ *     console support.
+ */
+struct uart_port * __init
+uart_get_console(struct uart_port *ports, int nr, struct console *co)
+{
+       int idx = co->index;
+
+       if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
+                                    ports[idx].membase == NULL))
+               for (idx = 0; idx < nr; idx++)
+                       if (ports[idx].iobase != 0 ||
+                           ports[idx].membase != NULL)
+                               break;
+
+       co->index = idx;
+
+       return ports + idx;
+}
+
+/**
+ *     uart_parse_options - Parse serial port baud/parity/bits/flow contro.
+ *     @options: pointer to option string
+ *     @baud: pointer to an 'int' variable for the baud rate.
+ *     @parity: pointer to an 'int' variable for the parity.
+ *     @bits: pointer to an 'int' variable for the number of data bits.
+ *     @flow: pointer to an 'int' variable for the flow control character.
+ *
+ *     uart_parse_options decodes a string containing the serial console
+ *     options.  The format of the string is <baud><parity><bits><flow>,
+ *     eg: 115200n8r
+ */
+void
+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+{
+       char *s = options;
+
+       *baud = simple_strtoul(s, NULL, 10);
+       while (*s >= '0' && *s <= '9')
+               s++;
+       if (*s)
+               *parity = *s++;
+       if (*s)
+               *bits = *s++ - '0';
+       if (*s)
+               *flow = *s;
+}
+EXPORT_SYMBOL_GPL(uart_parse_options);
+
+struct baud_rates {
+       unsigned int rate;
+       unsigned int cflag;
+};
+
+static const struct baud_rates baud_rates[] = {
+       { 921600, B921600 },
+       { 460800, B460800 },
+       { 230400, B230400 },
+       { 115200, B115200 },
+       {  57600, B57600  },
+       {  38400, B38400  },
+       {  19200, B19200  },
+       {   9600, B9600   },
+       {   4800, B4800   },
+       {   2400, B2400   },
+       {   1200, B1200   },
+       {      0, B38400  }
+};
+
+/**
+ *     uart_set_options - setup the serial console parameters
+ *     @port: pointer to the serial ports uart_port structure
+ *     @co: console pointer
+ *     @baud: baud rate
+ *     @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
+ *     @bits: number of data bits
+ *     @flow: flow control character - 'r' (rts)
+ */
+int
+uart_set_options(struct uart_port *port, struct console *co,
+                int baud, int parity, int bits, int flow)
+{
+       struct ktermios termios;
+       static struct ktermios dummy;
+       int i;
+
+       /*
+        * Ensure that the serial console lock is initialised
+        * early.
+        */
+       spin_lock_init(&port->lock);
+       lockdep_set_class(&port->lock, &port_lock_key);
+
+       memset(&termios, 0, sizeof(struct ktermios));
+
+       termios.c_cflag = CREAD | HUPCL | CLOCAL;
+
+       /*
+        * Construct a cflag setting.
+        */
+       for (i = 0; baud_rates[i].rate; i++)
+               if (baud_rates[i].rate <= baud)
+                       break;
+
+       termios.c_cflag |= baud_rates[i].cflag;
+
+       if (bits == 7)
+               termios.c_cflag |= CS7;
+       else
+               termios.c_cflag |= CS8;
+
+       switch (parity) {
+       case 'o': case 'O':
+               termios.c_cflag |= PARODD;
+               /*fall through*/
+       case 'e': case 'E':
+               termios.c_cflag |= PARENB;
+               break;
+       }
+
+       if (flow == 'r')
+               termios.c_cflag |= CRTSCTS;
+
+       /*
+        * some uarts on other side don't support no flow control.
+        * So we set * DTR in host uart to make them happy
+        */
+       port->mctrl |= TIOCM_DTR;
+
+       port->ops->set_termios(port, &termios, &dummy);
+       /*
+        * Allow the setting of the UART parameters with a NULL console
+        * too:
+        */
+       if (co)
+               co->cflag = termios.c_cflag;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uart_set_options);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+
+static void uart_change_pm(struct uart_state *state, int pm_state)
+{
+       struct uart_port *port = state->uart_port;
+
+       if (state->pm_state != pm_state) {
+               if (port->ops->pm)
+                       port->ops->pm(port, pm_state, state->pm_state);
+               state->pm_state = pm_state;
+       }
+}
+
+struct uart_match {
+       struct uart_port *port;
+       struct uart_driver *driver;
+};
+
+static int serial_match_port(struct device *dev, void *data)
+{
+       struct uart_match *match = data;
+       struct tty_driver *tty_drv = match->driver->tty_driver;
+       dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+               match->port->line;
+
+       return dev->devt == devt; /* Actually, only one tty per port */
+}
+
+int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+       struct device *tty_dev;
+       struct uart_match match = {uport, drv};
+       struct tty_struct *tty;
+
+       mutex_lock(&port->mutex);
+
+       /* Must be inside the mutex lock until we convert to tty_port */
+       tty = port->tty;
+
+       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+       if (device_may_wakeup(tty_dev)) {
+               if (!enable_irq_wake(uport->irq))
+                       uport->irq_wake = 1;
+               put_device(tty_dev);
+               mutex_unlock(&port->mutex);
+               return 0;
+       }
+       if (console_suspend_enabled || !uart_console(uport))
+               uport->suspended = 1;
+
+       if (port->flags & ASYNC_INITIALIZED) {
+               const struct uart_ops *ops = uport->ops;
+               int tries;
+
+               if (console_suspend_enabled || !uart_console(uport)) {
+                       set_bit(ASYNCB_SUSPENDED, &port->flags);
+                       clear_bit(ASYNCB_INITIALIZED, &port->flags);
+
+                       spin_lock_irq(&uport->lock);
+                       ops->stop_tx(uport);
+                       ops->set_mctrl(uport, 0);
+                       ops->stop_rx(uport);
+                       spin_unlock_irq(&uport->lock);
+               }
+
+               /*
+                * Wait for the transmitter to empty.
+                */
+               for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
+                       msleep(10);
+               if (!tries)
+                       printk(KERN_ERR "%s%s%s%d: Unable to drain "
+                                       "transmitter\n",
+                              uport->dev ? dev_name(uport->dev) : "",
+                              uport->dev ? ": " : "",
+                              drv->dev_name,
+                              drv->tty_driver->name_base + uport->line);
+
+               if (console_suspend_enabled || !uart_console(uport))
+                       ops->shutdown(uport);
+       }
+
+       /*
+        * Disable the console device before suspending.
+        */
+       if (console_suspend_enabled && uart_console(uport))
+               console_stop(uport->cons);
+
+       if (console_suspend_enabled || !uart_console(uport))
+               uart_change_pm(state, 3);
+
+       mutex_unlock(&port->mutex);
+
+       return 0;
+}
+
+int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+       struct device *tty_dev;
+       struct uart_match match = {uport, drv};
+       struct ktermios termios;
+
+       mutex_lock(&port->mutex);
+
+       tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+       if (!uport->suspended && device_may_wakeup(tty_dev)) {
+               if (uport->irq_wake) {
+                       disable_irq_wake(uport->irq);
+                       uport->irq_wake = 0;
+               }
+               mutex_unlock(&port->mutex);
+               return 0;
+       }
+       uport->suspended = 0;
+
+       /*
+        * Re-enable the console device after suspending.
+        */
+       if (console_suspend_enabled && uart_console(uport)) {
+               /*
+                * First try to use the console cflag setting.
+                */
+               memset(&termios, 0, sizeof(struct ktermios));
+               termios.c_cflag = uport->cons->cflag;
+
+               /*
+                * If that's unset, use the tty termios setting.
+                */
+               if (port->tty && port->tty->termios && termios.c_cflag == 0)
+                       termios = *(port->tty->termios);
+
+               uart_change_pm(state, 0);
+               uport->ops->set_termios(uport, &termios, NULL);
+               console_start(uport->cons);
+       }
+
+       if (port->flags & ASYNC_SUSPENDED) {
+               const struct uart_ops *ops = uport->ops;
+               int ret;
+
+               uart_change_pm(state, 0);
+               spin_lock_irq(&uport->lock);
+               ops->set_mctrl(uport, 0);
+               spin_unlock_irq(&uport->lock);
+               if (console_suspend_enabled || !uart_console(uport)) {
+                       /* Protected by port mutex for now */
+                       struct tty_struct *tty = port->tty;
+                       ret = ops->startup(uport);
+                       if (ret == 0) {
+                               if (tty)
+                                       uart_change_speed(tty, state, NULL);
+                               spin_lock_irq(&uport->lock);
+                               ops->set_mctrl(uport, uport->mctrl);
+                               ops->start_tx(uport);
+                               spin_unlock_irq(&uport->lock);
+                               set_bit(ASYNCB_INITIALIZED, &port->flags);
+                       } else {
+                               /*
+                                * Failed to resume - maybe hardware went away?
+                                * Clear the "initialized" flag so we won't try
+                                * to call the low level drivers shutdown method.
+                                */
+                               uart_shutdown(tty, state);
+                       }
+               }
+
+               clear_bit(ASYNCB_SUSPENDED, &port->flags);
+       }
+
+       mutex_unlock(&port->mutex);
+
+       return 0;
+}
+
+static inline void
+uart_report_port(struct uart_driver *drv, struct uart_port *port)
+{
+       char address[64];
+
+       switch (port->iotype) {
+       case UPIO_PORT:
+               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
+               break;
+       case UPIO_HUB6:
+               snprintf(address, sizeof(address),
+                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
+               break;
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               snprintf(address, sizeof(address),
+                        "MMIO 0x%llx", (unsigned long long)port->mapbase);
+               break;
+       default:
+               strlcpy(address, "*unknown*", sizeof(address));
+               break;
+       }
+
+       printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
+              port->dev ? dev_name(port->dev) : "",
+              port->dev ? ": " : "",
+              drv->dev_name,
+              drv->tty_driver->name_base + port->line,
+              address, port->irq, uart_type(port));
+}
+
+static void
+uart_configure_port(struct uart_driver *drv, struct uart_state *state,
+                   struct uart_port *port)
+{
+       unsigned int flags;
+
+       /*
+        * If there isn't a port here, don't do anything further.
+        */
+       if (!port->iobase && !port->mapbase && !port->membase)
+               return;
+
+       /*
+        * Now do the auto configuration stuff.  Note that config_port
+        * is expected to claim the resources and map the port for us.
+        */
+       flags = 0;
+       if (port->flags & UPF_AUTO_IRQ)
+               flags |= UART_CONFIG_IRQ;
+       if (port->flags & UPF_BOOT_AUTOCONF) {
+               if (!(port->flags & UPF_FIXED_TYPE)) {
+                       port->type = PORT_UNKNOWN;
+                       flags |= UART_CONFIG_TYPE;
+               }
+               port->ops->config_port(port, flags);
+       }
+
+       if (port->type != PORT_UNKNOWN) {
+               unsigned long flags;
+
+               uart_report_port(drv, port);
+
+               /* Power up port for set_mctrl() */
+               uart_change_pm(state, 0);
+
+               /*
+                * Ensure that the modem control lines are de-activated.
+                * keep the DTR setting that is set in uart_set_options()
+                * We probably don't need a spinlock around this, but
+                */
+               spin_lock_irqsave(&port->lock, flags);
+               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
+               spin_unlock_irqrestore(&port->lock, flags);
+
+               /*
+                * If this driver supports console, and it hasn't been
+                * successfully registered yet, try to re-register it.
+                * It may be that the port was not available.
+                */
+               if (port->cons && !(port->cons->flags & CON_ENABLED))
+                       register_console(port->cons);
+
+               /*
+                * Power down all ports by default, except the
+                * console if we have one.
+                */
+               if (!uart_console(port))
+                       uart_change_pm(state, 3);
+       }
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int uart_poll_init(struct tty_driver *driver, int line, char *options)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (!state || !state->uart_port)
+               return -1;
+
+       port = state->uart_port;
+       if (!(port->ops->poll_get_char && port->ops->poll_put_char))
+               return -1;
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+               return uart_set_options(port, NULL, baud, parity, bits, flow);
+       }
+
+       return 0;
+}
+
+static int uart_poll_get_char(struct tty_driver *driver, int line)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+
+       if (!state || !state->uart_port)
+               return -1;
+
+       port = state->uart_port;
+       return port->ops->poll_get_char(port);
+}
+
+static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
+{
+       struct uart_driver *drv = driver->driver_state;
+       struct uart_state *state = drv->state + line;
+       struct uart_port *port;
+
+       if (!state || !state->uart_port)
+               return;
+
+       port = state->uart_port;
+       port->ops->poll_put_char(port, ch);
+}
+#endif
+
+static const struct tty_operations uart_ops = {
+       .open           = uart_open,
+       .close          = uart_close,
+       .write          = uart_write,
+       .put_char       = uart_put_char,
+       .flush_chars    = uart_flush_chars,
+       .write_room     = uart_write_room,
+       .chars_in_buffer= uart_chars_in_buffer,
+       .flush_buffer   = uart_flush_buffer,
+       .ioctl          = uart_ioctl,
+       .throttle       = uart_throttle,
+       .unthrottle     = uart_unthrottle,
+       .send_xchar     = uart_send_xchar,
+       .set_termios    = uart_set_termios,
+       .set_ldisc      = uart_set_ldisc,
+       .stop           = uart_stop,
+       .start          = uart_start,
+       .hangup         = uart_hangup,
+       .break_ctl      = uart_break_ctl,
+       .wait_until_sent= uart_wait_until_sent,
+#ifdef CONFIG_PROC_FS
+       .proc_fops      = &uart_proc_fops,
+#endif
+       .tiocmget       = uart_tiocmget,
+       .tiocmset       = uart_tiocmset,
+       .get_icount     = uart_get_icount,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_init      = uart_poll_init,
+       .poll_get_char  = uart_poll_get_char,
+       .poll_put_char  = uart_poll_put_char,
+#endif
+};
+
+static const struct tty_port_operations uart_port_ops = {
+       .carrier_raised = uart_carrier_raised,
+       .dtr_rts        = uart_dtr_rts,
+};
+
+/**
+ *     uart_register_driver - register a driver with the uart core layer
+ *     @drv: low level driver structure
+ *
+ *     Register a uart driver with the core driver.  We in turn register
+ *     with the tty layer, and initialise the core driver per-port state.
+ *
+ *     We have a proc file in /proc/tty/driver which is named after the
+ *     normal driver.
+ *
+ *     drv->port should be NULL, and the per-port structures should be
+ *     registered using uart_add_one_port after this call has succeeded.
+ */
+int uart_register_driver(struct uart_driver *drv)
+{
+       struct tty_driver *normal;
+       int i, retval;
+
+       BUG_ON(drv->state);
+
+       /*
+        * Maybe we should be using a slab cache for this, especially if
+        * we have a large number of ports to handle.
+        */
+       drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
+       if (!drv->state)
+               goto out;
+
+       normal = alloc_tty_driver(drv->nr);
+       if (!normal)
+               goto out_kfree;
+
+       drv->tty_driver = normal;
+
+       normal->owner           = drv->owner;
+       normal->driver_name     = drv->driver_name;
+       normal->name            = drv->dev_name;
+       normal->major           = drv->major;
+       normal->minor_start     = drv->minor;
+       normal->type            = TTY_DRIVER_TYPE_SERIAL;
+       normal->subtype         = SERIAL_TYPE_NORMAL;
+       normal->init_termios    = tty_std_termios;
+       normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
+       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       normal->driver_state    = drv;
+       tty_set_operations(normal, &uart_ops);
+
+       /*
+        * Initialise the UART state(s).
+        */
+       for (i = 0; i < drv->nr; i++) {
+               struct uart_state *state = drv->state + i;
+               struct tty_port *port = &state->port;
+
+               tty_port_init(port);
+               port->ops = &uart_port_ops;
+               port->close_delay     = 500;    /* .5 seconds */
+               port->closing_wait    = 30000;  /* 30 seconds */
+               tasklet_init(&state->tlet, uart_tasklet_action,
+                            (unsigned long)state);
+       }
+
+       retval = tty_register_driver(normal);
+       if (retval >= 0)
+               return retval;
+
+       put_tty_driver(normal);
+out_kfree:
+       kfree(drv->state);
+out:
+       return -ENOMEM;
+}
+
+/**
+ *     uart_unregister_driver - remove a driver from the uart core layer
+ *     @drv: low level driver structure
+ *
+ *     Remove all references to a driver from the core driver.  The low
+ *     level driver must have removed all its ports via the
+ *     uart_remove_one_port() if it registered them with uart_add_one_port().
+ *     (ie, drv->port == NULL)
+ */
+void uart_unregister_driver(struct uart_driver *drv)
+{
+       struct tty_driver *p = drv->tty_driver;
+       tty_unregister_driver(p);
+       put_tty_driver(p);
+       kfree(drv->state);
+       drv->tty_driver = NULL;
+}
+
+struct tty_driver *uart_console_device(struct console *co, int *index)
+{
+       struct uart_driver *p = co->data;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+/**
+ *     uart_add_one_port - attach a driver-defined port structure
+ *     @drv: pointer to the uart low level driver structure for this port
+ *     @uport: uart port structure to use for this port.
+ *
+ *     This allows the driver to register its own uart_port structure
+ *     with the core driver.  The main purpose is to allow the low
+ *     level uart drivers to expand uart_port, rather than having yet
+ *     more levels of structures.
+ */
+int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state;
+       struct tty_port *port;
+       int ret = 0;
+       struct device *tty_dev;
+
+       BUG_ON(in_interrupt());
+
+       if (uport->line >= drv->nr)
+               return -EINVAL;
+
+       state = drv->state + uport->line;
+       port = &state->port;
+
+       mutex_lock(&port_mutex);
+       mutex_lock(&port->mutex);
+       if (state->uart_port) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       state->uart_port = uport;
+       state->pm_state = -1;
+
+       uport->cons = drv->cons;
+       uport->state = state;
+
+       /*
+        * If this port is a console, then the spinlock is already
+        * initialised.
+        */
+       if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
+               spin_lock_init(&uport->lock);
+               lockdep_set_class(&uport->lock, &port_lock_key);
+       }
+
+       uart_configure_port(drv, state, uport);
+
+       /*
+        * Register the port whether it's detected or not.  This allows
+        * setserial to be used to alter this ports parameters.
+        */
+       tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+       if (likely(!IS_ERR(tty_dev))) {
+               device_init_wakeup(tty_dev, 1);
+               device_set_wakeup_enable(tty_dev, 0);
+       } else
+               printk(KERN_ERR "Cannot register tty device on line %d\n",
+                      uport->line);
+
+       /*
+        * Ensure UPF_DEAD is not set.
+        */
+       uport->flags &= ~UPF_DEAD;
+
+ out:
+       mutex_unlock(&port->mutex);
+       mutex_unlock(&port_mutex);
+
+       return ret;
+}
+
+/**
+ *     uart_remove_one_port - detach a driver defined port structure
+ *     @drv: pointer to the uart low level driver structure for this port
+ *     @uport: uart port structure for this port
+ *
+ *     This unhooks (and hangs up) the specified port structure from the
+ *     core driver.  No further calls will be made to the low-level code
+ *     for this port.
+ */
+int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
+{
+       struct uart_state *state = drv->state + uport->line;
+       struct tty_port *port = &state->port;
+
+       BUG_ON(in_interrupt());
+
+       if (state->uart_port != uport)
+               printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+                       state->uart_port, uport);
+
+       mutex_lock(&port_mutex);
+
+       /*
+        * Mark the port "dead" - this prevents any opens from
+        * succeeding while we shut down the port.
+        */
+       mutex_lock(&port->mutex);
+       uport->flags |= UPF_DEAD;
+       mutex_unlock(&port->mutex);
+
+       /*
+        * Remove the devices from the tty layer
+        */
+       tty_unregister_device(drv->tty_driver, uport->line);
+
+       if (port->tty)
+               tty_vhangup(port->tty);
+
+       /*
+        * Free the port IO and memory resources, if any.
+        */
+       if (uport->type != PORT_UNKNOWN)
+               uport->ops->release_port(uport);
+
+       /*
+        * Indicate that there isn't a port here anymore.
+        */
+       uport->type = PORT_UNKNOWN;
+
+       /*
+        * Kill the tasklet, and free resources.
+        */
+       tasklet_kill(&state->tlet);
+
+       state->uart_port = NULL;
+       mutex_unlock(&port_mutex);
+
+       return 0;
+}
+
+/*
+ *     Are the two ports equivalent?
+ */
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+{
+       if (port1->iotype != port2->iotype)
+               return 0;
+
+       switch (port1->iotype) {
+       case UPIO_PORT:
+               return (port1->iobase == port2->iobase);
+       case UPIO_HUB6:
+               return (port1->iobase == port2->iobase) &&
+                      (port1->hub6   == port2->hub6);
+       case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
+       case UPIO_DWAPB32:
+               return (port1->mapbase == port2->mapbase);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(uart_match_port);
+
+EXPORT_SYMBOL(uart_write_wakeup);
+EXPORT_SYMBOL(uart_register_driver);
+EXPORT_SYMBOL(uart_unregister_driver);
+EXPORT_SYMBOL(uart_suspend_port);
+EXPORT_SYMBOL(uart_resume_port);
+EXPORT_SYMBOL(uart_add_one_port);
+EXPORT_SYMBOL(uart_remove_one_port);
+
+MODULE_DESCRIPTION("Serial driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_cs.c b/drivers/tty/serial/serial_cs.c
new file mode 100644 (file)
index 0000000..1ef4df9
--- /dev/null
@@ -0,0 +1,870 @@
+/*======================================================================
+
+    A driver for PCMCIA serial devices
+
+    serial_cs.c 1.134 2002/05/04 05:48:53
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "8250.h"
+
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Enable the speaker? */
+static int do_sound = 1;
+/* Skip strict UART tests? */
+static int buggy_uart;
+
+module_param(do_sound, int, 0444);
+module_param(buggy_uart, int, 0444);
+
+/*====================================================================*/
+
+/* Table of multi-port card ID's */
+
+struct serial_quirk {
+       unsigned int manfid;
+       unsigned int prodid;
+       int multi;              /* 1 = multifunction, > 1 = # ports */
+       void (*config)(struct pcmcia_device *);
+       void (*setup)(struct pcmcia_device *, struct uart_port *);
+       void (*wakeup)(struct pcmcia_device *);
+       int (*post)(struct pcmcia_device *);
+};
+
+struct serial_info {
+       struct pcmcia_device    *p_dev;
+       int                     ndev;
+       int                     multi;
+       int                     slave;
+       int                     manfid;
+       int                     prodid;
+       int                     c950ctrl;
+       int                     line[4];
+       const struct serial_quirk *quirk;
+};
+
+struct serial_cfg_mem {
+       tuple_t tuple;
+       cisparse_t parse;
+       u_char buf[256];
+};
+
+/*
+ * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
+ * manfid 0x0160, 0x0104
+ * This card appears to have a 14.7456MHz clock.
+ */
+/* Generic Modem: MD55x (GPRS/EDGE) have
+ * Elan VPU16551 UART with 14.7456MHz oscillator
+ * manfid 0x015D, 0x4C45
+ */
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+{
+       port->uartclk = 14745600;
+}
+
+static int quirk_post_ibm(struct pcmcia_device *link)
+{
+       u8 val;
+       int ret;
+
+       ret = pcmcia_read_config_byte(link, 0x800, &val);
+       if (ret)
+               goto failed;
+
+       ret = pcmcia_write_config_byte(link, 0x800, val | 1);
+       if (ret)
+               goto failed;
+       return 0;
+
+ failed:
+       return -ENODEV;
+}
+
+/*
+ * Nokia cards are not really multiport cards.  Shouldn't this
+ * be handled by setting the quirk entry .multi = 0 | 1 ?
+ */
+static void quirk_config_nokia(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->multi > 1)
+               info->multi = 1;
+}
+
+static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->c950ctrl)
+               outb(12, info->c950ctrl + 1);
+}
+
+/* request_region? oxsemi branch does no request_region too... */
+/*
+ * This sequence is needed to properly initialize MC45 attached to OXCF950.
+ * I tried decreasing these msleep()s, but it worked properly (survived
+ * 1000 stop/start operations) with these timeouts (or bigger).
+ */
+static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       unsigned int ctrl = info->c950ctrl;
+
+       outb(0xA, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(300);
+       outb(0xC, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(200);
+       outb(0xF, ctrl + 1);
+       msleep(100);
+       outb(0xE, ctrl + 1);
+       msleep(100);
+       outb(0xC, ctrl + 1);
+}
+
+/*
+ * Socket Dual IO: this enables irq's for second port
+ */
+static void quirk_config_socket(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       if (info->multi)
+               link->config_flags |= CONF_ENABLE_ESR;
+}
+
+static const struct serial_quirk quirks[] = {
+       {
+               .manfid = 0x0160,
+               .prodid = 0x0104,
+               .multi  = -1,
+               .setup  = quirk_setup_brainboxes_0104,
+       }, {
+               .manfid = 0x015D,
+               .prodid = 0x4C45,
+               .multi  = -1,
+               .setup  = quirk_setup_brainboxes_0104,
+       }, {
+               .manfid = MANFID_IBM,
+               .prodid = ~0,
+               .multi  = -1,
+               .post   = quirk_post_ibm,
+       }, {
+               .manfid = MANFID_INTEL,
+               .prodid = PRODID_INTEL_DUAL_RS232,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_NATINST,
+               .prodid = PRODID_NATINST_QUAD_RS232,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_NOKIA,
+               .prodid = ~0,
+               .multi  = -1,
+               .config = quirk_config_nokia,
+       }, {
+               .manfid = MANFID_OMEGA,
+               .prodid = PRODID_OMEGA_QSP_100,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_OXSEMI,
+               .prodid = ~0,
+               .multi  = -1,
+               .wakeup = quirk_wakeup_oxsemi,
+       }, {
+               .manfid = MANFID_POSSIO,
+               .prodid = PRODID_POSSIO_GCC,
+               .multi  = -1,
+               .wakeup = quirk_wakeup_possio_gcc,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232_D1,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_DUAL_RS232_G,
+               .multi  = 2,
+       }, {
+               .manfid = MANFID_QUATECH,
+               .prodid = PRODID_QUATECH_QUAD_RS232,
+               .multi  = 4,
+       }, {
+               .manfid = MANFID_SOCKET,
+               .prodid = PRODID_SOCKET_DUAL_RS232,
+               .multi  = 2,
+               .config = quirk_config_socket,
+       }, {
+               .manfid = MANFID_SOCKET,
+               .prodid = ~0,
+               .multi  = -1,
+               .config = quirk_config_socket,
+       }
+};
+
+
+static int serial_config(struct pcmcia_device * link);
+
+
+static void serial_remove(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       dev_dbg(&link->dev, "serial_release\n");
+
+       /*
+        * Recheck to see if the device is still configured.
+        */
+       for (i = 0; i < info->ndev; i++)
+               serial8250_unregister_port(info->line[i]);
+
+       if (!info->slave)
+               pcmcia_disable_device(link);
+}
+
+static int serial_suspend(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       for (i = 0; i < info->ndev; i++)
+               serial8250_suspend_port(info->line[i]);
+
+       return 0;
+}
+
+static int serial_resume(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       for (i = 0; i < info->ndev; i++)
+               serial8250_resume_port(info->line[i]);
+
+       if (info->quirk && info->quirk->wakeup)
+               info->quirk->wakeup(link);
+
+       return 0;
+}
+
+static int serial_probe(struct pcmcia_device *link)
+{
+       struct serial_info *info;
+
+       dev_dbg(&link->dev, "serial_attach()\n");
+
+       /* Create new serial device */
+       info = kzalloc(sizeof (*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->p_dev = link;
+       link->priv = info;
+
+       link->config_flags |= CONF_ENABLE_IRQ;
+       if (do_sound)
+               link->config_flags |= CONF_ENABLE_SPKR;
+
+       return serial_config(link);
+}
+
+static void serial_detach(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+
+       dev_dbg(&link->dev, "serial_detach\n");
+
+       /*
+        * Ensure that the ports have been released.
+        */
+       serial_remove(link);
+
+       /* free bits */
+       kfree(info);
+}
+
+/*====================================================================*/
+
+static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+                       unsigned int iobase, int irq)
+{
+       struct uart_port port;
+       int line;
+
+       memset(&port, 0, sizeof (struct uart_port));
+       port.iobase = iobase;
+       port.irq = irq;
+       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       port.uartclk = 1843200;
+       port.dev = &handle->dev;
+       if (buggy_uart)
+               port.flags |= UPF_BUGGY_UART;
+
+       if (info->quirk && info->quirk->setup)
+               info->quirk->setup(handle, &port);
+
+       line = serial8250_register_port(&port);
+       if (line < 0) {
+               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
+                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
+               return -EINVAL;
+       }
+
+       info->line[info->ndev] = line;
+       info->ndev++;
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int pfc_config(struct pcmcia_device *p_dev)
+{
+       unsigned int port = 0;
+       struct serial_info *info = p_dev->priv;
+
+       if ((p_dev->resource[1]->end != 0) &&
+               (resource_size(p_dev->resource[1]) == 8)) {
+               port = p_dev->resource[1]->start;
+               info->slave = 1;
+       } else if ((info->manfid == MANFID_OSITECH) &&
+               (resource_size(p_dev->resource[0]) == 0x40)) {
+               port = p_dev->resource[0]->start + 0x28;
+               info->slave = 1;
+       }
+       if (info->slave)
+               return setup_serial(p_dev, info, port, p_dev->irq);
+
+       dev_warn(&p_dev->dev, "no usable port range found, giving up\n");
+       return -ENODEV;
+}
+
+static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       static const int size_table[2] = { 8, 16 };
+       int *try = priv_data;
+
+       if (p_dev->resource[0]->start == 0)
+               return -ENODEV;
+
+       if ((*try & 0x1) == 0)
+               p_dev->io_lines = 16;
+
+       if (p_dev->resource[0]->end != size_table[(*try >> 1)])
+               return -ENODEV;
+
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
+}
+
+static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
+                                       void *priv_data)
+{
+       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       int j;
+
+       if (p_dev->io_lines > 3)
+               return -ENODEV;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 8;
+
+       for (j = 0; j < 5; j++) {
+               p_dev->resource[0]->start = base[j];
+               p_dev->io_lines = base[j] ? 16 : 3;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
+static int simple_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i = -ENODEV, try;
+
+       /* First pass: look for a config entry that looks normal.
+        * Two tries: without IO aliases, then with aliases */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
+       for (try = 0; try < 4; try++)
+               if (!pcmcia_loop_config(link, simple_config_check, &try))
+                       goto found_port;
+
+       /* Second pass: try to find an entry that isn't picky about
+          its base address, then try to grab any standard serial port
+          address, and finally try to get any free port. */
+       if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
+               goto found_port;
+
+       dev_warn(&link->dev, "no usable port range found, giving up\n");
+       return -1;
+
+found_port:
+       if (info->multi && (info->manfid == MANFID_3COM))
+               link->config_index &= ~(0x08);
+
+       /*
+        * Apply any configuration quirks.
+        */
+       if (info->quirk && info->quirk->config)
+               info->quirk->config(link);
+
+       i = pcmcia_enable_device(link);
+       if (i != 0)
+               return -1;
+       return setup_serial(link, info, link->resource[0]->start, link->irq);
+}
+
+static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       int *multi = priv_data;
+
+       if (p_dev->resource[1]->end)
+               return -EINVAL;
+
+       /* The quad port cards have bad CIS's, so just look for a
+          window larger than 8 ports and assume it will be right */
+       if (p_dev->resource[0]->end <= 8)
+               return -EINVAL;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = *multi * 8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+       return 0;
+}
+
+static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
+                                      void *priv_data)
+{
+       int *base2 = priv_data;
+
+       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
+               return -ENODEV;
+
+       p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+
+       *base2 = p_dev->resource[0]->start + 8;
+       return 0;
+}
+
+static int multi_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i, base2 = 0;
+
+       link->config_flags |= CONF_AUTO_SET_IO;
+       /* First, look for a generic full-sized window */
+       if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
+               base2 = link->resource[0]->start + 8;
+       else {
+               /* If that didn't work, look for two windows */
+               info->multi = 2;
+               if (pcmcia_loop_config(link, multi_config_check_notpicky,
+                                      &base2)) {
+                       dev_warn(&link->dev, "no usable port range "
+                              "found, giving up\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (!link->irq)
+               dev_warn(&link->dev, "no usable IRQ found, continuing...\n");
+
+       /*
+        * Apply any configuration quirks.
+        */
+       if (info->quirk && info->quirk->config)
+               info->quirk->config(link);
+
+       i = pcmcia_enable_device(link);
+       if (i != 0)
+               return -ENODEV;
+
+       /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+        * 8 registers are for the UART, the others are extra registers.
+        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+        */
+       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+                               info->prodid == PRODID_POSSIO_GCC)) {
+               int err;
+
+               if (link->config_index == 1 ||
+                   link->config_index == 3) {
+                       err = setup_serial(link, info, base2,
+                                       link->irq);
+                       base2 = link->resource[0]->start;
+               } else {
+                       err = setup_serial(link, info, link->resource[0]->start,
+                                       link->irq);
+               }
+               info->c950ctrl = base2;
+
+               /*
+                * FIXME: We really should wake up the port prior to
+                * handing it over to the serial layer.
+                */
+               if (info->quirk && info->quirk->wakeup)
+                       info->quirk->wakeup(link);
+
+               return 0;
+       }
+
+       setup_serial(link, info, link->resource[0]->start, link->irq);
+       for (i = 0; i < info->multi - 1; i++)
+               setup_serial(link, info, base2 + (8 * i),
+                               link->irq);
+       return 0;
+}
+
+static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)
+{
+       struct serial_info *info = p_dev->priv;
+
+       if (!p_dev->resource[0]->end)
+               return -EINVAL;
+
+       if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
+               info->multi = p_dev->resource[0]->end >> 3;
+
+       if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
+               && (p_dev->resource[1]->end == 8))
+               info->multi = 2;
+
+       return 0; /* break */
+}
+
+
+static int serial_config(struct pcmcia_device * link)
+{
+       struct serial_info *info = link->priv;
+       int i;
+
+       dev_dbg(&link->dev, "serial_config\n");
+
+       /* Is this a compliant multifunction card? */
+       info->multi = (link->socket->functions > 1);
+
+       /* Is this a multiport card? */
+       info->manfid = link->manf_id;
+       info->prodid = link->card_id;
+
+       for (i = 0; i < ARRAY_SIZE(quirks); i++)
+               if ((quirks[i].manfid == ~0 ||
+                    quirks[i].manfid == info->manfid) &&
+                   (quirks[i].prodid == ~0 ||
+                    quirks[i].prodid == info->prodid)) {
+                       info->quirk = &quirks[i];
+                       break;
+               }
+
+       /* Another check for dual-serial cards: look for either serial or
+          multifunction cards that ask for appropriate IO port ranges */
+       if ((info->multi == 0) &&
+           (link->has_func_id) &&
+           (link->socket->pcmcia_pfc == 0) &&
+           ((link->func_id == CISTPL_FUNCID_MULTI) ||
+            (link->func_id == CISTPL_FUNCID_SERIAL)))
+               pcmcia_loop_config(link, serial_check_for_multi, info);
+
+       /*
+        * Apply any multi-port quirk.
+        */
+       if (info->quirk && info->quirk->multi != -1)
+               info->multi = info->quirk->multi;
+
+       dev_info(&link->dev,
+               "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n",
+               link->manf_id, link->card_id,
+               link->socket->pcmcia_pfc, info->multi, info->quirk);
+       if (link->socket->pcmcia_pfc)
+               i = pfc_config(link);
+       else if (info->multi > 1)
+               i = multi_config(link);
+       else
+               i = simple_config(link);
+
+       if (i || info->ndev == 0)
+               goto failed;
+
+       /*
+        * Apply any post-init quirk.  FIXME: This should really happen
+        * before we register the port, since it might already be in use.
+        */
+       if (info->quirk && info->quirk->post)
+               if (info->quirk->post(link))
+                       goto failed;
+
+       return 0;
+
+failed:
+       dev_warn(&link->dev, "failed to initialize\n");
+       serial_remove(link);
+       return -ENODEV;
+}
+
+static struct pcmcia_device_id serial_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0b05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
+       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+       PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+       PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
+       PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
+       PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
+       PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
+       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
+       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+       PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
+       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
+       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
+       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
+       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
+       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
+       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
+       PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
+       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
+       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
+       PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
+       PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
+       PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"),  /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"),  /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
+       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100  1.00.",0x19ca78af,0xf964f42b),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232  1.00.",0x19ca78af,0x69fb7490),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
+       PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
+       PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+       PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
+       /* too generic */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
+       PCMCIA_DEVICE_FUNC_ID(2),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, serial_ids);
+
+MODULE_FIRMWARE("cis/PCMLM28.cis");
+MODULE_FIRMWARE("cis/DP83903.cis");
+MODULE_FIRMWARE("cis/3CCFEM556.cis");
+MODULE_FIRMWARE("cis/3CXEM556.cis");
+MODULE_FIRMWARE("cis/SW_8xx_SER.cis");
+MODULE_FIRMWARE("cis/SW_7xx_SER.cis");
+MODULE_FIRMWARE("cis/SW_555_SER.cis");
+MODULE_FIRMWARE("cis/MT5634ZLX.cis");
+MODULE_FIRMWARE("cis/COMpad2.cis");
+MODULE_FIRMWARE("cis/COMpad4.cis");
+MODULE_FIRMWARE("cis/RS-COM-2P.cis");
+
+static struct pcmcia_driver serial_cs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "serial_cs",
+       .probe          = serial_probe,
+       .remove         = serial_detach,
+       .id_table       = serial_ids,
+       .suspend        = serial_suspend,
+       .resume         = serial_resume,
+};
+
+static int __init init_serial_cs(void)
+{
+       return pcmcia_register_driver(&serial_cs_driver);
+}
+
+static void __exit exit_serial_cs(void)
+{
+       pcmcia_unregister_driver(&serial_cs_driver);
+}
+
+module_init(init_serial_cs);
+module_exit(exit_serial_cs);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
new file mode 100644 (file)
index 0000000..b196202
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ *  drivers/serial/serial_ks8695.c
+ *
+ *  Driver for KS8695 serial ports
+ *
+ *  Based on drivers/serial/serial_amba.c, by Kam Lee.
+ *
+ *  Copyright 2002-2005 Micrel Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/regs-uart.h>
+#include <mach/regs-irq.h>
+
+#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+#define SERIAL_KS8695_MAJOR    204
+#define SERIAL_KS8695_MINOR    16
+#define SERIAL_KS8695_DEVNAME  "ttyAM"
+
+#define SERIAL_KS8695_NR       1
+
+/*
+ * Access macros for the KS8695 UART
+ */
+#define UART_GET_CHAR(p)       (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
+#define UART_PUT_CHAR(p, c)    __raw_writel((c), (p)->membase + KS8695_URTH)
+#define UART_GET_FCR(p)                __raw_readl((p)->membase + KS8695_URFC)
+#define UART_PUT_FCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URFC)
+#define UART_GET_MSR(p)                __raw_readl((p)->membase + KS8695_URMS)
+#define UART_GET_LSR(p)                __raw_readl((p)->membase + KS8695_URLS)
+#define UART_GET_LCR(p)                __raw_readl((p)->membase + KS8695_URLC)
+#define UART_PUT_LCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URLC)
+#define UART_GET_MCR(p)                __raw_readl((p)->membase + KS8695_URMC)
+#define UART_PUT_MCR(p, c)     __raw_writel((c), (p)->membase + KS8695_URMC)
+#define UART_GET_BRDR(p)       __raw_readl((p)->membase + KS8695_URBD)
+#define UART_PUT_BRDR(p, c)    __raw_writel((c), (p)->membase + KS8695_URBD)
+
+#define KS8695_CLR_TX_INT()    __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
+
+#define UART_DUMMY_LSR_RX      0x100
+#define UART_PORT_SIZE         (KS8695_USR - KS8695_URRB + 4)
+
+static inline int tx_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 1;
+}
+
+static inline int rx_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 2;
+}
+
+static inline int ms_enabled(struct uart_port *port)
+{
+       return port->unused[0] & 4;
+}
+
+static inline void ms_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 4;
+       else
+               port->unused[0] &= ~4;
+}
+
+static inline void rx_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 2;
+       else
+               port->unused[0] &= ~2;
+}
+
+static inline void tx_enable(struct uart_port *port, int enabled)
+{
+       if(enabled)
+               port->unused[0] |= 1;
+       else
+               port->unused[0] &= ~1;
+}
+
+
+#ifdef SUPPORT_SYSRQ
+static struct console ks8695_console;
+#endif
+
+static void ks8695uart_stop_tx(struct uart_port *port)
+{
+       if (tx_enabled(port)) {
+               /* use disable_irq_nosync() and not disable_irq() to avoid self
+                * imposed deadlock by not waiting for irq handler to end,
+                * since this ks8695uart_stop_tx() is called from interrupt context.
+                */
+               disable_irq_nosync(KS8695_IRQ_UART_TX);
+               tx_enable(port, 0);
+       }
+}
+
+static void ks8695uart_start_tx(struct uart_port *port)
+{
+       if (!tx_enabled(port)) {
+               enable_irq(KS8695_IRQ_UART_TX);
+               tx_enable(port, 1);
+       }
+}
+
+static void ks8695uart_stop_rx(struct uart_port *port)
+{
+       if (rx_enabled(port)) {
+               disable_irq(KS8695_IRQ_UART_RX);
+               rx_enable(port, 0);
+       }
+}
+
+static void ks8695uart_enable_ms(struct uart_port *port)
+{
+       if (!ms_enabled(port)) {
+               enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+               ms_enable(port,1);
+       }
+}
+
+static void ks8695uart_disable_ms(struct uart_port *port)
+{
+       if (ms_enabled(port)) {
+               disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+               ms_enable(port,0);
+       }
+}
+
+static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int status, ch, lsr, flg, max_count = 256;
+
+       status = UART_GET_LSR(port);            /* clears pending LSR interrupts */
+       while ((status & URLS_URDR) && max_count--) {
+               ch = UART_GET_CHAR(port);
+               flg = TTY_NORMAL;
+
+               port->icount.rx++;
+
+               /*
+                * Note that the error handling code is
+                * out of the main execution path
+                */
+               lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
+               if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
+                       if (lsr & URLS_URBI) {
+                               lsr &= ~(URLS_URFE | URLS_URPE);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       }
+                       if (lsr & URLS_URPE)
+                               port->icount.parity++;
+                       if (lsr & URLS_URFE)
+                               port->icount.frame++;
+                       if (lsr & URLS_URROE)
+                               port->icount.overrun++;
+
+                       lsr &= port->read_status_mask;
+
+                       if (lsr & URLS_URBI)
+                               flg = TTY_BREAK;
+                       else if (lsr & URLS_URPE)
+                               flg = TTY_PARITY;
+                       else if (lsr & URLS_URFE)
+                               flg = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, lsr, URLS_URROE, ch, flg);
+
+ignore_char:
+               status = UART_GET_LSR(port);
+       }
+       tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int count;
+
+       if (port->x_char) {
+               KS8695_CLR_TX_INT();
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return IRQ_HANDLED;
+       }
+
+       if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+               ks8695uart_stop_tx(port);
+               return IRQ_HANDLED;
+       }
+
+       count = 16;     /* fifo size */
+       while (!uart_circ_empty(xmit) && (count-- > 0)) {
+               KS8695_CLR_TX_INT();
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               ks8695uart_stop_tx(port);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned int status;
+
+       /*
+        * clear modem interrupt by reading MSR
+        */
+       status = UART_GET_MSR(port);
+
+       if (status & URMS_URDDCD)
+               uart_handle_dcd_change(port, status & URMS_URDDCD);
+
+       if (status & URMS_URDDST)
+               port->icount.dsr++;
+
+       if (status & URMS_URDCTS)
+               uart_handle_cts_change(port, status & URMS_URDCTS);
+
+       if (status & URMS_URTERI)
+               port->icount.rng++;
+
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int ks8695uart_tx_empty(struct uart_port *port)
+{
+       return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
+{
+       unsigned int result = 0;
+       unsigned int status;
+
+       status = UART_GET_MSR(port);
+       if (status & URMS_URDCD)
+               result |= TIOCM_CAR;
+       if (status & URMS_URDSR)
+               result |= TIOCM_DSR;
+       if (status & URMS_URCTS)
+               result |= TIOCM_CTS;
+       if (status & URMS_URRI)
+               result |= TIOCM_RI;
+
+       return result;
+}
+
+static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+       unsigned int mcr;
+
+       mcr = UART_GET_MCR(port);
+       if (mctrl & TIOCM_RTS)
+               mcr |= URMC_URRTS;
+       else
+               mcr &= ~URMC_URRTS;
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= URMC_URDTR;
+       else
+               mcr &= ~URMC_URDTR;
+
+       UART_PUT_MCR(port, mcr);
+}
+
+static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned int lcr;
+
+       lcr = UART_GET_LCR(port);
+
+       if (break_state == -1)
+               lcr |= URLC_URSBC;
+       else
+               lcr &= ~URLC_URSBC;
+
+       UART_PUT_LCR(port, lcr);
+}
+
+static int ks8695uart_startup(struct uart_port *port)
+{
+       int retval;
+
+       set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
+       tx_enable(port, 0);
+       rx_enable(port, 1);
+       ms_enable(port, 1);
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
+       if (retval)
+               goto err_tx;
+
+       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
+       if (retval)
+               goto err_rx;
+
+       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
+       if (retval)
+               goto err_ls;
+
+       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
+       if (retval)
+               goto err_ms;
+
+       return 0;
+
+err_ms:
+       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+err_ls:
+       free_irq(KS8695_IRQ_UART_RX, port);
+err_rx:
+       free_irq(KS8695_IRQ_UART_TX, port);
+err_tx:
+       return retval;
+}
+
+static void ks8695uart_shutdown(struct uart_port *port)
+{
+       /*
+        * Free the interrupt
+        */
+       free_irq(KS8695_IRQ_UART_RX, port);
+       free_irq(KS8695_IRQ_UART_TX, port);
+       free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
+       free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+
+       /* disable break condition and fifos */
+       UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
+       UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
+}
+
+static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+       unsigned int lcr, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr = URCL_5;
+               break;
+       case CS6:
+               lcr = URCL_6;
+               break;
+       case CS7:
+               lcr = URCL_7;
+               break;
+       default:
+               lcr = URCL_8;
+               break;
+       }
+
+       /* stop bits */
+       if (termios->c_cflag & CSTOPB)
+               lcr |= URLC_URSB;
+
+       /* parity */
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {        /* Mark or Space parity */
+                       if (termios->c_cflag & PARODD)
+                               lcr |= URPE_MARK;
+                       else
+                               lcr |= URPE_SPACE;
+               }
+               else if (termios->c_cflag & PARODD)
+                       lcr |= URPE_ODD;
+               else
+                       lcr |= URPE_EVEN;
+       }
+
+       if (port->fifosize > 1)
+               fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       port->read_status_mask = URLS_URROE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (URLS_URFE | URLS_URPE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= URLS_URBI;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= URLS_URBI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= URLS_URROE;
+       }
+
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_DUMMY_LSR_RX;
+
+       /* first, disable everything */
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               ks8695uart_enable_ms(port);
+       else
+               ks8695uart_disable_ms(port);
+
+       /* Set baud rate */
+       UART_PUT_BRDR(port, quot);
+
+       UART_PUT_LCR(port, lcr);
+       UART_PUT_FCR(port, fcr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ks8695uart_type(struct uart_port *port)
+{
+       return port->type == PORT_KS8695 ? "KS8695" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void ks8695uart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int ks8695uart_request_port(struct uart_port *port)
+{
+       return request_mem_region(port->mapbase, UART_PORT_SIZE,
+                       "serial_ks8695") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ks8695uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_KS8695;
+               ks8695uart_request_port(port);
+       }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
+               ret = -EINVAL;
+       if (ser->irq != port->irq)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops ks8695uart_pops = {
+       .tx_empty       = ks8695uart_tx_empty,
+       .set_mctrl      = ks8695uart_set_mctrl,
+       .get_mctrl      = ks8695uart_get_mctrl,
+       .stop_tx        = ks8695uart_stop_tx,
+       .start_tx       = ks8695uart_start_tx,
+       .stop_rx        = ks8695uart_stop_rx,
+       .enable_ms      = ks8695uart_enable_ms,
+       .break_ctl      = ks8695uart_break_ctl,
+       .startup        = ks8695uart_startup,
+       .shutdown       = ks8695uart_shutdown,
+       .set_termios    = ks8695uart_set_termios,
+       .type           = ks8695uart_type,
+       .release_port   = ks8695uart_release_port,
+       .request_port   = ks8695uart_request_port,
+       .config_port    = ks8695uart_config_port,
+       .verify_port    = ks8695uart_verify_port,
+};
+
+static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
+       {
+               .membase        = (void *) KS8695_UART_VA,
+               .mapbase        = KS8695_UART_VA,
+               .iotype         = SERIAL_IO_MEM,
+               .irq            = KS8695_IRQ_UART_TX,
+               .uartclk        = KS8695_CLOCK_RATE * 16,
+               .fifosize       = 16,
+               .ops            = &ks8695uart_pops,
+               .flags          = ASYNC_BOOT_AUTOCONF,
+               .line           = 0,
+       }
+};
+
+#ifdef CONFIG_SERIAL_KS8695_CONSOLE
+static void ks8695_console_putchar(struct uart_port *port, int ch)
+{
+       while (!(UART_GET_LSR(port) & URLS_URTHRE))
+               barrier();
+
+       UART_PUT_CHAR(port, ch);
+}
+
+static void ks8695_console_write(struct console *co, const char *s, u_int count)
+{
+       struct uart_port *port = ks8695uart_ports + co->index;
+
+       uart_console_write(port, s, count, ks8695_console_putchar);
+}
+
+static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+       unsigned int lcr;
+
+       lcr = UART_GET_LCR(port);
+
+       switch (lcr & URLC_PARITY) {
+               case URPE_ODD:
+                       *parity = 'o';
+                       break;
+               case URPE_EVEN:
+                       *parity = 'e';
+                       break;
+               default:
+                       *parity = 'n';
+       }
+
+       switch (lcr & URLC_URCL) {
+               case URCL_5:
+                       *bits = 5;
+                       break;
+               case URCL_6:
+                       *bits = 6;
+                       break;
+               case URCL_7:
+                       *bits = 7;
+                       break;
+               default:
+                       *bits = 8;
+       }
+
+       *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
+       *baud /= 16;
+       *baud &= 0xFFFFFFF0;
+}
+
+static int __init ks8695_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               ks8695_console_get_options(port, &baud, &parity, &bits);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver ks8695_reg;
+
+static struct console ks8695_console = {
+       .name           = SERIAL_KS8695_DEVNAME,
+       .write          = ks8695_console_write,
+       .device         = uart_console_device,
+       .setup          = ks8695_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ks8695_reg,
+};
+
+static int __init ks8695_console_init(void)
+{
+       add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL);
+       register_console(&ks8695_console);
+       return 0;
+}
+
+console_initcall(ks8695_console_init);
+
+#define KS8695_CONSOLE &ks8695_console
+#else
+#define KS8695_CONSOLE NULL
+#endif
+
+static struct uart_driver ks8695_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial_ks8695",
+       .dev_name               = SERIAL_KS8695_DEVNAME,
+       .major                  = SERIAL_KS8695_MAJOR,
+       .minor                  = SERIAL_KS8695_MINOR,
+       .nr                     = SERIAL_KS8695_NR,
+       .cons                   = KS8695_CONSOLE,
+};
+
+static int __init ks8695uart_init(void)
+{
+       int i, ret;
+
+       printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
+
+       ret = uart_register_driver(&ks8695_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < SERIAL_KS8695_NR; i++)
+               uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+
+       return 0;
+}
+
+static void __exit ks8695uart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < SERIAL_KS8695_NR; i++)
+               uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+       uart_unregister_driver(&ks8695_reg);
+}
+
+module_init(ks8695uart_init);
+module_exit(ks8695uart_exit);
+
+MODULE_DESCRIPTION("KS8695 serial port driver");
+MODULE_AUTHOR("Micrel Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c
new file mode 100644 (file)
index 0000000..ea74470
--- /dev/null
@@ -0,0 +1,682 @@
+/* drivers/serial/serial_lh7a40x.c
+ *
+ *  Copyright (C) 2004 Coastal Environmental Systems
+ *
+ *  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.
+ *
+ */
+
+/* Driver for Sharp LH7A40X embedded serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
+ *
+ *  ---
+ *
+ * This driver supports the embedded UARTs of the Sharp LH7A40X series
+ * CPUs.  While similar to the 16550 and other UART chips, there is
+ * nothing close to register compatibility.  Moreover, some of the
+ * modem control lines are not available, either in the chip or they
+ * are lacking in the board-level implementation.
+ *
+ * - Use of SIRDIS
+ *   For simplicity, we disable the IR functions of any UART whenever
+ *   we enable it.
+ *
+ */
+
+
+#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#define DEV_MAJOR      204
+#define DEV_MINOR      16
+#define DEV_NR         3
+
+#define ISR_LOOP_LIMIT 256
+
+#define UR(p,o)        _UR ((p)->membase, o)
+#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
+#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
+#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
+
+#define UART_REG_SIZE  32
+
+#define UART_R_DATA    (0x00)
+#define UART_R_FCON    (0x04)
+#define UART_R_BRCON   (0x08)
+#define UART_R_CON     (0x0c)
+#define UART_R_STATUS  (0x10)
+#define UART_R_RAWISR  (0x14)
+#define UART_R_INTEN   (0x18)
+#define UART_R_ISR     (0x1c)
+
+#define UARTEN         (0x01)          /* UART enable */
+#define SIRDIS         (0x02)          /* Serial IR disable (UART1 only) */
+
+#define RxEmpty                (0x10)
+#define TxEmpty                (0x80)
+#define TxFull         (0x20)
+#define nRxRdy         RxEmpty
+#define nTxRdy         TxFull
+#define TxBusy         (0x08)
+
+#define RxBreak                (0x0800)
+#define RxOverrunError (0x0400)
+#define RxParityError  (0x0200)
+#define RxFramingError (0x0100)
+#define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError)
+
+#define DCD            (0x04)
+#define DSR            (0x02)
+#define CTS            (0x01)
+
+#define RxInt          (0x01)
+#define TxInt          (0x02)
+#define ModemInt       (0x04)
+#define RxTimeoutInt   (0x08)
+
+#define MSEOI          (0x10)
+
+#define WLEN_8         (0x60)
+#define WLEN_7         (0x40)
+#define WLEN_6         (0x20)
+#define WLEN_5         (0x00)
+#define WLEN           (0x60)  /* Mask for all word-length bits */
+#define STP2           (0x08)
+#define PEN            (0x02)  /* Parity Enable */
+#define EPS            (0x04)  /* Even Parity Set */
+#define FEN            (0x10)  /* FIFO Enable */
+#define BRK            (0x01)  /* Send Break */
+
+
+struct uart_port_lh7a40x {
+       struct uart_port port;
+       unsigned int statusPrev; /* Most recently read modem status */
+};
+
+static void lh7a40xuart_stop_tx (struct uart_port* port)
+{
+       BIT_CLR (port, UART_R_INTEN, TxInt);
+}
+
+static void lh7a40xuart_start_tx (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, TxInt);
+
+       /* *** FIXME: do I need to check for startup of the
+                     transmitter?  The old driver did, but AMBA
+                     doesn't . */
+}
+
+static void lh7a40xuart_stop_rx (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
+}
+
+static void lh7a40xuart_enable_ms (struct uart_port* port)
+{
+       BIT_SET (port, UART_R_INTEN, ModemInt);
+}
+
+static void lh7a40xuart_rx_chars (struct uart_port* port)
+{
+       struct tty_struct* tty = port->state->port.tty;
+       int cbRxMax = 256;      /* (Gross) limit on receive */
+       unsigned int data;      /* Received data and status */
+       unsigned int flag;
+
+       while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
+               data = UR (port, UART_R_DATA);
+               flag = TTY_NORMAL;
+               ++port->icount.rx;
+
+               if (unlikely(data & RxError)) {
+                       if (data & RxBreak) {
+                               data &= ~(RxFramingError | RxParityError);
+                               ++port->icount.brk;
+                               if (uart_handle_break (port))
+                                       continue;
+                       }
+                       else if (data & RxParityError)
+                               ++port->icount.parity;
+                       else if (data & RxFramingError)
+                               ++port->icount.frame;
+                       if (data & RxOverrunError)
+                               ++port->icount.overrun;
+
+                               /* Mask by termios, leave Rx'd byte */
+                       data &= port->read_status_mask | 0xff;
+
+                       if (data & RxBreak)
+                               flag = TTY_BREAK;
+                       else if (data & RxParityError)
+                               flag = TTY_PARITY;
+                       else if (data & RxFramingError)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char (port, (unsigned char) data))
+                       continue;
+
+               uart_insert_char(port, data, RxOverrunError, data, flag);
+       }
+       tty_flip_buffer_push (tty);
+       return;
+}
+
+static void lh7a40xuart_tx_chars (struct uart_port* port)
+{
+       struct circ_buf* xmit = &port->state->xmit;
+       int cbTxMax = port->fifosize;
+
+       if (port->x_char) {
+               UR (port, UART_R_DATA) = port->x_char;
+               ++port->icount.tx;
+               port->x_char = 0;
+               return;
+       }
+       if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
+               lh7a40xuart_stop_tx (port);
+               return;
+       }
+
+       /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
+          that at least half of the FIFO is empty.  Instead, we check
+          status for every character.  Using the AMBA method causes
+          the transmitter to drop characters. */
+
+       do {
+               UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               ++port->icount.tx;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (!(UR (port, UART_R_STATUS) & nTxRdy)
+                && cbTxMax--);
+
+       if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
+               uart_write_wakeup (port);
+
+       if (uart_circ_empty (xmit))
+               lh7a40xuart_stop_tx (port);
+}
+
+static void lh7a40xuart_modem_status (struct uart_port* port)
+{
+       unsigned int status = UR (port, UART_R_STATUS);
+       unsigned int delta
+               = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
+
+       BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
+
+       if (!delta)             /* Only happens if we missed 2 transitions */
+               return;
+
+       ((struct uart_port_lh7a40x*) port)->statusPrev = status;
+
+       if (delta & DCD)
+               uart_handle_dcd_change (port, status & DCD);
+
+       if (delta & DSR)
+               ++port->icount.dsr;
+
+       if (delta & CTS)
+               uart_handle_cts_change (port, status & CTS);
+
+       wake_up_interruptible (&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
+{
+       struct uart_port* port = dev_id;
+       unsigned int cLoopLimit = ISR_LOOP_LIMIT;
+       unsigned int isr = UR (port, UART_R_ISR);
+
+
+       do {
+               if (isr & (RxInt | RxTimeoutInt))
+                       lh7a40xuart_rx_chars(port);
+               if (isr & ModemInt)
+                       lh7a40xuart_modem_status (port);
+               if (isr & TxInt)
+                       lh7a40xuart_tx_chars (port);
+
+               if (--cLoopLimit == 0)
+                       break;
+
+               isr = UR (port, UART_R_ISR);
+       } while (isr & (RxInt | TxInt | RxTimeoutInt));
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
+{
+       return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
+{
+       unsigned int result = 0;
+       unsigned int status = UR (port, UART_R_STATUS);
+
+       if (status & DCD)
+               result |= TIOCM_CAR;
+       if (status & DSR)
+               result |= TIOCM_DSR;
+       if (status & CTS)
+               result |= TIOCM_CTS;
+
+       return result;
+}
+
+static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
+{
+       /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
+       /* Note, kernel appears to be setting DTR and RTS on console. */
+
+       /* *** FIXME: this deserves more work.  There's some work in
+              tracing all of the IO pins. */
+#if 0
+       if( port->mapbase == UART1_PHYS) {
+               gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
+
+               if (mctrl & TIOCM_RTS)
+                       gpio->pbdr &= ~GPIOB_UART1_RTS;
+               else
+                       gpio->pbdr |= GPIOB_UART1_RTS;
+       }
+#endif
+}
+
+static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
+       else
+               BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int lh7a40xuart_startup (struct uart_port* port)
+{
+       int retval;
+
+       retval = request_irq (port->irq, lh7a40xuart_int, 0,
+                             "serial_lh7a40x", port);
+       if (retval)
+               return retval;
+
+                               /* Initial modem control-line settings */
+       ((struct uart_port_lh7a40x*) port)->statusPrev
+               = UR (port, UART_R_STATUS);
+
+       /* There is presently no configuration option to enable IR.
+          Thus, we always disable it. */
+
+       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
+       BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
+
+       return 0;
+}
+
+static void lh7a40xuart_shutdown (struct uart_port* port)
+{
+       free_irq (port->irq, port);
+       BIT_CLR (port, UART_R_FCON, BRK | FEN);
+       BIT_CLR (port, UART_R_CON, UARTEN);
+}
+
+static void lh7a40xuart_set_termios (struct uart_port* port,
+                                    struct ktermios* termios,
+                                    struct ktermios* old)
+{
+       unsigned int con;
+       unsigned int inten;
+       unsigned int fcon;
+       unsigned long flags;
+       unsigned int baud;
+       unsigned int quot;
+
+       baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
+       quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               fcon = WLEN_5;
+               break;
+       case CS6:
+               fcon = WLEN_6;
+               break;
+       case CS7:
+               fcon = WLEN_7;
+               break;
+       case CS8:
+       default:
+               fcon = WLEN_8;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               fcon |= STP2;
+       if (termios->c_cflag & PARENB) {
+               fcon |= PEN;
+               if (!(termios->c_cflag & PARODD))
+                       fcon |= EPS;
+       }
+       if (port->fifosize > 1)
+               fcon |= FEN;
+
+       spin_lock_irqsave (&port->lock, flags);
+
+       uart_update_timeout (port, termios->c_cflag, baud);
+
+       port->read_status_mask = RxOverrunError;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= RxFramingError | RxParityError;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= RxBreak;
+
+               /* Figure mask for status we ignore */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= RxFramingError | RxParityError;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= RxBreak;
+               /* Ignore overrun when ignorning parity */
+               /* *** FIXME: is this in the right place? */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= RxOverrunError;
+       }
+
+               /* Ignore all receive errors when receive disabled */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RxError;
+
+       con   = UR (port, UART_R_CON);
+       inten = (UR (port, UART_R_INTEN) & ~ModemInt);
+
+       if (UART_ENABLE_MS (port, termios->c_cflag))
+               inten |= ModemInt;
+
+       BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
+       UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
+       UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
+       UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
+       UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
+       UR (port, UART_R_CON)   = con;          /* Restore UART mode */
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char* lh7a40xuart_type (struct uart_port* port)
+{
+       return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
+}
+
+static void lh7a40xuart_release_port (struct uart_port* port)
+{
+       release_mem_region (port->mapbase, UART_REG_SIZE);
+}
+
+static int lh7a40xuart_request_port (struct uart_port* port)
+{
+       return request_mem_region (port->mapbase, UART_REG_SIZE,
+                                  "serial_lh7a40x") != NULL
+               ? 0 : -EBUSY;
+}
+
+static void lh7a40xuart_config_port (struct uart_port* port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_LH7A40X;
+               lh7a40xuart_request_port (port);
+       }
+}
+
+static int lh7a40xuart_verify_port (struct uart_port* port,
+                                   struct serial_struct* ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600) /* *** FIXME: is this true? */
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops lh7a40x_uart_ops = {
+       .tx_empty       = lh7a40xuart_tx_empty,
+       .set_mctrl      = lh7a40xuart_set_mctrl,
+       .get_mctrl      = lh7a40xuart_get_mctrl,
+       .stop_tx        = lh7a40xuart_stop_tx,
+       .start_tx       = lh7a40xuart_start_tx,
+       .stop_rx        = lh7a40xuart_stop_rx,
+       .enable_ms      = lh7a40xuart_enable_ms,
+       .break_ctl      = lh7a40xuart_break_ctl,
+       .startup        = lh7a40xuart_startup,
+       .shutdown       = lh7a40xuart_shutdown,
+       .set_termios    = lh7a40xuart_set_termios,
+       .type           = lh7a40xuart_type,
+       .release_port   = lh7a40xuart_release_port,
+       .request_port   = lh7a40xuart_request_port,
+       .config_port    = lh7a40xuart_config_port,
+       .verify_port    = lh7a40xuart_verify_port,
+};
+
+static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART1_PHYS),
+                       .mapbase        = UART1_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART1INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               },
+       },
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART2_PHYS),
+                       .mapbase        = UART2_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART2INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               },
+       },
+       {
+               .port = {
+                       .membase        = (void*) io_p2v (UART3_PHYS),
+                       .mapbase        = UART3_PHYS,
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_UART3INTR,
+                       .uartclk        = 14745600/2,
+                       .fifosize       = 16,
+                       .ops            = &lh7a40x_uart_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               },
+       },
+};
+
+#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
+# define LH7A40X_CONSOLE NULL
+#else
+# define LH7A40X_CONSOLE &lh7a40x_console
+
+static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
+{
+       while (UR(port, UART_R_STATUS) & nTxRdy)
+               ;
+       UR(port, UART_R_DATA) = ch;
+}
+
+static void lh7a40xuart_console_write (struct console* co,
+                                      const char* s,
+                                      unsigned int count)
+{
+       struct uart_port* port = &lh7a40x_ports[co->index].port;
+       unsigned int con = UR (port, UART_R_CON);
+       unsigned int inten = UR (port, UART_R_INTEN);
+
+
+       UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
+       BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
+
+       uart_console_write(port, s, count, lh7a40xuart_console_putchar);
+
+                               /* Wait until all characters are sent */
+       while (UR (port, UART_R_STATUS) & TxBusy)
+               ;
+
+                               /* Restore control and interrupt mask */
+       UR (port, UART_R_CON) = con;
+       UR (port, UART_R_INTEN) = inten;
+}
+
+static void __init lh7a40xuart_console_get_options (struct uart_port* port,
+                                                   int* baud,
+                                                   int* parity,
+                                                   int* bits)
+{
+       if (UR (port, UART_R_CON) & UARTEN) {
+               unsigned int fcon = UR (port, UART_R_FCON);
+               unsigned int quot = UR (port, UART_R_BRCON) + 1;
+
+               switch (fcon & (PEN | EPS)) {
+               default:        *parity = 'n'; break;
+               case PEN:       *parity = 'o'; break;
+               case PEN | EPS: *parity = 'e'; break;
+               }
+
+               switch (fcon & WLEN) {
+               default:
+               case WLEN_8: *bits = 8; break;
+               case WLEN_7: *bits = 7; break;
+               case WLEN_6: *bits = 6; break;
+               case WLEN_5: *bits = 5; break;
+               }
+
+               *baud = port->uartclk/(16*quot);
+       }
+}
+
+static int __init lh7a40xuart_console_setup (struct console* co, char* options)
+{
+       struct uart_port* port;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index >= DEV_NR) /* Bounds check on device number */
+               co->index = 0;
+       port = &lh7a40x_ports[co->index].port;
+
+       if (options)
+               uart_parse_options (options, &baud, &parity, &bits, &flow);
+       else
+               lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
+
+       return uart_set_options (port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lh7a40x_reg;
+static struct console lh7a40x_console = {
+       .name           = "ttyAM",
+       .write          = lh7a40xuart_console_write,
+       .device         = uart_console_device,
+       .setup          = lh7a40xuart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &lh7a40x_reg,
+};
+
+static int __init lh7a40xuart_console_init(void)
+{
+       register_console (&lh7a40x_console);
+       return 0;
+}
+
+console_initcall (lh7a40xuart_console_init);
+
+#endif
+
+static struct uart_driver lh7a40x_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ttyAM",
+       .dev_name               = "ttyAM",
+       .major                  = DEV_MAJOR,
+       .minor                  = DEV_MINOR,
+       .nr                     = DEV_NR,
+       .cons                   = LH7A40X_CONSOLE,
+};
+
+static int __init lh7a40xuart_init(void)
+{
+       int ret;
+
+       printk (KERN_INFO "serial: LH7A40X serial driver\n");
+
+       ret = uart_register_driver (&lh7a40x_reg);
+
+       if (ret == 0) {
+               int i;
+
+               for (i = 0; i < DEV_NR; i++) {
+                       /* UART3, when used, requires GPIO pin reallocation */
+                       if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
+                               GPIO_PINMUX |= 1<<3;
+                       uart_add_one_port (&lh7a40x_reg,
+                                          &lh7a40x_ports[i].port);
+               }
+       }
+       return ret;
+}
+
+static void __exit lh7a40xuart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < DEV_NR; i++)
+               uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
+
+       uart_unregister_driver (&lh7a40x_reg);
+}
+
+module_init (lh7a40xuart_init);
+module_exit (lh7a40xuart_exit);
+
+MODULE_AUTHOR ("Marc Singer");
+MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
new file mode 100644 (file)
index 0000000..c50e9fb
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ *  drivers/serial/serial_txx9.c
+ *
+ * Derived from many drivers using generic_serial interface,
+ * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c
+ * (was in Linux/VR tree) by Jim Pick.
+ *
+ *  Copyright (C) 1999 Harald Koerfgen
+ *  Copyright (C) 2000 Jim Pick <jim@jimpick.com>
+ *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
+ *  Copyright (C) 2000-2002 Toshiba 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.
+ *
+ *  Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
+ */
+
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+
+static char *serial_version = "1.11";
+static char *serial_name = "TX39/49 Serial driver";
+
+#define PASS_LIMIT     256
+
+#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
+/* "ttyS" is used for standard serial driver */
+#define TXX9_TTY_NAME "ttyTX"
+#define TXX9_TTY_MINOR_START   196
+#define TXX9_TTY_MAJOR 204
+#else
+/* acts like standard serial driver */
+#define TXX9_TTY_NAME "ttyS"
+#define TXX9_TTY_MINOR_START   64
+#define TXX9_TTY_MAJOR TTY_MAJOR
+#endif
+
+/* flag aliases */
+#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
+#define UPF_TXX9_USE_SCLK      UPF_MAGIC_MULTIPLIER
+
+#ifdef CONFIG_PCI
+/* support for Toshiba TC86C001 SIO */
+#define ENABLE_SERIAL_TXX9_PCI
+#endif
+
+/*
+ * Number of serial ports
+ */
+#define UART_NR  CONFIG_SERIAL_TXX9_NR_UARTS
+
+struct uart_txx9_port {
+       struct uart_port        port;
+       /* No additional info for now */
+};
+
+#define TXX9_REGION_SIZE       0x24
+
+/* TXX9 Serial Registers */
+#define TXX9_SILCR     0x00
+#define TXX9_SIDICR    0x04
+#define TXX9_SIDISR    0x08
+#define TXX9_SICISR    0x0c
+#define TXX9_SIFCR     0x10
+#define TXX9_SIFLCR    0x14
+#define TXX9_SIBGR     0x18
+#define TXX9_SITFIFO   0x1c
+#define TXX9_SIRFIFO   0x20
+
+/* SILCR : Line Control */
+#define TXX9_SILCR_SCS_MASK    0x00000060
+#define TXX9_SILCR_SCS_IMCLK   0x00000000
+#define TXX9_SILCR_SCS_IMCLK_BG        0x00000020
+#define TXX9_SILCR_SCS_SCLK    0x00000040
+#define TXX9_SILCR_SCS_SCLK_BG 0x00000060
+#define TXX9_SILCR_UEPS        0x00000010
+#define TXX9_SILCR_UPEN        0x00000008
+#define TXX9_SILCR_USBL_MASK   0x00000004
+#define TXX9_SILCR_USBL_1BIT   0x00000000
+#define TXX9_SILCR_USBL_2BIT   0x00000004
+#define TXX9_SILCR_UMODE_MASK  0x00000003
+#define TXX9_SILCR_UMODE_8BIT  0x00000000
+#define TXX9_SILCR_UMODE_7BIT  0x00000001
+
+/* SIDICR : DMA/Int. Control */
+#define TXX9_SIDICR_TDE        0x00008000
+#define TXX9_SIDICR_RDE        0x00004000
+#define TXX9_SIDICR_TIE        0x00002000
+#define TXX9_SIDICR_RIE        0x00001000
+#define TXX9_SIDICR_SPIE       0x00000800
+#define TXX9_SIDICR_CTSAC      0x00000600
+#define TXX9_SIDICR_STIE_MASK  0x0000003f
+#define TXX9_SIDICR_STIE_OERS          0x00000020
+#define TXX9_SIDICR_STIE_CTSS          0x00000010
+#define TXX9_SIDICR_STIE_RBRKD 0x00000008
+#define TXX9_SIDICR_STIE_TRDY          0x00000004
+#define TXX9_SIDICR_STIE_TXALS 0x00000002
+#define TXX9_SIDICR_STIE_UBRKD 0x00000001
+
+/* SIDISR : DMA/Int. Status */
+#define TXX9_SIDISR_UBRK       0x00008000
+#define TXX9_SIDISR_UVALID     0x00004000
+#define TXX9_SIDISR_UFER       0x00002000
+#define TXX9_SIDISR_UPER       0x00001000
+#define TXX9_SIDISR_UOER       0x00000800
+#define TXX9_SIDISR_ERI        0x00000400
+#define TXX9_SIDISR_TOUT       0x00000200
+#define TXX9_SIDISR_TDIS       0x00000100
+#define TXX9_SIDISR_RDIS       0x00000080
+#define TXX9_SIDISR_STIS       0x00000040
+#define TXX9_SIDISR_RFDN_MASK  0x0000001f
+
+/* SICISR : Change Int. Status */
+#define TXX9_SICISR_OERS       0x00000020
+#define TXX9_SICISR_CTSS       0x00000010
+#define TXX9_SICISR_RBRKD      0x00000008
+#define TXX9_SICISR_TRDY       0x00000004
+#define TXX9_SICISR_TXALS      0x00000002
+#define TXX9_SICISR_UBRKD      0x00000001
+
+/* SIFCR : FIFO Control */
+#define TXX9_SIFCR_SWRST       0x00008000
+#define TXX9_SIFCR_RDIL_MASK   0x00000180
+#define TXX9_SIFCR_RDIL_1      0x00000000
+#define TXX9_SIFCR_RDIL_4      0x00000080
+#define TXX9_SIFCR_RDIL_8      0x00000100
+#define TXX9_SIFCR_RDIL_12     0x00000180
+#define TXX9_SIFCR_RDIL_MAX    0x00000180
+#define TXX9_SIFCR_TDIL_MASK   0x00000018
+#define TXX9_SIFCR_TDIL_MASK   0x00000018
+#define TXX9_SIFCR_TDIL_1      0x00000000
+#define TXX9_SIFCR_TDIL_4      0x00000001
+#define TXX9_SIFCR_TDIL_8      0x00000010
+#define TXX9_SIFCR_TDIL_MAX    0x00000010
+#define TXX9_SIFCR_TFRST       0x00000004
+#define TXX9_SIFCR_RFRST       0x00000002
+#define TXX9_SIFCR_FRSTE       0x00000001
+#define TXX9_SIO_TX_FIFO       8
+#define TXX9_SIO_RX_FIFO       16
+
+/* SIFLCR : Flow Control */
+#define TXX9_SIFLCR_RCS        0x00001000
+#define TXX9_SIFLCR_TES        0x00000800
+#define TXX9_SIFLCR_RTSSC      0x00000200
+#define TXX9_SIFLCR_RSDE       0x00000100
+#define TXX9_SIFLCR_TSDE       0x00000080
+#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e
+#define TXX9_SIFLCR_RTSTL_MAX  0x0000001e
+#define TXX9_SIFLCR_TBRK       0x00000001
+
+/* SIBGR : Baudrate Control */
+#define TXX9_SIBGR_BCLK_MASK   0x00000300
+#define TXX9_SIBGR_BCLK_T0     0x00000000
+#define TXX9_SIBGR_BCLK_T2     0x00000100
+#define TXX9_SIBGR_BCLK_T4     0x00000200
+#define TXX9_SIBGR_BCLK_T6     0x00000300
+#define TXX9_SIBGR_BRD_MASK    0x000000ff
+
+static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
+{
+       switch (up->port.iotype) {
+       default:
+               return __raw_readl(up->port.membase + offset);
+       case UPIO_PORT:
+               return inl(up->port.iobase + offset);
+       }
+}
+
+static inline void
+sio_out(struct uart_txx9_port *up, int offset, int value)
+{
+       switch (up->port.iotype) {
+       default:
+               __raw_writel(value, up->port.membase + offset);
+               break;
+       case UPIO_PORT:
+               outl(value, up->port.iobase + offset);
+               break;
+       }
+}
+
+static inline void
+sio_mask(struct uart_txx9_port *up, int offset, unsigned int value)
+{
+       sio_out(up, offset, sio_in(up, offset) & ~value);
+}
+static inline void
+sio_set(struct uart_txx9_port *up, int offset, unsigned int value)
+{
+       sio_out(up, offset, sio_in(up, offset) | value);
+}
+
+static inline void
+sio_quot_set(struct uart_txx9_port *up, int quot)
+{
+       quot >>= 1;
+       if (quot < 256)
+               sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0);
+       else if (quot < (256 << 2))
+               sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2);
+       else if (quot < (256 << 4))
+               sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4);
+       else if (quot < (256 << 6))
+               sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6);
+       else
+               sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
+}
+
+static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
+{
+       return container_of(port, struct uart_txx9_port, port);
+}
+
+static void serial_txx9_stop_tx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
+}
+
+static void serial_txx9_start_tx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
+}
+
+static void serial_txx9_stop_rx(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
+}
+
+static void serial_txx9_enable_ms(struct uart_port *port)
+{
+       /* TXX9-SIO can not control DTR... */
+}
+
+static void serial_txx9_initialize(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int tmout = 10000;
+
+       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
+       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
+        * immediately after soft reset causes bus error. */
+       mmiowb();
+       udelay(1);
+       while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
+               udelay(1);
+       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
+       /* initial settings */
+       sio_out(up, TXX9_SILCR,
+               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
+               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
+                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
+       sio_quot_set(up, uart_get_divisor(port, 9600));
+       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+       sio_out(up, TXX9_SIDICR, 0);
+}
+
+static inline void
+receive_chars(struct uart_txx9_port *up, unsigned int *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch;
+       unsigned int disr = *status;
+       int max_count = 256;
+       char flag;
+       unsigned int next_ignore_status_mask;
+
+       do {
+               ch = sio_in(up, TXX9_SIRFIFO);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               /* mask out RFDN_MASK bit added by previous overrun */
+               next_ignore_status_mask =
+                       up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
+               if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
+                                    TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (disr & TXX9_SIDISR_UBRK) {
+                               disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (disr & TXX9_SIDISR_UPER)
+                               up->port.icount.parity++;
+                       else if (disr & TXX9_SIDISR_UFER)
+                               up->port.icount.frame++;
+                       if (disr & TXX9_SIDISR_UOER) {
+                               up->port.icount.overrun++;
+                               /*
+                                * The receiver read buffer still hold
+                                * a char which caused overrun.
+                                * Ignore next char by adding RFDN_MASK
+                                * to ignore_status_mask temporarily.
+                                */
+                               next_ignore_status_mask |=
+                                       TXX9_SIDISR_RFDN_MASK;
+                       }
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       disr &= up->port.read_status_mask;
+
+                       if (disr & TXX9_SIDISR_UBRK) {
+                               flag = TTY_BREAK;
+                       } else if (disr & TXX9_SIDISR_UPER)
+                               flag = TTY_PARITY;
+                       else if (disr & TXX9_SIDISR_UFER)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
+
+       ignore_char:
+               up->port.ignore_status_mask = next_ignore_status_mask;
+               disr = sio_in(up, TXX9_SIDISR);
+       } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
+       spin_unlock(&up->port.lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&up->port.lock);
+       *status = disr;
+}
+
+static inline void transmit_chars(struct uart_txx9_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               sio_out(up, TXX9_SITFIFO, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               serial_txx9_stop_tx(&up->port);
+               return;
+       }
+
+       count = TXX9_SIO_TX_FIFO;
+       do {
+               sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               serial_txx9_stop_tx(&up->port);
+}
+
+static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
+{
+       int pass_counter = 0;
+       struct uart_txx9_port *up = dev_id;
+       unsigned int status;
+
+       while (1) {
+               spin_lock(&up->port.lock);
+               status = sio_in(up, TXX9_SIDISR);
+               if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
+                       status &= ~TXX9_SIDISR_TDIS;
+               if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
+                               TXX9_SIDISR_TOUT))) {
+                       spin_unlock(&up->port.lock);
+                       break;
+               }
+
+               if (status & TXX9_SIDISR_RDIS)
+                       receive_chars(up, &status);
+               if (status & TXX9_SIDISR_TDIS)
+                       transmit_chars(up);
+               /* Clear TX/RX Int. Status */
+               sio_mask(up, TXX9_SIDISR,
+                        TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
+                        TXX9_SIDISR_TOUT);
+               spin_unlock(&up->port.lock);
+
+               if (pass_counter++ > PASS_LIMIT)
+                       break;
+       }
+
+       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static unsigned int serial_txx9_tx_empty(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int ret;
+
+       /* no modem control lines */
+       ret = TIOCM_CAR | TIOCM_DSR;
+       ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
+       ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
+
+       return ret;
+}
+
+static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       if (mctrl & TIOCM_RTS)
+               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
+       else
+               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
+}
+
+static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+       else
+               sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_txx9_port *up)
+{
+       unsigned int tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       while (--tmout &&
+              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
+               udelay(1);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
+                       udelay(1);
+       }
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial_txx9_get_poll_char(struct uart_port *port)
+{
+       unsigned int ier;
+       unsigned char c;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
+               ;
+
+       c = sio_in(up, TXX9_SIRFIFO);
+
+       /*
+        *      Finally, clear RX interrupt status
+        *      and restore the IER
+        */
+       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
+       sio_out(up, TXX9_SIDICR, ier);
+       return c;
+}
+
+
+static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
+{
+       unsigned int ier;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       wait_for_xmitr(up);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       sio_out(up, TXX9_SITFIFO, c);
+       if (c == 10) {
+               wait_for_xmitr(up);
+               sio_out(up, TXX9_SITFIFO, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int serial_txx9_startup(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+       int retval;
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       /* clear reset */
+       sio_mask(up, TXX9_SIFCR,
+                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       sio_out(up, TXX9_SIDISR, 0);
+
+       retval = request_irq(up->port.irq, serial_txx9_interrupt,
+                            IRQF_SHARED, "serial_txx9", up);
+       if (retval)
+               return retval;
+
+       /*
+        * Now, initialize the UART
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /* Enable RX/TX */
+       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
+
+       /*
+        * Finally, enable interrupts.
+        */
+       sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
+
+       return 0;
+}
+
+static void serial_txx9_shutdown(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       sio_out(up, TXX9_SIDICR, 0);    /* disable all intrs */
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition
+        */
+       sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+       if (up->port.cons && up->port.line == up->port.cons->index) {
+               free_irq(up->port.irq, up);
+               return;
+       }
+#endif
+       /* reset FIFOs */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+       /* clear reset */
+       sio_mask(up, TXX9_SIFCR,
+                TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
+
+       /* Disable RX/TX */
+       sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
+
+       free_irq(up->port.irq, up);
+}
+
+static void
+serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       unsigned int cval, fcr = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
+       cval = sio_in(up, TXX9_SILCR);
+       /* byte size and parity */
+       cval &= ~TXX9_SILCR_UMODE_MASK;
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               cval |= TXX9_SILCR_UMODE_7BIT;
+               break;
+       default:
+       case CS5:       /* not supported */
+       case CS6:       /* not supported */
+       case CS8:
+               cval |= TXX9_SILCR_UMODE_8BIT;
+               break;
+       }
+
+       cval &= ~TXX9_SILCR_USBL_MASK;
+       if (termios->c_cflag & CSTOPB)
+               cval |= TXX9_SILCR_USBL_2BIT;
+       else
+               cval |= TXX9_SILCR_USBL_1BIT;
+       cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS);
+       if (termios->c_cflag & PARENB)
+               cval |= TXX9_SILCR_UPEN;
+       if (!(termios->c_cflag & PARODD))
+               cval |= TXX9_SILCR_UEPS;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2);
+       quot = uart_get_divisor(port, baud);
+
+       /* Set up FIFOs */
+       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+       fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = TXX9_SIDISR_UOER |
+               TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= TXX9_SIDISR_UBRK;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= TXX9_SIDISR_UBRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= TXX9_SIDISR_UOER;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= TXX9_SIDISR_RDIS;
+
+       /* CTS flow control flag */
+       if ((termios->c_cflag & CRTSCTS) &&
+           (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) {
+               sio_set(up, TXX9_SIFLCR,
+                       TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
+       } else {
+               sio_mask(up, TXX9_SIFLCR,
+                        TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
+       }
+
+       sio_out(up, TXX9_SILCR, cval);
+       sio_quot_set(up, quot);
+       sio_out(up, TXX9_SIFCR, fcr);
+
+       serial_txx9_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial_txx9_pm(struct uart_port *port, unsigned int state,
+             unsigned int oldstate)
+{
+       /*
+        * If oldstate was -1 this is called from
+        * uart_configure_port().  In this case do not initialize the
+        * port now, because the port was already initialized (for
+        * non-console port) or should not be initialized here (for
+        * console port).  If we initialized the port here we lose
+        * serial console settings.
+        */
+       if (state == 0 && oldstate != -1)
+               serial_txx9_initialize(port);
+}
+
+static int serial_txx9_request_resource(struct uart_txx9_port *up)
+{
+       unsigned int size = TXX9_REGION_SIZE;
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       default:
+               if (!up->port.mapbase)
+                       break;
+
+               if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) {
+                       ret = -EBUSY;
+                       break;
+               }
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       up->port.membase = ioremap(up->port.mapbase, size);
+                       if (!up->port.membase) {
+                               release_mem_region(up->port.mapbase, size);
+                               ret = -ENOMEM;
+                       }
+               }
+               break;
+
+       case UPIO_PORT:
+               if (!request_region(up->port.iobase, size, "serial_txx9"))
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static void serial_txx9_release_resource(struct uart_txx9_port *up)
+{
+       unsigned int size = TXX9_REGION_SIZE;
+
+       switch (up->port.iotype) {
+       default:
+               if (!up->port.mapbase)
+                       break;
+
+               if (up->port.flags & UPF_IOREMAP) {
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+               }
+
+               release_mem_region(up->port.mapbase, size);
+               break;
+
+       case UPIO_PORT:
+               release_region(up->port.iobase, size);
+               break;
+       }
+}
+
+static void serial_txx9_release_port(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       serial_txx9_release_resource(up);
+}
+
+static int serial_txx9_request_port(struct uart_port *port)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       return serial_txx9_request_resource(up);
+}
+
+static void serial_txx9_config_port(struct uart_port *port, int uflags)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+       int ret;
+
+       /*
+        * Find the region that we can probe for.  This in turn
+        * tells us whether we can probe for the type of port.
+        */
+       ret = serial_txx9_request_resource(up);
+       if (ret < 0)
+               return;
+       port->type = PORT_TXX9;
+       up->port.fifosize = TXX9_SIO_TX_FIFO;
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+       if (up->port.line == up->port.cons->index)
+               return;
+#endif
+       serial_txx9_initialize(port);
+}
+
+static const char *
+serial_txx9_type(struct uart_port *port)
+{
+       return "txx9";
+}
+
+static struct uart_ops serial_txx9_pops = {
+       .tx_empty       = serial_txx9_tx_empty,
+       .set_mctrl      = serial_txx9_set_mctrl,
+       .get_mctrl      = serial_txx9_get_mctrl,
+       .stop_tx        = serial_txx9_stop_tx,
+       .start_tx       = serial_txx9_start_tx,
+       .stop_rx        = serial_txx9_stop_rx,
+       .enable_ms      = serial_txx9_enable_ms,
+       .break_ctl      = serial_txx9_break_ctl,
+       .startup        = serial_txx9_startup,
+       .shutdown       = serial_txx9_shutdown,
+       .set_termios    = serial_txx9_set_termios,
+       .pm             = serial_txx9_pm,
+       .type           = serial_txx9_type,
+       .release_port   = serial_txx9_release_port,
+       .request_port   = serial_txx9_request_port,
+       .config_port    = serial_txx9_config_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = serial_txx9_get_poll_char,
+       .poll_put_char  = serial_txx9_put_poll_char,
+#endif
+};
+
+static struct uart_txx9_port serial_txx9_ports[UART_NR];
+
+static void __init serial_txx9_register_ports(struct uart_driver *drv,
+                                             struct device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               up->port.line = i;
+               up->port.ops = &serial_txx9_pops;
+               up->port.dev = dev;
+               if (up->port.iobase || up->port.mapbase)
+                       uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+
+static void serial_txx9_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SITFIFO, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void
+serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_txx9_port *up = &serial_txx9_ports[co->index];
+       unsigned int ier, flcr;
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+       /*
+        *      Disable flow-control if enabled (and unnecessary)
+        */
+       flcr = sio_in(up, TXX9_SIFLCR);
+       if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
+               sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
+
+       uart_console_write(&up->port, s, count, serial_txx9_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIFLCR, flcr);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+static int __init serial_txx9_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       struct uart_txx9_port *up;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       up = &serial_txx9_ports[co->index];
+       port = &up->port;
+       if (!port->ops)
+               return -ENODEV;
+
+       serial_txx9_initialize(&up->port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver serial_txx9_reg;
+static struct console serial_txx9_console = {
+       .name           = TXX9_TTY_NAME,
+       .write          = serial_txx9_console_write,
+       .device         = uart_console_device,
+       .setup          = serial_txx9_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &serial_txx9_reg,
+};
+
+static int __init serial_txx9_console_init(void)
+{
+       register_console(&serial_txx9_console);
+       return 0;
+}
+console_initcall(serial_txx9_console_init);
+
+#define SERIAL_TXX9_CONSOLE    &serial_txx9_console
+#else
+#define SERIAL_TXX9_CONSOLE    NULL
+#endif
+
+static struct uart_driver serial_txx9_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial_txx9",
+       .dev_name               = TXX9_TTY_NAME,
+       .major                  = TXX9_TTY_MAJOR,
+       .minor                  = TXX9_TTY_MINOR_START,
+       .nr                     = UART_NR,
+       .cons                   = SERIAL_TXX9_CONSOLE,
+};
+
+int __init early_serial_txx9_setup(struct uart_port *port)
+{
+       if (port->line >= ARRAY_SIZE(serial_txx9_ports))
+               return -ENODEV;
+
+       serial_txx9_ports[port->line].port = *port;
+       serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
+       serial_txx9_ports[port->line].port.flags |=
+               UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+       return 0;
+}
+
+static DEFINE_MUTEX(serial_txx9_mutex);
+
+/**
+ *     serial_txx9_register_port - register a serial port
+ *     @port: serial port template
+ *
+ *     Configure the serial port specified by the request.
+ *
+ *     The port is then probed and if necessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+static int __devinit serial_txx9_register_port(struct uart_port *port)
+{
+       int i;
+       struct uart_txx9_port *uart;
+       int ret = -ENOSPC;
+
+       mutex_lock(&serial_txx9_mutex);
+       for (i = 0; i < UART_NR; i++) {
+               uart = &serial_txx9_ports[i];
+               if (uart_match_port(&uart->port, port)) {
+                       uart_remove_one_port(&serial_txx9_reg, &uart->port);
+                       break;
+               }
+       }
+       if (i == UART_NR) {
+               /* Find unused port */
+               for (i = 0; i < UART_NR; i++) {
+                       uart = &serial_txx9_ports[i];
+                       if (!(uart->port.iobase || uart->port.mapbase))
+                               break;
+               }
+       }
+       if (i < UART_NR) {
+               uart->port.iobase = port->iobase;
+               uart->port.membase = port->membase;
+               uart->port.irq      = port->irq;
+               uart->port.uartclk  = port->uartclk;
+               uart->port.iotype   = port->iotype;
+               uart->port.flags    = port->flags
+                       | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+               uart->port.mapbase  = port->mapbase;
+               if (port->dev)
+                       uart->port.dev = port->dev;
+               ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
+       }
+       mutex_unlock(&serial_txx9_mutex);
+       return ret;
+}
+
+/**
+ *     serial_txx9_unregister_port - remove a txx9 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may not be called from interrupt
+ *     context.  We hand the port back to the our control.
+ */
+static void __devexit serial_txx9_unregister_port(int line)
+{
+       struct uart_txx9_port *uart = &serial_txx9_ports[line];
+
+       mutex_lock(&serial_txx9_mutex);
+       uart_remove_one_port(&serial_txx9_reg, &uart->port);
+       uart->port.flags = 0;
+       uart->port.type = PORT_UNKNOWN;
+       uart->port.iobase = 0;
+       uart->port.mapbase = 0;
+       uart->port.membase = NULL;
+       uart->port.dev = NULL;
+       mutex_unlock(&serial_txx9_mutex);
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.
+ */
+static int __devinit serial_txx9_probe(struct platform_device *dev)
+{
+       struct uart_port *p = dev->dev.platform_data;
+       struct uart_port port;
+       int ret, i;
+
+       memset(&port, 0, sizeof(struct uart_port));
+       for (i = 0; p && p->uartclk != 0; p++, i++) {
+               port.iobase     = p->iobase;
+               port.membase    = p->membase;
+               port.irq        = p->irq;
+               port.uartclk    = p->uartclk;
+               port.iotype     = p->iotype;
+               port.flags      = p->flags;
+               port.mapbase    = p->mapbase;
+               port.dev        = &dev->dev;
+               ret = serial_txx9_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_txx9_remove(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.dev == &dev->dev)
+                       serial_txx9_unregister_port(i);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_suspend_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+
+static int serial_txx9_resume(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_resume_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+#endif
+
+static struct platform_driver serial_txx9_plat_driver = {
+       .probe          = serial_txx9_probe,
+       .remove         = __devexit_p(serial_txx9_remove),
+#ifdef CONFIG_PM
+       .suspend        = serial_txx9_suspend,
+       .resume         = serial_txx9_resume,
+#endif
+       .driver         = {
+               .name   = "serial_txx9",
+               .owner  = THIS_MODULE,
+       },
+};
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+/*
+ * Probe one serial board.  Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int __devinit
+pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct uart_port port;
+       int line;
+       int rc;
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       memset(&port, 0, sizeof(port));
+       port.ops = &serial_txx9_pops;
+       port.flags |= UPF_TXX9_HAVE_CTS_LINE;
+       port.uartclk = 66670000;
+       port.irq = dev->irq;
+       port.iotype = UPIO_PORT;
+       port.iobase = pci_resource_start(dev, 1);
+       port.dev = &dev->dev;
+       line = serial_txx9_register_port(&port);
+       if (line < 0) {
+               printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
+               pci_disable_device(dev);
+               return line;
+       }
+       pci_set_drvdata(dev, &serial_txx9_ports[line]);
+
+       return 0;
+}
+
+static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       pci_set_drvdata(dev, NULL);
+
+       if (up) {
+               serial_txx9_unregister_port(up->port.line);
+               pci_disable_device(dev);
+       }
+}
+
+#ifdef CONFIG_PM
+static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       if (up)
+               uart_suspend_port(&serial_txx9_reg, &up->port);
+       pci_save_state(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+       return 0;
+}
+
+static int pciserial_txx9_resume_one(struct pci_dev *dev)
+{
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+       if (up)
+               uart_resume_port(&serial_txx9_reg, &up->port);
+       return 0;
+}
+#endif
+
+static const struct pci_device_id serial_txx9_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) },
+       { 0, }
+};
+
+static struct pci_driver serial_txx9_pci_driver = {
+       .name           = "serial_txx9",
+       .probe          = pciserial_txx9_init_one,
+       .remove         = __devexit_p(pciserial_txx9_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = pciserial_txx9_suspend_one,
+       .resume         = pciserial_txx9_resume_one,
+#endif
+       .id_table       = serial_txx9_pci_tbl,
+};
+
+MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
+#endif /* ENABLE_SERIAL_TXX9_PCI */
+
+static struct platform_device *serial_txx9_plat_devs;
+
+static int __init serial_txx9_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+
+       ret = uart_register_driver(&serial_txx9_reg);
+       if (ret)
+               goto out;
+
+       serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
+       if (!serial_txx9_plat_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
+       }
+
+       ret = platform_device_add(serial_txx9_plat_devs);
+       if (ret)
+               goto put_dev;
+
+       serial_txx9_register_ports(&serial_txx9_reg,
+                                  &serial_txx9_plat_devs->dev);
+
+       ret = platform_driver_register(&serial_txx9_plat_driver);
+       if (ret)
+               goto del_dev;
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+       ret = pci_register_driver(&serial_txx9_pci_driver);
+#endif
+       if (ret == 0)
+               goto out;
+
+ del_dev:
+       platform_device_del(serial_txx9_plat_devs);
+ put_dev:
+       platform_device_put(serial_txx9_plat_devs);
+ unreg_uart_drv:
+       uart_unregister_driver(&serial_txx9_reg);
+ out:
+       return ret;
+}
+
+static void __exit serial_txx9_exit(void)
+{
+       int i;
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+       pci_unregister_driver(&serial_txx9_pci_driver);
+#endif
+       platform_driver_unregister(&serial_txx9_plat_driver);
+       platform_device_unregister(serial_txx9_plat_devs);
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+               if (up->port.iobase || up->port.mapbase)
+                       uart_remove_one_port(&serial_txx9_reg, &up->port);
+       }
+
+       uart_unregister_driver(&serial_txx9_reg);
+}
+
+module_init(serial_txx9_init);
+module_exit(serial_txx9_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TX39/49 serial driver");
+
+MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
new file mode 100644 (file)
index 0000000..92c91c8
--- /dev/null
@@ -0,0 +1,2079 @@
+/*
+ * drivers/serial/sh-sci.c
+ *
+ * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *
+ *  Copyright (C) 2002 - 2011  Paul Mundt
+ *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
+ *
+ * based off of the old drivers/char/sh-sci.c by:
+ *
+ *   Copyright (C) 1999, 2000  Niibe Yutaka
+ *   Copyright (C) 2000  Sugioka Toshinobu
+ *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
+ *   Modified to support SecureEdge. David McCullough (2002)
+ *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ *   Removed SH7300 support (Jul 2007).
+ *
+ * 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.
+ */
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/serial_sci.h>
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_SUPERH
+#include <asm/sh_bios.h>
+#endif
+
+#ifdef CONFIG_H8300
+#include <asm/gpio.h>
+#endif
+
+#include "sh-sci.h"
+
+struct sci_port {
+       struct uart_port        port;
+
+       /* Port type */
+       unsigned int            type;
+
+       /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
+       unsigned int            irqs[SCIx_NR_IRQS];
+
+       /* Port enable callback */
+       void                    (*enable)(struct uart_port *port);
+
+       /* Port disable callback */
+       void                    (*disable)(struct uart_port *port);
+
+       /* Break timer */
+       struct timer_list       break_timer;
+       int                     break_flag;
+
+       /* SCSCR initialization */
+       unsigned int            scscr;
+
+       /* SCBRR calculation algo */
+       unsigned int            scbrr_algo_id;
+
+       /* Interface clock */
+       struct clk              *iclk;
+       /* Function clock */
+       struct clk              *fclk;
+
+       struct list_head        node;
+
+       struct dma_chan                 *chan_tx;
+       struct dma_chan                 *chan_rx;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct device                   *dma_dev;
+       unsigned int                    slave_tx;
+       unsigned int                    slave_rx;
+       struct dma_async_tx_descriptor  *desc_tx;
+       struct dma_async_tx_descriptor  *desc_rx[2];
+       dma_cookie_t                    cookie_tx;
+       dma_cookie_t                    cookie_rx[2];
+       dma_cookie_t                    active_rx;
+       struct scatterlist              sg_tx;
+       unsigned int                    sg_len_tx;
+       struct scatterlist              sg_rx[2];
+       size_t                          buf_len_rx;
+       struct sh_dmae_slave            param_tx;
+       struct sh_dmae_slave            param_rx;
+       struct work_struct              work_tx;
+       struct work_struct              work_rx;
+       struct timer_list               rx_timer;
+       unsigned int                    rx_timeout;
+#endif
+};
+
+struct sh_sci_priv {
+       spinlock_t lock;
+       struct list_head ports;
+       struct notifier_block clk_nb;
+};
+
+/* Function prototypes */
+static void sci_stop_tx(struct uart_port *port);
+
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+
+static struct sci_port sci_ports[SCI_NPORTS];
+static struct uart_driver sci_uart_driver;
+
+static inline struct sci_port *
+to_sci_port(struct uart_port *uart)
+{
+       return container_of(uart, struct sci_port, port);
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+
+#ifdef CONFIG_CONSOLE_POLL
+static inline void handle_error(struct uart_port *port)
+{
+       /* Clear error flags */
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+}
+
+static int sci_poll_get_char(struct uart_port *port)
+{
+       unsigned short status;
+       int c;
+
+       do {
+               status = sci_in(port, SCxSR);
+               if (status & SCxSR_ERRORS(port)) {
+                       handle_error(port);
+                       continue;
+               }
+               break;
+       } while (1);
+
+       if (!(status & SCxSR_RDxF(port)))
+               return NO_POLL_CHAR;
+
+       c = sci_in(port, SCxRDR);
+
+       /* Dummy read */
+       sci_in(port, SCxSR);
+       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+       return c;
+}
+#endif
+
+static void sci_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       unsigned short status;
+
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TDxE(port)));
+
+       sci_out(port, SCxTDR, c);
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+}
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+#if defined(__H8300H__) || defined(__H8300S__)
+static void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       int ch = (port->mapbase - SMR0) >> 3;
+
+       /* set DDR regs */
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].rx,
+                      H8300_GPIO_INPUT);
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].tx,
+                      H8300_GPIO_OUTPUT);
+
+       /* tx mark output*/
+       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (port->mapbase == 0xA4400000) {
+               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+       } else if (port->mapbase == 0xA4410000)
+               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xfc03), PORT_PVCR);
+               }
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xffc3), PORT_PVCR);
+               }
+       }
+}
+#elif defined(CONFIG_CPU_SH3)
+/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       /* We need to set SCPCR to enable RTS/CTS */
+       data = __raw_readw(SCPCR);
+       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+       __raw_writew(data & 0x0fcf, SCPCR);
+
+       if (!(cflag & CRTSCTS)) {
+               /* We need to set SCPCR to enable RTS/CTS */
+               data = __raw_readw(SCPCR);
+               /* Clear out SCP7MD1,0, SCP4MD1,0,
+                  Set SCP6MD1,0 = {01} (output)  */
+               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+
+               data = __raw_readb(SCPDR);
+               /* Set /RTS2 (bit6) = 0 */
+               __raw_writeb(data & 0xbf, SCPDR);
+       }
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (port->mapbase == 0xffe00000) {
+               data = __raw_readw(PSCR);
+               data &= ~0x03cf;
+               if (!(cflag & CRTSCTS))
+                       data |= 0x0340;
+
+               __raw_writew(data, PSCR);
+       }
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
+      defined(CONFIG_CPU_SUBTYPE_SHX3)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
+}
+#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
+}
+#else
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       /* Nothing to do */
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
+static int scif_txfill(struct uart_port *port)
+{
+       return sci_in(port, SCTFDR) & 0xff;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       return sci_in(port, SCRFDR) & 0xff;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+static int scif_txfill(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return sci_in(port, SCTFDR) & 0xff;
+       else
+               /* SCIF2 */
+               return sci_in(port, SCFDR) >> 8;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return SCIF_TXROOM_MAX - scif_txfill(port);
+       else
+               /* SCIF2 */
+               return SCIF2_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       if ((port->mapbase == 0xffe00000) ||
+           (port->mapbase == 0xffe08000)) {
+               /* SCIF0/1*/
+               return sci_in(port, SCRFDR) & 0xff;
+       } else {
+               /* SCIF2 */
+               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
+       }
+}
+#elif defined(CONFIG_ARCH_SH7372)
+static int scif_txfill(struct uart_port *port)
+{
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) >> 8;
+       else
+               return sci_in(port, SCTFDR);
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return port->fifosize - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+       else
+               return sci_in(port, SCRFDR);
+}
+#else
+static int scif_txfill(struct uart_port *port)
+{
+       return sci_in(port, SCFDR) >> 8;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+}
+#endif
+
+static int sci_txfill(struct uart_port *port)
+{
+       return !(sci_in(port, SCxSR) & SCI_TDRE);
+}
+
+static int sci_txroom(struct uart_port *port)
+{
+       return !sci_txfill(port);
+}
+
+static int sci_rxfill(struct uart_port *port)
+{
+       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+}
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+static void sci_transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int stopped = uart_tx_stopped(port);
+       unsigned short status;
+       unsigned short ctrl;
+       int count;
+
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_TDxE(port))) {
+               ctrl = sci_in(port, SCSCR);
+               if (uart_circ_empty(xmit))
+                       ctrl &= ~SCSCR_TIE;
+               else
+                       ctrl |= SCSCR_TIE;
+               sci_out(port, SCSCR, ctrl);
+               return;
+       }
+
+       if (port->type == PORT_SCI)
+               count = sci_txroom(port);
+       else
+               count = scif_txroom(port);
+
+       do {
+               unsigned char c;
+
+               if (port->x_char) {
+                       c = port->x_char;
+                       port->x_char = 0;
+               } else if (!uart_circ_empty(xmit) && !stopped) {
+                       c = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               } else {
+                       break;
+               }
+
+               sci_out(port, SCxTDR, c);
+
+               port->icount.tx++;
+       } while (--count > 0);
+
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (uart_circ_empty(xmit)) {
+               sci_stop_tx(port);
+       } else {
+               ctrl = sci_in(port, SCSCR);
+
+               if (port->type != PORT_SCI) {
+                       sci_in(port, SCxSR); /* Dummy read */
+                       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+               }
+
+               ctrl |= SCSCR_TIE;
+               sci_out(port, SCSCR, ctrl);
+       }
+}
+
+/* On SH3, SCIF may read end-of-break as a space->mark char */
+#define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
+
+static inline void sci_receive_chars(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int i, count, copied = 0;
+       unsigned short status;
+       unsigned char flag;
+
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_RDxF(port)))
+               return;
+
+       while (1) {
+               if (port->type == PORT_SCI)
+                       count = sci_rxfill(port);
+               else
+                       count = scif_rxfill(port);
+
+               /* Don't copy more bytes than there is room for in the buffer */
+               count = tty_buffer_request_room(tty, count);
+
+               /* If for any reason we can't copy more data, we're done! */
+               if (count == 0)
+                       break;
+
+               if (port->type == PORT_SCI) {
+                       char c = sci_in(port, SCxRDR);
+                       if (uart_handle_sysrq_char(port, c) ||
+                           sci_port->break_flag)
+                               count = 0;
+                       else
+                               tty_insert_flip_char(tty, c, TTY_NORMAL);
+               } else {
+                       for (i = 0; i < count; i++) {
+                               char c = sci_in(port, SCxRDR);
+                               status = sci_in(port, SCxSR);
+#if defined(CONFIG_CPU_SH3)
+                               /* Skip "chars" during break */
+                               if (sci_port->break_flag) {
+                                       if ((c == 0) &&
+                                           (status & SCxSR_FER(port))) {
+                                               count--; i--;
+                                               continue;
+                                       }
+
+                                       /* Nonzero => end-of-break */
+                                       dev_dbg(port->dev, "debounce<%02x>\n", c);
+                                       sci_port->break_flag = 0;
+
+                                       if (STEPFN(c)) {
+                                               count--; i--;
+                                               continue;
+                                       }
+                               }
+#endif /* CONFIG_CPU_SH3 */
+                               if (uart_handle_sysrq_char(port, c)) {
+                                       count--; i--;
+                                       continue;
+                               }
+
+                               /* Store data and status */
+                               if (status & SCxSR_FER(port)) {
+                                       flag = TTY_FRAME;
+                                       dev_notice(port->dev, "frame error\n");
+                               } else if (status & SCxSR_PER(port)) {
+                                       flag = TTY_PARITY;
+                                       dev_notice(port->dev, "parity error\n");
+                               } else
+                                       flag = TTY_NORMAL;
+
+                               tty_insert_flip_char(tty, c, flag);
+                       }
+               }
+
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+               copied += count;
+               port->icount.rx += count;
+       }
+
+       if (copied) {
+               /* Tell the rest of the system the news. New characters! */
+               tty_flip_buffer_push(tty);
+       } else {
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       }
+}
+
+#define SCI_BREAK_JIFFIES (HZ/20)
+/* The sci generates interrupts during the break,
+ * 1 per millisecond or so during the break period, for 9600 baud.
+ * So dont bother disabling interrupts.
+ * But dont want more than 1 break event.
+ * Use a kernel timer to periodically poll the rx line until
+ * the break is finished.
+ */
+static void sci_schedule_break_timer(struct sci_port *port)
+{
+       port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
+       add_timer(&port->break_timer);
+}
+/* Ensure that two consecutive samples find the break over. */
+static void sci_break_timer(unsigned long data)
+{
+       struct sci_port *port = (struct sci_port *)data;
+
+       if (sci_rxd_in(&port->port) == 0) {
+               port->break_flag = 1;
+               sci_schedule_break_timer(port);
+       } else if (port->break_flag == 1) {
+               /* break is over. */
+               port->break_flag = 2;
+               sci_schedule_break_timer(port);
+       } else
+               port->break_flag = 0;
+}
+
+static inline int sci_handle_errors(struct uart_port *port)
+{
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+
+       if (status & SCxSR_ORER(port)) {
+               /* overrun error */
+               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+                       copied++;
+
+               dev_notice(port->dev, "overrun error");
+       }
+
+       if (status & SCxSR_FER(port)) {
+               if (sci_rxd_in(port) == 0) {
+                       /* Notify of BREAK */
+                       struct sci_port *sci_port = to_sci_port(port);
+
+                       if (!sci_port->break_flag) {
+                               sci_port->break_flag = 1;
+                               sci_schedule_break_timer(sci_port);
+
+                               /* Do sysrq handling. */
+                               if (uart_handle_break(port))
+                                       return 0;
+
+                               dev_dbg(port->dev, "BREAK detected\n");
+
+                               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                                       copied++;
+                       }
+
+               } else {
+                       /* frame error */
+                       if (tty_insert_flip_char(tty, 0, TTY_FRAME))
+                               copied++;
+
+                       dev_notice(port->dev, "frame error\n");
+               }
+       }
+
+       if (status & SCxSR_PER(port)) {
+               /* parity error */
+               if (tty_insert_flip_char(tty, 0, TTY_PARITY))
+                       copied++;
+
+               dev_notice(port->dev, "parity error");
+       }
+
+       if (copied)
+               tty_flip_buffer_push(tty);
+
+       return copied;
+}
+
+static inline int sci_handle_fifo_overrun(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       int copied = 0;
+
+       if (port->type != PORT_SCIF)
+               return 0;
+
+       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+               sci_out(port, SCLSR, 0);
+
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               tty_flip_buffer_push(tty);
+
+               dev_notice(port->dev, "overrun error\n");
+               copied++;
+       }
+
+       return copied;
+}
+
+static inline int sci_handle_breaks(struct uart_port *port)
+{
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
+
+       if (uart_handle_break(port))
+               return 0;
+
+       if (!s->break_flag && status & SCxSR_BRK(port)) {
+#if defined(CONFIG_CPU_SH3)
+               /* Debounce break */
+               s->break_flag = 1;
+#endif
+               /* Notify of BREAK */
+               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                       copied++;
+
+               dev_dbg(port->dev, "BREAK detected\n");
+       }
+
+       if (copied)
+               tty_flip_buffer_push(tty);
+
+       copied += sci_handle_fifo_overrun(port);
+
+       return copied;
+}
+
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
+{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+
+       if (s->chan_rx) {
+               u16 scr = sci_in(port, SCSCR);
+               u16 ssr = sci_in(port, SCxSR);
+
+               /* Disable future Rx interrupts */
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       disable_irq_nosync(irq);
+                       scr |= 0x4000;
+               } else {
+                       scr &= ~SCSCR_RIE;
+               }
+               sci_out(port, SCSCR, scr);
+               /* Clear current interrupt */
+               sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+
+               return IRQ_HANDLED;
+       }
+#endif
+
+       /* I think sci_receive_chars has to be called irrespective
+        * of whether the I_IXOFF is set, otherwise, how is the interrupt
+        * to be disabled?
+        */
+       sci_receive_chars(ptr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       sci_transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+
+       /* Handle errors */
+       if (port->type == PORT_SCI) {
+               if (sci_handle_errors(port)) {
+                       /* discard character in rx buffer */
+                       sci_in(port, SCxSR);
+                       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               }
+       } else {
+               sci_handle_fifo_overrun(port);
+               sci_rx_interrupt(irq, ptr);
+       }
+
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+
+       /* Kick the transmission */
+       sci_tx_interrupt(irq, ptr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+
+       /* Handle BREAKs */
+       sci_handle_breaks(port);
+       sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+
+       return IRQ_HANDLED;
+}
+
+static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+{
+       /*
+        * Not all ports (such as SCIFA) will support REIE. Rather than
+        * special-casing the port type, we check the port initialization
+        * IRQ enable mask to see whether the IRQ is desired at all. If
+        * it's unset, it's logically inferred that there's no point in
+        * testing for it.
+        */
+       return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE);
+}
+
+static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+{
+       unsigned short ssr_status, scr_status, err_enabled;
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       irqreturn_t ret = IRQ_NONE;
+
+       ssr_status = sci_in(port, SCxSR);
+       scr_status = sci_in(port, SCSCR);
+       err_enabled = scr_status & port_rx_irq_mask(port);
+
+       /* Tx Interrupt */
+       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
+           !s->chan_tx)
+               ret = sci_tx_interrupt(irq, ptr);
+
+       /*
+        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+        * DR flags
+        */
+       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
+           (scr_status & SCSCR_RIE))
+               ret = sci_rx_interrupt(irq, ptr);
+
+       /* Error Interrupt */
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
+               ret = sci_er_interrupt(irq, ptr);
+
+       /* Break Interrupt */
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+               ret = sci_br_interrupt(irq, ptr);
+
+       return ret;
+}
+
+/*
+ * Here we define a transistion notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+static int sci_notifier(struct notifier_block *self,
+                       unsigned long phase, void *p)
+{
+       struct sh_sci_priv *priv = container_of(self,
+                                               struct sh_sci_priv, clk_nb);
+       struct sci_port *sci_port;
+       unsigned long flags;
+
+       if ((phase == CPUFREQ_POSTCHANGE) ||
+           (phase == CPUFREQ_RESUMECHANGE)) {
+               spin_lock_irqsave(&priv->lock, flags);
+               list_for_each_entry(sci_port, &priv->ports, node)
+                       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
+       return NOTIFY_OK;
+}
+
+static void sci_clk_enable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       clk_enable(sci_port->iclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+       clk_enable(sci_port->fclk);
+}
+
+static void sci_clk_disable(struct uart_port *port)
+{
+       struct sci_port *sci_port = to_sci_port(port);
+
+       clk_disable(sci_port->fclk);
+       clk_disable(sci_port->iclk);
+}
+
+static int sci_request_irq(struct sci_port *port)
+{
+       int i;
+       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
+               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+               sci_br_interrupt,
+       };
+       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
+                              "SCI Transmit Data Empty", "SCI Break" };
+
+       if (port->irqs[0] == port->irqs[1]) {
+               if (unlikely(!port->irqs[0]))
+                       return -ENODEV;
+
+               if (request_irq(port->irqs[0], sci_mpxed_interrupt,
+                               IRQF_DISABLED, "sci", port)) {
+                       dev_err(port->port.dev, "Can't allocate IRQ\n");
+                       return -ENODEV;
+               }
+       } else {
+               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+                       if (unlikely(!port->irqs[i]))
+                               continue;
+
+                       if (request_irq(port->irqs[i], handlers[i],
+                                       IRQF_DISABLED, desc[i], port)) {
+                               dev_err(port->port.dev, "Can't allocate IRQ\n");
+                               return -ENODEV;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void sci_free_irq(struct sci_port *port)
+{
+       int i;
+
+       if (port->irqs[0] == port->irqs[1])
+               free_irq(port->irqs[0], port);
+       else {
+               for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
+                       if (!port->irqs[i])
+                               continue;
+
+                       free_irq(port->irqs[i], port);
+               }
+       }
+}
+
+static unsigned int sci_tx_empty(struct uart_port *port)
+{
+       unsigned short status = sci_in(port, SCxSR);
+       unsigned short in_tx_fifo = scif_txfill(port);
+
+       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
+}
+
+static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
+       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
+       /* If you have signals for DTR and DCD, please implement here. */
+}
+
+static unsigned int sci_get_mctrl(struct uart_port *port)
+{
+       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
+          and CTS/RTS */
+
+       return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static void sci_dma_tx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       xmit->tail += sg_dma_len(&s->sg_tx);
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       port->icount.tx += sg_dma_len(&s->sg_tx);
+
+       async_tx_ack(s->desc_tx);
+       s->cookie_tx = -EINVAL;
+       s->desc_tx = NULL;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (!uart_circ_empty(xmit)) {
+               schedule_work(&s->work_tx);
+       } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Locking: called with port lock held */
+static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
+                          size_t count)
+{
+       struct uart_port *port = &s->port;
+       int i, active, room;
+
+       room = tty_buffer_request_room(tty, count);
+
+       if (s->active_rx == s->cookie_rx[0]) {
+               active = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               active = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return 0;
+       }
+
+       if (room < count)
+               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+                        count - room);
+       if (!room)
+               return room;
+
+       for (i = 0; i < room; i++)
+               tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
+                                    TTY_NORMAL);
+
+       port->icount.rx += room;
+
+       return room;
+}
+
+static void sci_dma_rx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned long flags;
+       int count;
+
+       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       count = sci_dma_rx_push(s, tty, s->buf_len_rx);
+
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (count)
+               tty_flip_buffer_push(tty);
+
+       schedule_work(&s->work_rx);
+}
+
+static void sci_start_rx(struct uart_port *port);
+static void sci_start_tx(struct uart_port *port);
+
+static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+{
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+
+       s->chan_rx = NULL;
+       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+       dma_release_channel(chan);
+       if (sg_dma_address(&s->sg_rx[0]))
+               dma_free_coherent(port->dev, s->buf_len_rx * 2,
+                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
+       if (enable_pio)
+               sci_start_rx(port);
+}
+
+static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+{
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+
+       s->chan_tx = NULL;
+       s->cookie_tx = -EINVAL;
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_tx(port);
+}
+
+static void sci_submit_rx(struct sci_port *s)
+{
+       struct dma_chan *chan = s->chan_rx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct scatterlist *sg = &s->sg_rx[i];
+               struct dma_async_tx_descriptor *desc;
+
+               desc = chan->device->device_prep_slave_sg(chan,
+                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
+
+               if (desc) {
+                       s->desc_rx[i] = desc;
+                       desc->callback = sci_dma_rx_complete;
+                       desc->callback_param = s;
+                       s->cookie_rx[i] = desc->tx_submit(desc);
+               }
+
+               if (!desc || s->cookie_rx[i] < 0) {
+                       if (i) {
+                               async_tx_ack(s->desc_rx[0]);
+                               s->cookie_rx[0] = -EINVAL;
+                       }
+                       if (desc) {
+                               async_tx_ack(desc);
+                               s->cookie_rx[i] = -EINVAL;
+                       }
+                       dev_warn(s->port.dev,
+                                "failed to re-start DMA, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
+       }
+
+       s->active_rx = s->cookie_rx[0];
+
+       dma_async_issue_pending(chan);
+}
+
+static void work_fn_rx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_rx);
+       struct uart_port *port = &s->port;
+       struct dma_async_tx_descriptor *desc;
+       int new;
+
+       if (s->active_rx == s->cookie_rx[0]) {
+               new = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               new = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return;
+       }
+       desc = s->desc_rx[new];
+
+       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
+           DMA_SUCCESS) {
+               /* Handle incomplete DMA receive */
+               struct tty_struct *tty = port->state->port.tty;
+               struct dma_chan *chan = s->chan_rx;
+               struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
+                                                      async_tx);
+               unsigned long flags;
+               int count;
+
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
+                       sh_desc->partial, sh_desc->cookie);
+
+               spin_lock_irqsave(&port->lock, flags);
+               count = sci_dma_rx_push(s, tty, sh_desc->partial);
+               spin_unlock_irqrestore(&port->lock, flags);
+
+               if (count)
+                       tty_flip_buffer_push(tty);
+
+               sci_submit_rx(s);
+
+               return;
+       }
+
+       s->cookie_rx[new] = desc->tx_submit(desc);
+       if (s->cookie_rx[new] < 0) {
+               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+               sci_rx_dma_release(s, true);
+               return;
+       }
+
+       s->active_rx = s->cookie_rx[!new];
+
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
+               s->cookie_rx[new], new, s->active_rx);
+}
+
+static void work_fn_tx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_tx);
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct scatterlist *sg = &s->sg_tx;
+
+       /*
+        * DMA is idle now.
+        * Port xmit buffer is already mapped, and it is one page... Just adjust
+        * offsets and lengths. Since it is a circular buffer, we have to
+        * transmit till the end, and then the rest. Take the port lock to get a
+        * consistent xmit buffer state.
+        */
+       spin_lock_irq(&port->lock);
+       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+               sg->offset;
+       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+       spin_unlock_irq(&port->lock);
+
+       BUG_ON(!sg_dma_len(sg));
+
+       desc = chan->device->device_prep_slave_sg(chan,
+                       sg, s->sg_len_tx, DMA_TO_DEVICE,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+
+       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+       spin_lock_irq(&port->lock);
+       s->desc_tx = desc;
+       desc->callback = sci_dma_tx_complete;
+       desc->callback_param = s;
+       spin_unlock_irq(&port->lock);
+       s->cookie_tx = desc->tx_submit(desc);
+       if (s->cookie_tx < 0) {
+               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+
+       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
+               xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+
+       dma_async_issue_pending(chan);
+}
+#endif
+
+static void sci_start_tx(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       unsigned short ctrl;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 new, scr = sci_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | 0x8000;
+               else
+                       new = scr & ~0x8000;
+               if (new != scr)
+                       sci_out(port, SCSCR, new);
+       }
+
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           s->cookie_tx < 0)
+               schedule_work(&s->work_tx);
+#endif
+
+       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl | SCSCR_TIE);
+       }
+}
+
+static void sci_stop_tx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+       ctrl = sci_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x8000;
+
+       ctrl &= ~SCSCR_TIE;
+
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_start_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
+
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_stop_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = sci_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
+
+       ctrl &= ~port_rx_irq_mask(port);
+
+       sci_out(port, SCSCR, ctrl);
+}
+
+static void sci_enable_ms(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+}
+
+static void sci_break_ctl(struct uart_port *port, int break_state)
+{
+       /* Nothing here yet .. */
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct sh_dmae_slave *param = slave;
+
+       dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
+               param->slave_id);
+
+       if (param->dma_dev == chan->device->dev) {
+               chan->private = param;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static void rx_timer_fn(unsigned long arg)
+{
+       struct sci_port *s = (struct sci_port *)arg;
+       struct uart_port *port = &s->port;
+       u16 scr = sci_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               scr &= ~0x4000;
+               enable_irq(s->irqs[1]);
+       }
+       sci_out(port, SCSCR, scr | SCSCR_RIE);
+       dev_dbg(port->dev, "DMA Rx timed out\n");
+       schedule_work(&s->work_rx);
+}
+
+static void sci_request_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       struct sh_dmae_slave *param;
+       struct dma_chan *chan;
+       dma_cap_mask_t mask;
+       int nent;
+
+       dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
+               port->line, s->dma_dev);
+
+       if (!s->dma_dev)
+               return;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       param = &s->param_tx;
+
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
+       param->slave_id = s->slave_tx;
+       param->dma_dev = s->dma_dev;
+
+       s->cookie_tx = -EINVAL;
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+       if (chan) {
+               s->chan_tx = chan;
+               sg_init_table(&s->sg_tx, 1);
+               /* UART circular tx buffer is an aligned page. */
+               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
+                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
+               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
+               if (!nent)
+                       sci_tx_dma_release(s, false);
+               else
+                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+                               sg_dma_len(&s->sg_tx),
+                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
+
+               s->sg_len_tx = nent;
+
+               INIT_WORK(&s->work_tx, work_fn_tx);
+       }
+
+       param = &s->param_rx;
+
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
+       param->slave_id = s->slave_rx;
+       param->dma_dev = s->dma_dev;
+
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+       if (chan) {
+               dma_addr_t dma[2];
+               void *buf[2];
+               int i;
+
+               s->chan_rx = chan;
+
+               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
+               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
+                                           &dma[0], GFP_KERNEL);
+
+               if (!buf[0]) {
+                       dev_warn(port->dev,
+                                "failed to allocate dma buffer, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+
+               buf[1] = buf[0] + s->buf_len_rx;
+               dma[1] = dma[0] + s->buf_len_rx;
+
+               for (i = 0; i < 2; i++) {
+                       struct scatterlist *sg = &s->sg_rx[i];
+
+                       sg_init_table(sg, 1);
+                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
+                                   (int)buf[i] & ~PAGE_MASK);
+                       sg_dma_address(sg) = dma[i];
+               }
+
+               INIT_WORK(&s->work_rx, work_fn_rx);
+               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
+
+               sci_submit_rx(s);
+       }
+}
+
+static void sci_free_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (!s->dma_dev)
+               return;
+
+       if (s->chan_tx)
+               sci_tx_dma_release(s, false);
+       if (s->chan_rx)
+               sci_rx_dma_release(s, false);
+}
+#endif
+
+static int sci_startup(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       if (s->enable)
+               s->enable(port);
+
+       sci_request_irq(s);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_request_dma(port);
+#endif
+       sci_start_tx(port);
+       sci_start_rx(port);
+
+       return 0;
+}
+
+static void sci_shutdown(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+       sci_stop_rx(port);
+       sci_stop_tx(port);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_free_dma(port);
+#endif
+       sci_free_irq(s);
+
+       if (s->disable)
+               s->disable(port);
+}
+
+static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
+                                  unsigned long freq)
+{
+       switch (algo_id) {
+       case SCBRR_ALGO_1:
+               return ((freq + 16 * bps) / (16 * bps) - 1);
+       case SCBRR_ALGO_2:
+               return ((freq + 16 * bps) / (32 * bps) - 1);
+       case SCBRR_ALGO_3:
+               return (((freq * 2) + 16 * bps) / (16 * bps) - 1);
+       case SCBRR_ALGO_4:
+               return (((freq * 2) + 16 * bps) / (32 * bps) - 1);
+       case SCBRR_ALGO_5:
+               return (((freq * 1000 / 32) / bps) - 1);
+       }
+
+       /* Warn, but use a safe default */
+       WARN_ON(1);
+       return ((freq + 16 * bps) / (32 * bps) - 1);
+}
+
+static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+{
+       struct sci_port *s = to_sci_port(port);
+       unsigned int status, baud, smr_val, max_baud;
+       int t = -1;
+       u16 scfcr = 0;
+
+       /*
+        * earlyprintk comes here early on with port->uartclk set to zero.
+        * the clock framework is not up and running at this point so here
+        * we assume that 115200 is the maximum baud rate. please note that
+        * the baud rate is not programmed during earlyprintk - it is assumed
+        * that the previous boot loader has enabled required clocks and
+        * setup the baud rate generator hardware for us already.
+        */
+       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
+       if (likely(baud && port->uartclk))
+               t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk);
+
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TEND(port)));
+
+       sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
+
+       if (port->type != PORT_SCI)
+               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
+
+       smr_val = sci_in(port, SCSMR) & 3;
+       if ((termios->c_cflag & CSIZE) == CS7)
+               smr_val |= 0x40;
+       if (termios->c_cflag & PARENB)
+               smr_val |= 0x20;
+       if (termios->c_cflag & PARODD)
+               smr_val |= 0x30;
+       if (termios->c_cflag & CSTOPB)
+               smr_val |= 0x08;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       sci_out(port, SCSMR, smr_val);
+
+       dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
+               s->scscr);
+
+       if (t > 0) {
+               if (t >= 256) {
+                       sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
+                       t >>= 2;
+               } else
+                       sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
+
+               sci_out(port, SCBRR, t);
+               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
+       }
+
+       sci_init_pins(port, termios->c_cflag);
+       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
+
+       sci_out(port, SCSCR, s->scscr);
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       /*
+        * Calculate delay for 1.5 DMA buffers: see
+        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
+        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
+        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
+        * sizes), but it has been found out experimentally, that this is not
+        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
+        * as a minimum seem to work perfectly.
+        */
+       if (s->chan_rx) {
+               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+                       port->fifosize / 2;
+               dev_dbg(port->dev,
+                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+                       s->rx_timeout * 1000 / HZ, port->timeout);
+               if (s->rx_timeout < msecs_to_jiffies(20))
+                       s->rx_timeout = msecs_to_jiffies(20);
+       }
+#endif
+
+       if ((termios->c_cflag & CREAD) != 0)
+               sci_start_rx(port);
+}
+
+static const char *sci_type(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_IRDA:
+               return "irda";
+       case PORT_SCI:
+               return "sci";
+       case PORT_SCIF:
+               return "scif";
+       case PORT_SCIFA:
+               return "scifa";
+       case PORT_SCIFB:
+               return "scifb";
+       }
+
+       return NULL;
+}
+
+static void sci_release_port(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+}
+
+static int sci_request_port(struct uart_port *port)
+{
+       /* Nothing here yet .. */
+       return 0;
+}
+
+static void sci_config_port(struct uart_port *port, int flags)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       port->type = s->type;
+
+       if (port->membase)
+               return;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap_nocache(port->mapbase, 0x40);
+
+               if (IS_ERR(port->membase))
+                       dev_err(port->dev, "can't remap port#%d\n", port->line);
+       } else {
+               /*
+                * For the simple (and majority of) cases where we don't
+                * need to do any remapping, just cast the cookie
+                * directly.
+                */
+               port->membase = (void __iomem *)port->mapbase;
+       }
+}
+
+static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
+               return -EINVAL;
+       if (ser->baud_base < 2400)
+               /* No paper tape reader for Mitch.. */
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct uart_ops sci_uart_ops = {
+       .tx_empty       = sci_tx_empty,
+       .set_mctrl      = sci_set_mctrl,
+       .get_mctrl      = sci_get_mctrl,
+       .start_tx       = sci_start_tx,
+       .stop_tx        = sci_stop_tx,
+       .stop_rx        = sci_stop_rx,
+       .enable_ms      = sci_enable_ms,
+       .break_ctl      = sci_break_ctl,
+       .startup        = sci_startup,
+       .shutdown       = sci_shutdown,
+       .set_termios    = sci_set_termios,
+       .type           = sci_type,
+       .release_port   = sci_release_port,
+       .request_port   = sci_request_port,
+       .config_port    = sci_config_port,
+       .verify_port    = sci_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = sci_poll_get_char,
+       .poll_put_char  = sci_poll_put_char,
+#endif
+};
+
+static int __devinit sci_init_single(struct platform_device *dev,
+                                    struct sci_port *sci_port,
+                                    unsigned int index,
+                                    struct plat_sci_port *p)
+{
+       struct uart_port *port = &sci_port->port;
+
+       port->ops       = &sci_uart_ops;
+       port->iotype    = UPIO_MEM;
+       port->line      = index;
+
+       switch (p->type) {
+       case PORT_SCIFB:
+               port->fifosize = 256;
+               break;
+       case PORT_SCIFA:
+               port->fifosize = 64;
+               break;
+       case PORT_SCIF:
+               port->fifosize = 16;
+               break;
+       default:
+               port->fifosize = 1;
+               break;
+       }
+
+       if (dev) {
+               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
+               if (IS_ERR(sci_port->iclk)) {
+                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
+                       if (IS_ERR(sci_port->iclk)) {
+                               dev_err(&dev->dev, "can't get iclk\n");
+                               return PTR_ERR(sci_port->iclk);
+                       }
+               }
+
+               /*
+                * The function clock is optional, ignore it if we can't
+                * find it.
+                */
+               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
+               if (IS_ERR(sci_port->fclk))
+                       sci_port->fclk = NULL;
+
+               sci_port->enable = sci_clk_enable;
+               sci_port->disable = sci_clk_disable;
+               port->dev = &dev->dev;
+       }
+
+       sci_port->break_timer.data = (unsigned long)sci_port;
+       sci_port->break_timer.function = sci_break_timer;
+       init_timer(&sci_port->break_timer);
+
+       port->mapbase   = p->mapbase;
+       port->membase   = p->membase;
+
+       port->irq               = p->irqs[SCIx_TXI_IRQ];
+       port->flags             = p->flags;
+       sci_port->type          = port->type = p->type;
+       sci_port->scscr         = p->scscr;
+       sci_port->scbrr_algo_id = p->scbrr_algo_id;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_port->dma_dev       = p->dma_dev;
+       sci_port->slave_tx      = p->dma_slave_tx;
+       sci_port->slave_rx      = p->dma_slave_rx;
+
+       dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
+               p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
+#endif
+
+       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
+       return 0;
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+static struct tty_driver *serial_console_device(struct console *co, int *index)
+{
+       struct uart_driver *p = &sci_uart_driver;
+       *index = co->index;
+       return p->tty_driver;
+}
+
+static void serial_console_putchar(struct uart_port *port, int ch)
+{
+       sci_poll_put_char(port, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+                                unsigned count)
+{
+       struct uart_port *port = co->data;
+       struct sci_port *sci_port = to_sci_port(port);
+       unsigned short bits;
+
+       if (sci_port->enable)
+               sci_port->enable(port);
+
+       uart_console_write(port, s, count, serial_console_putchar);
+
+       /* wait until fifo is empty and last bit has been transmitted */
+       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
+       while ((sci_in(port, SCxSR) & bits) != bits)
+               cpu_relax();
+
+       if (sci_port->disable)
+               sci_port->disable(port);
+}
+
+static int __devinit serial_console_setup(struct console *co, char *options)
+{
+       struct sci_port *sci_port;
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= SCI_NPORTS)
+               co->index = 0;
+
+       if (co->data) {
+               port = co->data;
+               sci_port = to_sci_port(port);
+       } else {
+               sci_port = &sci_ports[co->index];
+               port = &sci_port->port;
+               co->data = port;
+       }
+
+       /*
+        * Also need to check port->type, we don't actually have any
+        * UPIO_PORT ports, but uart_report_port() handily misreports
+        * it anyways if we don't have a port available by the time this is
+        * called.
+        */
+       if (!port->type)
+               return -ENODEV;
+
+       sci_config_port(port, 0);
+
+       if (sci_port->enable)
+               sci_port->enable(port);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       ret = uart_set_options(port, co, baud, parity, bits, flow);
+#if defined(__H8300H__) || defined(__H8300S__)
+       /* disable rx interrupt */
+       if (ret == 0)
+               sci_stop_rx(port);
+#endif
+       /* TODO: disable clock */
+       return ret;
+}
+
+static struct console serial_console = {
+       .name           = "ttySC",
+       .device         = serial_console_device,
+       .write          = serial_console_write,
+       .setup          = serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+static int __init sci_console_init(void)
+{
+       register_console(&serial_console);
+       return 0;
+}
+console_initcall(sci_console_init);
+
+static struct sci_port early_serial_port;
+static struct console early_serial_console = {
+       .name           = "early_ttySC",
+       .write          = serial_console_write,
+       .flags          = CON_PRINTBUFFER,
+};
+static char early_serial_buf[32];
+
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#define SCI_CONSOLE    (&serial_console)
+#else
+#define SCI_CONSOLE    0
+#endif
+
+static char banner[] __initdata =
+       KERN_INFO "SuperH SCI(F) driver initialized\n";
+
+static struct uart_driver sci_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "sci",
+       .dev_name       = "ttySC",
+       .major          = SCI_MAJOR,
+       .minor          = SCI_MINOR_START,
+       .nr             = SCI_NPORTS,
+       .cons           = SCI_CONSOLE,
+};
+
+
+static int sci_remove(struct platform_device *dev)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node) {
+               uart_remove_one_port(&sci_uart_driver, &p->port);
+               clk_put(p->iclk);
+               clk_put(p->fclk);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       kfree(priv);
+       return 0;
+}
+
+static int __devinit sci_probe_single(struct platform_device *dev,
+                                     unsigned int index,
+                                     struct plat_sci_port *p,
+                                     struct sci_port *sciport)
+{
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       unsigned long flags;
+       int ret;
+
+       /* Sanity check */
+       if (unlikely(index >= SCI_NPORTS)) {
+               dev_notice(&dev->dev, "Attempting to register port "
+                          "%d when only %d are available.\n",
+                          index+1, SCI_NPORTS);
+               dev_notice(&dev->dev, "Consider bumping "
+                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+               return 0;
+       }
+
+       ret = sci_init_single(dev, sciport, index, p);
+       if (ret)
+               return ret;
+
+       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&sciport->node);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_add(&sciport->node, &priv->ports);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.  The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
+ * remapping (such as sh64) should also set UPF_IOREMAP.
+ */
+static int __devinit sci_probe(struct platform_device *dev)
+{
+       struct plat_sci_port *p = dev->dev.platform_data;
+       struct sh_sci_priv *priv;
+       int i, ret = -EINVAL;
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+       if (is_early_platform_device(dev)) {
+               if (dev->id == -1)
+                       return -ENOTSUPP;
+               early_serial_console.index = dev->id;
+               early_serial_console.data = &early_serial_port.port;
+               sci_init_single(NULL, &early_serial_port, dev->id, p);
+               serial_console_setup(&early_serial_console, early_serial_buf);
+               if (!strstr(early_serial_buf, "keep"))
+                       early_serial_console.flags |= CON_BOOT;
+               register_console(&early_serial_console);
+               return 0;
+       }
+#endif
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&priv->ports);
+       spin_lock_init(&priv->lock);
+       platform_set_drvdata(dev, priv);
+
+       priv->clk_nb.notifier_call = sci_notifier;
+       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+
+       if (dev->id != -1) {
+               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
+               if (ret)
+                       goto err_unreg;
+       } else {
+               for (i = 0; p && p->flags != 0; p++, i++) {
+                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
+                       if (ret)
+                               goto err_unreg;
+               }
+       }
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+       sh_bios_gdb_detach();
+#endif
+
+       return 0;
+
+err_unreg:
+       sci_remove(dev);
+       return ret;
+}
+
+static int sci_suspend(struct device *dev)
+{
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_suspend_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int sci_resume(struct device *dev)
+{
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_resume_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static const struct dev_pm_ops sci_dev_pm_ops = {
+       .suspend        = sci_suspend,
+       .resume         = sci_resume,
+};
+
+static struct platform_driver sci_driver = {
+       .probe          = sci_probe,
+       .remove         = sci_remove,
+       .driver         = {
+               .name   = "sh-sci",
+               .owner  = THIS_MODULE,
+               .pm     = &sci_dev_pm_ops,
+       },
+};
+
+static int __init sci_init(void)
+{
+       int ret;
+
+       printk(banner);
+
+       ret = uart_register_driver(&sci_uart_driver);
+       if (likely(ret == 0)) {
+               ret = platform_driver_register(&sci_driver);
+               if (unlikely(ret))
+                       uart_unregister_driver(&sci_uart_driver);
+       }
+
+       return ret;
+}
+
+static void __exit sci_exit(void)
+{
+       platform_driver_unregister(&sci_driver);
+       uart_unregister_driver(&sci_uart_driver);
+}
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+early_platform_init_buffer("earlyprintk", &sci_driver,
+                          early_serial_buf, ARRAY_SIZE(early_serial_buf));
+#endif
+module_init(sci_init);
+module_exit(sci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-sci");
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
new file mode 100644 (file)
index 0000000..b223d6c
--- /dev/null
@@ -0,0 +1,507 @@
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_H8S2678)
+#include <asm/regs267x.h>
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
+# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+# define SCIF0         0xA4400000
+# define SCIF2         0xA4410000
+# define SCPCR 0xA4000116
+# define SCPDR 0xA4000136
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+      defined(CONFIG_ARCH_SH73A0) || \
+      defined(CONFIG_ARCH_SH7367) || \
+      defined(CONFIG_ARCH_SH7377) || \
+      defined(CONFIG_ARCH_SH7372)
+# define PORT_PTCR        0xA405011EUL
+# define PORT_PVCR        0xA4050122UL
+# define SCIF_ORER        0x0200   /* overrun error bit */
+#elif defined(CONFIG_SH_RTS7751R2D)
+# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751R)
+# define SCSPTR1 0xffe0001c /* 8  bit SCI */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
+# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
+# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define PACR 0xa4050100
+# define PBCR 0xa4050102
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
+# define SCSPTR1 0xffe10010    /* 16 bit SCIF */
+# define SCSPTR2 0xffe20010    /* 16 bit SCIF */
+# define SCSPTR3 0xffe30010    /* 16 bit SCIF */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+# define PADR                  0xA4050120
+# define PSDR                  0xA405013e
+# define PWDR                  0xA4050166
+# define PSCR                  0xA405011E
+# define SCIF_ORER             0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
+# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
+# define SCSPTR0               SCPDR0
+# define SCIF_ORER             0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+# define SCSPTR0                0xa4050160
+# define SCSPTR1                0xa405013e
+# define SCSPTR2                0xa4050160
+# define SCSPTR3                0xa405013e
+# define SCSPTR4                0xa4050128
+# define SCSPTR5                0xa4050128
+# define SCIF_ORER              0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+# define SCIF_ORER              0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
+# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+# define SCIF_PTR2_OFFS    0x0000020
+# define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
+#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_H8S2678)
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+# define SCSPTR0 0xfe4b0020
+# define SCSPTR1 0xfe4b0020
+# define SCSPTR2 0xfe4b0020
+# define SCIF_ORER 0x0001
+# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
+# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
+# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+# define SCSPTR0 0xff923020 /* 16 bit SCIF */
+# define SCSPTR1 0xff924020 /* 16 bit SCIF */
+# define SCSPTR2 0xff925020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
+# define SCSPTR1       0xffe10024      /* 16 bit SCIF */
+# define SCIF_ORER     0x0001          /* Overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7786)
+# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
+# define SCSPTR1       0xffeb0024      /* 16 bit SCIF */
+# define SCSPTR2       0xffec0024      /* 16 bit SCIF */
+# define SCSPTR3       0xffed0024      /* 16 bit SCIF */
+# define SCSPTR4       0xffee0024      /* 16 bit SCIF */
+# define SCSPTR5       0xffef0024      /* 16 bit SCIF */
+# define SCIF_ORER     0x0001          /* Overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7263)
+# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
+# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
+# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
+# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
+# if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
+#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
+#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
+#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
+# endif
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
+# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
+# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
+# define SCSPTR1 0xffc40020            /* 16 bit SCIF */
+# define SCSPTR2 0xffc50020            /* 16 bit SCIF */
+# define SCSPTR3 0xffc60020            /* 16 bit SCIF */
+# define SCIF_ORER 0x0001              /* Overrun error bit */
+#else
+# error CPU subtype not defined
+#endif
+
+/* SCxSR SCI */
+#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+
+#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
+
+/* SCxSR SCIF */
+#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+# define SCIF_ORER    0x0200
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
+# define SCIF_RFDC_MASK 0x007f
+# define SCIF_TXROOM_MAX 64
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
+# define SCIF_RFDC_MASK 0x007f
+# define SCIF_TXROOM_MAX 64
+/* SH7763 SCIF2 support */
+# define SCIF2_RFDC_MASK 0x001f
+# define SCIF2_TXROOM_MAX 16
+#else
+# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+# define SCIF_RFDC_MASK 0x001f
+# define SCIF_TXROOM_MAX 16
+#endif
+
+#ifndef SCIF_ORER
+#define SCIF_ORER      0x0000
+#endif
+
+#define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
+#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
+#define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
+#define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
+#define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
+#define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
+#define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
+#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+# define SCxSR_RDxF_CLEAR(port)         (sci_in(port, SCxSR) & 0xfffc)
+# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
+# define SCxSR_TDxE_CLEAR(port)         (sci_in(port, SCxSR) & 0xffdf)
+# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
+#else
+# define SCxSR_RDxF_CLEAR(port)         (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
+# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
+# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
+# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+#endif
+
+/* SCFCR */
+#define SCFCR_RFRST 0x0002
+#define SCFCR_TFRST 0x0004
+#define SCFCR_MCE   0x0008
+
+#define SCI_MAJOR              204
+#define SCI_MINOR_START                8
+
+#define SCI_IN(size, offset)                                   \
+  if ((size) == 8) {                                           \
+    return ioread8(port->membase + (offset));                  \
+  } else {                                                     \
+    return ioread16(port->membase + (offset));                 \
+  }
+#define SCI_OUT(size, offset, value)                           \
+  if ((size) == 8) {                                           \
+    iowrite8(value, port->membase + (offset));                 \
+  } else if ((size) == 16) {                                   \
+    iowrite16(value, port->membase + (offset));                        \
+  }
+
+#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
+      SCI_IN(scif_size, scif_offset)                                   \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_IN(sci_size, sci_offset);                                    \
+    }                                                                  \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
+      SCI_OUT(scif_size, scif_offset, value)                           \
+    } else {   /* PORT_SCI or PORT_SCIFA */                            \
+      SCI_OUT(sci_size, sci_offset, value);                            \
+    }                                                                  \
+  }
+
+#ifdef CONFIG_H8300
+/* h8300 don't have SCIF */
+#define CPU_SCIF_FNS(name)                                             \
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    return 0;                                                          \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+  }
+#else
+#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
+  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
+  {                                                                    \
+    SCI_IN(scif_size, scif_offset);                                    \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {                                                                    \
+    SCI_OUT(scif_size, scif_offset, value);                            \
+  }
+#endif
+
+#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
+  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
+  {                                                                    \
+    SCI_IN(sci_size, sci_offset);                                      \
+  }                                                                    \
+  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
+  {                                                                    \
+    SCI_OUT(sci_size, sci_offset, value);                              \
+  }
+
+#if defined(CONFIG_CPU_SH3) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377) || \
+    defined(CONFIG_ARCH_SH7372)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                                h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+      defined(CONFIG_ARCH_SH73A0) || \
+      defined(CONFIG_ARCH_SH7367) || \
+      defined(CONFIG_ARCH_SH7377)
+#define SCIF_FNS(name, scif_offset, scif_size) \
+  CPU_SCIF_FNS(name, scif_offset, scif_size)
+#elif defined(CONFIG_ARCH_SH7372)
+#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
+  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
+#define SCIF_FNS(name, scif_offset, scif_size) \
+  CPU_SCIF_FNS(name, scif_offset, scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+#endif
+#elif defined(__H8300H__) || defined(__H8300S__)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
+        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
+                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
+        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
+                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_ARCH_SH73A0) || \
+    defined(CONFIG_ARCH_SH7367) || \
+    defined(CONFIG_ARCH_SH7377)
+
+SCIF_FNS(SCSMR,  0x00, 16)
+SCIF_FNS(SCBRR,  0x04,  8)
+SCIF_FNS(SCSCR,  0x08, 16)
+SCIF_FNS(SCxSR,  0x14, 16)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCxTDR, 0x20,  8)
+SCIF_FNS(SCxRDR, 0x24,  8)
+SCIF_FNS(SCLSR,  0x00,  0)
+#elif defined(CONFIG_ARCH_SH7372)
+SCIF_FNS(SCSMR,  0x00, 16)
+SCIF_FNS(SCBRR,  0x04,  8)
+SCIF_FNS(SCSCR,  0x08, 16)
+SCIF_FNS(SCTDSR, 0x0c, 16)
+SCIF_FNS(SCFER,  0x10, 16)
+SCIF_FNS(SCxSR,  0x14, 16)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCTFDR, 0x38, 16)
+SCIF_FNS(SCRFDR, 0x3c, 16)
+SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
+SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
+SCIF_FNS(SCLSR,  0x00,  0)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+      defined(CONFIG_CPU_SUBTYPE_SH7724)
+SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
+SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
+SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
+SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
+SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
+SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
+SCIx_FNS(SCSPTR, 0,     0,    0,  0)
+SCIF_FNS(SCFCR,  0x18, 16)
+SCIF_FNS(SCFDR,  0x1c, 16)
+SCIF_FNS(SCLSR,  0x24, 16)
+#else
+/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
+/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
+SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
+SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
+SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
+SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
+SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
+SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
+SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
+SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
+SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
+SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
+SCIF_FNS(SCSPTR2,                      0,  0, 0x20, 16)
+SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
+SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
+SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
+#else
+SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
+#else
+SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
+#endif
+SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
+#endif
+#endif
+#define sci_in(port, reg) sci_##reg##_in(port)
+#define sci_out(port, reg, value) sci_##reg##_out(port, value)
+
+/* H8/300 series SCI pins assignment */
+#if defined(__H8300H__) || defined(__H8300S__)
+static const struct __attribute__((packed)) {
+       int port;             /* GPIO port no */
+       unsigned short rx,tx; /* GPIO bit no */
+} h8300_sci_pins[] = {
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_PB,
+               .rx   = H8300_GPIO_B7,
+               .tx   = H8300_GPIO_B6,
+       }
+#elif defined(CONFIG_H8S2678)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_P5,
+               .rx   = H8300_GPIO_B1,
+               .tx   = H8300_GPIO_B0,
+       }
+#endif
+};
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xfffffe80)
+               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7091)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000)
+               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+}
+#elif defined(__H8300H__) || defined(__H8300S__)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       int ch = (port->mapbase - SMR0) >> 3;
+       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+}
+#else /* default case for non-SCI processors */
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       return 1;
+}
+#endif
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
new file mode 100644 (file)
index 0000000..cff9a30
--- /dev/null
@@ -0,0 +1,1085 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/sysrq.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h> /* for mdelay */
+#include <linux/miscdevice.h>
+#include <linux/serial_core.h>
+
+#include <asm/io.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_sal.h>
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SN_SAL_MAX_CHARS 120
+
+/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
+ * avoid losing chars, (always has to be a power of 2) */
+#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
+
+#define SN_SAL_UART_FIFO_DEPTH 16
+#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
+
+/* sn_transmit_chars() calling args */
+#define TRANSMIT_BUFFERED      0
+#define TRANSMIT_RAW           1
+
+/* To use dynamic numbers only and not use the assigned major and minor,
+ * define the following.. */
+                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
+#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
+
+/* Device name we're using */
+#define DEVICE_NAME "ttySG"
+#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
+/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
+#define DEVICE_MAJOR 204
+#define DEVICE_MINOR 40
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+/*
+ * Port definition - this kinda drives it all
+ */
+struct sn_cons_port {
+       struct timer_list sc_timer;
+       struct uart_port sc_port;
+       struct sn_sal_ops {
+               int (*sal_puts_raw) (const char *s, int len);
+               int (*sal_puts) (const char *s, int len);
+               int (*sal_getc) (void);
+               int (*sal_input_pending) (void);
+               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
+       } *sc_ops;
+       unsigned long sc_interrupt_timeout;
+       int sc_is_asynch;
+};
+
+static struct sn_cons_port sal_console_port;
+static int sn_process_input;
+
+/* Only used if USE_DYNAMIC_MINOR is set to 1 */
+static struct miscdevice misc; /* used with misc_register for dynamic */
+
+extern void early_sn_setup(void);
+
+#undef DEBUG
+#ifdef DEBUG
+static int sn_debug_printf(const char *fmt, ...);
+#define DPRINTF(x...) sn_debug_printf(x)
+#else
+#define DPRINTF(x...) do { } while (0)
+#endif
+
+/* Prototypes */
+static int snt_hw_puts_raw(const char *, int);
+static int snt_hw_puts_buffered(const char *, int);
+static int snt_poll_getc(void);
+static int snt_poll_input_pending(void);
+static int snt_intr_getc(void);
+static int snt_intr_input_pending(void);
+static void sn_transmit_chars(struct sn_cons_port *, int);
+
+/* A table for polling:
+ */
+static struct sn_sal_ops poll_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_raw,
+       .sal_getc = snt_poll_getc,
+       .sal_input_pending = snt_poll_input_pending
+};
+
+/* A table for interrupts enabled */
+static struct sn_sal_ops intr_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_buffered,
+       .sal_getc = snt_intr_getc,
+       .sal_input_pending = snt_intr_input_pending,
+       .sal_wakeup_transmit = sn_transmit_chars
+};
+
+/* the console does output in two distinctly different ways:
+ * synchronous (raw) and asynchronous (buffered).  initally, early_printk
+ * does synchronous output.  any data written goes directly to the SAL
+ * to be output (incidentally, it is internally buffered by the SAL)
+ * after interrupts and timers are initialized and available for use,
+ * the console init code switches to asynchronous output.  this is
+ * also the earliest opportunity to begin polling for console input.
+ * after console initialization, console output and tty (serial port)
+ * output is buffered and sent to the SAL asynchronously (either by
+ * timer callback or by UART interrupt) */
+
+/* routines for running the console in polling mode */
+
+/**
+ * snt_poll_getc - Get a character from the console in polling mode
+ *
+ */
+static int snt_poll_getc(void)
+{
+       int ch;
+
+       ia64_sn_console_getc(&ch);
+       return ch;
+}
+
+/**
+ * snt_poll_input_pending - Check if any input is waiting - polling mode.
+ *
+ */
+static int snt_poll_input_pending(void)
+{
+       int status, input;
+
+       status = ia64_sn_console_check(&input);
+       return !status && input;
+}
+
+/* routines for an interrupt driven console (normal) */
+
+/**
+ * snt_intr_getc - Get a character from the console, interrupt mode
+ *
+ */
+static int snt_intr_getc(void)
+{
+       return ia64_sn_console_readc();
+}
+
+/**
+ * snt_intr_input_pending - Check if input is pending, interrupt mode
+ *
+ */
+static int snt_intr_input_pending(void)
+{
+       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
+}
+
+/* these functions are polled and interrupt */
+
+/**
+ * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int snt_hw_puts_raw(const char *s, int len)
+{
+       /* this will call the PROM and not return until this is done */
+       return ia64_sn_console_putb(s, len);
+}
+
+/**
+ * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int snt_hw_puts_buffered(const char *s, int len)
+{
+       /* queue data to the PROM */
+       return ia64_sn_console_xmit_chars((char *)s, len);
+}
+
+/* uart interface structs
+ * These functions are associated with the uart_port that the serial core
+ * infrastructure calls.
+ *
+ * Note: Due to how the console works, many routines are no-ops.
+ */
+
+/**
+ * snp_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *snp_type(struct uart_port *port)
+{
+       return ("SGI SN L1");
+}
+
+/**
+ * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
+ * @port: Port to operate on (we ignore since we only have one port)
+ *
+ */
+static unsigned int snp_tx_empty(struct uart_port *port)
+{
+       return 1;
+}
+
+/**
+ * snp_stop_tx - stop the transmitter - no-op for us
+ * @port: Port to operat eon - we ignore - no-op function
+ *
+ */
+static void snp_stop_tx(struct uart_port *port)
+{
+}
+
+/**
+ * snp_release_port - Free i/o and resources for port - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void snp_release_port(struct uart_port *port)
+{
+}
+
+/**
+ * snp_enable_ms - Force modem status interrupts on - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void snp_enable_ms(struct uart_port *port)
+{
+}
+
+/**
+ * snp_shutdown - shut down the port - free irq and disable - no-op for us
+ * @port: Port to shut down - we ignore
+ *
+ */
+static void snp_shutdown(struct uart_port *port)
+{
+}
+
+/**
+ * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
+ * @port: Port to operate on - we ignore
+ * @mctrl: Lines to set/unset - we ignore
+ *
+ */
+static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * snp_get_mctrl - get contorl line info, we just return a static value
+ * @port: port to operate on - we only have one port so we ignore this
+ *
+ */
+static unsigned int snp_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
+}
+
+/**
+ * snp_stop_rx - Stop the receiver - we ignor ethis
+ * @port: Port to operate on - we ignore
+ *
+ */
+static void snp_stop_rx(struct uart_port *port)
+{
+}
+
+/**
+ * snp_start_tx - Start transmitter
+ * @port: Port to operate on
+ *
+ */
+static void snp_start_tx(struct uart_port *port)
+{
+       if (sal_console_port.sc_ops->sal_wakeup_transmit)
+               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
+                                                            TRANSMIT_BUFFERED);
+
+}
+
+/**
+ * snp_break_ctl - handle breaks - ignored by us
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void snp_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+/**
+ * snp_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int snp_startup(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_set_termios - set termios stuff - we ignore these
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+snp_set_termios(struct uart_port *port, struct ktermios *termios,
+               struct ktermios *old)
+{
+}
+
+/**
+ * snp_request_port - allocate resources for port - ignored by us
+ * @port: port to operate on
+ *
+ */
+static int snp_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_config_port - allocate resources, set up - we ignore,  we're always on
+ * @port: Port to operate on
+ * @flags: flags used for port setup
+ *
+ */
+static void snp_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops sn_console_ops = {
+       .tx_empty = snp_tx_empty,
+       .set_mctrl = snp_set_mctrl,
+       .get_mctrl = snp_get_mctrl,
+       .stop_tx = snp_stop_tx,
+       .start_tx = snp_start_tx,
+       .stop_rx = snp_stop_rx,
+       .enable_ms = snp_enable_ms,
+       .break_ctl = snp_break_ctl,
+       .startup = snp_startup,
+       .shutdown = snp_shutdown,
+       .set_termios = snp_set_termios,
+       .pm = NULL,
+       .type = snp_type,
+       .release_port = snp_release_port,
+       .request_port = snp_request_port,
+       .config_port = snp_config_port,
+       .verify_port = NULL,
+};
+
+/* End of uart struct functions and defines */
+
+#ifdef DEBUG
+
+/**
+ * sn_debug_printf - close to hardware debugging printf
+ * @fmt: printf format
+ *
+ * This is as "close to the metal" as we can get, used when the driver
+ * itself may be broken.
+ *
+ */
+static int sn_debug_printf(const char *fmt, ...)
+{
+       static char printk_buf[1024];
+       int printed_len;
+       va_list args;
+
+       va_start(args, fmt);
+       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+
+       if (!sal_console_port.sc_ops) {
+               sal_console_port.sc_ops = &poll_ops;
+               early_sn_setup();
+       }
+       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
+
+       va_end(args);
+       return printed_len;
+}
+#endif                         /* DEBUG */
+
+/*
+ * Interrupt handling routines.
+ */
+
+/**
+ * sn_receive_chars - Grab characters, pass them to tty layer
+ * @port: Port to operate on
+ * @flags: irq flags
+ *
+ * Note: If we're not registered with the serial core infrastructure yet,
+ * we don't try to send characters to it...
+ *
+ */
+static void
+sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
+{
+       int ch;
+       struct tty_struct *tty;
+
+       if (!port) {
+               printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
+               return;
+       }
+
+       if (!port->sc_ops) {
+               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
+               return;
+       }
+
+       if (port->sc_port.state) {
+               /* The serial_core stuffs are initialized, use them */
+               tty = port->sc_port.state->port.tty;
+       }
+       else {
+               /* Not registered yet - can't pass to tty layer.  */
+               tty = NULL;
+       }
+
+       while (port->sc_ops->sal_input_pending()) {
+               ch = port->sc_ops->sal_getc();
+               if (ch < 0) {
+                       printk(KERN_ERR "sn_console: An error occured while "
+                              "obtaining data from the console (0x%0x)\n", ch);
+                       break;
+               }
+#ifdef CONFIG_MAGIC_SYSRQ
+                if (sysrq_requested) {
+                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+
+                        sysrq_requested = 0;
+                        if (ch && time_before(jiffies, sysrq_timeout)) {
+                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                                handle_sysrq(ch);
+                                spin_lock_irqsave(&port->sc_port.lock, flags);
+                                /* ignore actual sysrq command char */
+                                continue;
+                        }
+                }
+                if (ch == *sysrq_serial_ptr) {
+                        if (!(*++sysrq_serial_ptr)) {
+                                sysrq_requested = jiffies;
+                                sysrq_serial_ptr = sysrq_serial_str;
+                        }
+                       /*
+                        * ignore the whole sysrq string except for the
+                        * leading escape
+                        */
+                       if (ch != '\e')
+                               continue;
+                }
+                else
+                       sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+               /* record the character to pass up to the tty layer */
+               if (tty) {
+                       if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+                               break;
+               }
+               port->sc_port.icount.rx++;
+       }
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+}
+
+/**
+ * sn_transmit_chars - grab characters from serial core, send off
+ * @port: Port to operate on
+ * @raw: Transmit raw or buffered
+ *
+ * Note: If we're early, before we're registered with serial core, the
+ * writes are going through sn_sal_console_write because that's how
+ * register_console has been set up.  We currently could have asynch
+ * polls calling this function due to sn_sal_switch_to_asynch but we can
+ * ignore them until we register with the serial core stuffs.
+ *
+ */
+static void sn_transmit_chars(struct sn_cons_port *port, int raw)
+{
+       int xmit_count, tail, head, loops, ii;
+       int result;
+       char *start;
+       struct circ_buf *xmit;
+
+       if (!port)
+               return;
+
+       BUG_ON(!port->sc_is_asynch);
+
+       if (port->sc_port.state) {
+               /* We're initialized, using serial core infrastructure */
+               xmit = &port->sc_port.state->xmit;
+       } else {
+               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
+                * initialized yet.  Just return.  Writes are going through
+                * sn_sal_console_write (due to register_console) at this time.
+                */
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
+               /* Nothing to do. */
+               ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
+               return;
+       }
+
+       head = xmit->head;
+       tail = xmit->tail;
+       start = &xmit->buf[tail];
+
+       /* twice around gets the tail to the end of the buffer and
+        * then to the head, if needed */
+       loops = (head < tail) ? 2 : 1;
+
+       for (ii = 0; ii < loops; ii++) {
+               xmit_count = (head < tail) ?
+                   (UART_XMIT_SIZE - tail) : (head - tail);
+
+               if (xmit_count > 0) {
+                       if (raw == TRANSMIT_RAW)
+                               result =
+                                   port->sc_ops->sal_puts_raw(start,
+                                                              xmit_count);
+                       else
+                               result =
+                                   port->sc_ops->sal_puts(start, xmit_count);
+#ifdef DEBUG
+                       if (!result)
+                               DPRINTF("`");
+#endif
+                       if (result > 0) {
+                               xmit_count -= result;
+                               port->sc_port.icount.tx += result;
+                               tail += result;
+                               tail &= UART_XMIT_SIZE - 1;
+                               xmit->tail = tail;
+                               start = &xmit->buf[tail];
+                       }
+               }
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&port->sc_port);
+
+       if (uart_circ_empty(xmit))
+               snp_stop_tx(&port->sc_port);    /* no-op for us */
+}
+
+/**
+ * sn_sal_interrupt - Handle console interrupts
+ * @irq: irq #, useful for debug statements
+ * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
+ *
+ */
+static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
+       unsigned long flags;
+       int status = ia64_sn_console_intr_status();
+
+       if (!port)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+       if (status & SAL_CONSOLE_INTR_RECV) {
+               sn_receive_chars(port, flags);
+       }
+       if (status & SAL_CONSOLE_INTR_XMIT) {
+               sn_transmit_chars(port, TRANSMIT_BUFFERED);
+       }
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+/**
+ * sn_sal_timer_poll - this function handles polled console mode
+ * @data: A pointer to our sn_cons_port (which contains the uart port)
+ *
+ * data is the pointer that init_timer will store for us.  This function is
+ * associated with init_timer to see if there is any console traffic.
+ * Obviously not used in interrupt mode
+ *
+ */
+static void sn_sal_timer_poll(unsigned long data)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *)data;
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       if (!port->sc_port.irq) {
+               spin_lock_irqsave(&port->sc_port.lock, flags);
+               if (sn_process_input)
+                       sn_receive_chars(port, flags);
+               sn_transmit_chars(port, TRANSMIT_RAW);
+               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+               mod_timer(&port->sc_timer,
+                         jiffies + port->sc_interrupt_timeout);
+       }
+}
+
+/*
+ * Boot-time initialization code
+ */
+
+/**
+ * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * So this is used by sn_sal_serial_console_init (early on, before we're
+ * registered with serial core).  It's also used by sn_sal_module_init
+ * right after we've registered with serial core.  The later only happens
+ * if we didn't already come through here via sn_sal_serial_console_init.
+ *
+ */
+static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
+{
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       DPRINTF("sn_console: about to switch to asynchronous console\n");
+
+       /* without early_printk, we may be invoked late enough to race
+        * with other cpus doing console IO at this point, however
+        * console interrupts will never be enabled */
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+
+       /* early_printk invocation may have done this for us */
+       if (!port->sc_ops)
+               port->sc_ops = &poll_ops;
+
+       /* we can't turn on the console interrupt (as request_irq
+        * calls kmalloc, which isn't set up yet), so we rely on a
+        * timer to poll for input and push data from the console
+        * buffer.
+        */
+       init_timer(&port->sc_timer);
+       port->sc_timer.function = sn_sal_timer_poll;
+       port->sc_timer.data = (unsigned long)port;
+
+       if (IS_RUNNING_ON_SIMULATOR())
+               port->sc_interrupt_timeout = 6;
+       else {
+               /* 960cps / 16 char FIFO = 60HZ
+                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
+               port->sc_interrupt_timeout =
+                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
+       }
+       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
+
+       port->sc_is_asynch = 1;
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+}
+
+/**
+ * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * In sn_sal_module_init, after we're registered with serial core and
+ * the port is added, this function is called to switch us to interrupt
+ * mode.  We were previously in asynch/polling mode (using init_timer).
+ *
+ * We attempt to switch to interrupt mode here by calling
+ * request_irq.  If that works out, we enable receive interrupts.
+ */
+static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
+{
+       unsigned long flags;
+
+       if (port) {
+               DPRINTF("sn_console: switching to interrupt driven console\n");
+
+               if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
+                               IRQF_DISABLED | IRQF_SHARED,
+                               "SAL console driver", port) >= 0) {
+                       spin_lock_irqsave(&port->sc_port.lock, flags);
+                       port->sc_port.irq = SGI_UART_VECTOR;
+                       port->sc_ops = &intr_ops;
+
+                       /* turn on receive interrupts */
+                       ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+               }
+               else {
+                       printk(KERN_INFO
+                           "sn_console: console proceeding in polled mode\n");
+               }
+       }
+}
+
+/*
+ * Kernel console definitions
+ */
+
+static void sn_sal_console_write(struct console *, const char *, unsigned);
+static int sn_sal_console_setup(struct console *, char *);
+static struct uart_driver sal_console_uart;
+extern struct tty_driver *uart_console_device(struct console *, int *);
+
+static struct console sal_console = {
+       .name = DEVICE_NAME,
+       .write = sn_sal_console_write,
+       .device = uart_console_device,
+       .setup = sn_sal_console_setup,
+       .index = -1,            /* unspecified */
+       .data = &sal_console_uart,
+};
+
+#define SAL_CONSOLE    &sal_console
+
+static struct uart_driver sal_console_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "sn_console",
+       .dev_name = DEVICE_NAME,
+       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
+       .minor = 0,
+       .nr = 1,                /* one port */
+       .cons = SAL_CONSOLE,
+};
+
+/**
+ * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core
+ *
+ * Before this is called, we've been printing kernel messages in a special
+ * early mode not making use of the serial core infrastructure.  When our
+ * driver is loaded for real, we register the driver and port with serial
+ * core and try to enable interrupt driven mode.
+ *
+ */
+static int __init sn_sal_module_init(void)
+{
+       int retval;
+
+       if (!ia64_platform_is("sn2"))
+               return 0;
+
+       printk(KERN_INFO "sn_console: Console driver init\n");
+
+       if (USE_DYNAMIC_MINOR == 1) {
+               misc.minor = MISC_DYNAMIC_MINOR;
+               misc.name = DEVICE_NAME_DYNAMIC;
+               retval = misc_register(&misc);
+               if (retval != 0) {
+                       printk(KERN_WARNING "Failed to register console "
+                              "device using misc_register.\n");
+                       return -ENODEV;
+               }
+               sal_console_uart.major = MISC_MAJOR;
+               sal_console_uart.minor = misc.minor;
+       } else {
+               sal_console_uart.major = DEVICE_MAJOR;
+               sal_console_uart.minor = DEVICE_MINOR;
+       }
+
+       /* We register the driver and the port before switching to interrupts
+        * or async above so the proper uart structures are populated */
+
+       if (uart_register_driver(&sal_console_uart) < 0) {
+               printk
+                   ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
+                    __LINE__);
+               return -ENODEV;
+       }
+
+       spin_lock_init(&sal_console_port.sc_port.lock);
+
+       /* Setup the port struct with the minimum needed */
+       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
+       sal_console_port.sc_port.type = PORT_16550A;
+       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
+       sal_console_port.sc_port.ops = &sn_console_ops;
+       sal_console_port.sc_port.line = 0;
+
+       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
+               /* error - not sure what I'd do - so I'll do nothing */
+               printk(KERN_ERR "%s: unable to add port\n", __func__);
+       }
+
+       /* when this driver is compiled in, the console initialization
+        * will have already switched us into asynchronous operation
+        * before we get here through the module initcalls */
+       if (!sal_console_port.sc_is_asynch) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+       }
+
+       /* at this point (module_init) we can try to turn on interrupts */
+       if (!IS_RUNNING_ON_SIMULATOR()) {
+               sn_sal_switch_to_interrupts(&sal_console_port);
+       }
+       sn_process_input = 1;
+       return 0;
+}
+
+/**
+ * sn_sal_module_exit - When we're unloaded, remove the driver/port
+ *
+ */
+static void __exit sn_sal_module_exit(void)
+{
+       del_timer_sync(&sal_console_port.sc_timer);
+       uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
+       uart_unregister_driver(&sal_console_uart);
+       misc_deregister(&misc);
+}
+
+module_init(sn_sal_module_init);
+module_exit(sn_sal_module_exit);
+
+/**
+ * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
+ * @puts_raw : puts function to do the writing
+ * @s: input string
+ * @count: length
+ *
+ * We need a \r ahead of every \n for direct writes through
+ * ia64_sn_console_putb (what sal_puts_raw below actually does).
+ *
+ */
+
+static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
+                          const char *s, int count)
+{
+       const char *s1;
+
+       /* Output '\r' before each '\n' */
+       while ((s1 = memchr(s, '\n', count)) != NULL) {
+               puts_raw(s, s1 - s);
+               puts_raw("\r\n", 2);
+               count -= s1 + 1 - s;
+               s = s1 + 1;
+       }
+       puts_raw(s, count);
+}
+
+/**
+ * sn_sal_console_write - Print statements before serial core available
+ * @console: Console to operate on - we ignore since we have just one
+ * @s: String to send
+ * @count: length
+ *
+ * This is referenced in the console struct.  It is used for early
+ * console printing before we register with serial core and for things
+ * such as kdb.  The console_lock must be held when we get here.
+ *
+ * This function has some code for trying to print output even if the lock
+ * is held.  We try to cover the case where a lock holder could have died.
+ * We don't use this special case code if we're not registered with serial
+ * core yet.  After we're registered with serial core, the only time this
+ * function would be used is for high level kernel output like magic sys req,
+ * kdb, and printk's.
+ */
+static void
+sn_sal_console_write(struct console *co, const char *s, unsigned count)
+{
+       unsigned long flags = 0;
+       struct sn_cons_port *port = &sal_console_port;
+       static int stole_lock = 0;
+
+       BUG_ON(!port->sc_is_asynch);
+
+       /* We can't look at the xmit buffer if we're not registered with serial core
+        *  yet.  So only do the fancy recovery after registering
+        */
+       if (!port->sc_port.state) {
+               /* Not yet registered with serial core - simple case */
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+               return;
+       }
+
+       /* somebody really wants this output, might be an
+        * oops, kdb, panic, etc.  make sure they get it. */
+       if (spin_is_locked(&port->sc_port.lock)) {
+               int lhead = port->sc_port.state->xmit.head;
+               int ltail = port->sc_port.state->xmit.tail;
+               int counter, got_lock = 0;
+
+               /*
+                * We attempt to determine if someone has died with the
+                * lock. We wait ~20 secs after the head and tail ptrs
+                * stop moving and assume the lock holder is not functional
+                * and plow ahead. If the lock is freed within the time out
+                * period we re-get the lock and go ahead normally. We also
+                * remember if we have plowed ahead so that we don't have
+                * to wait out the time out period again - the asumption
+                * is that we will time out again.
+                */
+
+               for (counter = 0; counter < 150; mdelay(125), counter++) {
+                       if (!spin_is_locked(&port->sc_port.lock)
+                           || stole_lock) {
+                               if (!stole_lock) {
+                                       spin_lock_irqsave(&port->sc_port.lock,
+                                                         flags);
+                                       got_lock = 1;
+                               }
+                               break;
+                       } else {
+                               /* still locked */
+                               if ((lhead != port->sc_port.state->xmit.head)
+                                   || (ltail !=
+                                       port->sc_port.state->xmit.tail)) {
+                                       lhead =
+                                               port->sc_port.state->xmit.head;
+                                       ltail =
+                                               port->sc_port.state->xmit.tail;
+                                       counter = 0;
+                               }
+                       }
+               }
+               /* flush anything in the serial core xmit buffer, raw */
+               sn_transmit_chars(port, 1);
+               if (got_lock) {
+                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                       stole_lock = 0;
+               } else {
+                       /* fell thru */
+                       stole_lock = 1;
+               }
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+       } else {
+               stole_lock = 0;
+               spin_lock_irqsave(&port->sc_port.lock, flags);
+               sn_transmit_chars(port, 1);
+               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+       }
+}
+
+
+/**
+ * sn_sal_console_setup - Set up console for early printing
+ * @co: Console to work with
+ * @options: Options to set
+ *
+ * Altix console doesn't do anything with baud rates, etc, anyway.
+ *
+ * This isn't required since not providing the setup function in the
+ * console struct is ok.  However, other patches like KDB plop something
+ * here so providing it is easier.
+ *
+ */
+static int sn_sal_console_setup(struct console *co, char *options)
+{
+       return 0;
+}
+
+/**
+ * sn_sal_console_write_early - simple early output routine
+ * @co - console struct
+ * @s - string to print
+ * @count - count
+ *
+ * Simple function to provide early output, before even
+ * sn_sal_serial_console_init is called.  Referenced in the
+ * console struct registerd in sn_serial_console_early_setup.
+ *
+ */
+static void __init
+sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
+{
+       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
+}
+
+/* Used for very early console printing - again, before
+ * sn_sal_serial_console_init is run */
+static struct console sal_console_early __initdata = {
+       .name = "sn_sal",
+       .write = sn_sal_console_write_early,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+};
+
+/**
+ * sn_serial_console_early_setup - Sets up early console output support
+ *
+ * Register a console early on...  This is for output before even
+ * sn_sal_serial_cosnole_init is called.  This function is called from
+ * setup.c.  This allows us to do really early polled writes. When
+ * sn_sal_serial_console_init is called, this console is unregistered
+ * and a new one registered.
+ */
+int __init sn_serial_console_early_setup(void)
+{
+       if (!ia64_platform_is("sn2"))
+               return -1;
+
+       sal_console_port.sc_ops = &poll_ops;
+       spin_lock_init(&sal_console_port.sc_port.lock);
+       early_sn_setup();       /* Find SAL entry points */
+       register_console(&sal_console_early);
+
+       return 0;
+}
+
+/**
+ * sn_sal_serial_console_init - Early console output - set up for register
+ *
+ * This function is called when regular console init happens.  Because we
+ * support even earlier console output with sn_serial_console_early_setup
+ * (called from setup.c directly), this function unregisters the really
+ * early console.
+ *
+ * Note: Even if setup.c doesn't register sal_console_early, unregistering
+ * it here doesn't hurt anything.
+ *
+ */
+static int __init sn_sal_serial_console_init(void)
+{
+       if (ia64_platform_is("sn2")) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+               DPRINTF("sn_sal_serial_console_init : register console\n");
+               register_console(&sal_console);
+               unregister_console(&sal_console_early);
+       }
+       return 0;
+}
+
+console_initcall(sn_sal_serial_console_init);
diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c
new file mode 100644 (file)
index 0000000..6381a02
--- /dev/null
@@ -0,0 +1,247 @@
+/* suncore.c
+ *
+ * Common SUN serial routines.  Based entirely
+ * upon drivers/sbus/char/sunserial.c which is:
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Adaptation to new UART layer is:
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/serial_core.h>
+#include <linux/init.h>
+
+#include <asm/prom.h>
+
+#include "suncore.h"
+
+static int sunserial_current_minor = 64;
+
+int sunserial_register_minors(struct uart_driver *drv, int count)
+{
+       int err = 0;
+
+       drv->minor = sunserial_current_minor;
+       drv->nr += count;
+       /* Register the driver on the first call */
+       if (drv->nr == count)
+               err = uart_register_driver(drv);
+       if (err == 0) {
+               sunserial_current_minor += count;
+               drv->tty_driver->name_base = drv->minor - 64;
+       }
+       return err;
+}
+EXPORT_SYMBOL(sunserial_register_minors);
+
+void sunserial_unregister_minors(struct uart_driver *drv, int count)
+{
+       drv->nr -= count;
+       sunserial_current_minor -= count;
+
+       if (drv->nr == 0)
+               uart_unregister_driver(drv);
+}
+EXPORT_SYMBOL(sunserial_unregister_minors);
+
+int sunserial_console_match(struct console *con, struct device_node *dp,
+                           struct uart_driver *drv, int line, bool ignore_line)
+{
+       if (!con)
+               return 0;
+
+       drv->cons = con;
+
+       if (of_console_device != dp)
+               return 0;
+
+       if (!ignore_line) {
+               int off = 0;
+
+               if (of_console_options &&
+                   *of_console_options == 'b')
+                       off = 1;
+
+               if ((line & 1) != off)
+                       return 0;
+       }
+
+       if (!console_set_on_cmdline) {
+               con->index = line;
+               add_preferred_console(con->name, line, NULL);
+       }
+       return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
+
+void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
+{
+       const char *mode, *s;
+       char mode_prop[] = "ttyX-mode";
+       int baud, bits, stop, cflag;
+       char parity;
+
+       if (!strcmp(uart_dp->name, "rsc") ||
+           !strcmp(uart_dp->name, "rsc-console") ||
+           !strcmp(uart_dp->name, "rsc-control")) {
+               mode = of_get_property(uart_dp,
+                                      "ssp-console-modes", NULL);
+               if (!mode)
+                       mode = "115200,8,n,1,-";
+       } else if (!strcmp(uart_dp->name, "lom-console")) {
+               mode = "9600,8,n,1,-";
+       } else {
+               struct device_node *dp;
+               char c;
+
+               c = 'a';
+               if (of_console_options)
+                       c = *of_console_options;
+
+               mode_prop[3] = c;
+
+               dp = of_find_node_by_path("/options");
+               mode = of_get_property(dp, mode_prop, NULL);
+               if (!mode)
+                       mode = "9600,8,n,1,-";
+       }
+
+       cflag = CREAD | HUPCL | CLOCAL;
+
+       s = mode;
+       baud = simple_strtoul(s, NULL, 0);
+       s = strchr(s, ',');
+       bits = simple_strtoul(++s, NULL, 0);
+       s = strchr(s, ',');
+       parity = *(++s);
+       s = strchr(s, ',');
+       stop = simple_strtoul(++s, NULL, 0);
+       s = strchr(s, ',');
+       /* XXX handshake is not handled here. */
+
+       switch (baud) {
+               case 150: cflag |= B150; break;
+               case 300: cflag |= B300; break;
+               case 600: cflag |= B600; break;
+               case 1200: cflag |= B1200; break;
+               case 2400: cflag |= B2400; break;
+               case 4800: cflag |= B4800; break;
+               case 9600: cflag |= B9600; break;
+               case 19200: cflag |= B19200; break;
+               case 38400: cflag |= B38400; break;
+               case 57600: cflag |= B57600; break;
+               case 115200: cflag |= B115200; break;
+               case 230400: cflag |= B230400; break;
+               case 460800: cflag |= B460800; break;
+               default: baud = 9600; cflag |= B9600; break;
+       }
+
+       switch (bits) {
+               case 5: cflag |= CS5; break;
+               case 6: cflag |= CS6; break;
+               case 7: cflag |= CS7; break;
+               case 8: cflag |= CS8; break;
+               default: cflag |= CS8; break;
+       }
+
+       switch (parity) {
+               case 'o': cflag |= (PARENB | PARODD); break;
+               case 'e': cflag |= PARENB; break;
+               case 'n': default: break;
+       }
+
+       switch (stop) {
+               case 2: cflag |= CSTOPB; break;
+               case 1: default: break;
+       }
+
+       con->cflag = cflag;
+}
+
+/* Sun serial MOUSE auto baud rate detection.  */
+static struct mouse_baud_cflag {
+       int baud;
+       unsigned int cflag;
+} mouse_baud_table[] = {
+       { 1200, B1200 },
+       { 2400, B2400 },
+       { 4800, B4800 },
+       { 9600, B9600 },
+       { -1, ~0 },
+       { -1, ~0 },
+};
+
+unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud)
+{
+       int i;
+
+       for (i = 0; mouse_baud_table[i].baud != -1; i++)
+               if (mouse_baud_table[i].cflag == (cflag & CBAUD))
+                       break;
+
+       i += 1;
+       if (mouse_baud_table[i].baud == -1)
+               i = 0;
+
+       *new_baud = mouse_baud_table[i].baud;
+       return mouse_baud_table[i].cflag;
+}
+
+EXPORT_SYMBOL(suncore_mouse_baud_cflag_next);
+
+/* Basically, when the baud rate is wrong the mouse spits out
+ * breaks to us.
+ */
+int suncore_mouse_baud_detection(unsigned char ch, int is_break)
+{
+       static int mouse_got_break = 0;
+       static int ctr = 0;
+
+       if (is_break) {
+               /* Let a few normal bytes go by before we jump the gun
+                * and say we need to try another baud rate.
+                */
+               if (mouse_got_break && ctr < 8)
+                       return 1;
+
+               /* Ok, we need to try another baud. */
+               ctr = 0;
+               mouse_got_break = 1;
+               return 2;
+       }
+       if (mouse_got_break) {
+               ctr++;
+               if (ch == 0x87) {
+                       /* Correct baud rate determined. */
+                       mouse_got_break = 0;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(suncore_mouse_baud_detection);
+
+static int __init suncore_init(void)
+{
+       return 0;
+}
+
+static void __exit suncore_exit(void)
+{
+}
+
+module_init(suncore_init);
+module_exit(suncore_exit);
+
+MODULE_AUTHOR("Eddie C. Dost, David S. Miller");
+MODULE_DESCRIPTION("Sun serial common layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/suncore.h b/drivers/tty/serial/suncore.h
new file mode 100644 (file)
index 0000000..db20579
--- /dev/null
@@ -0,0 +1,33 @@
+/* suncore.h
+ *
+ * Generic SUN serial/kbd/ms layer.  Based entirely
+ * upon drivers/sbus/char/sunserial.h which is:
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Port to new UART layer is:
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SERIAL_SUN_H
+#define _SERIAL_SUN_H
+
+/* Serial keyboard defines for L1-A processing... */
+#define SUNKBD_RESET           0xff
+#define SUNKBD_L1              0x01
+#define SUNKBD_UP              0x80
+#define SUNKBD_A               0x4d
+
+extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
+extern int suncore_mouse_baud_detection(unsigned char, int);
+
+extern int sunserial_register_minors(struct uart_driver *, int);
+extern void sunserial_unregister_minors(struct uart_driver *, int);
+
+extern int sunserial_console_match(struct console *, struct device_node *,
+                                  struct uart_driver *, int, bool);
+extern void sunserial_console_termios(struct console *,
+                                     struct device_node *);
+
+#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
new file mode 100644 (file)
index 0000000..c901486
--- /dev/null
@@ -0,0 +1,661 @@
+/* sunhv.c: Serial driver for SUN4V hypervisor console.
+ *
+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/hypervisor.h>
+#include <asm/spitfire.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+
+#define CON_BREAK      ((long)-1)
+#define CON_HUP                ((long)-2)
+
+#define IGNORE_BREAK   0x1
+#define IGNORE_ALL     0x2
+
+static char *con_write_page;
+static char *con_read_page;
+
+static int hung_up = 0;
+
+static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
+{
+       while (!uart_circ_empty(xmit)) {
+               long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+
+               if (status != HV_EOK)
+                       break;
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
+{
+       while (!uart_circ_empty(xmit)) {
+               unsigned long ra = __pa(xmit->buf + xmit->tail);
+               unsigned long len, status, sent;
+
+               len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+                                     UART_XMIT_SIZE);
+               status = sun4v_con_write(ra, len, &sent);
+               if (status != HV_EOK)
+                       break;
+               xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
+               port->icount.tx += sent;
+       }
+}
+
+static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
+{
+       int saw_console_brk = 0;
+       int limit = 10000;
+
+       while (limit-- > 0) {
+               long status;
+               long c = sun4v_con_getchar(&status);
+
+               if (status == HV_EWOULDBLOCK)
+                       break;
+
+               if (c == CON_BREAK) {
+                       if (uart_handle_break(port))
+                               continue;
+                       saw_console_brk = 1;
+                       c = 0;
+               }
+
+               if (c == CON_HUP) {
+                       hung_up = 1;
+                       uart_handle_dcd_change(port, 0);
+               } else if (hung_up) {
+                       hung_up = 0;
+                       uart_handle_dcd_change(port, 1);
+               }
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(port, c);
+                       continue;
+               }
+
+               port->icount.rx++;
+
+               if (uart_handle_sysrq_char(port, c))
+                       continue;
+
+               tty_insert_flip_char(tty, c, TTY_NORMAL);
+       }
+
+       return saw_console_brk;
+}
+
+static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
+{
+       int saw_console_brk = 0;
+       int limit = 10000;
+
+       while (limit-- > 0) {
+               unsigned long ra = __pa(con_read_page);
+               unsigned long bytes_read, i;
+               long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
+
+               if (stat != HV_EOK) {
+                       bytes_read = 0;
+
+                       if (stat == CON_BREAK) {
+                               if (uart_handle_break(port))
+                                       continue;
+                               saw_console_brk = 1;
+                               *con_read_page = 0;
+                               bytes_read = 1;
+                       } else if (stat == CON_HUP) {
+                               hung_up = 1;
+                               uart_handle_dcd_change(port, 0);
+                               continue;
+                       } else {
+                               /* HV_EWOULDBLOCK, etc.  */
+                               break;
+                       }
+               }
+
+               if (hung_up) {
+                       hung_up = 0;
+                       uart_handle_dcd_change(port, 1);
+               }
+
+               for (i = 0; i < bytes_read; i++)
+                       uart_handle_sysrq_char(port, con_read_page[i]);
+
+               if (tty == NULL)
+                       continue;
+
+               port->icount.rx += bytes_read;
+
+               tty_insert_flip_string(tty, con_read_page, bytes_read);
+       }
+
+       return saw_console_brk;
+}
+
+struct sunhv_ops {
+       void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
+       int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
+};
+
+static struct sunhv_ops bychar_ops = {
+       .transmit_chars = transmit_chars_putchar,
+       .receive_chars = receive_chars_getchar,
+};
+
+static struct sunhv_ops bywrite_ops = {
+       .transmit_chars = transmit_chars_write,
+       .receive_chars = receive_chars_read,
+};
+
+static struct sunhv_ops *sunhv_ops = &bychar_ops;
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+
+       if (port->state != NULL)                /* Unopened serial console */
+               tty = port->state->port.tty;
+
+       if (sunhv_ops->receive_chars(port, tty))
+               sun_do_break();
+
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->state)
+               return;
+
+       xmit = &port->state->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       sunhv_ops->transmit_chars(port, xmit);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = receive_chars(port);
+       transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sunhv_tx_empty(struct uart_port *port)
+{
+       /* Transmitter is always empty for us.  If the circ buffer
+        * is non-empty or there is an x_char pending, our caller
+        * will do the right thing and ignore what we return here.
+        */
+       return TIOCSER_TEMT;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       return;
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sunhv_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_start_tx(struct uart_port *port)
+{
+       transmit_chars(port);
+}
+
+/* port->lock is not held.  */
+static void sunhv_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long flags;
+       int limit = 10000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               long status = sun4v_con_putchar(ch);
+               if (status == HV_EOK)
+                       break;
+               udelay(1);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sunhv_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state) {
+               unsigned long flags;
+               int limit = 10000;
+
+               spin_lock_irqsave(&port->lock, flags);
+
+               while (limit-- > 0) {
+                       long status = sun4v_con_putchar(CON_BREAK);
+                       if (status == HV_EOK)
+                               break;
+                       udelay(1);
+               }
+
+               spin_unlock_irqrestore(&port->lock, flags);
+       }
+}
+
+/* port->lock is not held.  */
+static int sunhv_startup(struct uart_port *port)
+{
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sunhv_shutdown(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= IGNORE_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= IGNORE_ALL;
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sunhv_type(struct uart_port *port)
+{
+       return "SUN4V HCONS";
+}
+
+static void sunhv_release_port(struct uart_port *port)
+{
+}
+
+static int sunhv_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunhv_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sunhv_pops = {
+       .tx_empty       = sunhv_tx_empty,
+       .set_mctrl      = sunhv_set_mctrl,
+       .get_mctrl      = sunhv_get_mctrl,
+       .stop_tx        = sunhv_stop_tx,
+       .start_tx       = sunhv_start_tx,
+       .send_xchar     = sunhv_send_xchar,
+       .stop_rx        = sunhv_stop_rx,
+       .enable_ms      = sunhv_enable_ms,
+       .break_ctl      = sunhv_break_ctl,
+       .startup        = sunhv_startup,
+       .shutdown       = sunhv_shutdown,
+       .set_termios    = sunhv_set_termios,
+       .type           = sunhv_type,
+       .release_port   = sunhv_release_port,
+       .request_port   = sunhv_request_port,
+       .config_port    = sunhv_config_port,
+       .verify_port    = sunhv_verify_port,
+};
+
+static struct uart_driver sunhv_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunhv",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static struct uart_port *sunhv_port;
+
+/* Copy 's' into the con_write_page, decoding "\n" into
+ * "\r\n" along the way.  We have to return two lengths
+ * because the caller needs to know how much to advance
+ * 's' and also how many bytes to output via con_write_page.
+ */
+static int fill_con_write_page(const char *s, unsigned int n,
+                              unsigned long *page_bytes)
+{
+       const char *orig_s = s;
+       char *p = con_write_page;
+       int left = PAGE_SIZE;
+
+       while (n--) {
+               if (*s == '\n') {
+                       if (left < 2)
+                               break;
+                       *p++ = '\r';
+                       left--;
+               } else if (left < 1)
+                       break;
+               *p++ = *s++;
+               left--;
+       }
+       *page_bytes = p - con_write_page;
+       return s - orig_s;
+}
+
+static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sunhv_port;
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else
+               spin_lock(&port->lock);
+
+       while (n > 0) {
+               unsigned long ra = __pa(con_write_page);
+               unsigned long page_bytes;
+               unsigned int cpy = fill_con_write_page(s, n,
+                                                      &page_bytes);
+
+               n -= cpy;
+               s += cpy;
+               while (page_bytes > 0) {
+                       unsigned long written;
+                       int limit = 1000000;
+
+                       while (limit--) {
+                               unsigned long stat;
+
+                               stat = sun4v_con_write(ra, page_bytes,
+                                                      &written);
+                               if (stat == HV_EOK)
+                                       break;
+                               udelay(1);
+                       }
+                       if (limit < 0)
+                               break;
+                       page_bytes -= written;
+                       ra += written;
+               }
+       }
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+static inline void sunhv_console_putchar(struct uart_port *port, char c)
+{
+       int limit = 1000000;
+
+       while (limit-- > 0) {
+               long status = sun4v_con_putchar(c);
+               if (status == HV_EOK)
+                       break;
+               udelay(1);
+       }
+}
+
+static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sunhv_port;
+       unsigned long flags;
+       int i, locked = 1;
+
+       local_irq_save(flags);
+       if (port->sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&port->lock);
+       } else
+               spin_lock(&port->lock);
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sunhv_console_putchar(port, '\r');
+               sunhv_console_putchar(port, *s++);
+       }
+
+       if (locked)
+               spin_unlock(&port->lock);
+       local_irq_restore(flags);
+}
+
+static struct console sunhv_console = {
+       .name   =       "ttyHV",
+       .write  =       sunhv_console_write_bychar,
+       .device =       uart_console_device,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunhv_reg,
+};
+
+static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       struct uart_port *port;
+       unsigned long minor;
+       int err;
+
+       if (op->archdata.irqs[0] == 0xffffffff)
+               return -ENODEV;
+
+       port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
+       if (unlikely(!port))
+               return -ENOMEM;
+
+       minor = 1;
+       if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
+           minor >= 1) {
+               err = -ENOMEM;
+               con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!con_write_page)
+                       goto out_free_port;
+
+               con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!con_read_page)
+                       goto out_free_con_write_page;
+
+               sunhv_console.write = sunhv_console_write_paged;
+               sunhv_ops = &bywrite_ops;
+       }
+
+       sunhv_port = port;
+
+       port->line = 0;
+       port->ops = &sunhv_pops;
+       port->type = PORT_SUNHV;
+       port->uartclk = ( 29491200 / 16 ); /* arbitrary */
+
+       port->membase = (unsigned char __iomem *) __pa(port);
+
+       port->irq = op->archdata.irqs[0];
+
+       port->dev = &op->dev;
+
+       err = sunserial_register_minors(&sunhv_reg, 1);
+       if (err)
+               goto out_free_con_read_page;
+
+       sunserial_console_match(&sunhv_console, op->dev.of_node,
+                               &sunhv_reg, port->line, false);
+
+       err = uart_add_one_port(&sunhv_reg, port);
+       if (err)
+               goto out_unregister_driver;
+
+       err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
+       if (err)
+               goto out_remove_port;
+
+       dev_set_drvdata(&op->dev, port);
+
+       return 0;
+
+out_remove_port:
+       uart_remove_one_port(&sunhv_reg, port);
+
+out_unregister_driver:
+       sunserial_unregister_minors(&sunhv_reg, 1);
+
+out_free_con_read_page:
+       kfree(con_read_page);
+
+out_free_con_write_page:
+       kfree(con_write_page);
+
+out_free_port:
+       kfree(port);
+       sunhv_port = NULL;
+       return err;
+}
+
+static int __devexit hv_remove(struct platform_device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(&dev->dev);
+
+       free_irq(port->irq, port);
+
+       uart_remove_one_port(&sunhv_reg, port);
+
+       sunserial_unregister_minors(&sunhv_reg, 1);
+
+       kfree(port);
+       sunhv_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id hv_match[] = {
+       {
+               .name = "console",
+               .compatible = "qcn",
+       },
+       {
+               .name = "console",
+               .compatible = "SUNW,sun4v-console",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hv_match);
+
+static struct of_platform_driver hv_driver = {
+       .driver = {
+               .name = "hv",
+               .owner = THIS_MODULE,
+               .of_match_table = hv_match,
+       },
+       .probe          = hv_probe,
+       .remove         = __devexit_p(hv_remove),
+};
+
+static int __init sunhv_init(void)
+{
+       if (tlb_type != hypervisor)
+               return -ENODEV;
+
+       return of_register_platform_driver(&hv_driver);
+}
+
+static void __exit sunhv_exit(void)
+{
+       of_unregister_platform_driver(&hv_driver);
+}
+
+module_init(sunhv_init);
+module_exit(sunhv_exit);
+
+MODULE_AUTHOR("David S. Miller");
+MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
new file mode 100644 (file)
index 0000000..5b246b1
--- /dev/null
@@ -0,0 +1,1152 @@
+/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 2002, 2006  David S. Miller (davem@davemloft.net)
+ *
+ * Rewrote buffer handling to use CIRC(Circular Buffer) macros.
+ *   Maxim Krasnyanskiy <maxk@qualcomm.com>
+ *
+ * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
+ * rates to be programmed into the UART.  Also eliminated a lot of
+ * duplicated code in the console setup.
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * Ported to new 2.5.x UART layer.
+ *   David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+#include "sunsab.h"
+
+struct uart_sunsab_port {
+       struct uart_port                port;           /* Generic UART port    */
+       union sab82532_async_regs       __iomem *regs;  /* Chip registers       */
+       unsigned long                   irqflags;       /* IRQ state flags      */
+       int                             dsr;            /* Current DSR state    */
+       unsigned int                    cec_timeout;    /* Chip poll timeout... */
+       unsigned int                    tec_timeout;    /* likewise             */
+       unsigned char                   interrupt_mask0;/* ISR0 masking         */
+       unsigned char                   interrupt_mask1;/* ISR1 masking         */
+       unsigned char                   pvr_dtr_bit;    /* Which PVR bit is DTR */
+       unsigned char                   pvr_dsr_bit;    /* Which PVR bit is DSR */
+       unsigned int                    gis_shift;
+       int                             type;           /* SAB82532 version     */
+
+       /* Setting configuration bits while the transmitter is active
+        * can cause garbage characters to get emitted by the chip.
+        * Therefore, we cache such writes here and do the real register
+        * write the next time the transmitter becomes idle.
+        */
+       unsigned int                    cached_ebrg;
+       unsigned char                   cached_mode;
+       unsigned char                   cached_pvr;
+       unsigned char                   cached_dafo;
+};
+
+/*
+ * This assumes you have a 29.4912 MHz clock for your UART.
+ */
+#define SAB_BASE_BAUD ( 29491200 / 16 )
+
+static char *sab82532_version[16] = {
+       "V1.0", "V2.0", "V3.2", "V(0x03)",
+       "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)",
+       "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
+       "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
+};
+
+#define SAB82532_MAX_TEC_TIMEOUT 200000        /* 1 character time (at 50 baud) */
+#define SAB82532_MAX_CEC_TIMEOUT  50000        /* 2.5 TX CLKs (at 50 baud) */
+
+#define SAB82532_RECV_FIFO_SIZE        32      /* Standard async fifo sizes */
+#define SAB82532_XMIT_FIFO_SIZE        32
+
+static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up)
+{
+       int timeout = up->tec_timeout;
+
+       while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout)
+               udelay(1);
+}
+
+static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
+{
+       int timeout = up->cec_timeout;
+
+       while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout)
+               udelay(1);
+}
+
+static struct tty_struct *
+receive_chars(struct uart_sunsab_port *up,
+             union sab82532_irq_status *stat)
+{
+       struct tty_struct *tty = NULL;
+       unsigned char buf[32];
+       int saw_console_brk = 0;
+       int free_fifo = 0;
+       int count = 0;
+       int i;
+
+       if (up->port.state != NULL)             /* Unopened serial console */
+               tty = up->port.state->port.tty;
+
+       /* Read number of BYTES (Character + Status) available. */
+       if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
+               count = SAB82532_RECV_FIFO_SIZE;
+               free_fifo++;
+       }
+
+       if (stat->sreg.isr0 & SAB82532_ISR0_TCD) {
+               count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1);
+               free_fifo++;
+       }
+
+       /* Issue a FIFO read command in case we where idle. */
+       if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
+               sunsab_cec_wait(up);
+               writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
+               return tty;
+       }
+
+       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+               free_fifo++;
+
+       /* Read the FIFO. */
+       for (i = 0; i < count; i++)
+               buf[i] = readb(&up->regs->r.rfifo[i]);
+
+       /* Issue Receive Message Complete command. */
+       if (free_fifo) {
+               sunsab_cec_wait(up);
+               writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr);
+       }
+
+       /* Count may be zero for BRK, so we check for it here */
+       if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) &&
+           (up->port.line == up->port.cons->index))
+               saw_console_brk = 1;
+
+       for (i = 0; i < count; i++) {
+               unsigned char ch = buf[i], flag;
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(&up->port, ch);
+                       continue;
+               }
+
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR |
+                                               SAB82532_ISR0_FERR |
+                                               SAB82532_ISR0_RFO)) ||
+                   unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
+                               stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
+                                                    SAB82532_ISR0_FERR);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       continue;
+                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
+                               up->port.icount.parity++;
+                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
+                               up->port.icount.frame++;
+                       if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       stat->sreg.isr0 &= (up->port.read_status_mask & 0xff);
+                       stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff);
+
+                       if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
+                               flag = TTY_BREAK;
+                       } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR)
+                               flag = TTY_PARITY;
+                       else if (stat->sreg.isr0 & SAB82532_ISR0_FERR)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
+                   (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+               if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       if (saw_console_brk)
+               sun_do_break();
+
+       return tty;
+}
+
+static void sunsab_stop_tx(struct uart_port *);
+static void sunsab_tx_idle(struct uart_sunsab_port *);
+
+static void transmit_chars(struct uart_sunsab_port *up,
+                          union sab82532_irq_status *stat)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int i;
+
+       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
+               up->interrupt_mask1 |= SAB82532_IMR1_ALLS;
+               writeb(up->interrupt_mask1, &up->regs->w.imr1);
+               set_bit(SAB82532_ALLS, &up->irqflags);
+       }
+
+#if 0 /* bde@nwlink.com says this check causes problems */
+       if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
+               return;
+#endif
+
+       if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW))
+               return;
+
+       set_bit(SAB82532_XPR, &up->irqflags);
+       sunsab_tx_idle(up);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               up->interrupt_mask1 |= SAB82532_IMR1_XPR;
+               writeb(up->interrupt_mask1, &up->regs->w.imr1);
+               return;
+       }
+
+       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       clear_bit(SAB82532_ALLS, &up->irqflags);
+
+       /* Stuff 32 bytes into Transmit FIFO. */
+       clear_bit(SAB82532_XPR, &up->irqflags);
+       for (i = 0; i < up->port.fifosize; i++) {
+               writeb(xmit->buf[xmit->tail],
+                      &up->regs->w.xfifo[i]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Issue a Transmit Frame command. */
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               sunsab_stop_tx(&up->port);
+}
+
+static void check_status(struct uart_sunsab_port *up,
+                        union sab82532_irq_status *stat)
+{
+       if (stat->sreg.isr0 & SAB82532_ISR0_CDSC)
+               uart_handle_dcd_change(&up->port,
+                                      !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD));
+
+       if (stat->sreg.isr1 & SAB82532_ISR1_CSC)
+               uart_handle_cts_change(&up->port,
+                                      (readb(&up->regs->r.star) & SAB82532_STAR_CTS));
+
+       if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) {
+               up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1;
+               up->port.icount.dsr++;
+       }
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsab_port *up = dev_id;
+       struct tty_struct *tty;
+       union sab82532_irq_status status;
+       unsigned long flags;
+       unsigned char gis;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       status.stat = 0;
+       gis = readb(&up->regs->r.gis) >> up->gis_shift;
+       if (gis & 1)
+               status.sreg.isr0 = readb(&up->regs->r.isr0);
+       if (gis & 2)
+               status.sreg.isr1 = readb(&up->regs->r.isr1);
+
+       tty = NULL;
+       if (status.stat) {
+               if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
+                                        SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
+                   (status.sreg.isr1 & SAB82532_ISR1_BRK))
+                       tty = receive_chars(up, &status);
+               if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
+                   (status.sreg.isr1 & SAB82532_ISR1_CSC))
+                       check_status(up, &status);
+               if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
+                       transmit_chars(up, &status);
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sunsab_tx_empty(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       int ret;
+
+       /* Do not need a lock for a state test like this.  */
+       if (test_bit(SAB82532_ALLS, &up->irqflags))
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* port->lock held by caller.  */
+static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       if (mctrl & TIOCM_RTS) {
+               up->cached_mode &= ~SAB82532_MODE_FRTS;
+               up->cached_mode |= SAB82532_MODE_RTS;
+       } else {
+               up->cached_mode |= (SAB82532_MODE_FRTS |
+                                   SAB82532_MODE_RTS);
+       }
+       if (mctrl & TIOCM_DTR) {
+               up->cached_pvr &= ~(up->pvr_dtr_bit);
+       } else {
+               up->cached_pvr |= up->pvr_dtr_bit;
+       }
+
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sunsab_get_mctrl(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned char val;
+       unsigned int result;
+
+       result = 0;
+
+       val = readb(&up->regs->r.pvr);
+       result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
+
+       val = readb(&up->regs->r.vstr);
+       result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR;
+
+       val = readb(&up->regs->r.star);
+       result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
+
+       return result;
+}
+
+/* port->lock held by caller.  */
+static void sunsab_stop_tx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       up->interrupt_mask1 |= SAB82532_IMR1_XPR;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_tx_idle(struct uart_sunsab_port *up)
+{
+       if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
+               u8 tmp;
+
+               clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
+               writeb(up->cached_mode, &up->regs->rw.mode);
+               writeb(up->cached_pvr, &up->regs->rw.pvr);
+               writeb(up->cached_dafo, &up->regs->w.dafo);
+
+               writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
+               tmp = readb(&up->regs->rw.ccr2);
+               tmp &= ~0xc0;
+               tmp |= (up->cached_ebrg >> 2) & 0xc0;
+               writeb(tmp, &up->regs->rw.ccr2);
+       }
+}
+
+/* port->lock held by caller.  */
+static void sunsab_start_tx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int i;
+
+       up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       
+       if (!test_bit(SAB82532_XPR, &up->irqflags))
+               return;
+
+       clear_bit(SAB82532_ALLS, &up->irqflags);
+       clear_bit(SAB82532_XPR, &up->irqflags);
+
+       for (i = 0; i < up->port.fifosize; i++) {
+               writeb(xmit->buf[xmit->tail],
+                      &up->regs->w.xfifo[i]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Issue a Transmit Frame command.  */
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
+}
+
+/* port->lock is not held.  */
+static void sunsab_send_xchar(struct uart_port *port, char ch)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       sunsab_tec_wait(up);
+       writeb(ch, &up->regs->w.tic);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_stop_rx(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+
+       up->interrupt_mask0 |= SAB82532_IMR0_TCD;
+       writeb(up->interrupt_mask1, &up->regs->w.imr0);
+}
+
+/* port->lock held by caller.  */
+static void sunsab_enable_ms(struct uart_port *port)
+{
+       /* For now we always receive these interrupts.  */
+}
+
+/* port->lock is not held.  */
+static void sunsab_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned char val;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       val = up->cached_dafo;
+       if (break_state)
+               val |= SAB82532_DAFO_XBRK;
+       else
+               val &= ~SAB82532_DAFO_XBRK;
+       up->cached_dafo = val;
+
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+/* port->lock is not held.  */
+static int sunsab_startup(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned char tmp;
+       int err = request_irq(up->port.irq, sunsab_interrupt,
+                             IRQF_SHARED, "sab", up);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Wait for any commands or immediate characters
+        */
+       sunsab_cec_wait(up);
+       sunsab_tec_wait(up);
+
+       /*
+        * Clear the FIFO buffers.
+        */
+       writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr);
+       sunsab_cec_wait(up);
+       writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr);
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) readb(&up->regs->r.isr0);
+       (void) readb(&up->regs->r.isr1);
+
+       /*
+        * Now, initialize the UART 
+        */
+       writeb(0, &up->regs->w.ccr0);                           /* power-down */
+       writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |
+              SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0);
+       writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1);
+       writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL |
+              SAB82532_CCR2_TOE, &up->regs->w.ccr2);
+       writeb(0, &up->regs->w.ccr3);
+       writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
+       up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
+                          SAB82532_MODE_RAC);
+       writeb(up->cached_mode, &up->regs->w.mode);
+       writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
+       
+       tmp = readb(&up->regs->rw.ccr0);
+       tmp |= SAB82532_CCR0_PU;        /* power-up */
+       writeb(tmp, &up->regs->rw.ccr0);
+
+       /*
+        * Finally, enable interrupts
+        */
+       up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
+                              SAB82532_IMR0_PLLA);
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
+                              SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
+                              SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
+                              SAB82532_IMR1_XPR);
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+       set_bit(SAB82532_ALLS, &up->irqflags);
+       set_bit(SAB82532_XPR, &up->irqflags);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sunsab_shutdown(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Disable Interrupts */
+       up->interrupt_mask0 = 0xff;
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = 0xff;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+
+       /* Disable break condition */
+       up->cached_dafo = readb(&up->regs->rw.dafo);
+       up->cached_dafo &= ~SAB82532_DAFO_XBRK;
+       writeb(up->cached_dafo, &up->regs->rw.dafo);
+
+       /* Disable Receiver */  
+       up->cached_mode &= ~SAB82532_MODE_RAC;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+
+       /*
+        * XXX FIXME
+        *
+        * If the chip is powered down here the system hangs/crashes during
+        * reboot or shutdown.  This needs to be investigated further,
+        * similar behaviour occurs in 2.4 when the driver is configured
+        * as a module only.  One hint may be that data is sometimes
+        * transmitted at 9600 baud during shutdown (regardless of the
+        * speed the chip was configured for when the port was open).
+        */
+#if 0
+       /* Power Down */        
+       tmp = readb(&up->regs->rw.ccr0);
+       tmp &= ~SAB82532_CCR0_PU;
+       writeb(tmp, &up->regs->rw.ccr0);
+#endif
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       free_irq(up->port.irq, up);
+}
+
+/*
+ * This is used to figure out the divisor speeds.
+ *
+ * The formula is:    Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)),
+ *
+ * with               0 <= N < 64 and 0 <= M < 16
+ */
+
+static void calc_ebrg(int baud, int *n_ret, int *m_ret)
+{
+       int     n, m;
+
+       if (baud == 0) {
+               *n_ret = 0;
+               *m_ret = 0;
+               return;
+       }
+     
+       /*
+        * We scale numbers by 10 so that we get better accuracy
+        * without having to use floating point.  Here we increment m
+        * until n is within the valid range.
+        */
+       n = (SAB_BASE_BAUD * 10) / baud;
+       m = 0;
+       while (n >= 640) {
+               n = n / 2;
+               m++;
+       }
+       n = (n+5) / 10;
+       /*
+        * We try very hard to avoid speeds with M == 0 since they may
+        * not work correctly for XTAL frequences above 10 MHz.
+        */
+       if ((m == 0) && ((n & 1) == 0)) {
+               n = n / 2;
+               m++;
+       }
+       *n_ret = n - 1;
+       *m_ret = m;
+}
+
+/* Internal routine, port->lock is held and local interrupts are disabled.  */
+static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag,
+                                 unsigned int iflag, unsigned int baud,
+                                 unsigned int quot)
+{
+       unsigned char dafo;
+       int bits, n, m;
+
+       /* Byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
+             case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
+             case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
+             case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;
+       }
+
+       if (cflag & CSTOPB) {
+               dafo |= SAB82532_DAFO_STOP;
+               bits++;
+       }
+
+       if (cflag & PARENB) {
+               dafo |= SAB82532_DAFO_PARE;
+               bits++;
+       }
+
+       if (cflag & PARODD) {
+               dafo |= SAB82532_DAFO_PAR_ODD;
+       } else {
+               dafo |= SAB82532_DAFO_PAR_EVEN;
+       }
+       up->cached_dafo = dafo;
+
+       calc_ebrg(baud, &n, &m);
+
+       up->cached_ebrg = n | (m << 6);
+
+       up->tec_timeout = (10 * 1000000) / baud;
+       up->cec_timeout = up->tec_timeout >> 2;
+
+       /* CTS flow control flags */
+       /* We encode read_status_mask and ignore_status_mask like so:
+        *
+        * ---------------------
+        * | ... | ISR1 | ISR0 |
+        * ---------------------
+        *  ..    15   8 7    0
+        */
+
+       up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
+                                    SAB82532_ISR0_RFO | SAB82532_ISR0_RPF |
+                                    SAB82532_ISR0_CDSC);
+       up->port.read_status_mask |= (SAB82532_ISR1_CSC |
+                                     SAB82532_ISR1_ALLS |
+                                     SAB82532_ISR1_XPR) << 8;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= (SAB82532_ISR0_PERR |
+                                             SAB82532_ISR0_FERR);
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= (SAB82532_ISR0_PERR |
+                                               SAB82532_ISR0_FERR);
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8);
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= SAB82532_ISR0_RFO;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= (SAB82532_ISR0_RPF |
+                                               SAB82532_ISR0_TCD);
+
+       uart_update_timeout(&up->port, cflag,
+                           (up->port.uartclk / (16 * quot)));
+
+       /* Now schedule a register update when the chip's
+        * transmitter is idle.
+        */
+       up->cached_mode |= SAB82532_MODE_RAC;
+       set_bit(SAB82532_REGS_PENDING, &up->irqflags);
+       if (test_bit(SAB82532_XPR, &up->irqflags))
+               sunsab_tx_idle(up);
+}
+
+/* port->lock is not held.  */
+static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
+                              struct ktermios *old)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
+       unsigned long flags;
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *sunsab_type(struct uart_port *port)
+{
+       struct uart_sunsab_port *up = (void *)port;
+       static char buf[36];
+       
+       sprintf(buf, "SAB82532 %s", sab82532_version[up->type]);
+       return buf;
+}
+
+static void sunsab_release_port(struct uart_port *port)
+{
+}
+
+static int sunsab_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunsab_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sunsab_pops = {
+       .tx_empty       = sunsab_tx_empty,
+       .set_mctrl      = sunsab_set_mctrl,
+       .get_mctrl      = sunsab_get_mctrl,
+       .stop_tx        = sunsab_stop_tx,
+       .start_tx       = sunsab_start_tx,
+       .send_xchar     = sunsab_send_xchar,
+       .stop_rx        = sunsab_stop_rx,
+       .enable_ms      = sunsab_enable_ms,
+       .break_ctl      = sunsab_break_ctl,
+       .startup        = sunsab_startup,
+       .shutdown       = sunsab_shutdown,
+       .set_termios    = sunsab_set_termios,
+       .type           = sunsab_type,
+       .release_port   = sunsab_release_port,
+       .request_port   = sunsab_request_port,
+       .config_port    = sunsab_config_port,
+       .verify_port    = sunsab_verify_port,
+};
+
+static struct uart_driver sunsab_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunsab",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static struct uart_sunsab_port *sunsab_ports;
+
+#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
+
+static void sunsab_console_putchar(struct uart_port *port, int c)
+{
+       struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
+
+       sunsab_tec_wait(up);
+       writeb(c, &up->regs->w.tic);
+}
+
+static void sunsab_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_sunsab_port *up = &sunsab_ports[con->index];
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       uart_console_write(&up->port, s, n, sunsab_console_putchar);
+       sunsab_tec_wait(up);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int sunsab_console_setup(struct console *con, char *options)
+{
+       struct uart_sunsab_port *up = &sunsab_ports[con->index];
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       /*
+        * The console framework calls us for each and every port
+        * registered. Defer the console setup until the requested
+        * port has been properly discovered. A bit of a hack,
+        * though...
+        */
+       if (up->port.type != PORT_SUNSAB)
+               return -1;
+
+       printk("Console: ttyS%d (SAB82532)\n",
+              (sunsab_reg.minor - 64) + con->index);
+
+       sunserial_console_termios(con, up->port.dev->of_node);
+
+       switch (con->cflag & CBAUD) {
+       case B150: baud = 150; break;
+       case B300: baud = 300; break;
+       case B600: baud = 600; break;
+       case B1200: baud = 1200; break;
+       case B2400: baud = 2400; break;
+       case B4800: baud = 4800; break;
+       default: case B9600: baud = 9600; break;
+       case B19200: baud = 19200; break;
+       case B38400: baud = 38400; break;
+       case B57600: baud = 57600; break;
+       case B115200: baud = 115200; break;
+       case B230400: baud = 230400; break;
+       case B460800: baud = 460800; break;
+       };
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&up->port.lock);
+
+       /*
+        * Initialize the hardware
+        */
+       sunsab_startup(&up->port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts
+        */
+       up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
+                               SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;
+       writeb(up->interrupt_mask0, &up->regs->w.imr0);
+       up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
+                               SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
+                               SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
+                               SAB82532_IMR1_XPR;
+       writeb(up->interrupt_mask1, &up->regs->w.imr1);
+
+       quot = uart_get_divisor(&up->port, baud);
+       sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
+       sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       
+       return 0;
+}
+
+static struct console sunsab_console = {
+       .name   =       "ttyS",
+       .write  =       sunsab_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunsab_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunsab_reg,
+};
+
+static inline struct console *SUNSAB_CONSOLE(void)
+{
+       return &sunsab_console;
+}
+#else
+#define SUNSAB_CONSOLE()       (NULL)
+#define sunsab_console_init()  do { } while (0)
+#endif
+
+static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
+                                    struct platform_device *op,
+                                    unsigned long offset,
+                                    int line)
+{
+       up->port.line = line;
+       up->port.dev = &op->dev;
+
+       up->port.mapbase = op->resource[0].start + offset;
+       up->port.membase = of_ioremap(&op->resource[0], offset,
+                                     sizeof(union sab82532_async_regs),
+                                     "sab");
+       if (!up->port.membase)
+               return -ENOMEM;
+       up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
+
+       up->port.irq = op->archdata.irqs[0];
+
+       up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
+       up->port.iotype = UPIO_MEM;
+
+       writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
+
+       up->port.ops = &sunsab_pops;
+       up->port.type = PORT_SUNSAB;
+       up->port.uartclk = SAB_BASE_BAUD;
+
+       up->type = readb(&up->regs->r.vstr) & 0x0f;
+       writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
+       writeb(0xff, &up->regs->w.pim);
+       if ((up->port.line & 0x1) == 0) {
+               up->pvr_dsr_bit = (1 << 0);
+               up->pvr_dtr_bit = (1 << 1);
+               up->gis_shift = 2;
+       } else {
+               up->pvr_dsr_bit = (1 << 3);
+               up->pvr_dtr_bit = (1 << 2);
+               up->gis_shift = 0;
+       }
+       up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
+       writeb(up->cached_pvr, &up->regs->w.pvr);
+       up->cached_mode = readb(&up->regs->rw.mode);
+       up->cached_mode |= SAB82532_MODE_FRTS;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+       up->cached_mode |= SAB82532_MODE_RTS;
+       writeb(up->cached_mode, &up->regs->rw.mode);
+
+       up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
+       up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
+
+       return 0;
+}
+
+static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int inst;
+       struct uart_sunsab_port *up;
+       int err;
+
+       up = &sunsab_ports[inst * 2];
+
+       err = sunsab_init_one(&up[0], op,
+                             0,
+                             (inst * 2) + 0);
+       if (err)
+               goto out;
+
+       err = sunsab_init_one(&up[1], op,
+                             sizeof(union sab82532_async_regs),
+                             (inst * 2) + 1);
+       if (err)
+               goto out1;
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
+                               &sunsab_reg, up[0].port.line,
+                               false);
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
+                               &sunsab_reg, up[1].port.line,
+                               false);
+
+       err = uart_add_one_port(&sunsab_reg, &up[0].port);
+       if (err)
+               goto out2;
+
+       err = uart_add_one_port(&sunsab_reg, &up[1].port);
+       if (err)
+               goto out3;
+
+       dev_set_drvdata(&op->dev, &up[0]);
+
+       inst++;
+
+       return 0;
+
+out3:
+       uart_remove_one_port(&sunsab_reg, &up[0].port);
+out2:
+       of_iounmap(&op->resource[0],
+                  up[1].port.membase,
+                  sizeof(union sab82532_async_regs));
+out1:
+       of_iounmap(&op->resource[0],
+                  up[0].port.membase,
+                  sizeof(union sab82532_async_regs));
+out:
+       return err;
+}
+
+static int __devexit sab_remove(struct platform_device *op)
+{
+       struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
+
+       uart_remove_one_port(&sunsab_reg, &up[1].port);
+       uart_remove_one_port(&sunsab_reg, &up[0].port);
+       of_iounmap(&op->resource[0],
+                  up[1].port.membase,
+                  sizeof(union sab82532_async_regs));
+       of_iounmap(&op->resource[0],
+                  up[0].port.membase,
+                  sizeof(union sab82532_async_regs));
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id sab_match[] = {
+       {
+               .name = "se",
+       },
+       {
+               .name = "serial",
+               .compatible = "sab82532",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sab_match);
+
+static struct of_platform_driver sab_driver = {
+       .driver = {
+               .name = "sab",
+               .owner = THIS_MODULE,
+               .of_match_table = sab_match,
+       },
+       .probe          = sab_probe,
+       .remove         = __devexit_p(sab_remove),
+};
+
+static int __init sunsab_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_channels = 0;
+
+       for_each_node_by_name(dp, "se")
+               num_channels += 2;
+       for_each_node_by_name(dp, "serial") {
+               if (of_device_is_compatible(dp, "sab82532"))
+                       num_channels += 2;
+       }
+
+       if (num_channels) {
+               sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) *
+                                      num_channels, GFP_KERNEL);
+               if (!sunsab_ports)
+                       return -ENOMEM;
+
+               err = sunserial_register_minors(&sunsab_reg, num_channels);
+               if (err) {
+                       kfree(sunsab_ports);
+                       sunsab_ports = NULL;
+
+                       return err;
+               }
+       }
+
+       return of_register_platform_driver(&sab_driver);
+}
+
+static void __exit sunsab_exit(void)
+{
+       of_unregister_platform_driver(&sab_driver);
+       if (sunsab_reg.nr) {
+               sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
+       }
+
+       kfree(sunsab_ports);
+       sunsab_ports = NULL;
+}
+
+module_init(sunsab_init);
+module_exit(sunsab_exit);
+
+MODULE_AUTHOR("Eddie C. Dost and David S. Miller");
+MODULE_DESCRIPTION("Sun SAB82532 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunsab.h b/drivers/tty/serial/sunsab.h
new file mode 100644 (file)
index 0000000..b78e1f7
--- /dev/null
@@ -0,0 +1,322 @@
+/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _SUNSAB_H
+#define _SUNSAB_H
+
+struct sab82532_async_rd_regs {
+       u8      rfifo[0x20];    /* Receive FIFO                         */
+       u8      star;           /* Status Register                      */
+       u8      __pad1;
+       u8      mode;           /* Mode Register                        */
+       u8      timr;           /* Timer Register                       */
+       u8      xon;            /* XON Character                        */
+       u8      xoff;           /* XOFF Character                       */
+       u8      tcr;            /* Termination Character Register       */
+       u8      dafo;           /* Data Format                          */
+       u8      rfc;            /* RFIFO Control Register               */
+       u8      __pad2;
+       u8      rbcl;           /* Receive Byte Count Low               */
+       u8      rbch;           /* Receive Byte Count High              */
+       u8      ccr0;           /* Channel Configuration Register 0     */
+       u8      ccr1;           /* Channel Configuration Register 1     */
+       u8      ccr2;           /* Channel Configuration Register 2     */
+       u8      ccr3;           /* Channel Configuration Register 3     */
+       u8      __pad3[4];
+       u8      vstr;           /* Version Status Register              */
+       u8      __pad4[3];
+       u8      gis;            /* Global Interrupt Status              */
+       u8      ipc;            /* Interrupt Port Configuration         */
+       u8      isr0;           /* Interrupt Status 0                   */
+       u8      isr1;           /* Interrupt Status 1                   */
+       u8      pvr;            /* Port Value Register                  */
+       u8      pis;            /* Port Interrupt Status                */
+       u8      pcr;            /* Port Configuration Register          */
+       u8      ccr4;           /* Channel Configuration Register 4     */
+};
+
+struct sab82532_async_wr_regs {
+       u8      xfifo[0x20];    /* Transmit FIFO                        */
+       u8      cmdr;           /* Command Register                     */
+       u8      __pad1;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad2;
+       u8      xbcl;           /* Transmit Byte Count Low              */
+       u8      xbch;           /* Transmit Byte Count High             */
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      tsax;           /* Time-Slot Assignment Reg. Transmit   */
+       u8      tsar;           /* Time-Slot Assignment Reg. Receive    */
+       u8      xccr;           /* Transmit Channel Capacity Register   */
+       u8      rccr;           /* Receive Channel Capacity Register    */
+       u8      bgr;            /* Baud Rate Generator Register         */
+       u8      tic;            /* Transmit Immediate Character         */
+       u8      mxn;            /* Mask XON Character                   */
+       u8      mxf;            /* Mask XOFF Character                  */
+       u8      iva;            /* Interrupt Vector Address             */
+       u8      ipc;
+       u8      imr0;           /* Interrupt Mask Register 0            */
+       u8      imr1;           /* Interrupt Mask Register 1            */
+       u8      pvr;
+       u8      pim;            /* Port Interrupt Mask                  */
+       u8      pcr;
+       u8      ccr4;
+};
+
+struct sab82532_async_rw_regs {        /* Read/Write registers                 */
+       u8      __pad1[0x20];
+       u8      __pad2;
+       u8      __pad3;
+       u8      mode;
+       u8      timr;
+       u8      xon;
+       u8      xoff;
+       u8      tcr;
+       u8      dafo;
+       u8      rfc;
+       u8      __pad4;
+       u8      __pad5;
+       u8      __pad6;
+       u8      ccr0;
+       u8      ccr1;
+       u8      ccr2;
+       u8      ccr3;
+       u8      __pad7;
+       u8      __pad8;
+       u8      __pad9;
+       u8      __pad10;
+       u8      __pad11;
+       u8      __pad12;
+       u8      __pad13;
+       u8      __pad14;
+       u8      __pad15;
+       u8      ipc;
+       u8      __pad16;
+       u8      __pad17;
+       u8      pvr;
+       u8      __pad18;
+       u8      pcr;
+       u8      ccr4;
+};
+
+union sab82532_async_regs {
+       __volatile__ struct sab82532_async_rd_regs      r;
+       __volatile__ struct sab82532_async_wr_regs      w;
+       __volatile__ struct sab82532_async_rw_regs      rw;
+};
+
+union sab82532_irq_status {
+       unsigned short                   stat;
+       struct {
+               unsigned char            isr0;
+               unsigned char            isr1;
+       } sreg;
+};
+
+/* irqflags bits */
+#define SAB82532_ALLS                  0x00000001
+#define SAB82532_XPR                   0x00000002
+#define SAB82532_REGS_PENDING          0x00000004
+
+/* RFIFO Status Byte */
+#define SAB82532_RSTAT_PE              0x80
+#define SAB82532_RSTAT_FE              0x40
+#define SAB82532_RSTAT_PARITY          0x01
+
+/* Status Register (STAR) */
+#define SAB82532_STAR_XDOV             0x80
+#define SAB82532_STAR_XFW              0x40
+#define SAB82532_STAR_RFNE             0x20
+#define SAB82532_STAR_FCS              0x10
+#define SAB82532_STAR_TEC              0x08
+#define SAB82532_STAR_CEC              0x04
+#define SAB82532_STAR_CTS              0x02
+
+/* Command Register (CMDR) */
+#define SAB82532_CMDR_RMC              0x80
+#define SAB82532_CMDR_RRES             0x40
+#define SAB82532_CMDR_RFRD             0x20
+#define SAB82532_CMDR_STI              0x10
+#define SAB82532_CMDR_XF               0x08
+#define SAB82532_CMDR_XRES             0x01
+
+/* Mode Register (MODE) */
+#define SAB82532_MODE_FRTS             0x40
+#define SAB82532_MODE_FCTS             0x20
+#define SAB82532_MODE_FLON             0x10
+#define SAB82532_MODE_RAC              0x08
+#define SAB82532_MODE_RTS              0x04
+#define SAB82532_MODE_TRS              0x02
+#define SAB82532_MODE_TLP              0x01
+
+/* Timer Register (TIMR) */
+#define SAB82532_TIMR_CNT_MASK         0xe0
+#define SAB82532_TIMR_VALUE_MASK       0x1f
+
+/* Data Format (DAFO) */
+#define SAB82532_DAFO_XBRK             0x40
+#define SAB82532_DAFO_STOP             0x20
+#define SAB82532_DAFO_PAR_SPACE                0x00
+#define SAB82532_DAFO_PAR_ODD          0x08
+#define SAB82532_DAFO_PAR_EVEN         0x10
+#define SAB82532_DAFO_PAR_MARK         0x18
+#define SAB82532_DAFO_PARE             0x04
+#define SAB82532_DAFO_CHL8             0x00
+#define SAB82532_DAFO_CHL7             0x01
+#define SAB82532_DAFO_CHL6             0x02
+#define SAB82532_DAFO_CHL5             0x03
+
+/* RFIFO Control Register (RFC) */
+#define SAB82532_RFC_DPS               0x40
+#define SAB82532_RFC_DXS               0x20
+#define SAB82532_RFC_RFDF              0x10
+#define SAB82532_RFC_RFTH_1            0x00
+#define SAB82532_RFC_RFTH_4            0x04
+#define SAB82532_RFC_RFTH_16           0x08
+#define SAB82532_RFC_RFTH_32           0x0c
+#define SAB82532_RFC_TCDE              0x01
+
+/* Received Byte Count High (RBCH) */
+#define SAB82532_RBCH_DMA              0x80
+#define SAB82532_RBCH_CAS              0x20
+
+/* Transmit Byte Count High (XBCH) */
+#define SAB82532_XBCH_DMA              0x80
+#define SAB82532_XBCH_CAS              0x20
+#define SAB82532_XBCH_XC               0x10
+
+/* Channel Configuration Register 0 (CCR0) */
+#define SAB82532_CCR0_PU               0x80
+#define SAB82532_CCR0_MCE              0x40
+#define SAB82532_CCR0_SC_NRZ           0x00
+#define SAB82532_CCR0_SC_NRZI          0x08
+#define SAB82532_CCR0_SC_FM0           0x10
+#define SAB82532_CCR0_SC_FM1           0x14
+#define SAB82532_CCR0_SC_MANCH         0x18
+#define SAB82532_CCR0_SM_HDLC          0x00
+#define SAB82532_CCR0_SM_SDLC_LOOP     0x01
+#define SAB82532_CCR0_SM_BISYNC                0x02
+#define SAB82532_CCR0_SM_ASYNC         0x03
+
+/* Channel Configuration Register 1 (CCR1) */
+#define SAB82532_CCR1_ODS              0x10
+#define SAB82532_CCR1_BCR              0x08
+#define SAB82532_CCR1_CM_MASK          0x07
+
+/* Channel Configuration Register 2 (CCR2) */
+#define SAB82532_CCR2_SOC1             0x80
+#define SAB82532_CCR2_SOC0             0x40
+#define SAB82532_CCR2_BR9              0x80
+#define SAB82532_CCR2_BR8              0x40
+#define SAB82532_CCR2_BDF              0x20
+#define SAB82532_CCR2_SSEL             0x10
+#define SAB82532_CCR2_XCS0             0x20
+#define SAB82532_CCR2_RCS0             0x10
+#define SAB82532_CCR2_TOE              0x08
+#define SAB82532_CCR2_RWX              0x04
+#define SAB82532_CCR2_DIV              0x01
+
+/* Channel Configuration Register 3 (CCR3) */
+#define SAB82532_CCR3_PSD              0x01
+
+/* Time Slot Assignment Register Transmit (TSAX) */
+#define SAB82532_TSAX_TSNX_MASK                0xfc
+#define SAB82532_TSAX_XCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAX_XCS1             0x01
+
+/* Time Slot Assignment Register Receive (TSAR) */
+#define SAB82532_TSAR_TSNR_MASK                0xfc
+#define SAB82532_TSAR_RCS2             0x02    /* see also CCR2 */
+#define SAB82532_TSAR_RCS1             0x01
+
+/* Version Status Register (VSTR) */
+#define SAB82532_VSTR_CD               0x80
+#define SAB82532_VSTR_DPLA             0x40
+#define SAB82532_VSTR_VN_MASK          0x0f
+#define SAB82532_VSTR_VN_1             0x00
+#define SAB82532_VSTR_VN_2             0x01
+#define SAB82532_VSTR_VN_3_2           0x02
+
+/* Global Interrupt Status Register (GIS) */
+#define SAB82532_GIS_PI                        0x80
+#define SAB82532_GIS_ISA1              0x08
+#define SAB82532_GIS_ISA0              0x04
+#define SAB82532_GIS_ISB1              0x02
+#define SAB82532_GIS_ISB0              0x01
+
+/* Interrupt Vector Address (IVA) */
+#define SAB82532_IVA_MASK              0xf1
+
+/* Interrupt Port Configuration (IPC) */
+#define SAB82532_IPC_VIS               0x80
+#define SAB82532_IPC_SLA1              0x10
+#define SAB82532_IPC_SLA0              0x08
+#define SAB82532_IPC_CASM              0x04
+#define SAB82532_IPC_IC_OPEN_DRAIN     0x00
+#define SAB82532_IPC_IC_ACT_LOW                0x01
+#define SAB82532_IPC_IC_ACT_HIGH       0x03
+
+/* Interrupt Status Register 0 (ISR0) */
+#define SAB82532_ISR0_TCD              0x80
+#define SAB82532_ISR0_TIME             0x40
+#define SAB82532_ISR0_PERR             0x20
+#define SAB82532_ISR0_FERR             0x10
+#define SAB82532_ISR0_PLLA             0x08
+#define SAB82532_ISR0_CDSC             0x04
+#define SAB82532_ISR0_RFO              0x02
+#define SAB82532_ISR0_RPF              0x01
+
+/* Interrupt Status Register 1 (ISR1) */
+#define SAB82532_ISR1_BRK              0x80
+#define SAB82532_ISR1_BRKT             0x40
+#define SAB82532_ISR1_ALLS             0x20
+#define SAB82532_ISR1_XOFF             0x10
+#define SAB82532_ISR1_TIN              0x08
+#define SAB82532_ISR1_CSC              0x04
+#define SAB82532_ISR1_XON              0x02
+#define SAB82532_ISR1_XPR              0x01
+
+/* Interrupt Mask Register 0 (IMR0) */
+#define SAB82532_IMR0_TCD              0x80
+#define SAB82532_IMR0_TIME             0x40
+#define SAB82532_IMR0_PERR             0x20
+#define SAB82532_IMR0_FERR             0x10
+#define SAB82532_IMR0_PLLA             0x08
+#define SAB82532_IMR0_CDSC             0x04
+#define SAB82532_IMR0_RFO              0x02
+#define SAB82532_IMR0_RPF              0x01
+
+/* Interrupt Mask Register 1 (IMR1) */
+#define SAB82532_IMR1_BRK              0x80
+#define SAB82532_IMR1_BRKT             0x40
+#define SAB82532_IMR1_ALLS             0x20
+#define SAB82532_IMR1_XOFF             0x10
+#define SAB82532_IMR1_TIN              0x08
+#define SAB82532_IMR1_CSC              0x04
+#define SAB82532_IMR1_XON              0x02
+#define SAB82532_IMR1_XPR              0x01
+
+/* Port Interrupt Status Register (PIS) */
+#define SAB82532_PIS_SYNC_B            0x08
+#define SAB82532_PIS_DTR_B             0x04
+#define SAB82532_PIS_DTR_A             0x02
+#define SAB82532_PIS_SYNC_A            0x01
+
+/* Channel Configuration Register 4 (CCR4) */
+#define SAB82532_CCR4_MCK4             0x80
+#define SAB82532_CCR4_EBRG             0x40
+#define SAB82532_CCR4_TST1             0x20
+#define SAB82532_CCR4_ICD              0x10
+
+
+#endif /* !(_SUNSAB_H) */
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
new file mode 100644 (file)
index 0000000..551ebfe
--- /dev/null
@@ -0,0 +1,1608 @@
+/*
+ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@yahoo.com)
+ *
+ * This is mainly a variation of 8250.c, credits go to authors mentioned
+ * therein.  In fact this driver should be merged into the generic 8250.c
+ * infrastructure perhaps using a 8250_sparc.c module.
+ *
+ * Fixed to use tty_get_baud_rate().
+ *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * Converted to new 2.5.x UART layer.
+ *   David S. Miller (davem@davemloft.net), 2002-Jul-29
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/slab.h>
+#ifdef CONFIG_SERIO
+#include <linux/serio.h>
+#endif
+#include <linux/serial_reg.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+
+/* We are on a NS PC87303 clocked with 24.0 MHz, which results
+ * in a UART clock of 1.8462 MHz.
+ */
+#define SU_BASE_BAUD   (1846200 / 16)
+
+enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
+static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+       { "unknown",    1,      0 },
+       { "8250",       1,      0 },
+       { "16450",      1,      0 },
+       { "16550",      1,      0 },
+       { "16550A",     16,     UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "Cirrus",     1,      0 },
+       { "ST16650",    1,      UART_CLEAR_FIFO | UART_STARTECH },
+       { "ST16650V2",  32,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "TI16750",    64,     UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "Startech",   1,      0 },
+       { "16C950/954", 128,    UART_CLEAR_FIFO | UART_USE_FIFO },
+       { "ST16654",    64,     UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "XR16850",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+       { "RSA",        2048,   UART_CLEAR_FIFO | UART_USE_FIFO }
+};
+
+struct uart_sunsu_port {
+       struct uart_port        port;
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned short          rev;
+       unsigned char           lcr;
+       unsigned int            lsr_break_flag;
+       unsigned int            cflag;
+
+       /* Probing information.  */
+       enum su_type            su_type;
+       unsigned int            type_probed;    /* XXX Stupid */
+       unsigned long           reg_size;
+
+#ifdef CONFIG_SERIO
+       struct serio            serio;
+       int                     serio_open;
+#endif
+};
+
+static unsigned int serial_in(struct uart_sunsu_port *up, int offset)
+{
+       offset <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+               outb(up->port.hub6 - 1 + offset, up->port.iobase);
+               return inb(up->port.iobase + 1);
+
+       case UPIO_MEM:
+               return readb(up->port.membase + offset);
+
+       default:
+               return inb(up->port.iobase + offset);
+       }
+}
+
+static void serial_out(struct uart_sunsu_port *up, int offset, int value)
+{
+#ifndef CONFIG_SPARC64
+       /*
+        * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
+        * connected with a gate then go to SlavIO. When IRQ4 goes tristated
+        * gate outputs a logical one. Since we use level triggered interrupts
+        * we have lockup and watchdog reset. We cannot mask IRQ because
+        * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
+        * This problem is similar to what Alpha people suffer, see serial.c.
+        */
+       if (offset == UART_MCR)
+               value |= UART_MCR_OUT2;
+#endif
+       offset <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case UPIO_HUB6:
+               outb(up->port.hub6 - 1 + offset, up->port.iobase);
+               outb(value, up->port.iobase + 1);
+               break;
+
+       case UPIO_MEM:
+               writeb(value, up->port.membase + offset);
+               break;
+
+       default:
+               outb(value, up->port.iobase + offset);
+       }
+}
+
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(up, offset)         serial_in(up, offset)
+#define serial_outp(up, offset, value) serial_out(up, offset, value)
+
+
+/*
+ * For the 16C950
+ */
+static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
+{
+       serial_out(up, UART_SCR, offset);
+       serial_out(up, UART_ICR, value);
+}
+
+#if 0 /* Unused currently */
+static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
+{
+       unsigned int value;
+
+       serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
+       serial_out(up, UART_SCR, offset);
+       value = serial_in(up, UART_ICR);
+       serial_icr_write(up, UART_ACR, up->acr);
+
+       return value;
+}
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RSA
+/*
+ * Attempts to turn on the RSA FIFO.  Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __enable_rsa(struct uart_sunsu_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       mode = serial_inp(up, UART_RSA_MSR);
+       result = mode & UART_RSA_MSR_FIFO;
+
+       if (!result) {
+               serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = mode & UART_RSA_MSR_FIFO;
+       }
+
+       if (result)
+               up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+       return result;
+}
+
+static void enable_rsa(struct uart_sunsu_port *up)
+{
+       if (up->port.type == PORT_RSA) {
+               if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+                       spin_lock_irq(&up->port.lock);
+                       __enable_rsa(up);
+                       spin_unlock_irq(&up->port.lock);
+               }
+               if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+                       serial_outp(up, UART_RSA_FRR, 0);
+       }
+}
+
+/*
+ * Attempts to turn off the RSA FIFO.  Returns zero on failure.
+ * It is unknown why interrupts were disabled in here.  However,
+ * the caller is expected to preserve this behaviour by grabbing
+ * the spinlock before calling this function.
+ */
+static void disable_rsa(struct uart_sunsu_port *up)
+{
+       unsigned char mode;
+       int result;
+
+       if (up->port.type == PORT_RSA &&
+           up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
+               spin_lock_irq(&up->port.lock);
+
+               mode = serial_inp(up, UART_RSA_MSR);
+               result = !(mode & UART_RSA_MSR_FIFO);
+
+               if (!result) {
+                       serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+                       mode = serial_inp(up, UART_RSA_MSR);
+                       result = !(mode & UART_RSA_MSR_FIFO);
+               }
+
+               if (result)
+                       up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+               spin_unlock_irq(&up->port.lock);
+       }
+}
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+static inline void __stop_tx(struct uart_sunsu_port *p)
+{
+       if (p->ier & UART_IER_THRI) {
+               p->ier &= ~UART_IER_THRI;
+               serial_out(p, UART_IER, p->ier);
+       }
+}
+
+static void sunsu_stop_tx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       __stop_tx(up);
+
+       /*
+        * We really want to stop the transmitter from sending.
+        */
+       if (up->port.type == PORT_16C950) {
+               up->acr |= UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void sunsu_start_tx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+
+       /*
+        * Re-enable the transmitter if we disabled it.
+        */
+       if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
+               up->acr &= ~UART_ACR_TXDIS;
+               serial_icr_write(up, UART_ACR, up->acr);
+       }
+}
+
+static void sunsu_stop_rx(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void sunsu_enable_ms(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct tty_struct *
+receive_chars(struct uart_sunsu_port *up, unsigned char *status)
+{
+       struct tty_struct *tty = up->port.state->port.tty;
+       unsigned char ch, flag;
+       int max_count = 256;
+       int saw_console_brk = 0;
+
+       do {
+               ch = serial_inp(up, UART_RX);
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               if (up->port.cons != NULL &&
+                                   up->port.line == up->port.cons->index)
+                                       saw_console_brk = 1;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+                       if (up->port.cons != NULL &&
+                           up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+
+                       if (*status & UART_LSR_BI) {
+                               flag = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               flag = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       goto ignore_char;
+               if ((*status & up->port.ignore_status_mask) == 0)
+                       tty_insert_flip_char(tty, ch, flag);
+               if (*status & UART_LSR_OE)
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character.
+                        */
+                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       ignore_char:
+               *status = serial_inp(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+
+       if (saw_console_brk)
+               sun_do_break();
+
+       return tty;
+}
+
+static void transmit_chars(struct uart_sunsu_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (up->port.x_char) {
+               serial_outp(up, UART_TX, up->port.x_char);
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_tx_stopped(&up->port)) {
+               sunsu_stop_tx(&up->port);
+               return;
+       }
+       if (uart_circ_empty(xmit)) {
+               __stop_tx(up);
+               return;
+       }
+
+       count = up->port.fifosize;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (uart_circ_empty(xmit))
+               __stop_tx(up);
+}
+
+static void check_modem_status(struct uart_sunsu_port *up)
+{
+       int status;
+
+       status = serial_in(up, UART_MSR);
+
+       if ((status & UART_MSR_ANY_DELTA) == 0)
+               return;
+
+       if (status & UART_MSR_TERI)
+               up->port.icount.rng++;
+       if (status & UART_MSR_DDSR)
+               up->port.icount.dsr++;
+       if (status & UART_MSR_DDCD)
+               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+       if (status & UART_MSR_DCTS)
+               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsu_port *up = dev_id;
+       unsigned long flags;
+       unsigned char status;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       do {
+               struct tty_struct *tty;
+
+               status = serial_inp(up, UART_LSR);
+               tty = NULL;
+               if (status & UART_LSR_DR)
+                       tty = receive_chars(up, &status);
+               check_modem_status(up);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(up);
+
+               spin_unlock_irqrestore(&up->port.lock, flags);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               spin_lock_irqsave(&up->port.lock, flags);
+
+       } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Separate interrupt handling path for keyboard/mouse ports.  */
+
+static void
+sunsu_change_speed(struct uart_port *port, unsigned int cflag,
+                  unsigned int iflag, unsigned int quot);
+
+static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
+{
+       unsigned int cur_cflag = up->cflag;
+       int quot, new_baud;
+
+       up->cflag &= ~CBAUD;
+       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
+
+       quot = up->port.uartclk / (16 * new_baud);
+
+       sunsu_change_speed(&up->port, up->cflag, 0, quot);
+}
+
+static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
+{
+       do {
+               unsigned char ch = serial_inp(up, UART_RX);
+
+               /* Stop-A is handled by drivers/char/keyboard.c now. */
+               if (up->su_type == SU_PORT_KBD) {
+#ifdef CONFIG_SERIO
+                       serio_interrupt(&up->serio, ch, 0);
+#endif
+               } else if (up->su_type == SU_PORT_MS) {
+                       int ret = suncore_mouse_baud_detection(ch, is_break);
+
+                       switch (ret) {
+                       case 2:
+                               sunsu_change_mouse_baud(up);
+                               /* fallthru */
+                       case 1:
+                               break;
+
+                       case 0:
+#ifdef CONFIG_SERIO
+                               serio_interrupt(&up->serio, ch, 0);
+#endif
+                               break;
+                       };
+               }
+       } while (serial_in(up, UART_LSR) & UART_LSR_DR);
+}
+
+static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunsu_port *up = dev_id;
+
+       if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
+               unsigned char status = serial_inp(up, UART_LSR);
+
+               if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
+                       receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int sunsu_tx_empty(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int sunsu_get_mctrl(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char status;
+       unsigned int ret;
+
+       status = serial_in(up, UART_MSR);
+
+       ret = 0;
+       if (status & UART_MSR_DCD)
+               ret |= TIOCM_CAR;
+       if (status & UART_MSR_RI)
+               ret |= TIOCM_RNG;
+       if (status & UART_MSR_DSR)
+               ret |= TIOCM_DSR;
+       if (status & UART_MSR_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       serial_out(up, UART_MCR, mcr);
+}
+
+static void sunsu_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               up->lcr |= UART_LCR_SBC;
+       else
+               up->lcr &= ~UART_LCR_SBC;
+       serial_out(up, UART_LCR, up->lcr);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int sunsu_startup(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+       int retval;
+
+       if (up->port.type == PORT_16C950) {
+               /* Wake up and initialize UART */
+               up->acr = 0;
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_IER, 0);
+               serial_outp(up, UART_LCR, 0);
+               serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, UART_EFR_ECB);
+               serial_outp(up, UART_LCR, 0);
+       }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * If this is an RSA port, see if we can kick it up to the
+        * higher speed clock.
+        */
+       enable_rsa(up);
+#endif
+
+       /*
+        * Clear the FIFO buffers and disable them.
+        * (they will be reenabled in set_termios())
+        */
+       if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+               serial_outp(up, UART_FCR, 0);
+       }
+
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       /*
+        * At this point, there's no way the LSR could still be 0xff;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (!(up->port.flags & UPF_BUGGY_UART) &&
+           (serial_inp(up, UART_LSR) == 0xff)) {
+               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+               return -ENODEV;
+       }
+
+       if (up->su_type != SU_PORT_PORT) {
+               retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt,
+                                    IRQF_SHARED, su_typev[up->su_type], up);
+       } else {
+               retval = request_irq(up->port.irq, sunsu_serial_interrupt,
+                                    IRQF_SHARED, su_typev[up->su_type], up);
+       }
+       if (retval) {
+               printk("su: Cannot register IRQ %d\n", up->port.irq);
+               return retval;
+       }
+
+       /*
+        * Now, initialize the UART
+        */
+       serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.mctrl |= TIOCM_OUT2;
+
+       sunsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        */
+       up->ier = UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(up, UART_IER, up->ier);
+
+       if (up->port.flags & UPF_FOURPORT) {
+               unsigned int icp;
+               /*
+                * Enable interrupts on the AST Fourport board
+                */
+               icp = (up->port.iobase & 0xfe0) | 0x01f;
+               outb_p(0x80, icp);
+               (void) inb_p(icp);
+       }
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void) serial_inp(up, UART_LSR);
+       (void) serial_inp(up, UART_RX);
+       (void) serial_inp(up, UART_IIR);
+       (void) serial_inp(up, UART_MSR);
+
+       return 0;
+}
+
+static void sunsu_shutdown(struct uart_port *port)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned long flags;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       serial_outp(up, UART_IER, 0);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (up->port.flags & UPF_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               inb((up->port.iobase & 0xfe0) | 0x1f);
+               up->port.mctrl |= TIOCM_OUT1;
+       } else
+               up->port.mctrl &= ~TIOCM_OUT2;
+
+       sunsu_set_mctrl(&up->port, up->port.mctrl);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+       serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                 UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       serial_outp(up, UART_FCR, 0);
+
+#ifdef CONFIG_SERIAL_8250_RSA
+       /*
+        * Reset the RSA board back to 115kbps compat mode.
+        */
+       disable_rsa(up);
+#endif
+
+       /*
+        * Read data port to reset things.
+        */
+       (void) serial_in(up, UART_RX);
+
+       free_irq(up->port.irq, up);
+}
+
+static void
+sunsu_change_speed(struct uart_port *port, unsigned int cflag,
+                  unsigned int iflag, unsigned int quot)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+       unsigned char cval, fcr = 0;
+       unsigned long flags;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               cval = 0x00;
+               break;
+       case CS6:
+               cval = 0x01;
+               break;
+       case CS7:
+               cval = 0x02;
+               break;
+       default:
+       case CS8:
+               cval = 0x03;
+               break;
+       }
+
+       if (cflag & CSTOPB)
+               cval |= 0x04;
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Work around a bug in the Oxford Semiconductor 952 rev B
+        * chip which causes it to seriously miscalculate baud rates
+        * when DLL is 0.
+        */
+       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
+           up->rev == 0x5201)
+               quot ++;
+
+       if (uart_config[up->port.type].flags & UART_USE_FIFO) {
+               if ((up->port.uartclk / quot) < (2400 * 16))
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_8250_RSA
+               else if (up->port.type == PORT_RSA)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+               else
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+       }
+       if (up->port.type == PORT_16750)
+               fcr |= UART_FCR7_64BYTE;
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       if (uart_config[up->port.type].flags & UART_STARTECH) {
+               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+       }
+       serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
+       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
+       if (up->port.type == PORT_16750)
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       serial_outp(up, UART_LCR, cval);                /* reset DLAB */
+       up->lcr = cval;                                 /* Save LCR */
+       if (up->port.type != PORT_16750) {
+               if (fcr & UART_FCR_ENABLE_FIFO) {
+                       /* emulated UARTs (Lucent Venus 167x) need two steps */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+               }
+               serial_outp(up, UART_FCR, fcr);         /* set fcr */
+       }
+
+       up->cflag = cflag;
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
+                 struct ktermios *old)
+{
+       unsigned int baud, quot;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       quot = uart_get_divisor(port, baud);
+
+       sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
+}
+
+static void sunsu_release_port(struct uart_port *port)
+{
+}
+
+static int sunsu_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sunsu_config_port(struct uart_port *port, int flags)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+       if (flags & UART_CONFIG_TYPE) {
+               /*
+                * We are supposed to call autoconfig here, but this requires
+                * splitting all the OBP probing crap from the UART probing.
+                * We'll do it when we kill sunsu.c altogether.
+                */
+               port->type = up->type_probed;   /* XXX */
+       }
+}
+
+static int
+sunsu_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static const char *
+sunsu_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops sunsu_pops = {
+       .tx_empty       = sunsu_tx_empty,
+       .set_mctrl      = sunsu_set_mctrl,
+       .get_mctrl      = sunsu_get_mctrl,
+       .stop_tx        = sunsu_stop_tx,
+       .start_tx       = sunsu_start_tx,
+       .stop_rx        = sunsu_stop_rx,
+       .enable_ms      = sunsu_enable_ms,
+       .break_ctl      = sunsu_break_ctl,
+       .startup        = sunsu_startup,
+       .shutdown       = sunsu_shutdown,
+       .set_termios    = sunsu_set_termios,
+       .type           = sunsu_type,
+       .release_port   = sunsu_release_port,
+       .request_port   = sunsu_request_port,
+       .config_port    = sunsu_config_port,
+       .verify_port    = sunsu_verify_port,
+};
+
+#define UART_NR        4
+
+static struct uart_sunsu_port sunsu_ports[UART_NR];
+
+#ifdef CONFIG_SERIO
+
+static DEFINE_SPINLOCK(sunsu_serio_lock);
+
+static int sunsu_serio_write(struct serio *serio, unsigned char ch)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+       int lsr;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+
+       do {
+               lsr = serial_in(up, UART_LSR);
+       } while (!(lsr & UART_LSR_THRE));
+
+       /* Send the character out. */
+       serial_out(up, UART_TX, ch);
+
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+
+       return 0;
+}
+
+static int sunsu_serio_open(struct serio *serio)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+       if (!up->serio_open) {
+               up->serio_open = 1;
+               ret = 0;
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+
+       return ret;
+}
+
+static void sunsu_serio_close(struct serio *serio)
+{
+       struct uart_sunsu_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunsu_serio_lock, flags);
+       up->serio_open = 0;
+       spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+}
+
+#endif /* CONFIG_SERIO */
+
+static void sunsu_autoconfig(struct uart_sunsu_port *up)
+{
+       unsigned char status1, status2, scratch, scratch2, scratch3;
+       unsigned char save_lcr, save_mcr;
+       unsigned long flags;
+
+       if (up->su_type == SU_PORT_NONE)
+               return;
+
+       up->type_probed = PORT_UNKNOWN;
+       up->port.iotype = UPIO_MEM;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       if (!(up->port.flags & UPF_BUGGY_UART)) {
+               /*
+                * Do a simple existence test first; if we fail this, there's
+                * no point trying anything else.
+                *
+                * 0x80 is used as a nonsense port to prevent against false
+                * positives due to ISA bus float.  The assumption is that
+                * 0x80 is a non-existent port; which should be safe since
+                * include/asm/io.h also makes this assumption.
+                */
+               scratch = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0);
+#ifdef __i386__
+               outb(0xff, 0x080);
+#endif
+               scratch2 = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, 0x0f);
+#ifdef __i386__
+               outb(0, 0x080);
+#endif
+               scratch3 = serial_inp(up, UART_IER);
+               serial_outp(up, UART_IER, scratch);
+               if (scratch2 != 0 || scratch3 != 0x0F)
+                       goto out;       /* We failed; there's nothing here */
+       }
+
+       save_mcr = serial_in(up, UART_MCR);
+       save_lcr = serial_in(up, UART_LCR);
+
+       /* 
+        * Check to see if a UART is really there.  Certain broken
+        * internal modems based on the Rockwell chipset fail this
+        * test, because they apparently don't implement the loopback
+        * test mode.  So this test is skipped on the COM 1 through
+        * COM 4 ports.  This *should* be safe, since no board
+        * manufacturer would be stupid enough to design a board
+        * that conflicts with COM 1-4 --- we hope!
+        */
+       if (!(up->port.flags & UPF_SKIP_TEST)) {
+               serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+               status1 = serial_inp(up, UART_MSR) & 0xF0;
+               serial_outp(up, UART_MCR, save_mcr);
+               if (status1 != 0x90)
+                       goto out;       /* We failed loopback test */
+       }
+       serial_outp(up, UART_LCR, 0xBF);        /* set up for StarTech test */
+       serial_outp(up, UART_EFR, 0);           /* EFR is the same as FCR */
+       serial_outp(up, UART_LCR, 0);
+       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(up, UART_IIR) >> 6;
+       switch (scratch) {
+               case 0:
+                       up->port.type = PORT_16450;
+                       break;
+               case 1:
+                       up->port.type = PORT_UNKNOWN;
+                       break;
+               case 2:
+                       up->port.type = PORT_16550;
+                       break;
+               case 3:
+                       up->port.type = PORT_16550A;
+                       break;
+       }
+       if (up->port.type == PORT_16550A) {
+               /* Check for Startech UART's */
+               serial_outp(up, UART_LCR, UART_LCR_DLAB);
+               if (serial_in(up, UART_EFR) == 0) {
+                       up->port.type = PORT_16650;
+               } else {
+                       serial_outp(up, UART_LCR, 0xBF);
+                       if (serial_in(up, UART_EFR) == 0)
+                               up->port.type = PORT_16650V2;
+               }
+       }
+       if (up->port.type == PORT_16550A) {
+               /* Check for TI 16750 */
+               serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+               serial_outp(up, UART_FCR,
+                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+               scratch = serial_in(up, UART_IIR) >> 5;
+               if (scratch == 7) {
+                       /*
+                        * If this is a 16750, and not a cheap UART
+                        * clone, then it should only go into 64 byte
+                        * mode if the UART_FCR7_64BYTE bit was set
+                        * while UART_LCR_DLAB was latched.
+                        */
+                       serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+                       serial_outp(up, UART_LCR, 0);
+                       serial_outp(up, UART_FCR,
+                                   UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+                       scratch = serial_in(up, UART_IIR) >> 5;
+                       if (scratch == 6)
+                               up->port.type = PORT_16750;
+               }
+               serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+       }
+       serial_outp(up, UART_LCR, save_lcr);
+       if (up->port.type == PORT_16450) {
+               scratch = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, 0xa5);
+               status1 = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, 0x5a);
+               status2 = serial_in(up, UART_SCR);
+               serial_outp(up, UART_SCR, scratch);
+
+               if ((status1 != 0xa5) || (status2 != 0x5a))
+                       up->port.type = PORT_8250;
+       }
+
+       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+       if (up->port.type == PORT_UNKNOWN)
+               goto out;
+       up->type_probed = up->port.type;        /* XXX */
+
+       /*
+        * Reset the UART.
+        */
+#ifdef CONFIG_SERIAL_8250_RSA
+       if (up->port.type == PORT_RSA)
+               serial_outp(up, UART_RSA_FRR, 0);
+#endif
+       serial_outp(up, UART_MCR, save_mcr);
+       serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+                                    UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       serial_outp(up, UART_FCR, 0);
+       (void)serial_in(up, UART_RX);
+       serial_outp(up, UART_IER, 0);
+
+out:
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver sunsu_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sunsu",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+};
+
+static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
+{
+       int quot, baud;
+#ifdef CONFIG_SERIO
+       struct serio *serio;
+#endif
+
+       if (up->su_type == SU_PORT_KBD) {
+               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
+               baud = 1200;
+       } else {
+               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
+               baud = 4800;
+       }
+       quot = up->port.uartclk / (16 * baud);
+
+       sunsu_autoconfig(up);
+       if (up->port.type == PORT_UNKNOWN)
+               return -ENODEV;
+
+       printk("%s: %s port at %llx, irq %u\n",
+              up->port.dev->of_node->full_name,
+              (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
+              (unsigned long long) up->port.mapbase,
+              up->port.irq);
+
+#ifdef CONFIG_SERIO
+       serio = &up->serio;
+       serio->port_data = up;
+
+       serio->id.type = SERIO_RS232;
+       if (up->su_type == SU_PORT_KBD) {
+               serio->id.proto = SERIO_SUNKBD;
+               strlcpy(serio->name, "sukbd", sizeof(serio->name));
+       } else {
+               serio->id.proto = SERIO_SUN;
+               serio->id.extra = 1;
+               strlcpy(serio->name, "sums", sizeof(serio->name));
+       }
+       strlcpy(serio->phys,
+               (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
+               sizeof(serio->phys));
+
+       serio->write = sunsu_serio_write;
+       serio->open = sunsu_serio_open;
+       serio->close = sunsu_serio_close;
+       serio->dev.parent = up->port.dev;
+
+       serio_register_port(serio);
+#endif
+
+       sunsu_change_speed(&up->port, up->cflag, 0, quot);
+
+       sunsu_startup(&up->port);
+       return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_SERIAL_SUNSU_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = serial_in(up, UART_LSR);
+
+               if (status & UART_LSR_BI)
+                       up->lsr_break_flag = UART_LSR_BI;
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+                       udelay(1);
+       }
+}
+
+static void sunsu_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_sunsu_port *up = (struct uart_sunsu_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ */
+static void sunsu_console_write(struct console *co, const char *s,
+                               unsigned int count)
+{
+       struct uart_sunsu_port *up = &sunsu_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       serial_out(up, UART_IER, 0);
+
+       uart_console_write(&up->port, s, count, sunsu_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+/*
+ *     Setup initial baud/bits/parity. We do two things here:
+ *     - construct a cflag setting for the first su_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+static int __init sunsu_console_setup(struct console *co, char *options)
+{
+       static struct ktermios dummy;
+       struct ktermios termios;
+       struct uart_port *port;
+
+       printk("Console: ttyS%d (SU)\n",
+              (sunsu_reg.minor - 64) + co->index);
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       port = &sunsu_ports[co->index].port;
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
+       /* Get firmware console settings.  */
+       sunserial_console_termios(co, port->dev->of_node);
+
+       memset(&termios, 0, sizeof(struct ktermios));
+       termios.c_cflag = co->cflag;
+       port->mctrl |= TIOCM_DTR;
+       port->ops->set_termios(port, &termios, &dummy);
+
+       return 0;
+}
+
+static struct console sunsu_console = {
+       .name   =       "ttyS",
+       .write  =       sunsu_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunsu_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunsu_reg,
+};
+
+/*
+ *     Register console.
+ */
+
+static inline struct console *SUNSU_CONSOLE(void)
+{
+       return &sunsu_console;
+}
+#else
+#define SUNSU_CONSOLE()                        (NULL)
+#define sunsu_serial_console_init()    do { } while (0)
+#endif
+
+static enum su_type __devinit su_get_type(struct device_node *dp)
+{
+       struct device_node *ap = of_find_node_by_path("/aliases");
+
+       if (ap) {
+               const char *keyb = of_get_property(ap, "keyboard", NULL);
+               const char *ms = of_get_property(ap, "mouse", NULL);
+
+               if (keyb) {
+                       if (dp == of_find_node_by_path(keyb))
+                               return SU_PORT_KBD;
+               }
+               if (ms) {
+                       if (dp == of_find_node_by_path(ms))
+                               return SU_PORT_MS;
+               }
+       }
+
+       return SU_PORT_PORT;
+}
+
+static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int inst;
+       struct device_node *dp = op->dev.of_node;
+       struct uart_sunsu_port *up;
+       struct resource *rp;
+       enum su_type type;
+       bool ignore_line;
+       int err;
+
+       type = su_get_type(dp);
+       if (type == SU_PORT_PORT) {
+               if (inst >= UART_NR)
+                       return -EINVAL;
+               up = &sunsu_ports[inst];
+       } else {
+               up = kzalloc(sizeof(*up), GFP_KERNEL);
+               if (!up)
+                       return -ENOMEM;
+       }
+
+       up->port.line = inst;
+
+       spin_lock_init(&up->port.lock);
+
+       up->su_type = type;
+
+       rp = &op->resource[0];
+       up->port.mapbase = rp->start;
+       up->reg_size = (rp->end - rp->start) + 1;
+       up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
+       if (!up->port.membase) {
+               if (type != SU_PORT_PORT)
+                       kfree(up);
+               return -ENOMEM;
+       }
+
+       up->port.irq = op->archdata.irqs[0];
+
+       up->port.dev = &op->dev;
+
+       up->port.type = PORT_UNKNOWN;
+       up->port.uartclk = (SU_BASE_BAUD * 16);
+
+       err = 0;
+       if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
+               err = sunsu_kbd_ms_init(up);
+               if (err) {
+                       of_iounmap(&op->resource[0],
+                                  up->port.membase, up->reg_size);
+                       kfree(up);
+                       return err;
+               }
+               dev_set_drvdata(&op->dev, up);
+
+               return 0;
+       }
+
+       up->port.flags |= UPF_BOOT_AUTOCONF;
+
+       sunsu_autoconfig(up);
+
+       err = -ENODEV;
+       if (up->port.type == PORT_UNKNOWN)
+               goto out_unmap;
+
+       up->port.ops = &sunsu_pops;
+
+       ignore_line = false;
+       if (!strcmp(dp->name, "rsc-console") ||
+           !strcmp(dp->name, "lom-console"))
+               ignore_line = true;
+
+       sunserial_console_match(SUNSU_CONSOLE(), dp,
+                               &sunsu_reg, up->port.line,
+                               ignore_line);
+       err = uart_add_one_port(&sunsu_reg, &up->port);
+       if (err)
+               goto out_unmap;
+
+       dev_set_drvdata(&op->dev, up);
+
+       inst++;
+
+       return 0;
+
+out_unmap:
+       of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+       return err;
+}
+
+static int __devexit su_remove(struct platform_device *op)
+{
+       struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
+       bool kbdms = false;
+
+       if (up->su_type == SU_PORT_MS ||
+           up->su_type == SU_PORT_KBD)
+               kbdms = true;
+
+       if (kbdms) {
+#ifdef CONFIG_SERIO
+               serio_unregister_port(&up->serio);
+#endif
+       } else if (up->port.type != PORT_UNKNOWN)
+               uart_remove_one_port(&sunsu_reg, &up->port);
+
+       if (up->port.membase)
+               of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+
+       if (kbdms)
+               kfree(up);
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id su_match[] = {
+       {
+               .name = "su",
+       },
+       {
+               .name = "su_pnp",
+       },
+       {
+               .name = "serial",
+               .compatible = "su",
+       },
+       {
+               .type = "serial",
+               .compatible = "su",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, su_match);
+
+static struct of_platform_driver su_driver = {
+       .driver = {
+               .name = "su",
+               .owner = THIS_MODULE,
+               .of_match_table = su_match,
+       },
+       .probe          = su_probe,
+       .remove         = __devexit_p(su_remove),
+};
+
+static int __init sunsu_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_uart = 0;
+
+       for_each_node_by_name(dp, "su") {
+               if (su_get_type(dp) == SU_PORT_PORT)
+                       num_uart++;
+       }
+       for_each_node_by_name(dp, "su_pnp") {
+               if (su_get_type(dp) == SU_PORT_PORT)
+                       num_uart++;
+       }
+       for_each_node_by_name(dp, "serial") {
+               if (of_device_is_compatible(dp, "su")) {
+                       if (su_get_type(dp) == SU_PORT_PORT)
+                               num_uart++;
+               }
+       }
+       for_each_node_by_type(dp, "serial") {
+               if (of_device_is_compatible(dp, "su")) {
+                       if (su_get_type(dp) == SU_PORT_PORT)
+                               num_uart++;
+               }
+       }
+
+       if (num_uart) {
+               err = sunserial_register_minors(&sunsu_reg, num_uart);
+               if (err)
+                       return err;
+       }
+
+       err = of_register_platform_driver(&su_driver);
+       if (err && num_uart)
+               sunserial_unregister_minors(&sunsu_reg, num_uart);
+
+       return err;
+}
+
+static void __exit sunsu_exit(void)
+{
+       if (sunsu_reg.nr)
+               sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
+}
+
+module_init(sunsu_init);
+module_exit(sunsu_exit);
+
+MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller");
+MODULE_DESCRIPTION("Sun SU serial port driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
new file mode 100644 (file)
index 0000000..c1967ac
--- /dev/null
@@ -0,0 +1,1655 @@
+/* sunzilog.c: Zilog serial driver for Sparc systems.
+ *
+ * Driver for Zilog serial chips found on Sun workstations and
+ * servers.  This driver could actually be made more generic.
+ *
+ * This is based on the old drivers/sbus/char/zs.c code.  A lot
+ * of code has been simply moved over directly from there but
+ * much has been rewritten.  Credits therefore go out to Eddie
+ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
+ * work there.
+ *
+ * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_SERIO
+#include <linux/serio.h>
+#endif
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+#include "sunzilog.h"
+
+/* On 32-bit sparcs we need to delay after register accesses
+ * to accommodate sun4 systems, but we do not need to flush writes.
+ * On 64-bit sparc we only need to flush single writes to ensure
+ * completion.
+ */
+#ifndef CONFIG_SPARC64
+#define ZSDELAY()              udelay(5)
+#define ZSDELAY_LONG()         udelay(20)
+#define ZS_WSYNC(channel)      do { } while (0)
+#else
+#define ZSDELAY()
+#define ZSDELAY_LONG()
+#define ZS_WSYNC(__channel) \
+       readb(&((__channel)->control))
+#endif
+
+#define ZS_CLOCK               4915200 /* Zilog input clock rate. */
+#define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_sunzilog_port {
+       struct uart_port                port;
+
+       /* IRQ servicing chain.  */
+       struct uart_sunzilog_port       *next;
+
+       /* Current values of Zilog write registers.  */
+       unsigned char                   curregs[NUM_ZSREGS];
+
+       unsigned int                    flags;
+#define SUNZILOG_FLAG_CONS_KEYB                0x00000001
+#define SUNZILOG_FLAG_CONS_MOUSE       0x00000002
+#define SUNZILOG_FLAG_IS_CONS          0x00000004
+#define SUNZILOG_FLAG_IS_KGDB          0x00000008
+#define SUNZILOG_FLAG_MODEM_STATUS     0x00000010
+#define SUNZILOG_FLAG_IS_CHANNEL_A     0x00000020
+#define SUNZILOG_FLAG_REGS_HELD                0x00000040
+#define SUNZILOG_FLAG_TX_STOPPED       0x00000080
+#define SUNZILOG_FLAG_TX_ACTIVE                0x00000100
+#define SUNZILOG_FLAG_ESCC             0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER      0x00000400
+
+       unsigned int cflag;
+
+       unsigned char                   parity_mask;
+       unsigned char                   prev_status;
+
+#ifdef CONFIG_SERIO
+       struct serio                    serio;
+       int                             serio_open;
+#endif
+};
+
+static void sunzilog_putchar(struct uart_port *port, int ch);
+
+#define ZILOG_CHANNEL_FROM_PORT(PORT)  ((struct zilog_channel __iomem *)((PORT)->membase))
+#define UART_ZILOG(PORT)               ((struct uart_sunzilog_port *)(PORT))
+
+#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
+#define ZS_IS_MOUSE(UP)        ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE)
+#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB)
+#define ZS_WANTS_MODEM_STATUS(UP)      ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_CHANNEL_A(UP)    ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)       ((UP)->flags & SUNZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)      ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)       ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE)
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ *
+ * The port lock must be held and local IRQs must be disabled
+ * when {read,write}_zsreg is invoked.
+ */
+static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
+                               unsigned char reg)
+{
+       unsigned char retval;
+
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       retval = readb(&channel->control);
+       ZSDELAY();
+
+       return retval;
+}
+
+static void write_zsreg(struct zilog_channel __iomem *channel,
+                       unsigned char reg, unsigned char value)
+{
+       writeb(reg, &channel->control);
+       ZSDELAY();
+       writeb(value, &channel->control);
+       ZSDELAY();
+}
+
+static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
+{
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               unsigned char regval;
+
+               regval = readb(&channel->control);
+               ZSDELAY();
+               if (regval & Rx_CH_AV)
+                       break;
+
+               regval = read_zsreg(channel, R1);
+               readb(&channel->data);
+               ZSDELAY();
+
+               if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+       }
+}
+
+/* This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+{
+       int i;
+       int escc;
+       unsigned char r15;
+
+       /* Let pending transmits finish.  */
+       for (i = 0; i < 1000; i++) {
+               unsigned char stat = read_zsreg(channel, R1);
+               if (stat & ALL_SNT)
+                       break;
+               udelay(100);
+       }
+
+       writeb(ERR_RES, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       sunzilog_clear_fifo(channel);
+
+       /* Disable all interrupts.  */
+       write_zsreg(channel, R1,
+                   regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+       /* Set parity, sync config, stop bits, and clock divisor.  */
+       write_zsreg(channel, R4, regs[R4]);
+
+       /* Set misc. TX/RX control bits.  */
+       write_zsreg(channel, R10, regs[R10]);
+
+       /* Set TX/RX controls sans the enable bits.  */
+       write_zsreg(channel, R3, regs[R3] & ~RxENAB);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+
+       /* Synchronous mode config.  */
+       write_zsreg(channel, R6, regs[R6]);
+       write_zsreg(channel, R7, regs[R7]);
+
+       /* Don't mess with the interrupt vector (R2, unused by us) and
+        * master interrupt control (R9).  We make sure this is setup
+        * properly at probe time then never touch it again.
+        */
+
+       /* Disable baud generator.  */
+       write_zsreg(channel, R14, regs[R14] & ~BRENAB);
+
+       /* Clock mode control.  */
+       write_zsreg(channel, R11, regs[R11]);
+
+       /* Lower and upper byte of baud rate generator divisor.  */
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+       
+       /* Now rewrite R14, with BRENAB (if set).  */
+       write_zsreg(channel, R14, regs[R14]);
+
+       /* External status interrupt control.  */
+       write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+       /* ESCC Extension Register */
+       r15 = read_zsreg(channel, R15);
+       if (r15 & 0x01) {
+               write_zsreg(channel, R7,  regs[R7p]);
+
+               /* External status interrupt and FIFO control.  */
+               write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+               escc = 1;
+       } else {
+                /* Clear FIFO bit case it is an issue */
+               regs[R15] &= ~FIFOEN;
+               escc = 0;
+       }
+
+       /* Reset external status interrupts.  */
+       write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
+       write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
+
+       /* Rewrite R3/R5, this time without enables masked.  */
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+
+       /* Rewrite R1, this time without IRQ enabled masked.  */
+       write_zsreg(channel, R1, regs[R1]);
+
+       return escc;
+}
+
+/* Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up,
+                                      struct zilog_channel __iomem *channel)
+{
+       if (!ZS_REGS_HELD(up)) {
+               if (ZS_TX_ACTIVE(up)) {
+                       up->flags |= SUNZILOG_FLAG_REGS_HELD;
+               } else {
+                       __load_zsregs(channel, up->curregs);
+               }
+       }
+}
+
+static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
+{
+       unsigned int cur_cflag = up->cflag;
+       int brg, new_baud;
+
+       up->cflag &= ~CBAUD;
+       up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
+
+       brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+       up->curregs[R12] = (brg & 0xff);
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port));
+}
+
+static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
+                                        unsigned char ch, int is_break)
+{
+       if (ZS_IS_KEYB(up)) {
+               /* Stop-A is handled by drivers/char/keyboard.c now. */
+#ifdef CONFIG_SERIO
+               if (up->serio_open)
+                       serio_interrupt(&up->serio, ch, 0);
+#endif
+       } else if (ZS_IS_MOUSE(up)) {
+               int ret = suncore_mouse_baud_detection(ch, is_break);
+
+               switch (ret) {
+               case 2:
+                       sunzilog_change_mouse_baud(up);
+                       /* fallthru */
+               case 1:
+                       break;
+
+               case 0:
+#ifdef CONFIG_SERIO
+                       if (up->serio_open)
+                               serio_interrupt(&up->serio, ch, 0);
+#endif
+                       break;
+               };
+       }
+}
+
+static struct tty_struct *
+sunzilog_receive_chars(struct uart_sunzilog_port *up,
+                      struct zilog_channel __iomem *channel)
+{
+       struct tty_struct *tty;
+       unsigned char ch, r1, flag;
+
+       tty = NULL;
+       if (up->port.state != NULL &&           /* Unopened serial console */
+           up->port.state->port.tty != NULL)   /* Keyboard || mouse */
+               tty = up->port.state->port.tty;
+
+       for (;;) {
+
+               r1 = read_zsreg(channel, R1);
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       writeb(ERR_RES, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+               }
+
+               ch = readb(&channel->control);
+               ZSDELAY();
+
+               /* This funny hack depends upon BRK_ABRT not interfering
+                * with the other bits we care about in R1.
+                */
+               if (ch & BRK_ABRT)
+                       r1 |= BRK_ABRT;
+
+               if (!(ch & Rx_CH_AV))
+                       break;
+
+               ch = readb(&channel->data);
+               ZSDELAY();
+
+               ch &= up->parity_mask;
+
+               if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
+                       sunzilog_kbdms_receive_chars(up, ch, 0);
+                       continue;
+               }
+
+               if (tty == NULL) {
+                       uart_handle_sysrq_char(&up->port, ch);
+                       continue;
+               }
+
+               /* A real serial line, record the character and status.  */
+               flag = TTY_NORMAL;
+               up->port.icount.rx++;
+               if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
+                       if (r1 & BRK_ABRT) {
+                               r1 &= ~(PAR_ERR | CRC_ERR);
+                               up->port.icount.brk++;
+                               if (uart_handle_break(&up->port))
+                                       continue;
+                       }
+                       else if (r1 & PAR_ERR)
+                               up->port.icount.parity++;
+                       else if (r1 & CRC_ERR)
+                               up->port.icount.frame++;
+                       if (r1 & Rx_OVR)
+                               up->port.icount.overrun++;
+                       r1 &= up->port.read_status_mask;
+                       if (r1 & BRK_ABRT)
+                               flag = TTY_BREAK;
+                       else if (r1 & PAR_ERR)
+                               flag = TTY_PARITY;
+                       else if (r1 & CRC_ERR)
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if (up->port.ignore_status_mask == 0xff ||
+                   (r1 & up->port.ignore_status_mask) == 0) {
+                       tty_insert_flip_char(tty, ch, flag);
+               }
+               if (r1 & Rx_OVR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       return tty;
+}
+
+static void sunzilog_status_handle(struct uart_sunzilog_port *up,
+                                  struct zilog_channel __iomem *channel)
+{
+       unsigned char status;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       writeb(RES_EXT_INT, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       if (status & BRK_ABRT) {
+               if (ZS_IS_MOUSE(up))
+                       sunzilog_kbdms_receive_chars(up, 0, 1);
+               if (ZS_IS_CONS(up)) {
+                       /* Wait for BREAK to deassert to avoid potentially
+                        * confusing the PROM.
+                        */
+                       while (1) {
+                               status = readb(&channel->control);
+                               ZSDELAY();
+                               if (!(status & BRK_ABRT))
+                                       break;
+                       }
+                       sun_do_break();
+                       return;
+               }
+       }
+
+       if (ZS_WANTS_MODEM_STATUS(up)) {
+               if (status & SYNC)
+                       up->port.icount.dsr++;
+
+               /* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+                * But it does not tell us which bit has changed, we have to keep
+                * track of this ourselves.
+                */
+               if ((status ^ up->prev_status) ^ DCD)
+                       uart_handle_dcd_change(&up->port,
+                                              (status & DCD));
+               if ((status ^ up->prev_status) ^ CTS)
+                       uart_handle_cts_change(&up->port,
+                                              (status & CTS));
+
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+       }
+
+       up->prev_status = status;
+}
+
+static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
+                                   struct zilog_channel __iomem *channel)
+{
+       struct circ_buf *xmit;
+
+       if (ZS_IS_CONS(up)) {
+               unsigned char status = readb(&channel->control);
+               ZSDELAY();
+
+               /* TX still busy?  Just wait for the next TX done interrupt.
+                *
+                * It can occur because of how we do serial console writes.  It would
+                * be nice to transmit console writes just like we normally would for
+                * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+                * easy because console writes cannot sleep.  One solution might be
+                * to poll on enough port->xmit space becomming free.  -DaveM
+                */
+               if (!(status & Tx_BUF_EMP))
+                       return;
+       }
+
+       up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE;
+
+       if (ZS_REGS_HELD(up)) {
+               __load_zsregs(channel, up->curregs);
+               up->flags &= ~SUNZILOG_FLAG_REGS_HELD;
+       }
+
+       if (ZS_TX_STOPPED(up)) {
+               up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
+               goto ack_tx_int;
+       }
+
+       if (up->port.x_char) {
+               up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+               writeb(up->port.x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+
+       if (up->port.state == NULL)
+               goto ack_tx_int;
+       xmit = &up->port.state->xmit;
+       if (uart_circ_empty(xmit))
+               goto ack_tx_int;
+
+       if (uart_tx_stopped(&up->port))
+               goto ack_tx_int;
+
+       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+       writeb(xmit->buf[xmit->tail], &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       up->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       return;
+
+ack_tx_int:
+       writeb(RES_Tx_P, &channel->control);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
+{
+       struct uart_sunzilog_port *up = dev_id;
+
+       while (up) {
+               struct zilog_channel __iomem *channel
+                       = ZILOG_CHANNEL_FROM_PORT(&up->port);
+               struct tty_struct *tty;
+               unsigned char r3;
+
+               spin_lock(&up->port.lock);
+               r3 = read_zsreg(channel, R3);
+
+               /* Channel A */
+               tty = NULL;
+               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHARxIP)
+                               tty = sunzilog_receive_chars(up, channel);
+                       if (r3 & CHAEXT)
+                               sunzilog_status_handle(up, channel);
+                       if (r3 & CHATxIP)
+                               sunzilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               /* Channel B */
+               up = up->next;
+               channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+               spin_lock(&up->port.lock);
+               tty = NULL;
+               if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+                       writeb(RES_H_IUS, &channel->control);
+                       ZSDELAY();
+                       ZS_WSYNC(channel);
+
+                       if (r3 & CHBRxIP)
+                               tty = sunzilog_receive_chars(up, channel);
+                       if (r3 & CHBEXT)
+                               sunzilog_status_handle(up, channel);
+                       if (r3 & CHBTxIP)
+                               sunzilog_transmit_chars(up, channel);
+               }
+               spin_unlock(&up->port.lock);
+
+               if (tty)
+                       tty_flip_buffer_push(tty);
+
+               up = up->next;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
+ * port lock, it is acquired here.
+ */
+static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
+{
+       struct zilog_channel __iomem *channel;
+       unsigned char status;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       return status;
+}
+
+/* The port lock is not held.  */
+static unsigned int sunzilog_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned char status;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       status = sunzilog_read_channel_status(port);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (status & Tx_BUF_EMP)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static unsigned int sunzilog_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int ret;
+
+       status = sunzilog_read_channel_status(port);
+
+       ret = 0;
+       if (status & DCD)
+               ret |= TIOCM_CAR;
+       if (status & SYNC)
+               ret |= TIOCM_DSR;
+       if (status & CTS)
+               ret |= TIOCM_CTS;
+
+       return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits;
+
+       set_bits = clear_bits = 0;
+
+       if (mctrl & TIOCM_RTS)
+               set_bits |= RTS;
+       else
+               clear_bits |= RTS;
+       if (mctrl & TIOCM_DTR)
+               set_bits |= DTR;
+       else
+               clear_bits |= DTR;
+
+       /* NOTE: Not subject to 'transmitter active' rule.  */ 
+       up->curregs[R5] |= set_bits;
+       up->curregs[R5] &= ~clear_bits;
+       write_zsreg(channel, R5, up->curregs[R5]);
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_stop_tx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+
+       up->flags |= SUNZILOG_FLAG_TX_STOPPED;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void sunzilog_start_tx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char status;
+
+       up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
+       up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
+
+       status = readb(&channel->control);
+       ZSDELAY();
+
+       /* TX busy?  Just wait for the TX done interrupt.  */
+       if (!(status & Tx_BUF_EMP))
+               return;
+
+       /* Send the first character to jump-start the TX done
+        * IRQ sending engine.
+        */
+       if (port->x_char) {
+               writeb(port->x_char, &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               port->icount.tx++;
+               port->x_char = 0;
+       } else {
+               struct circ_buf *xmit = &port->state->xmit;
+
+               writeb(xmit->buf[xmit->tail], &channel->data);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(&up->port);
+       }
+}
+
+/* The port lock is held.  */
+static void sunzilog_stop_rx(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       struct zilog_channel __iomem *channel;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable all RX interrupts.  */
+       up->curregs[R1] &= ~RxINT_MASK;
+       sunzilog_maybe_update_regs(up, channel);
+}
+
+/* The port lock is held.  */
+static void sunzilog_enable_ms(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char new_reg;
+
+       new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+       if (new_reg != up->curregs[R15]) {
+               up->curregs[R15] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
+       }
+}
+
+/* The port lock is not held.  */
+static void sunzilog_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       unsigned char set_bits, clear_bits, new_reg;
+       unsigned long flags;
+
+       set_bits = clear_bits = 0;
+
+       if (break_state)
+               set_bits |= SND_BRK;
+       else
+               clear_bits |= SND_BRK;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
+       if (new_reg != up->curregs[R5]) {
+               up->curregs[R5] = new_reg;
+
+               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               write_zsreg(channel, R5, up->curregs[R5]);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __sunzilog_startup(struct uart_sunzilog_port *up)
+{
+       struct zilog_channel __iomem *channel;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+       up->prev_status = readb(&channel->control);
+
+       /* Enable receiver and transmitter.  */
+       up->curregs[R3] |= RxENAB;
+       up->curregs[R5] |= TxENAB;
+
+       up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+       sunzilog_maybe_update_regs(up, channel);
+}
+
+static int sunzilog_startup(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       __sunzilog_startup(up);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return 0;
+}
+
+/*
+ * The test for ZS_IS_CONS is explained by the following e-mail:
+ *****
+ * From: Russell King <rmk@arm.linux.org.uk>
+ * Date: Sun, 8 Dec 2002 10:18:38 +0000
+ *
+ * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
+ * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
+ * > and I noticed that something is not right with reference
+ * > counting in this case. It seems that when the console
+ * > is open by kernel initially, this is not accounted
+ * > as an open, and uart_startup is not called.
+ *
+ * That is correct.  We are unable to call uart_startup when the serial
+ * console is initialised because it may need to allocate memory (as
+ * request_irq does) and the memory allocators may not have been
+ * initialised.
+ *
+ * 1. initialise the port into a state where it can send characters in the
+ *    console write method.
+ *
+ * 2. don't do the actual hardware shutdown in your shutdown() method (but
+ *    do the normal software shutdown - ie, free irqs etc)
+ *****
+ */
+static void sunzilog_shutdown(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+       struct zilog_channel __iomem *channel;
+       unsigned long flags;
+
+       if (ZS_IS_CONS(up))
+               return;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+       /* Disable receiver and transmitter.  */
+       up->curregs[R3] &= ~RxENAB;
+       up->curregs[R5] &= ~TxENAB;
+
+       /* Disable all interrupts and BRK assertion.  */
+       up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+       up->curregs[R5] &= ~SND_BRK;
+       sunzilog_maybe_update_regs(up, channel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void
+sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
+                      unsigned int iflag, int brg)
+{
+
+       up->curregs[R10] = NRZ;
+       up->curregs[R11] = TCBR | RCBR;
+
+       /* Program BAUD and clock source. */
+       up->curregs[R4] &= ~XCLK_MASK;
+       up->curregs[R4] |= X16CLK;
+       up->curregs[R12] = brg & 0xff;
+       up->curregs[R13] = (brg >> 8) & 0xff;
+       up->curregs[R14] = BRSRC | BRENAB;
+
+       /* Character size, stop bits, and parity. */
+       up->curregs[R3] &= ~RxN_MASK;
+       up->curregs[R5] &= ~TxN_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               up->curregs[R3] |= Rx5;
+               up->curregs[R5] |= Tx5;
+               up->parity_mask = 0x1f;
+               break;
+       case CS6:
+               up->curregs[R3] |= Rx6;
+               up->curregs[R5] |= Tx6;
+               up->parity_mask = 0x3f;
+               break;
+       case CS7:
+               up->curregs[R3] |= Rx7;
+               up->curregs[R5] |= Tx7;
+               up->parity_mask = 0x7f;
+               break;
+       case CS8:
+       default:
+               up->curregs[R3] |= Rx8;
+               up->curregs[R5] |= Tx8;
+               up->parity_mask = 0xff;
+               break;
+       };
+       up->curregs[R4] &= ~0x0c;
+       if (cflag & CSTOPB)
+               up->curregs[R4] |= SB2;
+       else
+               up->curregs[R4] |= SB1;
+       if (cflag & PARENB)
+               up->curregs[R4] |= PAR_ENAB;
+       else
+               up->curregs[R4] &= ~PAR_ENAB;
+       if (!(cflag & PARODD))
+               up->curregs[R4] |= PAR_EVEN;
+       else
+               up->curregs[R4] &= ~PAR_EVEN;
+
+       up->port.read_status_mask = Rx_OVR;
+       if (iflag & INPCK)
+               up->port.read_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= BRK_ABRT;
+
+       up->port.ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+       if (iflag & IGNBRK) {
+               up->port.ignore_status_mask |= BRK_ABRT;
+               if (iflag & IGNPAR)
+                       up->port.ignore_status_mask |= Rx_OVR;
+       }
+
+       if ((cflag & CREAD) == 0)
+               up->port.ignore_status_mask = 0xff;
+}
+
+/* The port lock is not held.  */
+static void
+sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       unsigned long flags;
+       int baud, brg;
+
+       baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
+
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
+       else
+               up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
+
+       up->cflag = termios->c_cflag;
+
+       sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *sunzilog_type(struct uart_port *port)
+{
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+       return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void sunzilog_release_port(struct uart_port *port)
+{
+}
+
+static int sunzilog_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void sunzilog_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int sunzilog_get_poll_char(struct uart_port *port)
+{
+       unsigned char ch, r1;
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
+       struct zilog_channel __iomem *channel
+               = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+
+       r1 = read_zsreg(channel, R1);
+       if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+               writeb(ERR_RES, &channel->control);
+               ZSDELAY();
+               ZS_WSYNC(channel);
+       }
+
+       ch = readb(&channel->control);
+       ZSDELAY();
+
+       /* This funny hack depends upon BRK_ABRT not interfering
+        * with the other bits we care about in R1.
+        */
+       if (ch & BRK_ABRT)
+               r1 |= BRK_ABRT;
+
+       if (!(ch & Rx_CH_AV))
+               return NO_POLL_CHAR;
+
+       ch = readb(&channel->data);
+       ZSDELAY();
+
+       ch &= up->parity_mask;
+       return ch;
+}
+
+static void sunzilog_put_poll_char(struct uart_port *port,
+                       unsigned char ch)
+{
+       struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
+
+       sunzilog_putchar(&up->port, ch);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops sunzilog_pops = {
+       .tx_empty       =       sunzilog_tx_empty,
+       .set_mctrl      =       sunzilog_set_mctrl,
+       .get_mctrl      =       sunzilog_get_mctrl,
+       .stop_tx        =       sunzilog_stop_tx,
+       .start_tx       =       sunzilog_start_tx,
+       .stop_rx        =       sunzilog_stop_rx,
+       .enable_ms      =       sunzilog_enable_ms,
+       .break_ctl      =       sunzilog_break_ctl,
+       .startup        =       sunzilog_startup,
+       .shutdown       =       sunzilog_shutdown,
+       .set_termios    =       sunzilog_set_termios,
+       .type           =       sunzilog_type,
+       .release_port   =       sunzilog_release_port,
+       .request_port   =       sunzilog_request_port,
+       .config_port    =       sunzilog_config_port,
+       .verify_port    =       sunzilog_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  =       sunzilog_get_poll_char,
+       .poll_put_char  =       sunzilog_put_poll_char,
+#endif
+};
+
+static int uart_chip_count;
+static struct uart_sunzilog_port *sunzilog_port_table;
+static struct zilog_layout __iomem **sunzilog_chip_regs;
+
+static struct uart_sunzilog_port *sunzilog_irq_chain;
+
+static struct uart_driver sunzilog_reg = {
+       .owner          =       THIS_MODULE,
+       .driver_name    =       "sunzilog",
+       .dev_name       =       "ttyS",
+       .major          =       TTY_MAJOR,
+};
+
+static int __init sunzilog_alloc_tables(int num_sunzilog)
+{
+       struct uart_sunzilog_port *up;
+       unsigned long size;
+       int num_channels = num_sunzilog * 2;
+       int i;
+
+       size = num_channels * sizeof(struct uart_sunzilog_port);
+       sunzilog_port_table = kzalloc(size, GFP_KERNEL);
+       if (!sunzilog_port_table)
+               return -ENOMEM;
+
+       for (i = 0; i < num_channels; i++) {
+               up = &sunzilog_port_table[i];
+
+               spin_lock_init(&up->port.lock);
+
+               if (i == 0)
+                       sunzilog_irq_chain = up;
+
+               if (i < num_channels - 1)
+                       up->next = up + 1;
+               else
+                       up->next = NULL;
+       }
+
+       size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
+       sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
+       if (!sunzilog_chip_regs) {
+               kfree(sunzilog_port_table);
+               sunzilog_irq_chain = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void sunzilog_free_tables(void)
+{
+       kfree(sunzilog_port_table);
+       sunzilog_irq_chain = NULL;
+       kfree(sunzilog_chip_regs);
+}
+
+#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
+
+static void sunzilog_putchar(struct uart_port *port, int ch)
+{
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+       /* This is a timed polling loop so do not switch the explicit
+        * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
+        */
+       do {
+               unsigned char val = readb(&channel->control);
+               if (val & Tx_BUF_EMP) {
+                       ZSDELAY();
+                       break;
+               }
+               udelay(5);
+       } while (--loops);
+
+       writeb(ch, &channel->data);
+       ZSDELAY();
+       ZS_WSYNC(channel);
+}
+
+#ifdef CONFIG_SERIO
+
+static DEFINE_SPINLOCK(sunzilog_serio_lock);
+
+static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+
+       sunzilog_putchar(&up->port, ch);
+
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+
+       return 0;
+}
+
+static int sunzilog_serio_open(struct serio *serio)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+       if (!up->serio_open) {
+               up->serio_open = 1;
+               ret = 0;
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+
+       return ret;
+}
+
+static void sunzilog_serio_close(struct serio *serio)
+{
+       struct uart_sunzilog_port *up = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sunzilog_serio_lock, flags);
+       up->serio_open = 0;
+       spin_unlock_irqrestore(&sunzilog_serio_lock, flags);
+}
+
+#endif /* CONFIG_SERIO */
+
+#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE
+static void
+sunzilog_console_write(struct console *con, const char *s, unsigned int count)
+{
+       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
+       unsigned long flags;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
+       uart_console_write(&up->port, s, count, sunzilog_putchar);
+       udelay(2);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init sunzilog_console_setup(struct console *con, char *options)
+{
+       struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
+       unsigned long flags;
+       int baud, brg;
+
+       if (up->port.type != PORT_SUNZILOG)
+               return -1;
+
+       printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
+              (sunzilog_reg.minor - 64) + con->index, con->index);
+
+       /* Get firmware console settings.  */
+       sunserial_console_termios(con, up->port.dev->of_node);
+
+       /* Firmware console speed is limited to 150-->38400 baud so
+        * this hackish cflag thing is OK.
+        */
+       switch (con->cflag & CBAUD) {
+       case B150: baud = 150; break;
+       case B300: baud = 300; break;
+       case B600: baud = 600; break;
+       case B1200: baud = 1200; break;
+       case B2400: baud = 2400; break;
+       case B4800: baud = 4800; break;
+       default: case B9600: baud = 9600; break;
+       case B19200: baud = 19200; break;
+       case B38400: baud = 38400; break;
+       };
+
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->curregs[R15] |= BRKIE;
+       sunzilog_convert_to_zs(up, con->cflag, 0, brg);
+
+       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+       __sunzilog_startup(up);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return 0;
+}
+
+static struct console sunzilog_console_ops = {
+       .name   =       "ttyS",
+       .write  =       sunzilog_console_write,
+       .device =       uart_console_device,
+       .setup  =       sunzilog_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sunzilog_reg,
+};
+
+static inline struct console *SUNZILOG_CONSOLE(void)
+{
+       return &sunzilog_console_ops;
+}
+
+#else
+#define SUNZILOG_CONSOLE()     (NULL)
+#endif
+
+static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
+{
+       int baud, brg;
+
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
+               up->cflag = B1200 | CS8 | CLOCAL | CREAD;
+               baud = 1200;
+       } else {
+               up->cflag = B4800 | CS8 | CLOCAL | CREAD;
+               baud = 4800;
+       }
+
+       up->curregs[R15] |= BRKIE;
+       brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+       sunzilog_convert_to_zs(up, up->cflag, 0, brg);
+       sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
+       __sunzilog_startup(up);
+}
+
+#ifdef CONFIG_SERIO
+static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
+{
+       struct serio *serio = &up->serio;
+
+       serio->port_data = up;
+
+       serio->id.type = SERIO_RS232;
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
+               serio->id.proto = SERIO_SUNKBD;
+               strlcpy(serio->name, "zskbd", sizeof(serio->name));
+       } else {
+               serio->id.proto = SERIO_SUN;
+               serio->id.extra = 1;
+               strlcpy(serio->name, "zsms", sizeof(serio->name));
+       }
+       strlcpy(serio->phys,
+               ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
+                "zs/serio0" : "zs/serio1"),
+               sizeof(serio->phys));
+
+       serio->write = sunzilog_serio_write;
+       serio->open = sunzilog_serio_open;
+       serio->close = sunzilog_serio_close;
+       serio->dev.parent = up->port.dev;
+
+       serio_register_port(serio);
+}
+#endif
+
+static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
+{
+       struct zilog_channel __iomem *channel;
+       unsigned long flags;
+       int baud, brg;
+
+       channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (ZS_IS_CHANNEL_A(up)) {
+               write_zsreg(channel, R9, FHWRES);
+               ZSDELAY_LONG();
+               (void) read_zsreg(channel, R0);
+       }
+
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE)) {
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
+               up->curregs[R7p] = 0x00;
+               sunzilog_init_kbdms(up);
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
+               write_zsreg(channel, R9, up->curregs[R9]);
+       } else {
+               /* Normal serial TTY. */
+               up->parity_mask = 0xff;
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
+               up->curregs[R10] = NRZ;
+               up->curregs[R11] = TCBR | RCBR;
+               baud = 9600;
+               brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+               up->curregs[R12] = (brg & 0xff);
+               up->curregs[R13] = (brg >> 8) & 0xff;
+               up->curregs[R14] = BRSRC | BRENAB;
+               up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+               up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+               if (__load_zsregs(channel, up->curregs)) {
+                       up->flags |= SUNZILOG_FLAG_ESCC;
+               }
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
+               write_zsreg(channel, R9, up->curregs[R9]);
+       }
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+#ifdef CONFIG_SERIO
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE))
+               sunzilog_register_serio(up);
+#endif
+}
+
+static int zilog_irq = -1;
+
+static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       static int kbm_inst, uart_inst;
+       int inst;
+       struct uart_sunzilog_port *up;
+       struct zilog_layout __iomem *rp;
+       int keyboard_mouse = 0;
+       int err;
+
+       if (of_find_property(op->dev.of_node, "keyboard", NULL))
+               keyboard_mouse = 1;
+
+       /* uarts must come before keyboards/mice */
+       if (keyboard_mouse)
+               inst = uart_chip_count + kbm_inst;
+       else
+               inst = uart_inst;
+
+       sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
+                                             sizeof(struct zilog_layout),
+                                             "zs");
+       if (!sunzilog_chip_regs[inst])
+               return -ENOMEM;
+
+       rp = sunzilog_chip_regs[inst];
+
+       if (zilog_irq == -1)
+               zilog_irq = op->archdata.irqs[0];
+
+       up = &sunzilog_port_table[inst * 2];
+
+       /* Channel A */
+       up[0].port.mapbase = op->resource[0].start + 0x00;
+       up[0].port.membase = (void __iomem *) &rp->channelA;
+       up[0].port.iotype = UPIO_MEM;
+       up[0].port.irq = op->archdata.irqs[0];
+       up[0].port.uartclk = ZS_CLOCK;
+       up[0].port.fifosize = 1;
+       up[0].port.ops = &sunzilog_pops;
+       up[0].port.type = PORT_SUNZILOG;
+       up[0].port.flags = 0;
+       up[0].port.line = (inst * 2) + 0;
+       up[0].port.dev = &op->dev;
+       up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
+       if (keyboard_mouse)
+               up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
+       sunzilog_init_hw(&up[0]);
+
+       /* Channel B */
+       up[1].port.mapbase = op->resource[0].start + 0x04;
+       up[1].port.membase = (void __iomem *) &rp->channelB;
+       up[1].port.iotype = UPIO_MEM;
+       up[1].port.irq = op->archdata.irqs[0];
+       up[1].port.uartclk = ZS_CLOCK;
+       up[1].port.fifosize = 1;
+       up[1].port.ops = &sunzilog_pops;
+       up[1].port.type = PORT_SUNZILOG;
+       up[1].port.flags = 0;
+       up[1].port.line = (inst * 2) + 1;
+       up[1].port.dev = &op->dev;
+       up[1].flags |= 0;
+       if (keyboard_mouse)
+               up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
+       sunzilog_init_hw(&up[1]);
+
+       if (!keyboard_mouse) {
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
+                                           &sunzilog_reg, up[0].port.line,
+                                           false))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
+               err = uart_add_one_port(&sunzilog_reg, &up[0].port);
+               if (err) {
+                       of_iounmap(&op->resource[0],
+                                  rp, sizeof(struct zilog_layout));
+                       return err;
+               }
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
+                                           &sunzilog_reg, up[1].port.line,
+                                           false))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
+               err = uart_add_one_port(&sunzilog_reg, &up[1].port);
+               if (err) {
+                       uart_remove_one_port(&sunzilog_reg, &up[0].port);
+                       of_iounmap(&op->resource[0],
+                                  rp, sizeof(struct zilog_layout));
+                       return err;
+               }
+               uart_inst++;
+       } else {
+               printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
+                      "is a %s\n",
+                      dev_name(&op->dev),
+                      (unsigned long long) up[0].port.mapbase,
+                      op->archdata.irqs[0], sunzilog_type(&up[0].port));
+               printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
+                      "is a %s\n",
+                      dev_name(&op->dev),
+                      (unsigned long long) up[1].port.mapbase,
+                      op->archdata.irqs[0], sunzilog_type(&up[1].port));
+               kbm_inst++;
+       }
+
+       dev_set_drvdata(&op->dev, &up[0]);
+
+       return 0;
+}
+
+static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
+{
+       if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
+#ifdef CONFIG_SERIO
+               serio_unregister_port(&up->serio);
+#endif
+       } else
+               uart_remove_one_port(&sunzilog_reg, &up->port);
+}
+
+static int __devexit zs_remove(struct platform_device *op)
+{
+       struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
+       struct zilog_layout __iomem *regs;
+
+       zs_remove_one(&up[0]);
+       zs_remove_one(&up[1]);
+
+       regs = sunzilog_chip_regs[up[0].port.line / 2];
+       of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id zs_match[] = {
+       {
+               .name = "zs",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, zs_match);
+
+static struct of_platform_driver zs_driver = {
+       .driver = {
+               .name = "zs",
+               .owner = THIS_MODULE,
+               .of_match_table = zs_match,
+       },
+       .probe          = zs_probe,
+       .remove         = __devexit_p(zs_remove),
+};
+
+static int __init sunzilog_init(void)
+{
+       struct device_node *dp;
+       int err;
+       int num_keybms = 0;
+       int num_sunzilog = 0;
+
+       for_each_node_by_name(dp, "zs") {
+               num_sunzilog++;
+               if (of_find_property(dp, "keyboard", NULL))
+                       num_keybms++;
+       }
+
+       if (num_sunzilog) {
+               err = sunzilog_alloc_tables(num_sunzilog);
+               if (err)
+                       goto out;
+
+               uart_chip_count = num_sunzilog - num_keybms;
+
+               err = sunserial_register_minors(&sunzilog_reg,
+                                               uart_chip_count * 2);
+               if (err)
+                       goto out_free_tables;
+       }
+
+       err = of_register_platform_driver(&zs_driver);
+       if (err)
+               goto out_unregister_uart;
+
+       if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
+               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
+                                 "zs", sunzilog_irq_chain);
+               if (err)
+                       goto out_unregister_driver;
+
+               /* Enable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] |= MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
+       }
+
+out:
+       return err;
+
+out_unregister_driver:
+       of_unregister_platform_driver(&zs_driver);
+
+out_unregister_uart:
+       if (num_sunzilog) {
+               sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
+               sunzilog_reg.cons = NULL;
+       }
+
+out_free_tables:
+       sunzilog_free_tables();
+       goto out;
+}
+
+static void __exit sunzilog_exit(void)
+{
+       of_unregister_platform_driver(&zs_driver);
+
+       if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+               /* Disable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] &= ~MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
+
+               free_irq(zilog_irq, sunzilog_irq_chain);
+               zilog_irq = -1;
+       }
+
+       if (sunzilog_reg.nr) {
+               sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
+               sunzilog_free_tables();
+       }
+}
+
+module_init(sunzilog_init);
+module_exit(sunzilog_exit);
+
+MODULE_AUTHOR("David S. Miller");
+MODULE_DESCRIPTION("Sun Zilog serial port driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sunzilog.h b/drivers/tty/serial/sunzilog.h
new file mode 100644 (file)
index 0000000..5dec7b4
--- /dev/null
@@ -0,0 +1,289 @@
+#ifndef _SUNZILOG_H
+#define _SUNZILOG_H
+
+struct zilog_channel {
+       volatile unsigned char control;
+       volatile unsigned char __pad1;
+       volatile unsigned char data;
+       volatile unsigned char __pad2;
+};
+
+struct zilog_layout {
+       struct zilog_channel channelB;
+       struct zilog_channel channelA;
+};
+
+#define        NUM_ZSREGS      17
+#define        R7p             16 /* Written as R7 with P15 bit 0 set */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENAB          0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxN_MASK       0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENAB        0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxN_MASK       0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 7' (ESCC Only) */
+#define        AUTO_TxFLAG     1       /* Automatic Tx SDLC Flag */
+#define        AUTO_EOM_RST    2       /* Automatic EOM Reset */
+#define        AUTOnRTS        4       /* Automatic /RTS pin deactivation */
+#define        RxFIFO_LVL      8       /* Receive FIFO interrupt level */
+#define        nDTRnREQ        0x10    /* /DTR/REQ timing */
+#define        TxFIFO_LVL      0x20    /* Transmit FIFO interrupt level */
+#define        EXT_RD_EN       0x40    /* Extended read register enable */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENAB  1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        WR7pEN  1       /* WR7' Enable (ESCC only) */
+#define        ZCIE    2       /* Zero count IE */
+#define        FIFOEN  4       /* FIFO Enable (ESCC only) */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC            0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        CRC_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY   0x00
+#define CHB_EXT_STAT   0x02
+#define CHB_Rx_AVAIL   0x04
+#define CHB_SPECIAL    0x06
+#define CHA_Tx_EMPTY   0x08
+#define CHA_EXT_STAT   0x0a
+#define CHA_Rx_AVAIL   0x0c
+#define CHA_SPECIAL    0x0e
+#define STATUS_MASK    0x0e
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    do { sbus_writeb(ERR_RES, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { sbus_writeb(RES_EXT_INT, &channel->control); \
+                                    udelay(5); } while(0)
+
+#define ZS_CLEARFIFO(channel)   do { sbus_readb(&channel->data); \
+                                    udelay(2); \
+                                    sbus_readb(&channel->data); \
+                                    udelay(2); \
+                                    sbus_readb(&channel->data); \
+                                    udelay(2); } while(0)
+
+#endif /* _SUNZILOG_H */
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
new file mode 100644 (file)
index 0000000..1f36b7e
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * timbuart.c timberdale FPGA UART driver
+ * Copyright (c) 2009 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include "timbuart.h"
+
+struct timbuart_port {
+       struct uart_port        port;
+       struct tasklet_struct   tasklet;
+       int                     usedma;
+       u32                     last_ier;
+       struct platform_device  *dev;
+};
+
+static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
+       921600, 1843200, 3250000};
+
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
+
+static void timbuart_stop_rx(struct uart_port *port)
+{
+       /* spin lock held by upper layer, disable all RX interrupts */
+       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
+       iowrite32(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_stop_tx(struct uart_port *port)
+{
+       /* spinlock held by upper layer, disable TX interrupt */
+       u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
+       iowrite32(ier, port->membase + TIMBUART_IER);
+}
+
+static void timbuart_start_tx(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       /* do not transfer anything here -> fire off the tasklet */
+       tasklet_schedule(&uart->tasklet);
+}
+
+static unsigned int timbuart_tx_empty(struct uart_port *port)
+{
+       u32 isr = ioread32(port->membase + TIMBUART_ISR);
+
+       return (isr & TXBE) ? TIOCSER_TEMT : 0;
+}
+
+static void timbuart_flush_buffer(struct uart_port *port)
+{
+       if (!timbuart_tx_empty(port)) {
+               u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
+                       TIMBUART_CTRL_FLSHTX;
+
+               iowrite8(ctl, port->membase + TIMBUART_CTRL);
+               iowrite32(TXBF, port->membase + TIMBUART_ISR);
+       }
+}
+
+static void timbuart_rx_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = port->state->port.tty;
+
+       while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
+               u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
+               port->icount.rx++;
+               tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->state->port.tty);
+       spin_lock(&port->lock);
+
+       dev_dbg(port->dev, "%s - total read %d bytes\n",
+               __func__, port->icount.rx);
+}
+
+static void timbuart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
+               !uart_circ_empty(xmit)) {
+               iowrite8(xmit->buf[xmit->tail],
+                       port->membase + TIMBUART_TXFIFO);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       dev_dbg(port->dev,
+               "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
+                __func__,
+               port->icount.tx,
+               ioread8(port->membase + TIMBUART_CTRL),
+               port->mctrl & TIOCM_RTS,
+               ioread8(port->membase + TIMBUART_BAUDRATE));
+}
+
+static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+
+       if (port->x_char)
+               return;
+
+       if (isr & TXFLAGS) {
+               timbuart_tx_chars(port);
+               /* clear all TX interrupts */
+               iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
+
+               if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+                       uart_write_wakeup(port);
+       } else
+               /* Re-enable any tx interrupt */
+               *ier |= uart->last_ier & TXFLAGS;
+
+       /* enable interrupts if there are chars in the transmit buffer,
+        * Or if we delivered some bytes and want the almost empty interrupt
+        * we wake up the upper layer later when we got the interrupt
+        * to give it some time to go out...
+        */
+       if (!uart_circ_empty(xmit))
+               *ier |= TXBAE;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
+{
+       if (isr & RXFLAGS) {
+               /* Some RX status is set */
+               if (isr & RXBF) {
+                       u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
+                               TIMBUART_CTRL_FLSHRX;
+                       iowrite8(ctl, port->membase + TIMBUART_CTRL);
+                       port->icount.overrun++;
+               } else if (isr & (RXDP))
+                       timbuart_rx_chars(port);
+
+               /* ack all RX interrupts */
+               iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
+       }
+
+       /* always have the RX interrupts enabled */
+       *ier |= RXBAF | RXBF | RXTT;
+
+       dev_dbg(port->dev, "%s - leaving\n", __func__);
+}
+
+void timbuart_tasklet(unsigned long arg)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)arg;
+       u32 isr, ier = 0;
+
+       spin_lock(&uart->port.lock);
+
+       isr = ioread32(uart->port.membase + TIMBUART_ISR);
+       dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
+
+       if (!uart->usedma)
+               timbuart_handle_tx_port(&uart->port, isr, &ier);
+
+       timbuart_mctrl_check(&uart->port, isr, &ier);
+
+       if (!uart->usedma)
+               timbuart_handle_rx_port(&uart->port, isr, &ier);
+
+       iowrite32(ier, uart->port.membase + TIMBUART_IER);
+
+       spin_unlock(&uart->port.lock);
+       dev_dbg(uart->port.dev, "%s leaving\n", __func__);
+}
+
+static unsigned int timbuart_get_mctrl(struct uart_port *port)
+{
+       u8 cts = ioread8(port->membase + TIMBUART_CTRL);
+       dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
+
+       if (cts & TIMBUART_CTRL_CTS)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
+
+       if (mctrl & TIOCM_RTS)
+               iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
+       else
+               iowrite8(0, port->membase + TIMBUART_CTRL);
+}
+
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
+{
+       unsigned int cts;
+
+       if (isr & CTS_DELTA) {
+               /* ack */
+               iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
+               cts = timbuart_get_mctrl(port);
+               uart_handle_cts_change(port, cts & TIOCM_CTS);
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+       }
+
+       *ier |= CTS_DELTA;
+}
+
+static void timbuart_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void timbuart_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static int timbuart_startup(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+
+       dev_dbg(port->dev, "%s\n", __func__);
+
+       iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
+       iowrite32(0x1ff, port->membase + TIMBUART_ISR);
+       /* Enable all but TX interrupts */
+       iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
+               port->membase + TIMBUART_IER);
+
+       return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
+               "timb-uart", uart);
+}
+
+static void timbuart_shutdown(struct uart_port *port)
+{
+       struct timbuart_port *uart =
+               container_of(port, struct timbuart_port, port);
+       dev_dbg(port->dev, "%s\n", __func__);
+       free_irq(port->irq, uart);
+       iowrite32(0, port->membase + TIMBUART_IER);
+}
+
+static int get_bindex(int baud)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(baudrates); i++)
+               if (baud <= baudrates[i])
+                       return i;
+
+       return -1;
+}
+
+static void timbuart_set_termios(struct uart_port *port,
+       struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned int baud;
+       short bindex;
+       unsigned long flags;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       bindex = get_bindex(baud);
+       dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
+
+       if (bindex < 0)
+               bindex = 0;
+       baud = baudrates[bindex];
+
+       /* The serial layer calls into this once with old = NULL when setting
+          up initially */
+       if (old)
+               tty_termios_copy_hw(termios, old);
+       tty_termios_encode_baud_rate(termios, baud, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+       iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
+       uart_update_timeout(port, termios->c_cflag, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *timbuart_type(struct uart_port *port)
+{
+       return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
+}
+
+/* We do not request/release mappings of the registers here,
+ * currently it's done in the proble function.
+ */
+static void timbuart_release_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       release_mem_region(port->mapbase, size);
+}
+
+static int timbuart_request_port(struct uart_port *port)
+{
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size =
+               resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
+
+       if (!request_mem_region(port->mapbase, size, "timb-uart"))
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
+{
+       struct timbuart_port *uart = (struct timbuart_port *)devid;
+
+       if (ioread8(uart->port.membase + TIMBUART_IPR)) {
+               uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
+
+               /* disable interrupts, the tasklet enables them again */
+               iowrite32(0, uart->port.membase + TIMBUART_IER);
+
+               /* fire off bottom half */
+               tasklet_schedule(&uart->tasklet);
+
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void timbuart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_TIMBUART;
+               timbuart_request_port(port);
+       }
+}
+
+static int timbuart_verify_port(struct uart_port *port,
+       struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+static struct uart_ops timbuart_ops = {
+       .tx_empty = timbuart_tx_empty,
+       .set_mctrl = timbuart_set_mctrl,
+       .get_mctrl = timbuart_get_mctrl,
+       .stop_tx = timbuart_stop_tx,
+       .start_tx = timbuart_start_tx,
+       .flush_buffer = timbuart_flush_buffer,
+       .stop_rx = timbuart_stop_rx,
+       .enable_ms = timbuart_enable_ms,
+       .break_ctl = timbuart_break_ctl,
+       .startup = timbuart_startup,
+       .shutdown = timbuart_shutdown,
+       .set_termios = timbuart_set_termios,
+       .type = timbuart_type,
+       .release_port = timbuart_release_port,
+       .request_port = timbuart_request_port,
+       .config_port = timbuart_config_port,
+       .verify_port = timbuart_verify_port
+};
+
+static struct uart_driver timbuart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = "timberdale_uart",
+       .dev_name = "ttyTU",
+       .major = TIMBUART_MAJOR,
+       .minor = TIMBUART_MINOR,
+       .nr = 1
+};
+
+static int __devinit timbuart_probe(struct platform_device *dev)
+{
+       int err, irq;
+       struct timbuart_port *uart;
+       struct resource *iomem;
+
+       dev_dbg(&dev->dev, "%s\n", __func__);
+
+       uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+       if (!uart) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+
+       uart->usedma = 0;
+
+       uart->port.uartclk = 3250000 * 16;
+       uart->port.fifosize  = TIMBUART_FIFO_SIZE;
+       uart->port.regshift  = 2;
+       uart->port.iotype  = UPIO_MEM;
+       uart->port.ops = &timbuart_ops;
+       uart->port.irq = 0;
+       uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+       uart->port.line  = 0;
+       uart->port.dev  = &dev->dev;
+
+       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               err = -ENOMEM;
+               goto err_register;
+       }
+       uart->port.mapbase = iomem->start;
+       uart->port.membase = NULL;
+
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               err = -EINVAL;
+               goto err_register;
+       }
+       uart->port.irq = irq;
+
+       tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
+
+       err = uart_register_driver(&timbuart_driver);
+       if (err)
+               goto err_register;
+
+       err = uart_add_one_port(&timbuart_driver, &uart->port);
+       if (err)
+               goto err_add_port;
+
+       platform_set_drvdata(dev, uart);
+
+       return 0;
+
+err_add_port:
+       uart_unregister_driver(&timbuart_driver);
+err_register:
+       kfree(uart);
+err_mem:
+       printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
+               err);
+
+       return err;
+}
+
+static int __devexit timbuart_remove(struct platform_device *dev)
+{
+       struct timbuart_port *uart = platform_get_drvdata(dev);
+
+       tasklet_kill(&uart->tasklet);
+       uart_remove_one_port(&timbuart_driver, &uart->port);
+       uart_unregister_driver(&timbuart_driver);
+       kfree(uart);
+
+       return 0;
+}
+
+static struct platform_driver timbuart_platform_driver = {
+       .driver = {
+               .name   = "timb-uart",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = timbuart_probe,
+       .remove         = __devexit_p(timbuart_remove),
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init timbuart_init(void)
+{
+       return platform_driver_register(&timbuart_platform_driver);
+}
+
+static void __exit timbuart_exit(void)
+{
+       platform_driver_unregister(&timbuart_platform_driver);
+}
+
+module_init(timbuart_init);
+module_exit(timbuart_exit);
+
+MODULE_DESCRIPTION("Timberdale UART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:timb-uart");
+
diff --git a/drivers/tty/serial/timbuart.h b/drivers/tty/serial/timbuart.h
new file mode 100644 (file)
index 0000000..7e56676
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * timbuart.c timberdale FPGA GPIO driver
+ * Copyright (c) 2009 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA UART
+ */
+
+#ifndef _TIMBUART_H
+#define _TIMBUART_H
+
+#define TIMBUART_FIFO_SIZE     2048
+
+#define TIMBUART_RXFIFO                0x08
+#define TIMBUART_TXFIFO                0x0c
+#define TIMBUART_IER           0x10
+#define TIMBUART_IPR           0x14
+#define TIMBUART_ISR           0x18
+#define TIMBUART_CTRL          0x1c
+#define TIMBUART_BAUDRATE      0x20
+
+#define TIMBUART_CTRL_RTS      0x01
+#define TIMBUART_CTRL_CTS      0x02
+#define TIMBUART_CTRL_FLSHTX   0x40
+#define TIMBUART_CTRL_FLSHRX   0x80
+
+#define TXBF           0x01
+#define TXBAE          0x02
+#define CTS_DELTA      0x04
+#define RXDP           0x08
+#define RXBAF          0x10
+#define RXBF           0x20
+#define RXTT           0x40
+#define RXBNAE         0x80
+#define TXBE           0x100
+
+#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
+#define TXFLAGS (TXBF | TXBAE)
+
+#define TIMBUART_MAJOR 204
+#define TIMBUART_MINOR 192
+
+#endif /* _TIMBUART_H */
+
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
new file mode 100644 (file)
index 0000000..d2fce86
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+/* Match table for of_platform binding */
+static struct of_device_id ulite_of_match[] __devinitdata = {
+       { .compatible = "xlnx,opb-uartlite-1.00.b", },
+       { .compatible = "xlnx,xps-uartlite-1.00.a", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
+#endif
+
+#define ULITE_NAME             "ttyUL"
+#define ULITE_MAJOR            204
+#define ULITE_MINOR            187
+#define ULITE_NR_UARTS         4
+
+/* ---------------------------------------------------------------------
+ * Register definitions
+ *
+ * For register details see datasheet:
+ * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf 
+ */
+
+#define ULITE_RX               0x00
+#define ULITE_TX               0x04
+#define ULITE_STATUS           0x08
+#define ULITE_CONTROL          0x0c
+
+#define ULITE_REGION           16
+
+#define ULITE_STATUS_RXVALID   0x01
+#define ULITE_STATUS_RXFULL    0x02
+#define ULITE_STATUS_TXEMPTY   0x04
+#define ULITE_STATUS_TXFULL    0x08
+#define ULITE_STATUS_IE                0x10
+#define ULITE_STATUS_OVERRUN   0x20
+#define ULITE_STATUS_FRAME     0x40
+#define ULITE_STATUS_PARITY    0x80
+
+#define ULITE_CONTROL_RST_TX   0x01
+#define ULITE_CONTROL_RST_RX   0x02
+#define ULITE_CONTROL_IE       0x10
+
+
+static struct uart_port ulite_ports[ULITE_NR_UARTS];
+
+/* ---------------------------------------------------------------------
+ * Core UART driver operations
+ */
+
+static int ulite_receive(struct uart_port *port, int stat)
+{
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned char ch = 0;
+       char flag = TTY_NORMAL;
+
+       if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+                    | ULITE_STATUS_FRAME)) == 0)
+               return 0;
+
+       /* stats */
+       if (stat & ULITE_STATUS_RXVALID) {
+               port->icount.rx++;
+               ch = ioread32be(port->membase + ULITE_RX);
+
+               if (stat & ULITE_STATUS_PARITY)
+                       port->icount.parity++;
+       }
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               port->icount.overrun++;
+
+       if (stat & ULITE_STATUS_FRAME)
+               port->icount.frame++;
+
+
+       /* drop byte with parity error if IGNPAR specificed */
+       if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+               stat &= ~ULITE_STATUS_RXVALID;
+
+       stat &= port->read_status_mask;
+
+       if (stat & ULITE_STATUS_PARITY)
+               flag = TTY_PARITY;
+
+
+       stat &= ~port->ignore_status_mask;
+
+       if (stat & ULITE_STATUS_RXVALID)
+               tty_insert_flip_char(tty, ch, flag);
+
+       if (stat & ULITE_STATUS_FRAME)
+               tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+       return 1;
+}
+
+static int ulite_transmit(struct uart_port *port, int stat)
+{
+       struct circ_buf *xmit  = &port->state->xmit;
+
+       if (stat & ULITE_STATUS_TXFULL)
+               return 0;
+
+       if (port->x_char) {
+               iowrite32be(port->x_char, port->membase + ULITE_TX);
+               port->x_char = 0;
+               port->icount.tx++;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return 0;
+
+       iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+       port->icount.tx++;
+
+       /* wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       return 1;
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       int busy, n = 0;
+
+       do {
+               int stat = ioread32be(port->membase + ULITE_STATUS);
+               busy  = ulite_receive(port, stat);
+               busy |= ulite_transmit(port, stat);
+               n++;
+       } while (busy);
+
+       /* work done? */
+       if (n > 1) {
+               tty_flip_buffer_push(port->state->port.tty);
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ret = ioread32be(port->membase + ULITE_STATUS);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+       ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+       /* don't forward any more data (like !CREAD) */
+       port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+               | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+       /* N/A */
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+       int ret;
+
+       ret = request_irq(port->irq, ulite_isr,
+                         IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port);
+       if (ret)
+               return ret;
+
+       iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+              port->membase + ULITE_CONTROL);
+       iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+       return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+       iowrite32be(0, port->membase + ULITE_CONTROL);
+       ioread32be(port->membase + ULITE_CONTROL); /* dummy */
+       free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+               | ULITE_STATUS_TXFULL;
+
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |=
+                       ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |=
+                       ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* update timeout */
+       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+       return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, ULITE_REGION);
+       iounmap(port->membase);
+       port->membase = NULL;
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+       pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
+                port, (unsigned long long) port->mapbase);
+
+       if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
+               dev_err(port->dev, "Memory region busy\n");
+               return -EBUSY;
+       }
+
+       port->membase = ioremap(port->mapbase, ULITE_REGION);
+       if (!port->membase) {
+               dev_err(port->dev, "Unable to map registers\n");
+               release_mem_region(port->mapbase, ULITE_REGION);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+       if (!ulite_request_port(port))
+               port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       /* we don't want the core code to modify any port params */
+       return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int ulite_get_poll_char(struct uart_port *port)
+{
+       if (!(ioread32be(port->membase + ULITE_STATUS)
+                                               & ULITE_STATUS_RXVALID))
+               return NO_POLL_CHAR;
+
+       return ioread32be(port->membase + ULITE_RX);
+}
+
+static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
+{
+       while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
+               cpu_relax();
+
+       /* write char to device */
+       iowrite32be(ch, port->membase + ULITE_TX);
+}
+#endif
+
+static struct uart_ops ulite_ops = {
+       .tx_empty       = ulite_tx_empty,
+       .set_mctrl      = ulite_set_mctrl,
+       .get_mctrl      = ulite_get_mctrl,
+       .stop_tx        = ulite_stop_tx,
+       .start_tx       = ulite_start_tx,
+       .stop_rx        = ulite_stop_rx,
+       .enable_ms      = ulite_enable_ms,
+       .break_ctl      = ulite_break_ctl,
+       .startup        = ulite_startup,
+       .shutdown       = ulite_shutdown,
+       .set_termios    = ulite_set_termios,
+       .type           = ulite_type,
+       .release_port   = ulite_release_port,
+       .request_port   = ulite_request_port,
+       .config_port    = ulite_config_port,
+       .verify_port    = ulite_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = ulite_get_poll_char,
+       .poll_put_char  = ulite_put_poll_char,
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * Console driver operations
+ */
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+       int i;
+       u8 val;
+
+       /* Spin waiting for TX fifo to have space available */
+       for (i = 0; i < 100000; i++) {
+               val = ioread32be(port->membase + ULITE_STATUS);
+               if ((val & ULITE_STATUS_TXFULL) == 0)
+                       break;
+               cpu_relax();
+       }
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+       ulite_console_wait_tx(port);
+       iowrite32be(ch, port->membase + ULITE_TX);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+                               unsigned int count)
+{
+       struct uart_port *port = &ulite_ports[co->index];
+       unsigned long flags;
+       unsigned int ier;
+       int locked = 1;
+
+       if (oops_in_progress) {
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       } else
+               spin_lock_irqsave(&port->lock, flags);
+
+       /* save and disable interrupt */
+       ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
+       iowrite32be(0, port->membase + ULITE_CONTROL);
+
+       uart_console_write(port, s, count, ulite_console_putchar);
+
+       ulite_console_wait_tx(port);
+
+       /* restore interrupt state */
+       if (ier)
+               iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+       if (locked)
+               spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __devinit ulite_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= ULITE_NR_UARTS)
+               return -EINVAL;
+
+       port = &ulite_ports[co->index];
+
+       /* Has the device been initialized yet? */
+       if (!port->mapbase) {
+               pr_debug("console on ttyUL%i not present\n", co->index);
+               return -ENODEV;
+       }
+
+       /* not initialized yet? */
+       if (!port->membase) {
+               if (ulite_request_port(port))
+                       return -ENODEV;
+       }
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+       .name   = ULITE_NAME,
+       .write  = ulite_console_write,
+       .device = uart_console_device,
+       .setup  = ulite_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
+       .data   = &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+       register_console(&ulite_console);
+       return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "uartlite",
+       .dev_name       = ULITE_NAME,
+       .major          = ULITE_MAJOR,
+       .minor          = ULITE_MINOR,
+       .nr             = ULITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+       .cons           = &ulite_console,
+#endif
+};
+
+/* ---------------------------------------------------------------------
+ * Port assignment functions (mapping devices to uart_port structures)
+ */
+
+/** ulite_assign: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ * @id: requested id number.  Pass -1 for automatic port assignment
+ * @base: base address of uartlite registers
+ * @irq: irq number for uartlite
+ *
+ * Returns: 0 on success, <0 otherwise
+ */
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
+{
+       struct uart_port *port;
+       int rc;
+
+       /* if id = -1; then scan for a free id and use that */
+       if (id < 0) {
+               for (id = 0; id < ULITE_NR_UARTS; id++)
+                       if (ulite_ports[id].mapbase == 0)
+                               break;
+       }
+       if (id < 0 || id >= ULITE_NR_UARTS) {
+               dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
+               return -EINVAL;
+       }
+
+       if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
+               dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+                       ULITE_NAME, id);
+               return -EBUSY;
+       }
+
+       port = &ulite_ports[id];
+
+       spin_lock_init(&port->lock);
+       port->fifosize = 16;
+       port->regshift = 2;
+       port->iotype = UPIO_MEM;
+       port->iobase = 1; /* mark port in use */
+       port->mapbase = base;
+       port->membase = NULL;
+       port->ops = &ulite_ops;
+       port->irq = irq;
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = dev;
+       port->type = PORT_UNKNOWN;
+       port->line = id;
+
+       dev_set_drvdata(dev, port);
+
+       /* Register the port */
+       rc = uart_add_one_port(&ulite_uart_driver, port);
+       if (rc) {
+               dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+               port->mapbase = 0;
+               dev_set_drvdata(dev, NULL);
+               return rc;
+       }
+
+       return 0;
+}
+
+/** ulite_release: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ */
+static int __devexit ulite_release(struct device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(dev);
+       int rc = 0;
+
+       if (port) {
+               rc = uart_remove_one_port(&ulite_uart_driver, port);
+               dev_set_drvdata(dev, NULL);
+               port->mapbase = 0;
+       }
+
+       return rc;
+}
+
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+       struct resource *res, *res2;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res2)
+               return -ENODEV;
+
+       return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
+}
+
+static int __devexit ulite_remove(struct platform_device *pdev)
+{
+       return ulite_release(&pdev->dev);
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:uartlite");
+
+static struct platform_driver ulite_platform_driver = {
+       .probe  = ulite_probe,
+       .remove = __devexit_p(ulite_remove),
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name  = "uartlite",
+                  },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus bindings
+ */
+#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
+static int __devinit
+ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
+{
+       struct resource res;
+       const unsigned int *id;
+       int irq, rc;
+
+       dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
+
+       rc = of_address_to_resource(op->dev.of_node, 0, &res);
+       if (rc) {
+               dev_err(&op->dev, "invalid address\n");
+               return rc;
+       }
+
+       irq = irq_of_parse_and_map(op->dev.of_node, 0);
+
+       id = of_get_property(op->dev.of_node, "port-number", NULL);
+
+       return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
+}
+
+static int __devexit ulite_of_remove(struct platform_device *op)
+{
+       return ulite_release(&op->dev);
+}
+
+static struct of_platform_driver ulite_of_driver = {
+       .probe = ulite_of_probe,
+       .remove = __devexit_p(ulite_of_remove),
+       .driver = {
+               .name = "uartlite",
+               .owner = THIS_MODULE,
+               .of_match_table = ulite_of_match,
+       },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ulite_of_register(void)
+{
+       pr_debug("uartlite: calling of_register_platform_driver()\n");
+       return of_register_platform_driver(&ulite_of_driver);
+}
+
+static inline void __exit ulite_of_unregister(void)
+{
+       of_unregister_platform_driver(&ulite_of_driver);
+}
+#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
+/* Appropriate config not enabled; do nothing helpers */
+static inline int __init ulite_of_register(void) { return 0; }
+static inline void __exit ulite_of_unregister(void) { }
+#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */
+
+/* ---------------------------------------------------------------------
+ * Module setup/teardown
+ */
+
+int __init ulite_init(void)
+{
+       int ret;
+
+       pr_debug("uartlite: calling uart_register_driver()\n");
+       ret = uart_register_driver(&ulite_uart_driver);
+       if (ret)
+               goto err_uart;
+
+       ret = ulite_of_register();
+       if (ret)
+               goto err_of;
+
+       pr_debug("uartlite: calling platform_driver_register()\n");
+       ret = platform_driver_register(&ulite_platform_driver);
+       if (ret)
+               goto err_plat;
+
+       return 0;
+
+err_plat:
+       ulite_of_unregister();
+err_of:
+       uart_unregister_driver(&ulite_uart_driver);
+err_uart:
+       printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
+       return ret;
+}
+
+void __exit ulite_exit(void)
+{
+       platform_driver_unregister(&ulite_platform_driver);
+       ulite_of_unregister();
+       uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
new file mode 100644 (file)
index 0000000..3f4848e
--- /dev/null
@@ -0,0 +1,1537 @@
+/*
+ * Freescale QUICC Engine UART device driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * This driver adds support for UART devices via Freescale's QUICC Engine
+ * found on some Freescale SOCs.
+ *
+ * If Soft-UART support is needed but not already present, then this driver
+ * will request and upload the "Soft-UART" microcode upon probe.  The
+ * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X"
+ * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC,
+ * (e.g. "11" for 1.1).
+ */
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/fs_uart_pd.h>
+#include <asm/ucc_slow.h>
+
+#include <linux/firmware.h>
+#include <asm/reg.h>
+
+/*
+ * The GUMR flag for Soft UART.  This would normally be defined in qe.h,
+ * but Soft-UART is a hack and we want to keep everything related to it in
+ * this file.
+ */
+#define UCC_SLOW_GUMR_H_SUART          0x00004000      /* Soft-UART */
+
+/*
+ * soft_uart is 1 if we need to use Soft-UART mode
+ */
+static int soft_uart;
+/*
+ * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise.
+ */
+static int firmware_loaded;
+
+/* Enable this macro to configure all serial ports in internal loopback
+   mode */
+/* #define LOOPBACK */
+
+/* The major and minor device numbers are defined in
+ * http://www.lanana.org/docs/device-list/devices-2.6+.txt.  For the QE
+ * UART, we have major number 204 and minor numbers 46 - 49, which are the
+ * same as for the CPM2.  This decision was made because no Freescale part
+ * has both a CPM and a QE.
+ */
+#define SERIAL_QE_MAJOR 204
+#define SERIAL_QE_MINOR 46
+
+/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */
+#define UCC_MAX_UART    4
+
+/* The number of buffer descriptors for receiving characters. */
+#define RX_NUM_FIFO     4
+
+/* The number of buffer descriptors for transmitting characters. */
+#define TX_NUM_FIFO     4
+
+/* The maximum size of the character buffer for a single RX BD. */
+#define RX_BUF_SIZE     32
+
+/* The maximum size of the character buffer for a single TX BD. */
+#define TX_BUF_SIZE     32
+
+/*
+ * The number of jiffies to wait after receiving a close command before the
+ * device is actually closed.  This allows the last few characters to be
+ * sent over the wire.
+ */
+#define UCC_WAIT_CLOSING 100
+
+struct ucc_uart_pram {
+       struct ucc_slow_pram common;
+       u8 res1[8];             /* reserved */
+       __be16 maxidl;          /* Maximum idle chars */
+       __be16 idlc;            /* temp idle counter */
+       __be16 brkcr;           /* Break count register */
+       __be16 parec;           /* receive parity error counter */
+       __be16 frmec;           /* receive framing error counter */
+       __be16 nosec;           /* receive noise counter */
+       __be16 brkec;           /* receive break condition counter */
+       __be16 brkln;           /* last received break length */
+       __be16 uaddr[2];        /* UART address character 1 & 2 */
+       __be16 rtemp;           /* Temp storage */
+       __be16 toseq;           /* Transmit out of sequence char */
+       __be16 cchars[8];       /* control characters 1-8 */
+       __be16 rccm;            /* receive control character mask */
+       __be16 rccr;            /* receive control character register */
+       __be16 rlbc;            /* receive last break character */
+       __be16 res2;            /* reserved */
+       __be32 res3;            /* reserved, should be cleared */
+       u8 res4;                /* reserved, should be cleared */
+       u8 res5[3];             /* reserved, should be cleared */
+       __be32 res6;            /* reserved, should be cleared */
+       __be32 res7;            /* reserved, should be cleared */
+       __be32 res8;            /* reserved, should be cleared */
+       __be32 res9;            /* reserved, should be cleared */
+       __be32 res10;           /* reserved, should be cleared */
+       __be32 res11;           /* reserved, should be cleared */
+       __be32 res12;           /* reserved, should be cleared */
+       __be32 res13;           /* reserved, should be cleared */
+/* The rest is for Soft-UART only */
+       __be16 supsmr;          /* 0x90, Shadow UPSMR */
+       __be16 res92;           /* 0x92, reserved, initialize to 0 */
+       __be32 rx_state;        /* 0x94, RX state, initialize to 0 */
+       __be32 rx_cnt;          /* 0x98, RX count, initialize to 0 */
+       u8 rx_length;           /* 0x9C, Char length, set to 1+CL+PEN+1+SL */
+       u8 rx_bitmark;          /* 0x9D, reserved, initialize to 0 */
+       u8 rx_temp_dlst_qe;     /* 0x9E, reserved, initialize to 0 */
+       u8 res14[0xBC - 0x9F];  /* reserved */
+       __be32 dump_ptr;        /* 0xBC, Dump pointer */
+       __be32 rx_frame_rem;    /* 0xC0, reserved, initialize to 0 */
+       u8 rx_frame_rem_size;   /* 0xC4, reserved, initialize to 0 */
+       u8 tx_mode;             /* 0xC5, mode, 0=AHDLC, 1=UART */
+       __be16 tx_state;        /* 0xC6, TX state */
+       u8 res15[0xD0 - 0xC8];  /* reserved */
+       __be32 resD0;           /* 0xD0, reserved, initialize to 0 */
+       u8 resD4;               /* 0xD4, reserved, initialize to 0 */
+       __be16 resD5;           /* 0xD5, reserved, initialize to 0 */
+} __attribute__ ((packed));
+
+/* SUPSMR definitions, for Soft-UART only */
+#define UCC_UART_SUPSMR_SL             0x8000
+#define UCC_UART_SUPSMR_RPM_MASK       0x6000
+#define UCC_UART_SUPSMR_RPM_ODD        0x0000
+#define UCC_UART_SUPSMR_RPM_LOW        0x2000
+#define UCC_UART_SUPSMR_RPM_EVEN       0x4000
+#define UCC_UART_SUPSMR_RPM_HIGH       0x6000
+#define UCC_UART_SUPSMR_PEN            0x1000
+#define UCC_UART_SUPSMR_TPM_MASK       0x0C00
+#define UCC_UART_SUPSMR_TPM_ODD        0x0000
+#define UCC_UART_SUPSMR_TPM_LOW        0x0400
+#define UCC_UART_SUPSMR_TPM_EVEN       0x0800
+#define UCC_UART_SUPSMR_TPM_HIGH       0x0C00
+#define UCC_UART_SUPSMR_FRZ            0x0100
+#define UCC_UART_SUPSMR_UM_MASK        0x00c0
+#define UCC_UART_SUPSMR_UM_NORMAL       0x0000
+#define UCC_UART_SUPSMR_UM_MAN_MULTI    0x0040
+#define UCC_UART_SUPSMR_UM_AUTO_MULTI   0x00c0
+#define UCC_UART_SUPSMR_CL_MASK        0x0030
+#define UCC_UART_SUPSMR_CL_8           0x0030
+#define UCC_UART_SUPSMR_CL_7           0x0020
+#define UCC_UART_SUPSMR_CL_6           0x0010
+#define UCC_UART_SUPSMR_CL_5           0x0000
+
+#define UCC_UART_TX_STATE_AHDLC        0x00
+#define UCC_UART_TX_STATE_UART         0x01
+#define UCC_UART_TX_STATE_X1           0x00
+#define UCC_UART_TX_STATE_X16          0x80
+
+#define UCC_UART_PRAM_ALIGNMENT 0x100
+
+#define UCC_UART_SIZE_OF_BD     UCC_SLOW_SIZE_OF_BD
+#define NUM_CONTROL_CHARS       8
+
+/* Private per-port data structure */
+struct uart_qe_port {
+       struct uart_port port;
+       struct ucc_slow __iomem *uccp;
+       struct ucc_uart_pram __iomem *uccup;
+       struct ucc_slow_info us_info;
+       struct ucc_slow_private *us_private;
+       struct device_node *np;
+       unsigned int ucc_num;   /* First ucc is 0, not 1 */
+
+       u16 rx_nrfifos;
+       u16 rx_fifosize;
+       u16 tx_nrfifos;
+       u16 tx_fifosize;
+       int wait_closing;
+       u32 flags;
+       struct qe_bd *rx_bd_base;
+       struct qe_bd *rx_cur;
+       struct qe_bd *tx_bd_base;
+       struct qe_bd *tx_cur;
+       unsigned char *tx_buf;
+       unsigned char *rx_buf;
+       void *bd_virt;          /* virtual address of the BD buffers */
+       dma_addr_t bd_dma_addr; /* bus address of the BD buffers */
+       unsigned int bd_size;   /* size of BD buffer space */
+};
+
+static struct uart_driver ucc_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ucc_uart",
+       .dev_name       = "ttyQE",
+       .major          = SERIAL_QE_MAJOR,
+       .minor          = SERIAL_QE_MINOR,
+       .nr             = UCC_MAX_UART,
+};
+
+/*
+ * Virtual to physical address translation.
+ *
+ * Given the virtual address for a character buffer, this function returns
+ * the physical (DMA) equivalent.
+ */
+static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
+{
+       if (likely((addr >= qe_port->bd_virt)) &&
+           (addr < (qe_port->bd_virt + qe_port->bd_size)))
+               return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
+
+       /* something nasty happened */
+       printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
+       BUG();
+       return 0;
+}
+
+/*
+ * Physical to virtual address translation.
+ *
+ * Given the physical (DMA) address for a character buffer, this function
+ * returns the virtual equivalent.
+ */
+static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
+{
+       /* sanity check */
+       if (likely((addr >= qe_port->bd_dma_addr) &&
+                  (addr < (qe_port->bd_dma_addr + qe_port->bd_size))))
+               return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
+
+       /* something nasty happened */
+       printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
+       BUG();
+       return NULL;
+}
+
+/*
+ * Return 1 if the QE is done transmitting all buffers for this port
+ *
+ * This function scans each BD in sequence.  If we find a BD that is not
+ * ready (READY=1), then we return 0 indicating that the QE is still sending
+ * data.  If we reach the last BD (WRAP=1), then we know we've scanned
+ * the entire list, and all BDs are done.
+ */
+static unsigned int qe_uart_tx_empty(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct qe_bd *bdp = qe_port->tx_bd_base;
+
+       while (1) {
+               if (in_be16(&bdp->status) & BD_SC_READY)
+                       /* This BD is not done, so return "not done" */
+                       return 0;
+
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       /*
+                        * This BD is done and it's the last one, so return
+                        * "done"
+                        */
+                       return 1;
+
+               bdp++;
+       };
+}
+
+/*
+ * Set the modem control lines
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), we
+ * don't need that support. This function must exist, however, otherwise
+ * the kernel will panic.
+ */
+void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Get the current modem control line status
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), this
+ * driver currently doesn't support that, so we always return Carrier
+ * Detect, Data Set Ready, and Clear To Send.
+ */
+static unsigned int qe_uart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/*
+ * Disable the transmit interrupt.
+ *
+ * Although this function is called "stop_tx", it does not actually stop
+ * transmission of data.  Instead, it tells the QE to not generate an
+ * interrupt when the UCC is finished sending characters.
+ */
+static void qe_uart_stop_tx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Transmit as many characters to the HW as possible.
+ *
+ * This function will attempt to stuff of all the characters from the
+ * kernel's transmit buffer into TX BDs.
+ *
+ * A return value of non-zero indicates that it successfully stuffed all
+ * characters from the kernel buffer.
+ *
+ * A return value of zero indicates that there are still characters in the
+ * kernel's buffer that have not been transmitted, but there are no more BDs
+ * available.  This function should be called again after a BD has been made
+ * available.
+ */
+static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
+{
+       struct qe_bd *bdp;
+       unsigned char *p;
+       unsigned int count;
+       struct uart_port *port = &qe_port->port;
+       struct circ_buf *xmit = &port->state->xmit;
+
+       bdp = qe_port->rx_cur;
+
+       /* Handle xon/xoff */
+       if (port->x_char) {
+               /* Pick next descriptor and fill from buffer */
+               bdp = qe_port->tx_cur;
+
+               p = qe2cpu_addr(bdp->buf, qe_port);
+
+               *p++ = port->x_char;
+               out_be16(&bdp->length, 1);
+               setbits16(&bdp->status, BD_SC_READY);
+               /* Get next BD. */
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->tx_bd_base;
+               else
+                       bdp++;
+               qe_port->tx_cur = bdp;
+
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               qe_uart_stop_tx(port);
+               return 0;
+       }
+
+       /* Pick next descriptor and fill from buffer */
+       bdp = qe_port->tx_cur;
+
+       while (!(in_be16(&bdp->status) & BD_SC_READY) &&
+              (xmit->tail != xmit->head)) {
+               count = 0;
+               p = qe2cpu_addr(bdp->buf, qe_port);
+               while (count < qe_port->tx_fifosize) {
+                       *p++ = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                       port->icount.tx++;
+                       count++;
+                       if (xmit->head == xmit->tail)
+                               break;
+               }
+
+               out_be16(&bdp->length, count);
+               setbits16(&bdp->status, BD_SC_READY);
+
+               /* Get next BD. */
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->tx_bd_base;
+               else
+                       bdp++;
+       }
+       qe_port->tx_cur = bdp;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit)) {
+               /* The kernel buffer is empty, so turn off TX interrupts.  We
+                  don't need to be told when the QE is finished transmitting
+                  the data. */
+               qe_uart_stop_tx(port);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Start transmitting data
+ *
+ * This function will start transmitting any available data, if the port
+ * isn't already transmitting data.
+ */
+static void qe_uart_start_tx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       /* If we currently are transmitting, then just return */
+       if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX)
+               return;
+
+       /* Otherwise, pump the port and start transmission */
+       if (qe_uart_tx_pump(qe_port))
+               setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Stop transmitting data
+ */
+static void qe_uart_stop_rx(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+}
+
+/*
+ * Enable status change interrupts
+ *
+ * We don't support status change interrupts, but we need to define this
+ * function otherwise the kernel will panic.
+ */
+static void qe_uart_enable_ms(struct uart_port *port)
+{
+}
+
+/* Start or stop sending  break signal
+ *
+ * This function controls the sending of a break signal.  If break_state=1,
+ * then we start sending a break signal.  If break_state=0, then we stop
+ * sending the break signal.
+ */
+static void qe_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+
+       if (break_state)
+               ucc_slow_stop_tx(qe_port->us_private);
+       else
+               ucc_slow_restart_tx(qe_port->us_private);
+}
+
+/* ISR helper function for receiving character.
+ *
+ * This function is called by the ISR to handling receiving characters
+ */
+static void qe_uart_int_rx(struct uart_qe_port *qe_port)
+{
+       int i;
+       unsigned char ch, *cp;
+       struct uart_port *port = &qe_port->port;
+       struct tty_struct *tty = port->state->port.tty;
+       struct qe_bd *bdp;
+       u16 status;
+       unsigned int flg;
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = qe_port->rx_cur;
+       while (1) {
+               status = in_be16(&bdp->status);
+
+               /* If this one is empty, then we assume we've read them all */
+               if (status & BD_SC_EMPTY)
+                       break;
+
+               /* get number of characters, and check space in RX buffer */
+               i = in_be16(&bdp->length);
+
+               /* If we don't have enough room in RX buffer for the entire BD,
+                * then we try later, which will be the next RX interrupt.
+                */
+               if (tty_buffer_request_room(tty, i) < i) {
+                       dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n");
+                       return;
+               }
+
+               /* get pointer */
+               cp = qe2cpu_addr(bdp->buf, qe_port);
+
+               /* loop through the buffer */
+               while (i-- > 0) {
+                       ch = *cp++;
+                       port->icount.rx++;
+                       flg = TTY_NORMAL;
+
+                       if (!i && status &
+                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+                               goto handle_error;
+                       if (uart_handle_sysrq_char(port, ch))
+                               continue;
+
+error_return:
+                       tty_insert_flip_char(tty, ch, flg);
+
+               }
+
+               /* This BD is ready to be used again. Clear status. get next */
+               clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+                       BD_SC_OV | BD_SC_ID, BD_SC_EMPTY);
+               if (in_be16(&bdp->status) & BD_SC_WRAP)
+                       bdp = qe_port->rx_bd_base;
+               else
+                       bdp++;
+
+       }
+
+       /* Write back buffer pointer */
+       qe_port->rx_cur = bdp;
+
+       /* Activate BH processing */
+       tty_flip_buffer_push(tty);
+
+       return;
+
+       /* Error processing */
+
+handle_error:
+       /* Statistics */
+       if (status & BD_SC_BR)
+               port->icount.brk++;
+       if (status & BD_SC_PR)
+               port->icount.parity++;
+       if (status & BD_SC_FR)
+               port->icount.frame++;
+       if (status & BD_SC_OV)
+               port->icount.overrun++;
+
+       /* Mask out ignored conditions */
+       status &= port->read_status_mask;
+
+       /* Handle the remaining ones */
+       if (status & BD_SC_BR)
+               flg = TTY_BREAK;
+       else if (status & BD_SC_PR)
+               flg = TTY_PARITY;
+       else if (status & BD_SC_FR)
+               flg = TTY_FRAME;
+
+       /* Overrun does not affect the current character ! */
+       if (status & BD_SC_OV)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+#ifdef SUPPORT_SYSRQ
+       port->sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/* Interrupt handler
+ *
+ * This interrupt handler is called after a BD is processed.
+ */
+static irqreturn_t qe_uart_int(int irq, void *data)
+{
+       struct uart_qe_port *qe_port = (struct uart_qe_port *) data;
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       u16 events;
+
+       /* Clear the interrupts */
+       events = in_be16(&uccp->ucce);
+       out_be16(&uccp->ucce, events);
+
+       if (events & UCC_UART_UCCE_BRKE)
+               uart_handle_break(&qe_port->port);
+
+       if (events & UCC_UART_UCCE_RX)
+               qe_uart_int_rx(qe_port);
+
+       if (events & UCC_UART_UCCE_TX)
+               qe_uart_tx_pump(qe_port);
+
+       return events ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/* Initialize buffer descriptors
+ *
+ * This function initializes all of the RX and TX buffer descriptors.
+ */
+static void qe_uart_initbd(struct uart_qe_port *qe_port)
+{
+       int i;
+       void *bd_virt;
+       struct qe_bd *bdp;
+
+       /* Set the physical address of the host memory buffers in the buffer
+        * descriptors, and the virtual address for us to work with.
+        */
+       bd_virt = qe_port->bd_virt;
+       bdp = qe_port->rx_bd_base;
+       qe_port->rx_cur = qe_port->rx_bd_base;
+       for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) {
+               out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT);
+               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+               out_be16(&bdp->length, 0);
+               bd_virt += qe_port->rx_fifosize;
+               bdp++;
+       }
+
+       /* */
+       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
+       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+       out_be16(&bdp->length, 0);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       bd_virt = qe_port->bd_virt +
+               L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+       qe_port->tx_cur = qe_port->tx_bd_base;
+       bdp = qe_port->tx_bd_base;
+       for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) {
+               out_be16(&bdp->status, BD_SC_INTRPT);
+               out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+               out_be16(&bdp->length, 0);
+               bd_virt += qe_port->tx_fifosize;
+               bdp++;
+       }
+
+       /* Loopback requires the preamble bit to be set on the first TX BD */
+#ifdef LOOPBACK
+       setbits16(&qe_port->tx_cur->status, BD_SC_P);
+#endif
+
+       out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT);
+       out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+       out_be16(&bdp->length, 0);
+}
+
+/*
+ * Initialize a UCC for UART.
+ *
+ * This function configures a given UCC to be used as a UART device. Basic
+ * UCC initialization is handled in qe_uart_request_port().  This function
+ * does all the UART-specific stuff.
+ */
+static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
+{
+       u32 cecr_subblock;
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       struct ucc_uart_pram *uccup = qe_port->uccup;
+
+       unsigned int i;
+
+       /* First, disable TX and RX in the UCC */
+       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+       /* Program the UCC UART parameter RAM */
+       out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+       out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+       out_be16(&uccup->common.mrblr, qe_port->rx_fifosize);
+       out_be16(&uccup->maxidl, 0x10);
+       out_be16(&uccup->brkcr, 1);
+       out_be16(&uccup->parec, 0);
+       out_be16(&uccup->frmec, 0);
+       out_be16(&uccup->nosec, 0);
+       out_be16(&uccup->brkec, 0);
+       out_be16(&uccup->uaddr[0], 0);
+       out_be16(&uccup->uaddr[1], 0);
+       out_be16(&uccup->toseq, 0);
+       for (i = 0; i < 8; i++)
+               out_be16(&uccup->cchars[i], 0xC000);
+       out_be16(&uccup->rccm, 0xc0ff);
+
+       /* Configure the GUMR registers for UART */
+       if (soft_uart) {
+               /* Soft-UART requires a 1X multiplier for TX */
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW,
+                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX);
+       } else {
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h,
+                       UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX,
+                       UCC_SLOW_GUMR_H_RFW);
+       }
+
+#ifdef LOOPBACK
+       clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+               UCC_SLOW_GUMR_L_DIAG_LOOP);
+       clrsetbits_be32(&uccp->gumr_h,
+               UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN,
+               UCC_SLOW_GUMR_H_CDS);
+#endif
+
+       /* Disable rx interrupts  and clear all pending events.  */
+       out_be16(&uccp->uccm, 0);
+       out_be16(&uccp->ucce, 0xffff);
+       out_be16(&uccp->udsr, 0x7e7e);
+
+       /* Initialize UPSMR */
+       out_be16(&uccp->upsmr, 0);
+
+       if (soft_uart) {
+               out_be16(&uccup->supsmr, 0x30);
+               out_be16(&uccup->res92, 0);
+               out_be32(&uccup->rx_state, 0);
+               out_be32(&uccup->rx_cnt, 0);
+               out_8(&uccup->rx_bitmark, 0);
+               out_8(&uccup->rx_length, 10);
+               out_be32(&uccup->dump_ptr, 0x4000);
+               out_8(&uccup->rx_temp_dlst_qe, 0);
+               out_be32(&uccup->rx_frame_rem, 0);
+               out_8(&uccup->rx_frame_rem_size, 0);
+               /* Soft-UART requires TX to be 1X */
+               out_8(&uccup->tx_mode,
+                       UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1);
+               out_be16(&uccup->tx_state, 0);
+               out_8(&uccup->resD4, 0);
+               out_be16(&uccup->resD5, 0);
+
+               /* Set UART mode.
+                * Enable receive and transmit.
+                */
+
+               /* From the microcode errata:
+                * 1.GUMR_L register, set mode=0010 (QMC).
+                * 2.Set GUMR_H[17] bit. (UART/AHDLC mode).
+                * 3.Set GUMR_H[19:20] (Transparent mode)
+                * 4.Clear GUMR_H[26] (RFW)
+                * ...
+                * 6.Receiver must use 16x over sampling
+                */
+               clrsetbits_be32(&uccp->gumr_l,
+                       UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+                       UCC_SLOW_GUMR_L_RDCR_MASK,
+                       UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 |
+                       UCC_SLOW_GUMR_L_RDCR_16);
+
+               clrsetbits_be32(&uccp->gumr_h,
+                       UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN,
+                       UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX |
+                       UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL);
+
+#ifdef LOOPBACK
+               clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+                               UCC_SLOW_GUMR_L_DIAG_LOOP);
+               clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP |
+                         UCC_SLOW_GUMR_H_CDS);
+#endif
+
+               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
+               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+                       QE_CR_PROTOCOL_UNSPECIFIED, 0);
+       } else {
+               cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
+               qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+                       QE_CR_PROTOCOL_UART, 0);
+       }
+}
+
+/*
+ * Initialize the port.
+ */
+static int qe_uart_startup(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       int ret;
+
+       /*
+        * If we're using Soft-UART mode, then we need to make sure the
+        * firmware has been uploaded first.
+        */
+       if (soft_uart && !firmware_loaded) {
+               dev_err(port->dev, "Soft-UART firmware not uploaded\n");
+               return -ENODEV;
+       }
+
+       qe_uart_initbd(qe_port);
+       qe_uart_init_ucc(qe_port);
+
+       /* Install interrupt handler. */
+       ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart",
+               qe_port);
+       if (ret) {
+               dev_err(port->dev, "could not claim IRQ %u\n", port->irq);
+               return ret;
+       }
+
+       /* Startup rx-int */
+       setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+       ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+       return 0;
+}
+
+/*
+ * Shutdown the port.
+ */
+static void qe_uart_shutdown(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       unsigned int timeout = 20;
+
+       /* Disable RX and TX */
+
+       /* Wait for all the BDs marked sent */
+       while (!qe_uart_tx_empty(port)) {
+               if (!--timeout) {
+                       dev_warn(port->dev, "shutdown timeout\n");
+                       break;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(2);
+       }
+
+       if (qe_port->wait_closing) {
+               /* Wait a bit longer */
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(qe_port->wait_closing);
+       }
+
+       /* Stop uarts */
+       ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+       clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX);
+
+       /* Shut them really down and reinit buffer descriptors */
+       ucc_slow_graceful_stop_tx(qe_port->us_private);
+       qe_uart_initbd(qe_port);
+
+       free_irq(port->irq, qe_port);
+}
+
+/*
+ * Set the serial port parameters.
+ */
+static void qe_uart_set_termios(struct uart_port *port,
+                               struct ktermios *termios, struct ktermios *old)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow __iomem *uccp = qe_port->uccp;
+       unsigned int baud;
+       unsigned long flags;
+       u16 upsmr = in_be16(&uccp->upsmr);
+       struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
+       u16 supsmr = in_be16(&uccup->supsmr);
+       u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+
+       /* byte size */
+       upsmr &= UCC_UART_UPSMR_CL_MASK;
+       supsmr &= UCC_UART_SUPSMR_CL_MASK;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               upsmr |= UCC_UART_UPSMR_CL_5;
+               supsmr |= UCC_UART_SUPSMR_CL_5;
+               char_length += 5;
+               break;
+       case CS6:
+               upsmr |= UCC_UART_UPSMR_CL_6;
+               supsmr |= UCC_UART_SUPSMR_CL_6;
+               char_length += 6;
+               break;
+       case CS7:
+               upsmr |= UCC_UART_UPSMR_CL_7;
+               supsmr |= UCC_UART_SUPSMR_CL_7;
+               char_length += 7;
+               break;
+       default:        /* case CS8 */
+               upsmr |= UCC_UART_UPSMR_CL_8;
+               supsmr |= UCC_UART_SUPSMR_CL_8;
+               char_length += 8;
+               break;
+       }
+
+       /* If CSTOPB is set, we want two stop bits */
+       if (termios->c_cflag & CSTOPB) {
+               upsmr |= UCC_UART_UPSMR_SL;
+               supsmr |= UCC_UART_SUPSMR_SL;
+               char_length++;  /* + SL */
+       }
+
+       if (termios->c_cflag & PARENB) {
+               upsmr |= UCC_UART_UPSMR_PEN;
+               supsmr |= UCC_UART_SUPSMR_PEN;
+               char_length++;  /* + PEN */
+
+               if (!(termios->c_cflag & PARODD)) {
+                       upsmr &= ~(UCC_UART_UPSMR_RPM_MASK |
+                                  UCC_UART_UPSMR_TPM_MASK);
+                       upsmr |= UCC_UART_UPSMR_RPM_EVEN |
+                               UCC_UART_UPSMR_TPM_EVEN;
+                       supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK |
+                                   UCC_UART_SUPSMR_TPM_MASK);
+                       supsmr |= UCC_UART_SUPSMR_RPM_EVEN |
+                               UCC_UART_SUPSMR_TPM_EVEN;
+               }
+       }
+
+       /*
+        * Set up parity check flag
+        */
+       port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= BD_SC_BR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->read_status_mask &= ~BD_SC_EMPTY;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+
+       /* Do we really need a spinlock here? */
+       spin_lock_irqsave(&port->lock, flags);
+
+       out_be16(&uccp->upsmr, upsmr);
+       if (soft_uart) {
+               out_be16(&uccup->supsmr, supsmr);
+               out_8(&uccup->rx_length, char_length);
+
+               /* Soft-UART requires a 1X multiplier for TX */
+               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+               qe_setbrg(qe_port->us_info.tx_clock, baud, 1);
+       } else {
+               qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+               qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return a pointer to a string that describes what kind of port this is.
+ */
+static const char *qe_uart_type(struct uart_port *port)
+{
+       return "QE";
+}
+
+/*
+ * Allocate any memory and I/O resources required by the port.
+ */
+static int qe_uart_request_port(struct uart_port *port)
+{
+       int ret;
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow_info *us_info = &qe_port->us_info;
+       struct ucc_slow_private *uccs;
+       unsigned int rx_size, tx_size;
+       void *bd_virt;
+       dma_addr_t bd_dma_addr = 0;
+
+       ret = ucc_slow_init(us_info, &uccs);
+       if (ret) {
+               dev_err(port->dev, "could not initialize UCC%u\n",
+                      qe_port->ucc_num);
+               return ret;
+       }
+
+       qe_port->us_private = uccs;
+       qe_port->uccp = uccs->us_regs;
+       qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
+       qe_port->rx_bd_base = uccs->rx_bd;
+       qe_port->tx_bd_base = uccs->tx_bd;
+
+       /*
+        * Allocate the transmit and receive data buffers.
+        */
+
+       rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+       tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
+
+       bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
+               GFP_KERNEL);
+       if (!bd_virt) {
+               dev_err(port->dev, "could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+
+       qe_port->bd_virt = bd_virt;
+       qe_port->bd_dma_addr = bd_dma_addr;
+       qe_port->bd_size = rx_size + tx_size;
+
+       qe_port->rx_buf = bd_virt;
+       qe_port->tx_buf = qe_port->rx_buf + rx_size;
+
+       return 0;
+}
+
+/*
+ * Configure the port.
+ *
+ * We say we're a CPM-type port because that's mostly true.  Once the device
+ * is configured, this driver operates almost identically to the CPM serial
+ * driver.
+ */
+static void qe_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_CPM;
+               qe_uart_request_port(port);
+       }
+}
+
+/*
+ * Release any memory and I/O resources that were allocated in
+ * qe_uart_request_port().
+ */
+static void qe_uart_release_port(struct uart_port *port)
+{
+       struct uart_qe_port *qe_port =
+               container_of(port, struct uart_qe_port, port);
+       struct ucc_slow_private *uccs = qe_port->us_private;
+
+       dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
+                         qe_port->bd_dma_addr);
+
+       ucc_slow_free(uccs);
+}
+
+/*
+ * Verify that the data in serial_struct is suitable for this device.
+ */
+static int qe_uart_verify_port(struct uart_port *port,
+                              struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+               return -EINVAL;
+
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
+               return -EINVAL;
+
+       if (ser->baud_base < 9600)
+               return -EINVAL;
+
+       return 0;
+}
+/* UART operations
+ *
+ * Details on these functions can be found in Documentation/serial/driver
+ */
+static struct uart_ops qe_uart_pops = {
+       .tx_empty       = qe_uart_tx_empty,
+       .set_mctrl      = qe_uart_set_mctrl,
+       .get_mctrl      = qe_uart_get_mctrl,
+       .stop_tx        = qe_uart_stop_tx,
+       .start_tx       = qe_uart_start_tx,
+       .stop_rx        = qe_uart_stop_rx,
+       .enable_ms      = qe_uart_enable_ms,
+       .break_ctl      = qe_uart_break_ctl,
+       .startup        = qe_uart_startup,
+       .shutdown       = qe_uart_shutdown,
+       .set_termios    = qe_uart_set_termios,
+       .type           = qe_uart_type,
+       .release_port   = qe_uart_release_port,
+       .request_port   = qe_uart_request_port,
+       .config_port    = qe_uart_config_port,
+       .verify_port    = qe_uart_verify_port,
+};
+
+/*
+ * Obtain the SOC model number and revision level
+ *
+ * This function parses the device tree to obtain the SOC model.  It then
+ * reads the SVR register to the revision.
+ *
+ * The device tree stores the SOC model two different ways.
+ *
+ * The new way is:
+ *
+ *             cpu@0 {
+ *                     compatible = "PowerPC,8323";
+ *                     device_type = "cpu";
+ *                     ...
+ *
+ *
+ * The old way is:
+ *              PowerPC,8323@0 {
+ *                     device_type = "cpu";
+ *                     ...
+ *
+ * This code first checks the new way, and then the old way.
+ */
+static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
+{
+       struct device_node *np;
+       const char *soc_string;
+       unsigned int svr;
+       unsigned int soc;
+
+       /* Find the CPU node */
+       np = of_find_node_by_type(NULL, "cpu");
+       if (!np)
+               return 0;
+       /* Find the compatible property */
+       soc_string = of_get_property(np, "compatible", NULL);
+       if (!soc_string)
+               /* No compatible property, so try the name. */
+               soc_string = np->name;
+
+       /* Extract the SOC number from the "PowerPC," string */
+       if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
+               return 0;
+
+       /* Get the revision from the SVR */
+       svr = mfspr(SPRN_SVR);
+       *rev_h = (svr >> 4) & 0xf;
+       *rev_l = svr & 0xf;
+
+       return soc;
+}
+
+/*
+ * requst_firmware_nowait() callback function
+ *
+ * This function is called by the kernel when a firmware is made available,
+ * or if it times out waiting for the firmware.
+ */
+static void uart_firmware_cont(const struct firmware *fw, void *context)
+{
+       struct qe_firmware *firmware;
+       struct device *dev = context;
+       int ret;
+
+       if (!fw) {
+               dev_err(dev, "firmware not found\n");
+               return;
+       }
+
+       firmware = (struct qe_firmware *) fw->data;
+
+       if (firmware->header.length != fw->size) {
+               dev_err(dev, "invalid firmware\n");
+               goto out;
+       }
+
+       ret = qe_upload_firmware(firmware);
+       if (ret) {
+               dev_err(dev, "could not load firmware\n");
+               goto out;
+       }
+
+       firmware_loaded = 1;
+ out:
+       release_firmware(fw);
+}
+
+static int ucc_uart_probe(struct platform_device *ofdev,
+       const struct of_device_id *match)
+{
+       struct device_node *np = ofdev->dev.of_node;
+       const unsigned int *iprop;      /* Integer OF properties */
+       const char *sprop;      /* String OF properties */
+       struct uart_qe_port *qe_port = NULL;
+       struct resource res;
+       int ret;
+
+       /*
+        * Determine if we need Soft-UART mode
+        */
+       if (of_find_property(np, "soft-uart", NULL)) {
+               dev_dbg(&ofdev->dev, "using Soft-UART mode\n");
+               soft_uart = 1;
+       }
+
+       /*
+        * If we are using Soft-UART, determine if we need to upload the
+        * firmware, too.
+        */
+       if (soft_uart) {
+               struct qe_firmware_info *qe_fw_info;
+
+               qe_fw_info = qe_get_firmware_info();
+
+               /* Check if the firmware has been uploaded. */
+               if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) {
+                       firmware_loaded = 1;
+               } else {
+                       char filename[32];
+                       unsigned int soc;
+                       unsigned int rev_h;
+                       unsigned int rev_l;
+
+                       soc = soc_info(&rev_h, &rev_l);
+                       if (!soc) {
+                               dev_err(&ofdev->dev, "unknown CPU model\n");
+                               return -ENXIO;
+                       }
+                       sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin",
+                               soc, rev_h, rev_l);
+
+                       dev_info(&ofdev->dev, "waiting for firmware %s\n",
+                               filename);
+
+                       /*
+                        * We call request_firmware_nowait instead of
+                        * request_firmware so that the driver can load and
+                        * initialize the ports without holding up the rest of
+                        * the kernel.  If hotplug support is enabled in the
+                        * kernel, then we use it.
+                        */
+                       ret = request_firmware_nowait(THIS_MODULE,
+                               FW_ACTION_HOTPLUG, filename, &ofdev->dev,
+                               GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
+                       if (ret) {
+                               dev_err(&ofdev->dev,
+                                       "could not load firmware %s\n",
+                                       filename);
+                               return ret;
+                       }
+               }
+       }
+
+       qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL);
+       if (!qe_port) {
+               dev_err(&ofdev->dev, "can't allocate QE port structure\n");
+               return -ENOMEM;
+       }
+
+       /* Search for IRQ and mapbase */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
+               kfree(qe_port);
+               return ret;
+       }
+       if (!res.start) {
+               dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+       qe_port->port.mapbase = res.start;
+
+       /* Get the UCC number (device ID) */
+       /* UCCs are numbered 1-7 */
+       iprop = of_get_property(np, "cell-index", NULL);
+       if (!iprop) {
+               iprop = of_get_property(np, "device-id", NULL);
+               if (!iprop) {
+                       kfree(qe_port);
+                       dev_err(&ofdev->dev, "UCC is unspecified in "
+                               "device tree\n");
+                       return -EINVAL;
+               }
+       }
+
+       if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
+               dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
+               kfree(qe_port);
+               return -ENODEV;
+       }
+       qe_port->ucc_num = *iprop - 1;
+
+       /*
+        * In the future, we should not require the BRG to be specified in the
+        * device tree.  If no clock-source is specified, then just pick a BRG
+        * to use.  This requires a new QE library function that manages BRG
+        * assignments.
+        */
+
+       sprop = of_get_property(np, "rx-clock-name", NULL);
+       if (!sprop) {
+               dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+       qe_port->us_info.rx_clock = qe_clock_source(sprop);
+       if ((qe_port->us_info.rx_clock < QE_BRG1) ||
+           (qe_port->us_info.rx_clock > QE_BRG16)) {
+               dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+#ifdef LOOPBACK
+       /* In internal loopback mode, TX and RX must use the same clock */
+       qe_port->us_info.tx_clock = qe_port->us_info.rx_clock;
+#else
+       sprop = of_get_property(np, "tx-clock-name", NULL);
+       if (!sprop) {
+               dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+       qe_port->us_info.tx_clock = qe_clock_source(sprop);
+#endif
+       if ((qe_port->us_info.tx_clock < QE_BRG1) ||
+           (qe_port->us_info.tx_clock > QE_BRG16)) {
+               dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
+               kfree(qe_port);
+               return -ENODEV;
+       }
+
+       /* Get the port number, numbered 0-3 */
+       iprop = of_get_property(np, "port-number", NULL);
+       if (!iprop) {
+               dev_err(&ofdev->dev, "missing port-number in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+       qe_port->port.line = *iprop;
+       if (qe_port->port.line >= UCC_MAX_UART) {
+               dev_err(&ofdev->dev, "port-number must be 0-%u\n",
+                       UCC_MAX_UART - 1);
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       qe_port->port.irq = irq_of_parse_and_map(np, 0);
+       if (qe_port->port.irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
+                      qe_port->ucc_num + 1);
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       /*
+        * Newer device trees have an "fsl,qe" compatible property for the QE
+        * node, but we still need to support older device trees.
+        */
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (!np) {
+               np = of_find_node_by_type(NULL, "qe");
+               if (!np) {
+                       dev_err(&ofdev->dev, "could not find 'qe' node\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+       }
+
+       iprop = of_get_property(np, "brg-frequency", NULL);
+       if (!iprop) {
+               dev_err(&ofdev->dev,
+                      "missing brg-frequency in device tree\n");
+               kfree(qe_port);
+               return -EINVAL;
+       }
+
+       if (*iprop)
+               qe_port->port.uartclk = *iprop;
+       else {
+               /*
+                * Older versions of U-Boot do not initialize the brg-frequency
+                * property, so in this case we assume the BRG frequency is
+                * half the QE bus frequency.
+                */
+               iprop = of_get_property(np, "bus-frequency", NULL);
+               if (!iprop) {
+                       dev_err(&ofdev->dev,
+                               "missing QE bus-frequency in device tree\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+               if (*iprop)
+                       qe_port->port.uartclk = *iprop / 2;
+               else {
+                       dev_err(&ofdev->dev,
+                               "invalid QE bus-frequency in device tree\n");
+                       kfree(qe_port);
+                       return -EINVAL;
+               }
+       }
+
+       spin_lock_init(&qe_port->port.lock);
+       qe_port->np = np;
+       qe_port->port.dev = &ofdev->dev;
+       qe_port->port.ops = &qe_uart_pops;
+       qe_port->port.iotype = UPIO_MEM;
+
+       qe_port->tx_nrfifos = TX_NUM_FIFO;
+       qe_port->tx_fifosize = TX_BUF_SIZE;
+       qe_port->rx_nrfifos = RX_NUM_FIFO;
+       qe_port->rx_fifosize = RX_BUF_SIZE;
+
+       qe_port->wait_closing = UCC_WAIT_CLOSING;
+       qe_port->port.fifosize = 512;
+       qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+
+       qe_port->us_info.ucc_num = qe_port->ucc_num;
+       qe_port->us_info.regs = (phys_addr_t) res.start;
+       qe_port->us_info.irq = qe_port->port.irq;
+
+       qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos;
+       qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos;
+
+       /* Make sure ucc_slow_init() initializes both TX and RX */
+       qe_port->us_info.init_tx = 1;
+       qe_port->us_info.init_rx = 1;
+
+       /* Add the port to the uart sub-system.  This will cause
+        * qe_uart_config_port() to be called, so the us_info structure must
+        * be initialized.
+        */
+       ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port);
+       if (ret) {
+               dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
+                      qe_port->port.line);
+               kfree(qe_port);
+               return ret;
+       }
+
+       dev_set_drvdata(&ofdev->dev, qe_port);
+
+       dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
+               qe_port->ucc_num + 1, qe_port->port.line);
+
+       /* Display the mknod command for this device */
+       dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n",
+              qe_port->port.line, SERIAL_QE_MAJOR,
+              SERIAL_QE_MINOR + qe_port->port.line);
+
+       return 0;
+}
+
+static int ucc_uart_remove(struct platform_device *ofdev)
+{
+       struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
+
+       dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
+
+       uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(qe_port);
+
+       return 0;
+}
+
+static struct of_device_id ucc_uart_match[] = {
+       {
+               .type = "serial",
+               .compatible = "ucc_uart",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ucc_uart_match);
+
+static struct of_platform_driver ucc_uart_of_driver = {
+       .driver = {
+               .name = "ucc_uart",
+               .owner = THIS_MODULE,
+               .of_match_table    = ucc_uart_match,
+       },
+       .probe          = ucc_uart_probe,
+       .remove         = ucc_uart_remove,
+};
+
+static int __init ucc_uart_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Freescale QUICC Engine UART device driver\n");
+#ifdef LOOPBACK
+       printk(KERN_INFO "ucc-uart: Using loopback mode\n");
+#endif
+
+       ret = uart_register_driver(&ucc_uart_driver);
+       if (ret) {
+               printk(KERN_ERR "ucc-uart: could not register UART driver\n");
+               return ret;
+       }
+
+       ret = of_register_platform_driver(&ucc_uart_of_driver);
+       if (ret)
+               printk(KERN_ERR
+                      "ucc-uart: could not register platform driver\n");
+
+       return ret;
+}
+
+static void __exit ucc_uart_exit(void)
+{
+       printk(KERN_INFO
+              "Freescale QUICC Engine UART device driver unloading\n");
+
+       of_unregister_platform_driver(&ucc_uart_of_driver);
+       uart_unregister_driver(&ucc_uart_driver);
+}
+
+module_init(ucc_uart_init);
+module_exit(ucc_uart_exit);
+
+MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART");
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR);
+
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
new file mode 100644 (file)
index 0000000..3beb6ab
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ *  Driver for NEC VR4100 series Serial Interface Unit.
+ *
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  Based on drivers/serial/8250.c, by Russell King.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <asm/io.h>
+#include <asm/vr41xx/siu.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#define SIU_BAUD_BASE  1152000
+#define SIU_MAJOR      204
+#define SIU_MINOR_BASE 82
+
+#define RX_MAX_COUNT   256
+#define TX_MAX_COUNT   15
+
+#define SIUIRSEL       0x08
+ #define TMICMODE      0x20
+ #define TMICTX                0x10
+ #define IRMSEL                0x0c
+ #define IRMSEL_HP     0x08
+ #define IRMSEL_TEMIC  0x04
+ #define IRMSEL_SHARP  0x00
+ #define IRUSESEL      0x02
+ #define SIRSEL                0x01
+
+static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
+       [0 ... SIU_PORTS_MAX-1] = {
+               .lock   = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
+               .irq    = -1,
+       },
+};
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+#endif
+
+#define siu_read(port, offset)         readb((port)->membase + (offset))
+#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
+
+void vr41xx_select_siu_interface(siu_interface_t interface)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       if (interface == SIU_INTERFACE_IRDA)
+               irsel |= SIRSEL;
+       else
+               irsel &= ~SIRSEL;
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
+
+void vr41xx_use_irda(irda_use_t use)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       if (use == FIR_USE_IRDA)
+               irsel |= IRUSESEL;
+       else
+               irsel &= ~IRUSESEL;
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_use_irda);
+
+void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
+{
+       struct uart_port *port;
+       unsigned long flags;
+       uint8_t irsel;
+
+       port = &siu_uart_ports[0];
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       irsel = siu_read(port, SIUIRSEL);
+       irsel &= ~(IRMSEL | TMICTX | TMICMODE);
+       switch (module) {
+       case SHARP_IRDA:
+               irsel |= IRMSEL_SHARP;
+               break;
+       case TEMIC_IRDA:
+               irsel |= IRMSEL_TEMIC | TMICMODE;
+               if (speed == IRDA_TX_4MBPS)
+                       irsel |= TMICTX;
+               break;
+       case HP_IRDA:
+               irsel |= IRMSEL_HP;
+               break;
+       default:
+               break;
+       }
+       siu_write(port, SIUIRSEL, irsel);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
+
+static inline void siu_clear_fifo(struct uart_port *port)
+{
+       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+       siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+                                 UART_FCR_CLEAR_XMIT);
+       siu_write(port, UART_FCR, 0);
+}
+
+static inline unsigned long siu_port_size(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_VR41XX_SIU:
+               return 11UL;
+       case PORT_VR41XX_DSIU:
+               return 8UL;
+       }
+
+       return 0;
+}
+
+static inline unsigned int siu_check_type(struct uart_port *port)
+{
+       if (port->line == 0)
+               return PORT_VR41XX_SIU;
+       if (port->line == 1 && port->irq != -1)
+               return PORT_VR41XX_DSIU;
+
+       return PORT_UNKNOWN;
+}
+
+static inline const char *siu_type_name(struct uart_port *port)
+{
+       switch (port->type) {
+       case PORT_VR41XX_SIU:
+               return "SIU";
+       case PORT_VR41XX_DSIU:
+               return "DSIU";
+       }
+
+       return NULL;
+}
+
+static unsigned int siu_tx_empty(struct uart_port *port)
+{
+       uint8_t lsr;
+
+       lsr = siu_read(port, UART_LSR);
+       if (lsr & UART_LSR_TEMT)
+               return TIOCSER_TEMT;
+
+       return 0;
+}
+
+static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       uint8_t mcr = 0;
+
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       siu_write(port, UART_MCR, mcr);
+}
+
+static unsigned int siu_get_mctrl(struct uart_port *port)
+{
+       uint8_t msr;
+       unsigned int mctrl = 0;
+
+       msr = siu_read(port, UART_MSR);
+       if (msr & UART_MSR_DCD)
+               mctrl |= TIOCM_CAR;
+       if (msr & UART_MSR_RI)
+               mctrl |= TIOCM_RNG;
+       if (msr & UART_MSR_DSR)
+               mctrl |= TIOCM_DSR;
+       if (msr & UART_MSR_CTS)
+               mctrl |= TIOCM_CTS;
+
+       return mctrl;
+}
+
+static void siu_stop_tx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_THRI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_start_tx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier |= UART_IER_THRI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_stop_rx(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_RLSI;
+       siu_write(port, UART_IER, ier);
+
+       port->read_status_mask &= ~UART_LSR_DR;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_enable_ms(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t ier;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       ier = siu_read(port, UART_IER);
+       ier |= UART_IER_MSI;
+       siu_write(port, UART_IER, ier);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       uint8_t lcr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       lcr = siu_read(port, UART_LCR);
+       if (ctl == -1)
+               lcr |= UART_LCR_SBC;
+       else
+               lcr &= ~UART_LCR_SBC;
+       siu_write(port, UART_LCR, lcr);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static inline void receive_chars(struct uart_port *port, uint8_t *status)
+{
+       struct tty_struct *tty;
+       uint8_t lsr, ch;
+       char flag;
+       int max_count = RX_MAX_COUNT;
+
+       tty = port->state->port.tty;
+       lsr = *status;
+
+       do {
+               ch = siu_read(port, UART_RX);
+               port->icount.rx++;
+               flag = TTY_NORMAL;
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+               lsr |= lsr_break_flag[port->line];
+               lsr_break_flag[port->line] = 0;
+#endif
+               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
+                                   UART_LSR_PE | UART_LSR_OE))) {
+                       if (lsr & UART_LSR_BI) {
+                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                               port->icount.brk++;
+
+                               if (uart_handle_break(port))
+                                       goto ignore_char;
+                       }
+
+                       if (lsr & UART_LSR_FE)
+                               port->icount.frame++;
+                       if (lsr & UART_LSR_PE)
+                               port->icount.parity++;
+                       if (lsr & UART_LSR_OE)
+                               port->icount.overrun++;
+
+                       lsr &= port->read_status_mask;
+                       if (lsr & UART_LSR_BI)
+                               flag = TTY_BREAK;
+                       if (lsr & UART_LSR_FE)
+                               flag = TTY_FRAME;
+                       if (lsr & UART_LSR_PE)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+
+               uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+
+       ignore_char:
+               lsr = siu_read(port, UART_LSR);
+       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+
+       tty_flip_buffer_push(tty);
+
+       *status = lsr;
+}
+
+static inline void check_modem_status(struct uart_port *port)
+{
+       uint8_t msr;
+
+       msr = siu_read(port, UART_MSR);
+       if ((msr & UART_MSR_ANY_DELTA) == 0)
+               return;
+       if (msr & UART_MSR_DDCD)
+               uart_handle_dcd_change(port, msr & UART_MSR_DCD);
+       if (msr & UART_MSR_TERI)
+               port->icount.rng++;
+       if (msr & UART_MSR_DDSR)
+               port->icount.dsr++;
+       if (msr & UART_MSR_DCTS)
+               uart_handle_cts_change(port, msr & UART_MSR_CTS);
+
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static inline void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+       int max_count = TX_MAX_COUNT;
+
+       xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               siu_write(port, UART_TX, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               siu_stop_tx(port);
+               return;
+       }
+
+       do {
+               siu_write(port, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (max_count-- > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               siu_stop_tx(port);
+}
+
+static irqreturn_t siu_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port;
+       uint8_t iir, lsr;
+
+       port = (struct uart_port *)dev_id;
+
+       iir = siu_read(port, UART_IIR);
+       if (iir & UART_IIR_NO_INT)
+               return IRQ_NONE;
+
+       lsr = siu_read(port, UART_LSR);
+       if (lsr & UART_LSR_DR)
+               receive_chars(port, &lsr);
+
+       check_modem_status(port);
+
+       if (lsr & UART_LSR_THRE)
+               transmit_chars(port);
+
+       return IRQ_HANDLED;
+}
+
+static int siu_startup(struct uart_port *port)
+{
+       int retval;
+
+       if (port->membase == NULL)
+               return -ENODEV;
+
+       siu_clear_fifo(port);
+
+       (void)siu_read(port, UART_LSR);
+       (void)siu_read(port, UART_RX);
+       (void)siu_read(port, UART_IIR);
+       (void)siu_read(port, UART_MSR);
+
+       if (siu_read(port, UART_LSR) == 0xff)
+               return -ENODEV;
+
+       retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
+       if (retval)
+               return retval;
+
+       if (port->type == PORT_VR41XX_DSIU)
+               vr41xx_enable_dsiuint(DSIUINT_ALL);
+
+       siu_write(port, UART_LCR, UART_LCR_WLEN8);
+
+       spin_lock_irq(&port->lock);
+       siu_set_mctrl(port, port->mctrl);
+       spin_unlock_irq(&port->lock);
+
+       siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
+
+       (void)siu_read(port, UART_LSR);
+       (void)siu_read(port, UART_RX);
+       (void)siu_read(port, UART_IIR);
+       (void)siu_read(port, UART_MSR);
+
+       return 0;
+}
+
+static void siu_shutdown(struct uart_port *port)
+{
+       unsigned long flags;
+       uint8_t lcr;
+
+       siu_write(port, UART_IER, 0);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->mctrl &= ~TIOCM_OUT2;
+       siu_set_mctrl(port, port->mctrl);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       lcr = siu_read(port, UART_LCR);
+       lcr &= ~UART_LCR_SBC;
+       siu_write(port, UART_LCR, lcr);
+
+       siu_clear_fifo(port);
+
+       (void)siu_read(port, UART_RX);
+
+       if (port->type == PORT_VR41XX_DSIU)
+               vr41xx_disable_dsiuint(DSIUINT_ALL);
+
+       free_irq(port->irq, port);
+}
+
+static void siu_set_termios(struct uart_port *port, struct ktermios *new,
+                            struct ktermios *old)
+{
+       tcflag_t c_cflag, c_iflag;
+       uint8_t lcr, fcr, ier;
+       unsigned int baud, quot;
+       unsigned long flags;
+
+       c_cflag = new->c_cflag;
+       switch (c_cflag & CSIZE) {
+       case CS5:
+               lcr = UART_LCR_WLEN5;
+               break;
+       case CS6:
+               lcr = UART_LCR_WLEN6;
+               break;
+       case CS7:
+               lcr = UART_LCR_WLEN7;
+               break;
+       default:
+               lcr = UART_LCR_WLEN8;
+               break;
+       }
+
+       if (c_cflag & CSTOPB)
+               lcr |= UART_LCR_STOP;
+       if (c_cflag & PARENB)
+               lcr |= UART_LCR_PARITY;
+       if ((c_cflag & PARODD) != PARODD)
+               lcr |= UART_LCR_EPAR;
+       if (c_cflag & CMSPAR)
+               lcr |= UART_LCR_SPAR;
+
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, c_cflag, baud);
+
+       c_iflag = new->c_iflag;
+
+       port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
+       if (c_iflag & INPCK)
+               port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= UART_LSR_BI;
+
+       port->ignore_status_mask = 0;
+       if (c_iflag & IGNPAR)
+               port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (c_iflag & IGNBRK) {
+               port->ignore_status_mask |= UART_LSR_BI;
+               if (c_iflag & IGNPAR)
+                       port->ignore_status_mask |= UART_LSR_OE;
+       }
+
+       if ((c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= UART_LSR_DR;
+
+       ier = siu_read(port, UART_IER);
+       ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(port, c_cflag))
+               ier |= UART_IER_MSI;
+       siu_write(port, UART_IER, ier);
+
+       siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
+
+       siu_write(port, UART_DLL, (uint8_t)quot);
+       siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
+
+       siu_write(port, UART_LCR, lcr);
+
+       siu_write(port, UART_FCR, fcr);
+
+       siu_set_mctrl(port, port->mctrl);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+       switch (state) {
+       case 0:
+               switch (port->type) {
+               case PORT_VR41XX_SIU:
+                       vr41xx_supply_clock(SIU_CLOCK);
+                       break;
+               case PORT_VR41XX_DSIU:
+                       vr41xx_supply_clock(DSIU_CLOCK);
+                       break;
+               }
+               break;
+       case 3:
+               switch (port->type) {
+               case PORT_VR41XX_SIU:
+                       vr41xx_mask_clock(SIU_CLOCK);
+                       break;
+               case PORT_VR41XX_DSIU:
+                       vr41xx_mask_clock(DSIU_CLOCK);
+                       break;
+               }
+               break;
+       }
+}
+
+static const char *siu_type(struct uart_port *port)
+{
+       return siu_type_name(port);
+}
+
+static void siu_release_port(struct uart_port *port)
+{
+       unsigned long size;
+
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+
+       size = siu_port_size(port);
+       release_mem_region(port->mapbase, size);
+}
+
+static int siu_request_port(struct uart_port *port)
+{
+       unsigned long size;
+       struct resource *res;
+
+       size = siu_port_size(port);
+       res = request_mem_region(port->mapbase, size, siu_type_name(port));
+       if (res == NULL)
+               return -EBUSY;
+
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_resource(res);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static void siu_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = siu_check_type(port);
+               (void)siu_request_port(port);
+       }
+}
+
+static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
+{
+       if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
+               return -EINVAL;
+       if (port->irq != serial->irq)
+               return -EINVAL;
+       if (port->iotype != serial->io_type)
+               return -EINVAL;
+       if (port->mapbase != (unsigned long)serial->iomem_base)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct uart_ops siu_uart_ops = {
+       .tx_empty       = siu_tx_empty,
+       .set_mctrl      = siu_set_mctrl,
+       .get_mctrl      = siu_get_mctrl,
+       .stop_tx        = siu_stop_tx,
+       .start_tx       = siu_start_tx,
+       .stop_rx        = siu_stop_rx,
+       .enable_ms      = siu_enable_ms,
+       .break_ctl      = siu_break_ctl,
+       .startup        = siu_startup,
+       .shutdown       = siu_shutdown,
+       .set_termios    = siu_set_termios,
+       .pm             = siu_pm,
+       .type           = siu_type,
+       .release_port   = siu_release_port,
+       .request_port   = siu_request_port,
+       .config_port    = siu_config_port,
+       .verify_port    = siu_verify_port,
+};
+
+static int siu_init_ports(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       struct resource *res;
+       int *type = pdev->dev.platform_data;
+       int i;
+
+       if (!type)
+               return 0;
+
+       port = siu_uart_ports;
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
+               port->type = type[i];
+               if (port->type == PORT_UNKNOWN)
+                       continue;
+               port->irq = platform_get_irq(pdev, i);
+               port->uartclk = SIU_BAUD_BASE * 16;
+               port->fifosize = 16;
+               port->regshift = 0;
+               port->iotype = UPIO_MEM;
+               port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+               port->line = i;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               port->mapbase = res->start;
+               port++;
+       }
+
+       return i;
+}
+
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+
+#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+       int timeout = 10000;
+       uint8_t lsr, msr;
+
+       do {
+               lsr = siu_read(port, UART_LSR);
+               if (lsr & UART_LSR_BI)
+                       lsr_break_flag[port->line] = UART_LSR_BI;
+
+               if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
+                       break;
+       } while (timeout-- > 0);
+
+       if (port->flags & UPF_CONS_FLOW) {
+               timeout = 1000000;
+
+               do {
+                       msr = siu_read(port, UART_MSR);
+                       if ((msr & UART_MSR_CTS) != 0)
+                               break;
+               } while (timeout-- > 0);
+       }
+}
+
+static void siu_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmitr(port);
+       siu_write(port, UART_TX, ch);
+}
+
+static void siu_console_write(struct console *con, const char *s, unsigned count)
+{
+       struct uart_port *port;
+       uint8_t ier;
+
+       port = &siu_uart_ports[con->index];
+
+       ier = siu_read(port, UART_IER);
+       siu_write(port, UART_IER, 0);
+
+       uart_console_write(port, s, count, siu_console_putchar);
+
+       wait_for_xmitr(port);
+       siu_write(port, UART_IER, ier);
+}
+
+static int __init siu_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int parity = 'n';
+       int bits = 8;
+       int flow = 'n';
+
+       if (con->index >= SIU_PORTS_MAX)
+               con->index = 0;
+
+       port = &siu_uart_ports[con->index];
+       if (port->membase == NULL) {
+               if (port->mapbase == 0)
+                       return -ENODEV;
+               port->membase = ioremap(port->mapbase, siu_port_size(port));
+       }
+
+       if (port->type == PORT_VR41XX_SIU)
+               vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+
+       if (options != NULL)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver siu_uart_driver;
+
+static struct console siu_console = {
+       .name   = "ttyVR",
+       .write  = siu_console_write,
+       .device = uart_console_device,
+       .setup  = siu_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &siu_uart_driver,
+};
+
+static int __devinit siu_console_init(void)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
+               port = &siu_uart_ports[i];
+               port->ops = &siu_uart_ops;
+       }
+
+       register_console(&siu_console);
+
+       return 0;
+}
+
+console_initcall(siu_console_init);
+
+void __init vr41xx_siu_early_setup(struct uart_port *port)
+{
+       if (port->type == PORT_UNKNOWN)
+               return;
+
+       siu_uart_ports[port->line].line = port->line;
+       siu_uart_ports[port->line].type = port->type;
+       siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].ops = &siu_uart_ops;
+}
+
+#define SERIAL_VR41XX_CONSOLE  &siu_console
+#else
+#define SERIAL_VR41XX_CONSOLE  NULL
+#endif
+
+static struct uart_driver siu_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "SIU",
+       .dev_name       = "ttyVR",
+       .major          = SIU_MAJOR,
+       .minor          = SIU_MINOR_BASE,
+       .cons           = SERIAL_VR41XX_CONSOLE,
+};
+
+static int __devinit siu_probe(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int num, i, retval;
+
+       num = siu_init_ports(dev);
+       if (num <= 0)
+               return -ENODEV;
+
+       siu_uart_driver.nr = num;
+       retval = uart_register_driver(&siu_uart_driver);
+       if (retval)
+               return retval;
+
+       for (i = 0; i < num; i++) {
+               port = &siu_uart_ports[i];
+               port->ops = &siu_uart_ops;
+               port->dev = &dev->dev;
+
+               retval = uart_add_one_port(&siu_uart_driver, port);
+               if (retval < 0) {
+                       port->dev = NULL;
+                       break;
+               }
+       }
+
+       if (i == 0 && retval < 0) {
+               uart_unregister_driver(&siu_uart_driver);
+               return retval;
+       }
+
+       return 0;
+}
+
+static int __devexit siu_remove(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if (port->dev == &dev->dev) {
+                       uart_remove_one_port(&siu_uart_driver, port);
+                       port->dev = NULL;
+               }
+       }
+
+       uart_unregister_driver(&siu_uart_driver);
+
+       return 0;
+}
+
+static int siu_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if ((port->type == PORT_VR41XX_SIU ||
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
+                       uart_suspend_port(&siu_uart_driver, port);
+
+       }
+
+       return 0;
+}
+
+static int siu_resume(struct platform_device *dev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; i < siu_uart_driver.nr; i++) {
+               port = &siu_uart_ports[i];
+               if ((port->type == PORT_VR41XX_SIU ||
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
+                       uart_resume_port(&siu_uart_driver, port);
+       }
+
+       return 0;
+}
+
+static struct platform_driver siu_device_driver = {
+       .probe          = siu_probe,
+       .remove         = __devexit_p(siu_remove),
+       .suspend        = siu_suspend,
+       .resume         = siu_resume,
+       .driver         = {
+               .name   = "SIU",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init vr41xx_siu_init(void)
+{
+       return platform_driver_register(&siu_device_driver);
+}
+
+static void __exit vr41xx_siu_exit(void)
+{
+       platform_driver_unregister(&siu_device_driver);
+}
+
+module_init(vr41xx_siu_init);
+module_exit(vr41xx_siu_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:SIU");
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
new file mode 100644 (file)
index 0000000..322bf56
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * drivers/serial/vt8500_serial.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on msm_serial.c, which is:
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/*
+ * UART Register offsets
+ */
+
+#define VT8500_URTDR           0x0000  /* Transmit data */
+#define VT8500_URRDR           0x0004  /* Receive data */
+#define VT8500_URDIV           0x0008  /* Clock/Baud rate divisor */
+#define VT8500_URLCR           0x000C  /* Line control */
+#define VT8500_URICR           0x0010  /* IrDA control */
+#define VT8500_URIER           0x0014  /* Interrupt enable */
+#define VT8500_URISR           0x0018  /* Interrupt status */
+#define VT8500_URUSR           0x001c  /* UART status */
+#define VT8500_URFCR           0x0020  /* FIFO control */
+#define VT8500_URFIDX          0x0024  /* FIFO index */
+#define VT8500_URBKR           0x0028  /* Break signal count */
+#define VT8500_URTOD           0x002c  /* Time out divisor */
+#define VT8500_TXFIFO          0x1000  /* Transmit FIFO (16x8) */
+#define VT8500_RXFIFO          0x1020  /* Receive FIFO (16x10) */
+
+/*
+ * Interrupt enable and status bits
+ */
+
+#define TXDE   (1 << 0)        /* Tx Data empty */
+#define RXDF   (1 << 1)        /* Rx Data full */
+#define TXFAE  (1 << 2)        /* Tx FIFO almost empty */
+#define TXFE   (1 << 3)        /* Tx FIFO empty */
+#define RXFAF  (1 << 4)        /* Rx FIFO almost full */
+#define RXFF   (1 << 5)        /* Rx FIFO full */
+#define TXUDR  (1 << 6)        /* Tx underrun */
+#define RXOVER (1 << 7)        /* Rx overrun */
+#define PER    (1 << 8)        /* Parity error */
+#define FER    (1 << 9)        /* Frame error */
+#define TCTS   (1 << 10)       /* Toggle of CTS */
+#define RXTOUT (1 << 11)       /* Rx timeout */
+#define BKDONE (1 << 12)       /* Break signal done */
+#define ERR    (1 << 13)       /* AHB error response */
+
+#define RX_FIFO_INTS   (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
+#define TX_FIFO_INTS   (TXFAE | TXFE | TXUDR)
+
+struct vt8500_port {
+       struct uart_port        uart;
+       char                    name[16];
+       struct clk              *clk;
+       unsigned int            ier;
+};
+
+static inline void vt8500_write(struct uart_port *port, unsigned int val,
+                            unsigned int off)
+{
+       writel(val, port->membase + off);
+}
+
+static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
+{
+       return readl(port->membase + off);
+}
+
+static void vt8500_stop_tx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_stop_rx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~RX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_enable_ms(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier |= TCTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+       if (!tty) {
+               /* Discard data: no tty available */
+               int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
+               u16 ch;
+               while (count--)
+                       ch = readw(port->membase + VT8500_RXFIFO);
+               return;
+       }
+
+       /*
+        * Handle overrun
+        */
+       if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+
+       /* and now the main RX loop */
+       while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
+               unsigned int c;
+               char flag = TTY_NORMAL;
+
+               c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
+
+               /* Mask conditions we're ignorning. */
+               c &= ~port->read_status_mask;
+
+               if (c & FER) {
+                       port->icount.frame++;
+                       flag = TTY_FRAME;
+               } else if (c & PER) {
+                       port->icount.parity++;
+                       flag = TTY_PARITY;
+               }
+               port->icount.rx++;
+
+               if (!uart_handle_sysrq_char(port, c))
+                       tty_insert_flip_char(tty, c, flag);
+       }
+
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               writeb(port->x_char, port->membase + VT8500_TXFIFO);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               vt8500_stop_tx(port);
+               return;
+       }
+
+       while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
+               if (uart_circ_empty(xmit))
+                       break;
+
+               writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               vt8500_stop_tx(port);
+}
+
+static void vt8500_start_tx(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port = container_of(port,
+                                                      struct vt8500_port,
+                                                      uart);
+
+       vt8500_port->ier &= ~TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+       handle_tx(port);
+       vt8500_port->ier |= TX_FIFO_INTS;
+       vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+       port->icount.cts++;
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t vt8500_irq(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       unsigned long isr;
+
+       spin_lock(&port->lock);
+       isr = vt8500_read(port, VT8500_URISR);
+
+       /* Acknowledge active status bits */
+       vt8500_write(port, isr, VT8500_URISR);
+
+       if (isr & RX_FIFO_INTS)
+               handle_rx(port);
+       if (isr & TX_FIFO_INTS)
+               handle_tx(port);
+       if (isr & TCTS)
+               handle_delta_cts(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int vt8500_tx_empty(struct uart_port *port)
+{
+       return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
+                                               TIOCSER_TEMT : 0;
+}
+
+static unsigned int vt8500_get_mctrl(struct uart_port *port)
+{
+       unsigned int usr;
+
+       usr = vt8500_read(port, VT8500_URUSR);
+       if (usr & (1 << 4))
+               return TIOCM_CTS;
+       else
+               return 0;
+}
+
+static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
+{
+       if (break_ctl)
+               vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+                            VT8500_URLCR);
+}
+
+static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+       unsigned long div;
+       unsigned int loops = 1000;
+
+       div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+
+       if (unlikely((baud < 900) || (baud > 921600)))
+               div |= 7;
+       else
+               div |= (921600 / baud) - 1;
+
+       while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
+               cpu_relax();
+       vt8500_write(port, div, VT8500_URDIV);
+
+       return baud;
+}
+
+static int vt8500_startup(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       int ret;
+
+       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+                "vt8500_serial%d", port->line);
+
+       ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
+                         vt8500_port->name, port);
+       if (unlikely(ret))
+               return ret;
+
+       vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */
+
+       return 0;
+}
+
+static void vt8500_shutdown(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+
+       vt8500_port->ier = 0;
+
+       /* disable interrupts and FIFOs */
+       vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
+       vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
+       free_irq(port->irq, port);
+}
+
+static void vt8500_set_termios(struct uart_port *port,
+                              struct ktermios *termios,
+                              struct ktermios *old)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       unsigned long flags;
+       unsigned int baud, lcr;
+       unsigned int loops = 1000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* calculate and set baud rate */
+       baud = uart_get_baud_rate(port, termios, old, 900, 921600);
+       baud = vt8500_set_baud_rate(port, baud);
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+
+       /* calculate parity */
+       lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
+       lcr &= ~((1 << 5) | (1 << 4));
+       if (termios->c_cflag & PARENB) {
+               lcr |= (1 << 4);
+               termios->c_cflag &= ~CMSPAR;
+               if (termios->c_cflag & PARODD)
+                       lcr |= (1 << 5);
+       }
+
+       /* calculate bits per char */
+       lcr &= ~(1 << 2);
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               break;
+       case CS8:
+       default:
+               lcr |= (1 << 2);
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= CS8;
+               break;
+       }
+
+       /* calculate stop bits */
+       lcr &= ~(1 << 3);
+       if (termios->c_cflag & CSTOPB)
+               lcr |= (1 << 3);
+
+       /* set parity, bits per char, and stop bit */
+       vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
+
+       /* Configure status bits to ignore based on termio flags. */
+       port->read_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->read_status_mask = FER | PER;
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /* Reset FIFOs */
+       vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
+       while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
+                                                       && --loops)
+               cpu_relax();
+
+       /* Every possible FIFO-related interrupt */
+       vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
+
+       /*
+        * CTS flow control
+        */
+       if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
+               vt8500_port->ier |= TCTS;
+
+       vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
+       vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *vt8500_type(struct uart_port *port)
+{
+       struct vt8500_port *vt8500_port =
+                       container_of(port, struct vt8500_port, uart);
+       return vt8500_port->name;
+}
+
+static void vt8500_release_port(struct uart_port *port)
+{
+}
+
+static int vt8500_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void vt8500_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_VT8500;
+}
+
+static int vt8500_verify_port(struct uart_port *port,
+                             struct serial_struct *ser)
+{
+       if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
+               return -EINVAL;
+       if (unlikely(port->irq != ser->irq))
+               return -EINVAL;
+       return 0;
+}
+
+static struct vt8500_port *vt8500_uart_ports[4];
+static struct uart_driver vt8500_uart_driver;
+
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = vt8500_read(port, VT8500_URFIDX);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while (status & 0x10);
+}
+
+static void vt8500_console_putchar(struct uart_port *port, int c)
+{
+       wait_for_xmitr(port);
+       writeb(c, port->membase + VT8500_TXFIFO);
+}
+
+static void vt8500_console_write(struct console *co, const char *s,
+                             unsigned int count)
+{
+       struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
+       unsigned long ier;
+
+       BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
+
+       ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
+       vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
+
+       uart_console_write(&vt8500_port->uart, s, count,
+                          vt8500_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and switch back to FIFO
+        */
+       wait_for_xmitr(&vt8500_port->uart);
+       vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
+}
+
+static int __init vt8500_console_setup(struct console *co, char *options)
+{
+       struct vt8500_port *vt8500_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
+               return -ENXIO;
+
+       vt8500_port = vt8500_uart_ports[co->index];
+
+       if (!vt8500_port)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&vt8500_port->uart,
+                                co, baud, parity, bits, flow);
+}
+
+static struct console vt8500_console = {
+       .name = "ttyWMT",
+       .write = vt8500_console_write,
+       .device = uart_console_device,
+       .setup = vt8500_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &vt8500_uart_driver,
+};
+
+#define VT8500_CONSOLE (&vt8500_console)
+
+#else
+#define VT8500_CONSOLE NULL
+#endif
+
+static struct uart_ops vt8500_uart_pops = {
+       .tx_empty       = vt8500_tx_empty,
+       .set_mctrl      = vt8500_set_mctrl,
+       .get_mctrl      = vt8500_get_mctrl,
+       .stop_tx        = vt8500_stop_tx,
+       .start_tx       = vt8500_start_tx,
+       .stop_rx        = vt8500_stop_rx,
+       .enable_ms      = vt8500_enable_ms,
+       .break_ctl      = vt8500_break_ctl,
+       .startup        = vt8500_startup,
+       .shutdown       = vt8500_shutdown,
+       .set_termios    = vt8500_set_termios,
+       .type           = vt8500_type,
+       .release_port   = vt8500_release_port,
+       .request_port   = vt8500_request_port,
+       .config_port    = vt8500_config_port,
+       .verify_port    = vt8500_verify_port,
+};
+
+static struct uart_driver vt8500_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "vt8500_serial",
+       .dev_name       = "ttyWMT",
+       .nr             = 6,
+       .cons           = VT8500_CONSOLE,
+};
+
+static int __init vt8500_serial_probe(struct platform_device *pdev)
+{
+       struct vt8500_port *vt8500_port;
+       struct resource *mmres, *irqres;
+       int ret;
+
+       mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
+       if (!vt8500_port)
+               return -ENOMEM;
+
+       vt8500_port->uart.type = PORT_VT8500;
+       vt8500_port->uart.iotype = UPIO_MEM;
+       vt8500_port->uart.mapbase = mmres->start;
+       vt8500_port->uart.irq = irqres->start;
+       vt8500_port->uart.fifosize = 16;
+       vt8500_port->uart.ops = &vt8500_uart_pops;
+       vt8500_port->uart.line = pdev->id;
+       vt8500_port->uart.dev = &pdev->dev;
+       vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       vt8500_port->uart.uartclk = 24000000;
+
+       snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+                "VT8500 UART%d", pdev->id);
+
+       vt8500_port->uart.membase = ioremap(mmres->start,
+                                           mmres->end - mmres->start + 1);
+       if (!vt8500_port->uart.membase) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       vt8500_uart_ports[pdev->id] = vt8500_port;
+
+       uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+
+       platform_set_drvdata(pdev, vt8500_port);
+
+       return 0;
+
+err:
+       kfree(vt8500_port);
+       return ret;
+}
+
+static int __devexit vt8500_serial_remove(struct platform_device *pdev)
+{
+       struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+       kfree(vt8500_port);
+
+       return 0;
+}
+
+static struct platform_driver vt8500_platform_driver = {
+       .probe  = vt8500_serial_probe,
+       .remove = vt8500_serial_remove,
+       .driver = {
+               .name = "vt8500_serial",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init vt8500_serial_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&vt8500_uart_driver);
+       if (unlikely(ret))
+               return ret;
+
+       ret = platform_driver_register(&vt8500_platform_driver);
+
+       if (unlikely(ret))
+               uart_unregister_driver(&vt8500_uart_driver);
+
+       return ret;
+}
+
+static void __exit vt8500_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+       unregister_console(&vt8500_console);
+#endif
+       platform_driver_unregister(&vt8500_platform_driver);
+       uart_unregister_driver(&vt8500_uart_driver);
+}
+
+module_init(vt8500_serial_init);
+module_exit(vt8500_serial_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("Driver for vt8500 serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
new file mode 100644 (file)
index 0000000..1a7fd3e
--- /dev/null
@@ -0,0 +1,1304 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4  signal        SCC
+ * 2     1     TxD       <-  A.TxD
+ * 3     4     RxD       ->  A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal        SCC
+ * 2     2     TxD       <-  B.TxD
+ * 3     5     RxD       ->  B.RxD
+ * 4           RTS       <- ~A.RTS
+ * 5           CTS       -> ~B.CTS
+ * 6     6     DSR       -> ~A.SYNC
+ * 8           CD        -> ~B.DCD
+ * 12          DSRS(DCE) -> ~A.CTS  (*)
+ * 15          TxC       ->  B.TxC
+ * 17          RxC       ->  B.RxC
+ * 20    1     DTR       <- ~A.DTR
+ * 22          RI        -> ~A.DCD
+ * 23          DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ *     is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd.  This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS    2               /* Max # of ZS chips supported.  */
+#define ZS_NUM_CHAN    2               /* 2 channels per chip.  */
+#define ZS_CHAN_A      0               /* Index of the channel A.  */
+#define ZS_CHAN_B      1               /* Index of the channel B.  */
+#define ZS_CHAN_IO_SIZE 8              /* IOMEM space size.  */
+#define ZS_CHAN_IO_STRIDE 4            /* Register alignment.  */
+#define ZS_CHAN_IO_OFFSET 1            /* The SCC resides on the high byte
+                                          of the 16-bit IOBUS.  */
+#define ZS_CLOCK        7372800        /* Z85C30 PCLK input clock rate.  */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+       resource_size_t scc[ZS_NUM_SCCS];
+       int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+       0,                              /* write 0 */
+       PAR_SPEC,                       /* write 1 */
+       0,                              /* write 2 */
+       0,                              /* write 3 */
+       X16CLK | SB1,                   /* write 4 */
+       0,                              /* write 5 */
+       0, 0, 0,                        /* write 6, 7, 8 */
+       MIE | DLC | NV,                 /* write 9 */
+       NRZ,                            /* write 10 */
+       TCBR | RCBR,                    /* write 11 */
+       0, 0,                           /* BRG time constant, write 12 + 13 */
+       BRSRC | BRENABL,                /* write 14 */
+       0,                              /* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+       udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob();
+               recovery_delay();
+       }
+       retval = readb(control);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+       void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+       if (reg != 0) {
+               writeb(reg & 0xf, control);
+               fast_iob(); recovery_delay();
+       }
+       writeb(value, control);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+       u8 retval;
+
+       retval = readb(data);
+       recovery_delay();
+       return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+       void __iomem *data = zport->port.membase +
+                            ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+       writeb(value, data);
+       fast_iob();
+       recovery_delay();
+       return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+       struct zs_port *zport;
+       int i, j;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+               if (!zport->scc)
+                       continue;
+
+               for (j = 0; j < 16; j++)
+                       printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+               printk("\n");
+               for (j = 0; j < 16; j++)
+                       printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+               printk("\n\n");
+       }
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_lock_irq(lock);
+       else
+               spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+       if (irq)
+               spin_unlock_irq(lock);
+       else
+               spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+       int loops = 10000;
+
+       while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops)
+               read_zsdata(zport);
+       return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+       struct zs_scc *scc = zport->scc;
+       int loops = 10000;
+
+       while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) {
+               zs_spin_unlock_cond_irq(&scc->zlock, irq);
+               udelay(2);
+               zs_spin_lock_cond_irq(&scc->zlock, irq);
+       }
+       return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+       /* Let the current transmission finish.  */
+       zs_line_drain(zport, irq);
+       /* Load 'em up.  */
+       write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+       write_zsreg(zport, R5, regs[5] & ~TxENAB);
+       write_zsreg(zport, R4, regs[4]);
+       write_zsreg(zport, R9, regs[9]);
+       write_zsreg(zport, R1, regs[1]);
+       write_zsreg(zport, R2, regs[2]);
+       write_zsreg(zport, R10, regs[10]);
+       write_zsreg(zport, R14, regs[14] & ~BRENABL);
+       write_zsreg(zport, R11, regs[11]);
+       write_zsreg(zport, R12, regs[12]);
+       write_zsreg(zport, R13, regs[13]);
+       write_zsreg(zport, R14, regs[14]);
+       write_zsreg(zport, R15, regs[15]);
+       if (regs[3] & RxENABLE)
+               write_zsreg(zport, R3, regs[3]);
+       if (regs[5] & TxENAB)
+               write_zsreg(zport, R5, regs[5]);
+       return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting.  This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space.
+ */
+static unsigned int zs_tx_empty(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 status;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       status = read_zsreg(zport, R1);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+                                       struct zs_port *zport_b)
+{
+       u8 status_a, status_b;
+       unsigned int mctrl;
+
+       status_a = read_zsreg(zport_a, R0);
+       status_b = read_zsreg(zport_b, R0);
+
+       mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+               ((status_b & DCD) ? TIOCM_CAR : 0) |
+               ((status_a & DCD) ? TIOCM_RNG : 0) |
+               ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+       return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+       return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+       struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+       unsigned int mmask, mctrl, delta;
+       u8 mask_a, mask_b;
+
+       if (zport == zport_a)
+               return 0;
+
+       mask_a = zport_a->regs[15];
+       mask_b = zport->regs[15];
+
+       mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+               ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+               ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+               ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+       mctrl = zport->mctrl;
+       if (mmask) {
+               mctrl &= ~mmask;
+               mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+       }
+
+       delta = mctrl ^ zport->mctrl;
+       if (delta)
+               zport->mctrl = mctrl;
+
+       return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned int mctrl;
+
+       spin_lock(&scc->zlock);
+       mctrl = zs_raw_get_mctrl(zport);
+       spin_unlock(&scc->zlock);
+
+       return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       u8 oldloop, newloop;
+
+       spin_lock(&scc->zlock);
+       if (zport != zport_a) {
+               if (mctrl & TIOCM_DTR)
+                       zport_a->regs[5] |= DTR;
+               else
+                       zport_a->regs[5] &= ~DTR;
+               if (mctrl & TIOCM_RTS)
+                       zport_a->regs[5] |= RTS;
+               else
+                       zport_a->regs[5] &= ~RTS;
+               write_zsreg(zport_a, R5, zport_a->regs[5]);
+       }
+
+       /* Rarely modified, so don't poke at hardware unless necessary. */
+       oldloop = zport->regs[14];
+       newloop = oldloop;
+       if (mctrl & TIOCM_LOOP)
+               newloop |= LOOPBAK;
+       else
+               newloop &= ~LOOPBAK;
+       if (newloop != oldloop) {
+               zport->regs[14] = newloop;
+               write_zsreg(zport, R14, zport->regs[14]);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+       write_zsreg(zport, R0, RES_Tx_P);
+       zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_stop_tx(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       if (zport->tx_stopped) {
+               zs_transmit_drain(zport, 0);
+               zport->tx_stopped = 0;
+               zs_raw_transmit_chars(zport);
+       }
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       spin_lock(&scc->zlock);
+       zport->regs[15] &= ~BRKIE;
+       zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+       zport->regs[1] |= RxINT_DISAB;
+
+       if (zport != zport_a) {
+               /* A-side DCD tracks RI and SYNC tracks DSR.  */
+               zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+               write_zsreg(zport_a, R15, zport_a->regs[15]);
+               if (!(zport_a->regs[15] & BRKIE)) {
+                       zport_a->regs[1] &= ~EXT_INT_ENAB;
+                       write_zsreg(zport_a, R1, zport_a->regs[1]);
+               }
+
+               /* This-side DCD tracks DCD and CTS tracks CTS.  */
+               zport->regs[15] &= ~(DCDIE | CTSIE);
+               zport->regs[1] &= ~EXT_INT_ENAB;
+       } else {
+               /* DCD tracks RI and SYNC tracks DSR for the B side.  */
+               if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+                       zport->regs[1] &= ~EXT_INT_ENAB;
+       }
+
+       write_zsreg(zport, R15, zport->regs[15]);
+       write_zsreg(zport, R1, zport->regs[1]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+       if (zport == zport_a)
+               return;
+
+       spin_lock(&scc->zlock);
+
+       /* Clear Ext interrupts if not being handled already.  */
+       if (!(zport_a->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport_a, R0, RES_EXT_INT);
+
+       /* A-side DCD tracks RI and SYNC tracks DSR.  */
+       zport_a->regs[1] |= EXT_INT_ENAB;
+       zport_a->regs[15] |= DCDIE | SYNCIE;
+
+       /* This-side DCD tracks DCD and CTS tracks CTS.  */
+       zport->regs[15] |= DCDIE | CTSIE;
+
+       zs_raw_xor_mctrl(zport);
+
+       write_zsreg(zport_a, R1, zport_a->regs[1]);
+       write_zsreg(zport_a, R15, zport_a->regs[15]);
+       write_zsreg(zport, R15, zport->regs[15]);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       if (break_state == -1)
+               zport->regs[5] |= SND_BRK;
+       else
+               zport->regs[5] &= ~SND_BRK;
+       write_zsreg(zport, R5, zport->regs[5]);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100                  /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                  /* SysRq event software flag.  */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       struct uart_icount *icount;
+       unsigned int avail, status, ch, flag;
+       int count;
+
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               avail = read_zsreg(zport, R0) & Rx_CH_AV;
+               spin_unlock(&scc->zlock);
+               if (!avail)
+                       break;
+
+               spin_lock(&scc->zlock);
+               status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+               ch = read_zsdata(zport);
+               spin_unlock(&scc->zlock);
+
+               flag = TTY_NORMAL;
+
+               icount = &uport->icount;
+               icount->rx++;
+
+               /* Handle the null char got when BREAK is removed.  */
+               if (!ch)
+                       status |= zport->tty_break;
+               if (unlikely(status &
+                            (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+                       zport->tty_break = 0;
+
+                       /* Reset the error indication.  */
+                       if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+                               spin_lock(&scc->zlock);
+                               write_zsreg(zport, R0, ERR_RES);
+                               spin_unlock(&scc->zlock);
+                       }
+
+                       if (status & (Rx_SYS | Rx_BRK)) {
+                               icount->brk++;
+                               /* SysRq discards the null char.  */
+                               if (status & Rx_SYS)
+                                       continue;
+                       } else if (status & FRM_ERR)
+                               icount->frame++;
+                       else if (status & PAR_ERR)
+                               icount->parity++;
+                       if (status & Rx_OVR)
+                               icount->overrun++;
+
+                       status &= uport->read_status_mask;
+                       if (status & Rx_BRK)
+                               flag = TTY_BREAK;
+                       else if (status & FRM_ERR)
+                               flag = TTY_FRAME;
+                       else if (status & PAR_ERR)
+                               flag = TTY_PARITY;
+               }
+
+               if (uart_handle_sysrq_char(uport, ch))
+                       continue;
+
+               uart_insert_char(uport, status, Rx_OVR, ch, flag);
+       }
+
+       tty_flip_buffer_push(uport->state->port.tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+       struct circ_buf *xmit = &zport->port.state->xmit;
+
+       /* XON/XOFF chars.  */
+       if (zport->port.x_char) {
+               write_zsdata(zport, zport->port.x_char);
+               zport->port.icount.tx++;
+               zport->port.x_char = 0;
+               return;
+       }
+
+       /* If nothing to do or stopped or hardware stopped.  */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+               zs_raw_stop_tx(zport);
+               return;
+       }
+
+       /* Send char.  */
+       write_zsdata(zport, xmit->buf[xmit->tail]);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+       zport->port.icount.tx++;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&zport->port);
+
+       /* Are we are done?  */
+       if (uart_circ_empty(xmit))
+               zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+
+       spin_lock(&scc->zlock);
+       zs_raw_transmit_chars(zport);
+       spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+       struct uart_port *uport = &zport->port;
+       struct zs_scc *scc = zport->scc;
+       unsigned int delta;
+       u8 status, brk;
+
+       spin_lock(&scc->zlock);
+
+       /* Get status from Read Register 0.  */
+       status = read_zsreg(zport, R0);
+
+       if (zport->regs[15] & BRKIE) {
+               brk = status & BRK_ABRT;
+               if (brk && !zport->brk) {
+                       spin_unlock(&scc->zlock);
+                       if (uart_handle_break(uport))
+                               zport->tty_break = Rx_SYS;
+                       else
+                               zport->tty_break = Rx_BRK;
+                       spin_lock(&scc->zlock);
+               }
+               zport->brk = brk;
+       }
+
+       if (zport != zport_a) {
+               delta = zs_raw_xor_mctrl(zport);
+               spin_unlock(&scc->zlock);
+
+               if (delta & TIOCM_CTS)
+                       uart_handle_cts_change(uport,
+                                              zport->mctrl & TIOCM_CTS);
+               if (delta & TIOCM_CAR)
+                       uart_handle_dcd_change(uport,
+                                              zport->mctrl & TIOCM_CAR);
+               if (delta & TIOCM_RNG)
+                       uport->icount.dsr++;
+               if (delta & TIOCM_DSR)
+                       uport->icount.rng++;
+
+               if (delta)
+                       wake_up_interruptible(&uport->state->port.delta_msr_wait);
+
+               spin_lock(&scc->zlock);
+       }
+
+       /* Clear the status condition...  */
+       write_zsreg(zport, R0, RES_EXT_INT);
+
+       spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+       struct zs_scc *scc = dev_id;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+       irqreturn_t status = IRQ_NONE;
+       u8 zs_intreg;
+       int count;
+
+       /*
+        * NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+       for (count = 16; count; count--) {
+               spin_lock(&scc->zlock);
+               zs_intreg = read_zsreg(zport_a, R3);
+               spin_unlock(&scc->zlock);
+               if (!zs_intreg)
+                       break;
+
+               /*
+                * We do not like losing characters, so we prioritise
+                * interrupt sources a little bit differently than
+                * the SCC would, was it allowed to.
+                */
+               if (zs_intreg & CHBRxIP)
+                       zs_receive_chars(zport_b);
+               if (zs_intreg & CHARxIP)
+                       zs_receive_chars(zport_a);
+               if (zs_intreg & CHBEXT)
+                       zs_status_handle(zport_b, zport_a);
+               if (zs_intreg & CHAEXT)
+                       zs_status_handle(zport_a, zport_a);
+               if (zs_intreg & CHBTxIP)
+                       zs_transmit_chars(zport_b);
+               if (zs_intreg & CHATxIP)
+                       zs_transmit_chars(zport_a);
+
+               status = IRQ_HANDLED;
+       }
+
+       return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+       int ret;
+
+       irq_guard = atomic_add_return(1, &scc->irq_guard);
+       if (irq_guard == 1) {
+               ret = request_irq(zport->port.irq, zs_interrupt,
+                                 IRQF_SHARED, "scc", scc);
+               if (ret) {
+                       atomic_add(-1, &scc->irq_guard);
+                       printk(KERN_ERR "zs: can't get irq %d\n",
+                              zport->port.irq);
+                       return ret;
+               }
+       }
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       /* Clear the receive FIFO.  */
+       zs_receive_drain(zport);
+
+       /* Clear the interrupt registers.  */
+       write_zsreg(zport, R0, ERR_RES);
+       write_zsreg(zport, R0, RES_Tx_P);
+       /* But Ext only if not being handled already.  */
+       if (!(zport->regs[1] & EXT_INT_ENAB))
+               write_zsreg(zport, R0, RES_EXT_INT);
+
+       /* Finally, enable sequencing and interrupts.  */
+       zport->regs[1] &= ~RxINT_MASK;
+       zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+       zport->regs[3] |= RxENABLE;
+       zport->regs[15] |= BRKIE;
+       write_zsreg(zport, R1, zport->regs[1]);
+       write_zsreg(zport, R3, zport->regs[3]);
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R15, zport->regs[15]);
+
+       /* Record the current state of RR0.  */
+       zport->mctrl = zs_raw_get_mctrl(zport);
+       zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+       zport->tx_stopped = 1;
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       int irq_guard;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+
+       zport->regs[3] &= ~RxENABLE;
+       write_zsreg(zport, R5, zport->regs[5]);
+       write_zsreg(zport, R3, zport->regs[3]);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       irq_guard = atomic_add_return(-1, &scc->irq_guard);
+       if (!irq_guard)
+               free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (!scc->initialised) {
+               /* Reset the pointer first, just in case...  */
+               read_zsreg(zport, R0);
+               /* And let the current transmission finish.  */
+               zs_line_drain(zport, irq);
+               write_zsreg(zport, R9, FHWRES);
+               udelay(10);
+               write_zsreg(zport, R9, 0);
+               scc->initialised = 1;
+       }
+       load_zsregs(zport, zport->regs, irq);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+                          struct ktermios *old_termios)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+       int irq;
+       unsigned int baud, brg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+
+       /* Byte size.  */
+       zport->regs[3] &= ~RxNBITS_MASK;
+       zport->regs[5] &= ~TxNBITS_MASK;
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               zport->regs[3] |= Rx5;
+               zport->regs[5] |= Tx5;
+               break;
+       case CS6:
+               zport->regs[3] |= Rx6;
+               zport->regs[5] |= Tx6;
+               break;
+       case CS7:
+               zport->regs[3] |= Rx7;
+               zport->regs[5] |= Tx7;
+               break;
+       case CS8:
+       default:
+               zport->regs[3] |= Rx8;
+               zport->regs[5] |= Tx8;
+               break;
+       }
+
+       /* Parity and stop bits.  */
+       zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+       if (termios->c_cflag & CSTOPB)
+               zport->regs[4] |= SB2;
+       else
+               zport->regs[4] |= SB1;
+       if (termios->c_cflag & PARENB)
+               zport->regs[4] |= PAR_ENA;
+       if (!(termios->c_cflag & PARODD))
+               zport->regs[4] |= PAR_EVEN;
+       switch (zport->clk_mode) {
+       case 64:
+               zport->regs[4] |= X64CLK;
+               break;
+       case 32:
+               zport->regs[4] |= X32CLK;
+               break;
+       case 16:
+               zport->regs[4] |= X16CLK;
+               break;
+       case 1:
+               zport->regs[4] |= X1CLK;
+               break;
+       default:
+               BUG();
+       }
+
+       baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+                                 uport->uartclk / zport->clk_mode / 4);
+
+       brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+       zport->regs[12] = brg & 0xff;
+       zport->regs[13] = (brg >> 8) & 0xff;
+
+       uart_update_timeout(uport, termios->c_cflag, baud);
+
+       uport->read_status_mask = Rx_OVR;
+       if (termios->c_iflag & INPCK)
+               uport->read_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               uport->read_status_mask |= Rx_BRK;
+
+       uport->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+       if (termios->c_iflag & IGNBRK) {
+               uport->ignore_status_mask |= Rx_BRK;
+               if (termios->c_iflag & IGNPAR)
+                       uport->ignore_status_mask |= Rx_OVR;
+       }
+
+       if (termios->c_cflag & CREAD)
+               zport->regs[3] |= RxENABLE;
+       else
+               zport->regs[3] &= ~RxENABLE;
+
+       if (zport != zport_a) {
+               if (!(termios->c_cflag & CLOCAL)) {
+                       zport->regs[15] |= DCDIE;
+               } else
+                       zport->regs[15] &= ~DCDIE;
+               if (termios->c_cflag & CRTSCTS) {
+                       zport->regs[15] |= CTSIE;
+               } else
+                       zport->regs[15] &= ~CTSIE;
+               zs_raw_xor_mctrl(zport);
+       }
+
+       /* Load up the new values.  */
+       load_zsregs(zport, zport->regs, irq);
+
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Hack alert!
+ * Required solely so that the initial PROM-based console
+ * works undisturbed in parallel with this one.
+ */
+static void zs_pm(struct uart_port *uport, unsigned int state,
+                 unsigned int oldstate)
+{
+       struct zs_port *zport = to_zport(uport);
+
+       if (state < 3)
+               zport->regs[5] |= TxENAB;
+       else
+               zport->regs[5] &= ~TxENAB;
+       write_zsreg(zport, R5, zport->regs[5]);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+       return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+       iounmap(uport->membase);
+       uport->membase = 0;
+       release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+       if (!uport->membase)
+               uport->membase = ioremap_nocache(uport->mapbase,
+                                                ZS_CHAN_IO_SIZE);
+       if (!uport->membase) {
+               printk(KERN_ERR "zs: Cannot map MMIO\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+       int ret;
+
+       if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+               printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+               return -EBUSY;
+       }
+       ret = zs_map_port(uport);
+       if (ret) {
+               release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+               return ret;
+       }
+       return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+       struct zs_port *zport = to_zport(uport);
+
+       if (flags & UART_CONFIG_TYPE) {
+               if (zs_request_port(uport))
+                       return;
+
+               uport->type = PORT_ZS;
+
+               zs_reset(zport);
+       }
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+       struct zs_port *zport = to_zport(uport);
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+               ret = -EINVAL;
+       if (ser->irq != uport->irq)
+               ret = -EINVAL;
+       if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+               ret = -EINVAL;
+       return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+       .tx_empty       = zs_tx_empty,
+       .set_mctrl      = zs_set_mctrl,
+       .get_mctrl      = zs_get_mctrl,
+       .stop_tx        = zs_stop_tx,
+       .start_tx       = zs_start_tx,
+       .stop_rx        = zs_stop_rx,
+       .enable_ms      = zs_enable_ms,
+       .break_ctl      = zs_break_ctl,
+       .startup        = zs_startup,
+       .shutdown       = zs_shutdown,
+       .set_termios    = zs_set_termios,
+       .pm             = zs_pm,
+       .type           = zs_type,
+       .release_port   = zs_release_port,
+       .request_port   = zs_request_port,
+       .config_port    = zs_config_port,
+       .verify_port    = zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+       static int probed;
+       struct zs_parms zs_parms;
+       int chip, side, irq;
+       int n_chips = 0;
+       int i;
+
+       if (probed)
+               return 0;
+
+       irq = dec_interrupt[DEC_IRQ_SCC0];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC0;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+               n_chips++;
+       }
+       irq = dec_interrupt[DEC_IRQ_SCC1];
+       if (irq >= 0) {
+               zs_parms.scc[n_chips] = IOASIC_SCC1;
+               zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+               n_chips++;
+       }
+       if (!n_chips)
+               return -ENXIO;
+
+       probed = 1;
+
+       for (chip = 0; chip < n_chips; chip++) {
+               spin_lock_init(&zs_sccs[chip].zlock);
+               for (side = 0; side < ZS_NUM_CHAN; side++) {
+                       struct zs_port *zport = &zs_sccs[chip].zport[side];
+                       struct uart_port *uport = &zport->port;
+
+                       zport->scc      = &zs_sccs[chip];
+                       zport->clk_mode = 16;
+
+                       uport->irq      = zs_parms.irq[chip];
+                       uport->uartclk  = ZS_CLOCK;
+                       uport->fifosize = 1;
+                       uport->iotype   = UPIO_MEM;
+                       uport->flags    = UPF_BOOT_AUTOCONF;
+                       uport->ops      = &zs_ops;
+                       uport->line     = chip * ZS_NUM_CHAN + side;
+                       uport->mapbase  = dec_kn_slot_base +
+                                         zs_parms.scc[chip] +
+                                         (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+                       for (i = 0; i < ZS_NUM_REGS; i++)
+                               zport->regs[i] = zs_init_regs[i];
+               }
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+       struct zs_port *zport = to_zport(uport);
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       if (zs_transmit_drain(zport, irq))
+               write_zsdata(zport, ch);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+                            unsigned int count)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct zs_scc *scc = zport->scc;
+       unsigned long flags;
+       u8 txint, txenb;
+       int irq;
+
+       /* Disable transmit interrupts and enable the transmitter. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       txint = zport->regs[1];
+       txenb = zport->regs[5];
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] = txint & ~TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] = txenb | TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+
+       uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+       /* Restore transmit interrupts and the transmitter enable. */
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+       zs_line_drain(zport, irq);
+       if (!(txenb & TxENAB)) {
+               zport->regs[5] &= ~TxENAB;
+               write_zsreg(zport, R5, zport->regs[5]);
+       }
+       if (txint & TxINT_ENAB) {
+               zport->regs[1] |= TxINT_ENAB;
+               write_zsreg(zport, R1, zport->regs[1]);
+       }
+       spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity.  We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+       int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+       struct zs_port *zport = &zs_sccs[chip].zport[side];
+       struct uart_port *uport = &zport->port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       ret = zs_map_port(uport);
+       if (ret)
+               return ret;
+
+       zs_reset(zport);
+       zs_pm(uport, 0, -1);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+       .name   = "ttyS",
+       .write  = zs_console_write,
+       .device = uart_console_device,
+       .setup  = zs_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+       .data   = &zs_reg,
+};
+
+/*
+ *     Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+       int ret;
+
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+       register_console(&zs_console);
+
+       return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE      &zs_console
+#else
+#define SERIAL_ZS_CONSOLE      NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "serial",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = ZS_NUM_SCCS * ZS_NUM_CHAN,
+       .cons                   = SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+       int i, ret;
+
+       pr_info("%s%s\n", zs_name, zs_version);
+
+       /* Find out how many Z85C30 SCCs we have.  */
+       ret = zs_probe_sccs();
+       if (ret)
+               return ret;
+
+       ret = uart_register_driver(&zs_reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_add_one_port(&zs_reg, uport);
+       }
+
+       return 0;
+}
+
+static void __exit zs_exit(void)
+{
+       int i;
+
+       for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+               struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+               struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+               struct uart_port *uport = &zport->port;
+
+               if (zport->scc)
+                       uart_remove_one_port(&zs_reg, uport);
+       }
+
+       uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/tty/serial/zs.h b/drivers/tty/serial/zs.h
new file mode 100644 (file)
index 0000000..aa921b5
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+       struct zs_scc   *scc;                   /* Containing SCC.  */
+       struct uart_port port;                  /* Underlying UART.  */
+
+       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
+
+       unsigned int    tty_break;              /* Set on BREAK condition.  */
+       int             tx_stopped;             /* Output is suspended.  */
+
+       unsigned int    mctrl;                  /* State of modem lines.  */
+       u8              brk;                    /* BREAK state from RR0.  */
+
+       u8              regs[ZS_NUM_REGS];      /* Channel write registers.  */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+       struct zs_port  zport[2];
+       spinlock_t      zlock;
+       atomic_t        irq_guard;
+       int             initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#define R0             0       /* Register selects */
+#define R1             1
+#define R2             2
+#define R3             3
+#define R4             4
+#define R5             5
+#define R6             6
+#define R7             7
+#define R8             8
+#define R9             9
+#define R10            10
+#define R11            11
+#define R12            12
+#define R13            13
+#define R14            14
+#define R15            15
+
+#define NULLCODE       0       /* Null Code */
+#define POINT_HIGH     0x8     /* Select upper half of registers */
+#define RES_EXT_INT    0x10    /* Reset Ext. Status Interrupts */
+#define SEND_ABORT     0x18    /* HDLC Abort */
+#define RES_RxINT_FC   0x20    /* Reset RxINT on First Character */
+#define RES_Tx_P       0x28    /* Reset TxINT Pending */
+#define ERR_RES                0x30    /* Error Reset */
+#define RES_H_IUS      0x38    /* Reset highest IUS */
+
+#define RES_Rx_CRC     0x40    /* Reset Rx CRC Checker */
+#define RES_Tx_CRC     0x80    /* Reset Tx CRC Checker */
+#define RES_EOM_L      0xC0    /* Reset EOM latch */
+
+/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#define EXT_INT_ENAB   0x1     /* Ext Int Enable */
+#define TxINT_ENAB     0x2     /* Tx Int Enable */
+#define PAR_SPEC       0x4     /* Parity is special condition */
+
+#define RxINT_DISAB    0       /* Rx Int Disable */
+#define RxINT_FCERR    0x8     /* Rx Int on First Character Only or Error */
+#define RxINT_ALL      0x10    /* Int on all Rx Characters or error */
+#define RxINT_ERR      0x18    /* Int on error only */
+#define RxINT_MASK     0x18
+
+#define WT_RDY_RT      0x20    /* Wait/Ready on R/T */
+#define WT_FN_RDYFN    0x40    /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB    0x80    /* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#define RxENABLE       0x1     /* Rx Enable */
+#define SYNC_L_INH     0x2     /* Sync Character Load Inhibit */
+#define ADD_SM         0x4     /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB     0x8     /* Rx CRC Enable */
+#define ENT_HM         0x10    /* Enter Hunt Mode */
+#define AUTO_ENAB      0x20    /* Auto Enables */
+#define Rx5            0x0     /* Rx 5 Bits/Character */
+#define Rx7            0x40    /* Rx 7 Bits/Character */
+#define Rx6            0x80    /* Rx 6 Bits/Character */
+#define Rx8            0xc0    /* Rx 8 Bits/Character */
+#define RxNBITS_MASK   0xc0
+
+/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#define PAR_ENA                0x1     /* Parity Enable */
+#define PAR_EVEN       0x2     /* Parity Even/Odd* */
+
+#define SYNC_ENAB      0       /* Sync Modes Enable */
+#define SB1            0x4     /* 1 stop bit/char */
+#define SB15           0x8     /* 1.5 stop bits/char */
+#define SB2            0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define MONSYNC                0       /* 8 Bit Sync character */
+#define BISYNC         0x10    /* 16 bit sync character */
+#define SDLC           0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC                0x30    /* External Sync Mode */
+
+#define X1CLK          0x0     /* x1 clock mode */
+#define X16CLK         0x40    /* x16 clock mode */
+#define X32CLK         0x80    /* x32 clock mode */
+#define X64CLK         0xc0    /* x64 clock mode */
+#define XCLK_MASK      0xc0
+
+/* Write Register 5 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB     0x1     /* Tx CRC Enable */
+#define RTS            0x2     /* RTS */
+#define SDLC_CRC       0x4     /* SDLC/CRC-16 */
+#define TxENAB         0x8     /* Tx Enable */
+#define SND_BRK                0x10    /* Send Break */
+#define Tx5            0x0     /* Tx 5 bits (or less)/character */
+#define Tx7            0x20    /* Tx 7 bits/character */
+#define Tx6            0x40    /* Tx 6 bits/character */
+#define Tx8            0x60    /* Tx 8 bits/character */
+#define TxNBITS_MASK   0x60
+#define DTR            0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS            1       /* Vector Includes Status */
+#define NV             2       /* No Vector */
+#define DLC            4       /* Disable Lower Chain */
+#define MIE            8       /* Master Interrupt Enable */
+#define STATHI         0x10    /* Status high */
+#define SOFTACK                0x20    /* Software Interrupt Acknowledge */
+#define NORESET                0       /* No reset on write to R9 */
+#define CHRB           0x40    /* Reset channel B */
+#define CHRA           0x80    /* Reset channel A */
+#define FHWRES         0xc0    /* Force hardware reset */
+
+/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
+#define BIT6           1       /* 6 bit/8bit sync */
+#define LOOPMODE       2       /* SDLC Loop mode */
+#define ABUNDER                4       /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE       8       /* Mark/flag on idle */
+#define GAOP           0x10    /* Go active on poll */
+#define NRZ            0       /* NRZ mode */
+#define NRZI           0x20    /* NRZI mode */
+#define FM1            0x40    /* FM1 (transition = 1) */
+#define FM0            0x60    /* FM0 (transition = 0) */
+#define CRCPS          0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode Control) */
+#define TRxCXT         0       /* TRxC = Xtal output */
+#define TRxCTC         1       /* TRxC = Transmit clock */
+#define TRxCBR         2       /* TRxC = BR Generator Output */
+#define TRxCDP         3       /* TRxC = DPLL output */
+#define TRxCOI         4       /* TRxC O/I */
+#define TCRTxCP                0       /* Transmit clock = RTxC pin */
+#define TCTRxCP                8       /* Transmit clock = TRxC pin */
+#define TCBR           0x10    /* Transmit clock = BR Generator output */
+#define TCDPLL         0x18    /* Transmit clock = DPLL output */
+#define RCRTxCP                0       /* Receive clock = RTxC pin */
+#define RCTRxCP                0x20    /* Receive clock = TRxC pin */
+#define RCBR           0x40    /* Receive clock = BR Generator output */
+#define RCDPLL         0x60    /* Receive clock = DPLL output */
+#define RTxCX          0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 14 (Miscellaneous Control Bits) */
+#define BRENABL                1       /* Baud rate generator enable */
+#define BRSRC          2       /* Baud rate generator source */
+#define DTRREQ         4       /* DTR/Request function */
+#define AUTOECHO       8       /* Auto Echo */
+#define LOOPBAK                0x10    /* Local loopback */
+#define SEARCH         0x20    /* Enter search mode */
+#define RMC            0x40    /* Reset missing clock */
+#define DISDPLL                0x60    /* Disable DPLL */
+#define SSBR           0x80    /* Set DPLL source = BR generator */
+#define SSRTxC         0xa0    /* Set DPLL source = RTxC */
+#define SFMM           0xc0    /* Set FM mode */
+#define SNRZI          0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (External/Status Interrupt Control) */
+#define WR7P_EN                1       /* WR7 Prime SDLC Feature Enable */
+#define ZCIE           2       /* Zero count IE */
+#define DCDIE          8       /* DCD IE */
+#define SYNCIE         0x10    /* Sync/hunt IE */
+#define CTSIE          0x20    /* CTS IE */
+#define TxUIE          0x40    /* Tx Underrun/EOM IE */
+#define BRKIE          0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#define Rx_CH_AV       0x1     /* Rx Character Available */
+#define ZCOUNT         0x2     /* Zero count */
+#define Tx_BUF_EMP     0x4     /* Tx Buffer empty */
+#define DCD            0x8     /* DCD */
+#define SYNC_HUNT      0x10    /* Sync/hunt */
+#define CTS            0x20    /* CTS */
+#define TxEOM          0x40    /* Tx underrun */
+#define BRK_ABRT       0x80    /* Break/Abort */
+
+/* Read Register 1 (Special Receive Condition Status) */
+#define ALL_SNT                0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3           0x8     /* 0/3 */
+#define RES4           0x4     /* 0/4 */
+#define RES5           0xc     /* 0/5 */
+#define RES6           0x2     /* 0/6 */
+#define RES7           0xa     /* 0/7 */
+#define RES8           0x6     /* 0/8 */
+#define RES18          0xe     /* 1/8 */
+#define RES28          0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR                0x10    /* Parity Error */
+#define Rx_OVR         0x20    /* Rx Overrun Error */
+#define FRM_ERR                0x40    /* CRC/Framing Error */
+#define END_FR         0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (Interrupt Vector (WR2) -- channel A).  */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel A only).  */
+#define CHBEXT         0x1     /* Channel B Ext/Stat IP */
+#define CHBTxIP                0x2     /* Channel B Tx IP */
+#define CHBRxIP                0x4     /* Channel B Rx IP */
+#define CHAEXT         0x8     /* Channel A Ext/Stat IP */
+#define CHATxIP                0x10    /* Channel A Tx IP */
+#define CHARxIP                0x20    /* Channel A Rx IP */
+
+/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous Status Bits) */
+#define ONLOOP         2       /* On loop */
+#define LOOPSEND       0x10    /* Loop sending */
+#define CLK2MIS                0x40    /* Two clocks missing */
+#define CLK1MIS                0x80    /* One clock missing */
+
+/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
index c556ed9..81f1395 100644 (file)
@@ -46,7 +46,7 @@
 #include <asm/irq_regs.h>
 
 /* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
+static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
 static bool sysrq_on(void)
@@ -571,6 +571,7 @@ struct sysrq_state {
        unsigned int alt_use;
        bool active;
        bool need_reinject;
+       bool reinjecting;
 };
 
 static void sysrq_reinject_alt_sysrq(struct work_struct *work)
@@ -581,6 +582,10 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
        unsigned int alt_code = sysrq->alt_use;
 
        if (sysrq->need_reinject) {
+               /* we do not want the assignment to be reordered */
+               sysrq->reinjecting = true;
+               mb();
+
                /* Simulate press and release of Alt + SysRq */
                input_inject_event(handle, EV_KEY, alt_code, 1);
                input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
@@ -589,6 +594,9 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
                input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
                input_inject_event(handle, EV_KEY, alt_code, 0);
                input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+
+               mb();
+               sysrq->reinjecting = false;
        }
 }
 
@@ -599,6 +607,13 @@ static bool sysrq_filter(struct input_handle *handle,
        bool was_active = sysrq->active;
        bool suppress;
 
+       /*
+        * Do not filter anything if we are in the process of re-injecting
+        * Alt+SysRq combination.
+        */
+       if (sysrq->reinjecting)
+               return false;
+
        switch (type) {
 
        case EV_SYN:
@@ -629,7 +644,7 @@ static bool sysrq_filter(struct input_handle *handle,
                                sysrq->alt_use = sysrq->alt;
                                /*
                                 * If nothing else will be pressed we'll need
-                                * to * re-inject Alt-SysRq keysroke.
+                                * to re-inject Alt-SysRq keysroke.
                                 */
                                sysrq->need_reinject = true;
                        }
index 464d09d..0065da4 100644 (file)
@@ -3256,8 +3256,8 @@ static ssize_t show_cons_active(struct device *dev,
        struct console *c;
        ssize_t count = 0;
 
-       acquire_console_sem();
-       for (c = console_drivers; c; c = c->next) {
+       console_lock();
+       for_each_console(c) {
                if (!c->device)
                        continue;
                if (!c->write)
@@ -3271,7 +3271,7 @@ static ssize_t show_cons_active(struct device *dev,
        while (i--)
                count += sprintf(buf + count, "%s%d%c",
                                 cs[i]->name, cs[i]->index, i ? ' ':'\n');
-       release_console_sem();
+       console_unlock();
 
        return count;
 }
@@ -3306,7 +3306,7 @@ int __init tty_init(void)
        if (IS_ERR(consdev))
                consdev = NULL;
        else
-               device_create_file(consdev, &dev_attr_active);
+               WARN_ON(device_create_file(consdev, &dev_attr_active) < 0);
 
 #ifdef CONFIG_VT
        vty_init(&console_fops);
index ebae344..c956ed6 100644 (file)
@@ -316,9 +316,9 @@ int paste_selection(struct tty_struct *tty)
        /* always called with BTM from vt_ioctl */
        WARN_ON(!tty_locked());
 
-       acquire_console_sem();
+       console_lock();
        poke_blanked_console();
-       release_console_sem();
+       console_unlock();
 
        ld = tty_ldisc_ref(tty);
        if (!ld) {
index eab3a1f..a672ed1 100644 (file)
@@ -202,7 +202,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        /* Select the proper current console and verify
         * sanity of the situation under the console lock.
         */
-       acquire_console_sem();
+       console_lock();
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
@@ -336,9 +336,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                 * the pagefault handling code may want to call printk().
                 */
 
-               release_console_sem();
+               console_unlock();
                ret = copy_to_user(buf, con_buf_start, orig_count);
-               acquire_console_sem();
+               console_lock();
 
                if (ret) {
                        read += (orig_count - ret);
@@ -354,7 +354,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        if (read)
                ret = read;
 unlock_out:
-       release_console_sem();
+       console_unlock();
        mutex_unlock(&con_buf_mtx);
        return ret;
 }
@@ -379,7 +379,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
        /* Select the proper current console and verify
         * sanity of the situation under the console lock.
         */
-       acquire_console_sem();
+       console_lock();
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
@@ -414,9 +414,9 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
                /* Temporarily drop the console lock so that we can read
                 * in the write data from userspace safely.
                 */
-               release_console_sem();
+               console_unlock();
                ret = copy_from_user(con_buf, buf, this_round);
-               acquire_console_sem();
+               console_lock();
 
                if (ret) {
                        this_round -= ret;
@@ -542,7 +542,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
                vcs_scr_updated(vc);
 
 unlock_out:
-       release_console_sem();
+       console_unlock();
 
        mutex_unlock(&con_buf_mtx);
 
index 76407ec..147ede3 100644 (file)
@@ -1003,9 +1003,9 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
        struct vc_data *vc = tty->driver_data;
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 
@@ -1271,7 +1271,7 @@ static void default_attr(struct vc_data *vc)
        vc->vc_color = vc->vc_def_color;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_m(struct vc_data *vc)
 {
        int i;
@@ -1415,7 +1415,7 @@ int mouse_reporting(void)
        return vc_cons[fg_console].d->vc_report_mouse;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void set_mode(struct vc_data *vc, int on_off)
 {
        int i;
@@ -1485,7 +1485,7 @@ static void set_mode(struct vc_data *vc, int on_off)
                }
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void setterm_command(struct vc_data *vc)
 {
        switch(vc->vc_par[0]) {
@@ -1545,7 +1545,7 @@ static void setterm_command(struct vc_data *vc)
        }
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_at(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_cols - vc->vc_x)
@@ -1555,7 +1555,7 @@ static void csi_at(struct vc_data *vc, unsigned int nr)
        insert_char(vc, nr);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_L(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_rows - vc->vc_y)
@@ -1566,7 +1566,7 @@ static void csi_L(struct vc_data *vc, unsigned int nr)
        vc->vc_need_wrap = 0;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_P(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_cols - vc->vc_x)
@@ -1576,7 +1576,7 @@ static void csi_P(struct vc_data *vc, unsigned int nr)
        delete_char(vc, nr);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_M(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_rows - vc->vc_y)
@@ -1587,7 +1587,7 @@ static void csi_M(struct vc_data *vc, unsigned int nr)
        vc->vc_need_wrap = 0;
 }
 
-/* console_sem is held (except via vc_init->reset_terminal */
+/* console_lock is held (except via vc_init->reset_terminal */
 static void save_cur(struct vc_data *vc)
 {
        vc->vc_saved_x          = vc->vc_x;
@@ -1603,7 +1603,7 @@ static void save_cur(struct vc_data *vc)
        vc->vc_saved_G1         = vc->vc_G1_charset;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void restore_cur(struct vc_data *vc)
 {
        gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
@@ -1625,7 +1625,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
        EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
        ESpalette };
 
-/* console_sem is held (except via vc_init()) */
+/* console_lock is held (except via vc_init()) */
 static void reset_terminal(struct vc_data *vc, int do_clear)
 {
        vc->vc_top              = 0;
@@ -1685,7 +1685,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
            csi_J(vc, 2);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 {
        /*
@@ -2119,7 +2119,7 @@ static int is_double_width(uint32_t ucs)
        return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
 }
 
-/* acquires console_sem */
+/* acquires console_lock */
 static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
 #ifdef VT_BUF_VRAM_ONLY
@@ -2147,11 +2147,11 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
 
        might_sleep();
 
-       acquire_console_sem();
+       console_lock();
        vc = tty->driver_data;
        if (vc == NULL) {
                printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -2159,7 +2159,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
        if (!vc_cons_allocated(currcons)) {
            /* could this happen? */
                printk_once("con_write: tty %d not allocated\n", currcons+1);
-           release_console_sem();
+           console_unlock();
            return 0;
        }
 
@@ -2375,7 +2375,7 @@ rescan_last_byte:
        }
        FLUSH
        console_conditional_schedule();
-       release_console_sem();
+       console_unlock();
        notify_update(vc);
        return n;
 #undef FLUSH
@@ -2388,11 +2388,11 @@ rescan_last_byte:
  * 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.
+ * ensured with console_lock.
  */
 static void console_callback(struct work_struct *ignored)
 {
-       acquire_console_sem();
+       console_lock();
 
        if (want_console >= 0) {
                if (want_console != fg_console &&
@@ -2422,7 +2422,7 @@ static void console_callback(struct work_struct *ignored)
        }
        notify_update(vc_cons[fg_console].d);
 
-       release_console_sem();
+       console_unlock();
 }
 
 int set_console(int nr)
@@ -2603,7 +2603,7 @@ static struct console vt_console_driver = {
  */
 
 /*
- * Generally a bit racy with respect to console_sem().
+ * Generally a bit racy with respect to console_lock();.
  *
  * There are some functions which don't need it.
  *
@@ -2629,17 +2629,17 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        switch (type)
        {
                case TIOCL_SETSEL:
-                       acquire_console_sem();
+                       console_lock();
                        ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_PASTESEL:
                        ret = paste_selection(tty);
                        break;
                case TIOCL_UNBLANKSCREEN:
-                       acquire_console_sem();
+                       console_lock();
                        unblank_screen();
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_SELLOADLUT:
                        ret = sel_loadlut(p);
@@ -2688,10 +2688,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                        }
                        break;
                case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
-                       acquire_console_sem();
+                       console_lock();
                        ignore_poke = 1;
                        do_blank_screen(0);
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_BLANKEDSCREEN:
                        ret = console_blanked;
@@ -2790,11 +2790,11 @@ static void con_flush_chars(struct tty_struct *tty)
                return;
 
        /* if we race with con_close(), vt may be null */
-       acquire_console_sem();
+       console_lock();
        vc = tty->driver_data;
        if (vc)
                set_cursor(vc);
-       release_console_sem();
+       console_unlock();
 }
 
 /*
@@ -2805,7 +2805,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
        unsigned int currcons = tty->index;
        int ret = 0;
 
-       acquire_console_sem();
+       console_lock();
        if (tty->driver_data == NULL) {
                ret = vc_allocate(currcons);
                if (ret == 0) {
@@ -2813,7 +2813,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
 
                        /* Still being freed */
                        if (vc->port.tty) {
-                               release_console_sem();
+                               console_unlock();
                                return -ERESTARTSYS;
                        }
                        tty->driver_data = vc;
@@ -2827,11 +2827,11 @@ static int con_open(struct tty_struct *tty, struct file *filp)
                                tty->termios->c_iflag |= IUTF8;
                        else
                                tty->termios->c_iflag &= ~IUTF8;
-                       release_console_sem();
+                       console_unlock();
                        return ret;
                }
        }
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 
@@ -2844,9 +2844,9 @@ static void con_shutdown(struct tty_struct *tty)
 {
        struct vc_data *vc = tty->driver_data;
        BUG_ON(vc == NULL);
-       acquire_console_sem();
+       console_lock();
        vc->port.tty = NULL;
-       release_console_sem();
+       console_unlock();
        tty_shutdown(tty);
 }
 
@@ -2893,13 +2893,13 @@ static int __init con_init(void)
        struct vc_data *vc;
        unsigned int currcons = 0, i;
 
-       acquire_console_sem();
+       console_lock();
 
        if (conswitchp)
                display_desc = conswitchp->con_startup();
        if (!display_desc) {
                fg_console = 0;
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -2946,7 +2946,7 @@ static int __init con_init(void)
        printable = 1;
        printk("\n");
 
-       release_console_sem();
+       console_unlock();
 
 #ifdef CONFIG_VT_CONSOLE
        register_console(&vt_console_driver);
@@ -2994,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops)
        if (IS_ERR(tty0dev))
                tty0dev = NULL;
        else
-               device_create_file(tty0dev, &dev_attr_active);
+               WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0);
 
        vcs_init();
 
@@ -3037,7 +3037,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* check if driver is registered */
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3122,7 +3122,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
 
        retval = 0;
 err:
-       release_console_sem();
+       console_unlock();
        module_put(owner);
        return retval;
 };
@@ -3171,7 +3171,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* check if driver is registered and if it is unbindable */
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3185,7 +3185,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        }
 
        if (retval) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
@@ -3204,12 +3204,12 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        }
 
        if (retval) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
        if (!con_is_bound(csw)) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
@@ -3238,7 +3238,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        if (!con_is_bound(csw))
                con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
 
-       release_console_sem();
+       console_unlock();
        /* ignore return value, binding should not fail */
        bind_con_driver(defcsw, first, last, deflt);
 err:
@@ -3538,14 +3538,14 @@ int register_con_driver(const struct consw *csw, int first, int last)
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
                con_driver = &registered_con_driver[i];
 
                /* already registered */
                if (con_driver->con == csw)
-                       retval = -EINVAL;
+                       retval = -EBUSY;
        }
 
        if (retval)
@@ -3592,7 +3592,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
        }
 
 err:
-       release_console_sem();
+       console_unlock();
        module_put(owner);
        return retval;
 }
@@ -3613,7 +3613,7 @@ int unregister_con_driver(const struct consw *csw)
 {
        int i, retval = -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* cannot unregister a bound driver */
        if (con_is_bound(csw))
@@ -3639,7 +3639,7 @@ int unregister_con_driver(const struct consw *csw)
                }
        }
 err:
-       release_console_sem();
+       console_unlock();
        return retval;
 }
 EXPORT_SYMBOL(unregister_con_driver);
@@ -3656,7 +3656,12 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
        int err;
 
        err = register_con_driver(csw, first, last);
-
+       /* if we get an busy error we still want to bind the console driver
+        * and return success, as we may have unbound the console driver
+       Â * but not unregistered it.
+       */
+       if (err == -EBUSY)
+               err = 0;
        if (!err)
                bind_con_driver(csw, first, last, deflt);
 
@@ -3934,9 +3939,9 @@ int con_set_cmap(unsigned char __user *arg)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = set_get_cmap (arg,1);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
@@ -3945,9 +3950,9 @@ int con_get_cmap(unsigned char __user *arg)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = set_get_cmap (arg,0);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
@@ -3994,12 +3999,12 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
        } else
                font.data = NULL;
 
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_get)
                rc = vc->vc_sw->con_font_get(vc, &font);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
 
        if (rc)
                goto out;
@@ -4076,12 +4081,12 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
        font.data = memdup_user(op->data, size);
        if (IS_ERR(font.data))
                return PTR_ERR(font.data);
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_set)
                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
        kfree(font.data);
        return rc;
 }
@@ -4103,12 +4108,12 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
        else
                name[MAX_FONT_NAME - 1] = 0;
 
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_default)
                rc = vc->vc_sw->con_font_default(vc, &font, s);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
        if (!rc) {
                op->width = font.width;
                op->height = font.height;
@@ -4124,7 +4129,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
        if (vc->vc_mode != KD_TEXT)
                return -EINVAL;
 
-       acquire_console_sem();
+       console_lock();
        if (!vc->vc_sw->con_font_copy)
                rc = -ENOSYS;
        else if (con < 0 || !vc_cons_allocated(con))
@@ -4133,7 +4138,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
                rc = 0;
        else
                rc = vc->vc_sw->con_font_copy(vc, con);
-       release_console_sem();
+       console_unlock();
        return rc;
 }
 
index 6b68a0f..1235ebd 100644 (file)
@@ -649,12 +649,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                /*
                 * explicitly blank/unblank the screen if switching modes
                 */
-               acquire_console_sem();
+               console_lock();
                if (arg == KD_TEXT)
                        do_unblank_screen(1);
                else
                        do_blank_screen(1);
-               release_console_sem();
+               console_unlock();
                break;
 
        case KDGETMODE:
@@ -893,7 +893,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret = -EINVAL;
                        goto out;
                }
-               acquire_console_sem();
+               console_lock();
                vc->vt_mode = tmp;
                /* the frsig is ignored, so we set it to 0 */
                vc->vt_mode.frsig = 0;
@@ -901,7 +901,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                vc->vt_pid = get_pid(task_pid(current));
                /* no switch is required -- saw@shade.msu.ru */
                vc->vt_newvt = -1;
-               release_console_sem();
+               console_unlock();
                break;
        }
 
@@ -910,9 +910,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                struct vt_mode tmp;
                int rc;
 
-               acquire_console_sem();
+               console_lock();
                memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-               release_console_sem();
+               console_unlock();
 
                rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
                if (rc)
@@ -965,9 +965,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret =  -ENXIO;
                else {
                        arg--;
-                       acquire_console_sem();
+                       console_lock();
                        ret = vc_allocate(arg);
-                       release_console_sem();
+                       console_unlock();
                        if (ret)
                                break;
                        set_console(arg);
@@ -990,7 +990,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret = -ENXIO;
                else {
                        vsa.console--;
-                       acquire_console_sem();
+                       console_lock();
                        ret = vc_allocate(vsa.console);
                        if (ret == 0) {
                                struct vc_data *nvc;
@@ -1003,7 +1003,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                put_pid(nvc->vt_pid);
                                nvc->vt_pid = get_pid(task_pid(current));
                        }
-                       release_console_sem();
+                       console_unlock();
                        if (ret)
                                break;
                        /* Commence switch and lock */
@@ -1044,7 +1044,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                /*
                 * Switching-from response
                 */
-               acquire_console_sem();
+               console_lock();
                if (vc->vt_newvt >= 0) {
                        if (arg == 0)
                                /*
@@ -1063,7 +1063,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                vc->vt_newvt = -1;
                                ret = vc_allocate(newvt);
                                if (ret) {
-                                       release_console_sem();
+                                       console_unlock();
                                        break;
                                }
                                /*
@@ -1083,7 +1083,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        if (arg != VT_ACKACQ)
                                ret = -EINVAL;
                }
-               release_console_sem();
+               console_unlock();
                break;
 
         /*
@@ -1096,20 +1096,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                }
                if (arg == 0) {
                    /* deallocate all unused consoles, but leave 0 */
-                       acquire_console_sem();
+                       console_lock();
                        for (i=1; i<MAX_NR_CONSOLES; i++)
                                if (! VT_BUSY(i))
                                        vc_deallocate(i);
-                       release_console_sem();
+                       console_unlock();
                } else {
                        /* deallocate a single console, if possible */
                        arg--;
                        if (VT_BUSY(arg))
                                ret = -EBUSY;
                        else if (arg) {                       /* leave 0 */
-                               acquire_console_sem();
+                               console_lock();
                                vc_deallocate(arg);
-                               release_console_sem();
+                               console_unlock();
                        }
                }
                break;
@@ -1126,7 +1126,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                    get_user(cc, &vtsizes->v_cols))
                        ret = -EFAULT;
                else {
-                       acquire_console_sem();
+                       console_lock();
                        for (i = 0; i < MAX_NR_CONSOLES; i++) {
                                vc = vc_cons[i].d;
 
@@ -1135,7 +1135,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                        vc_resize(vc_cons[i].d, cc, ll);
                                }
                        }
-                       release_console_sem();
+                       console_unlock();
                }
                break;
        }
@@ -1187,14 +1187,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                for (i = 0; i < MAX_NR_CONSOLES; i++) {
                        if (!vc_cons[i].d)
                                continue;
-                       acquire_console_sem();
+                       console_lock();
                        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();
+                       console_unlock();
                }
                break;
        }
@@ -1367,7 +1367,7 @@ void vc_SAK(struct work_struct *work)
        struct vc_data *vc;
        struct tty_struct *tty;
 
-       acquire_console_sem();
+       console_lock();
        vc = vc_con->d;
        if (vc) {
                tty = vc->port.tty;
@@ -1379,7 +1379,7 @@ void vc_SAK(struct work_struct *work)
                        __do_SAK(tty);
                reset_vc(vc);
        }
-       release_console_sem();
+       console_unlock();
 }
 
 #ifdef CONFIG_COMPAT
@@ -1737,10 +1737,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
 {
        int prev;
 
-       acquire_console_sem();
+       console_lock();
        /* Graphics mode - up to X */
        if (disable_vt_switch) {
-               release_console_sem();
+               console_unlock();
                return 0;
        }
        prev = fg_console;
@@ -1748,7 +1748,7 @@ int vt_move_to_console(unsigned int vt, int alloc)
        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();
+               console_unlock();
                return -ENOSPC;
        }
 
@@ -1758,10 +1758,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
                 * Let the calling function know so it can decide
                 * what to do.
                 */
-               release_console_sem();
+               console_unlock();
                return -EIO;
        }
-       release_console_sem();
+       console_unlock();
        tty_lock();
        if (vt_waitactive(vt + 1)) {
                pr_debug("Suspend: Can't switch VCs.");
@@ -1781,8 +1781,8 @@ int vt_move_to_console(unsigned int vt, int alloc)
  */
 void pm_set_vt_switch(int do_switch)
 {
-       acquire_console_sem();
+       console_lock();
        disable_vt_switch = !do_switch;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(pm_set_vt_switch);
index d6ede98..4ab49d4 100644 (file)
@@ -1607,6 +1607,7 @@ static const struct usb_device_id acm_ids[] = {
        { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
        { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
        { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
+       { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
        { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
 
        /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
index 6ee4451..47085e5 100644 (file)
@@ -342,7 +342,7 @@ static ssize_t wdm_write
                goto outnp;
        }
 
-       if (!file->f_flags && O_NONBLOCK)
+       if (!(file->f_flags & O_NONBLOCK))
                r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
                                                                &desc->flags));
        else
index bcc2477..18d02e3 100644 (file)
@@ -123,9 +123,9 @@ config USB_OTG
 
 config USB_OTG_WHITELIST
        bool "Rely on OTG Targeted Peripherals List"
-       depends on USB_OTG || EMBEDDED
+       depends on USB_OTG || EXPERT
        default y if USB_OTG
-       default n if EMBEDDED
+       default n if EXPERT
        help
          If you say Y here, the "otg_whitelist.h" file will be used as a
          product whitelist, so USB peripherals not listed there will be
@@ -141,7 +141,7 @@ config USB_OTG_WHITELIST
 
 config USB_OTG_BLACKLIST_HUB
        bool "Disable external hubs"
-       depends on USB_OTG || EMBEDDED
+       depends on USB_OTG || EXPERT
        help
          If you say Y here, then Linux will refuse to enumerate
          external hubs.  OTG hosts are allowed to reduce hardware
index 9da2505..df502a9 100644 (file)
@@ -192,12 +192,12 @@ int usb_create_ep_devs(struct device *parent,
        ep_dev->dev.parent = parent;
        ep_dev->dev.release = ep_device_release;
        dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
-       device_enable_async_suspend(&ep_dev->dev);
 
        retval = device_register(&ep_dev->dev);
        if (retval)
                goto error_register;
 
+       device_enable_async_suspend(&ep_dev->dev);
        endpoint->ep_dev = ep_dev;
        return retval;
 
index b55d460..f71e8e3 100644 (file)
@@ -405,7 +405,12 @@ static int suspend_common(struct device *dev, bool do_wakeup)
                        return retval;
        }
 
-       synchronize_irq(pci_dev->irq);
+       /* If MSI-X is enabled, the driver will have synchronized all vectors
+        * in pci_suspend(). If MSI or legacy PCI is enabled, that will be
+        * synchronized here.
+        */
+       if (!hcd->msix_enabled)
+               synchronize_irq(pci_dev->irq);
 
        /* Downstream ports from this root hub should already be quiesced, so
         * there will be no DMA activity.  Now we can shut down the upstream
index 6a95017..e935f71 100644 (file)
@@ -1955,7 +1955,6 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 
        dev_dbg(&rhdev->dev, "usb %s%s\n",
                        (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
-       clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
        if (!hcd->driver->bus_resume)
                return -ENOENT;
        if (hcd->state == HC_STATE_RUNNING)
@@ -1963,6 +1962,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 
        hcd->state = HC_STATE_RESUMING;
        status = hcd->driver->bus_resume(hcd);
+       clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
        if (status == 0) {
                /* TRSMRCY = 10 msec */
                msleep(10);
index b98efae..0f299b7 100644 (file)
@@ -676,6 +676,8 @@ static void hub_init_func3(struct work_struct *ws);
 static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 {
        struct usb_device *hdev = hub->hdev;
+       struct usb_hcd *hcd;
+       int ret;
        int port1;
        int status;
        bool need_debounce_delay = false;
@@ -714,6 +716,25 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                        usb_autopm_get_interface_no_resume(
                                        to_usb_interface(hub->intfdev));
                        return;         /* Continues at init2: below */
+               } else if (type == HUB_RESET_RESUME) {
+                       /* The internal host controller state for the hub device
+                        * may be gone after a host power loss on system resume.
+                        * Update the device's info so the HW knows it's a hub.
+                        */
+                       hcd = bus_to_hcd(hdev->bus);
+                       if (hcd->driver->update_hub_device) {
+                               ret = hcd->driver->update_hub_device(hcd, hdev,
+                                               &hub->tt, GFP_NOIO);
+                               if (ret < 0) {
+                                       dev_err(hub->intfdev, "Host not "
+                                                       "accepting hub info "
+                                                       "update.\n");
+                                       dev_err(hub->intfdev, "LS/FS devices "
+                                                       "and hubs may not work "
+                                                       "under this hub\n.");
+                               }
+                       }
+                       hub_power_on(hub, true);
                } else {
                        hub_power_on(hub, true);
                }
@@ -2660,17 +2681,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
        mutex_lock(&usb_address0_mutex);
 
-       if (!udev->config && oldspeed == USB_SPEED_SUPER) {
-               /* Don't reset USB 3.0 devices during an initial setup */
-               usb_set_device_state(udev, USB_STATE_DEFAULT);
-       } else {
-               /* Reset the device; full speed may morph to high speed */
-               /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
-               retval = hub_port_reset(hub, port1, udev, delay);
-               if (retval < 0)         /* error or disconnect */
-                       goto fail;
-               /* success, speed is known */
-       }
+       /* Reset the device; full speed may morph to high speed */
+       /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
+       retval = hub_port_reset(hub, port1, udev, delay);
+       if (retval < 0)         /* error or disconnect */
+               goto fail;
+       /* success, speed is known */
+
        retval = -ENODEV;
 
        if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
@@ -2732,6 +2749,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                udev->ttport = hdev->ttport;
        } else if (udev->speed != USB_SPEED_HIGH
                        && hdev->speed == USB_SPEED_HIGH) {
+               if (!hub->tt.hub) {
+                       dev_err(&udev->dev, "parent hub has no TT\n");
+                       retval = -EINVAL;
+                       goto fail;
+               }
                udev->tt = &hub->tt;
                udev->ttport = port1;
        }
index 44c5954..81ce6a8 100644 (file)
@@ -48,6 +48,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04b4, 0x0526), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
 
+       /* Samsung Android phone modem - ID conflict with SPH-I500 */
+       { USB_DEVICE(0x04e8, 0x6601), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* Roland SC-8820 */
        { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -68,6 +72,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* M-Systems Flash Disk Pioneers */
        { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Keytouch QWERTY Panel keyboard */
+       { USB_DEVICE(0x0926, 0x3333), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
        { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
 
index 1dc9739..d500996 100644 (file)
@@ -509,7 +509,7 @@ config USB_LANGWELL
        select USB_GADGET_SELECTED
 
 config USB_GADGET_EG20T
-       boolean "Intel EG20T(Topcliff) USB Device controller"
+       boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
        depends on PCI
        select USB_GADGET_DUALSPEED
        help
@@ -525,6 +525,11 @@ config USB_GADGET_EG20T
          This driver dose not support interrupt transfer or isochronous
          transfer modes.
 
+         This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is
+         for IVI(In-Vehicle Infotainment) use.
+         ML7213 is companion chip for Intel Atom E6xx series.
+         ML7213 is completely compatible for Intel EG20T PCH.
+
 config USB_EG20T
        tristate
        depends on USB_GADGET_EG20T
@@ -541,6 +546,8 @@ config USB_GADGET_CI13XXX_MSM
          ci13xxx_udc core.
          This driver depends on OTG driver for PHY initialization,
          clock management, powering up VBUS, and power management.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "ci13xxx_msm" and force all
index 31656a2..a1c67ae 100644 (file)
@@ -76,10 +76,21 @@ static DEFINE_SPINLOCK(udc_lock);
 
 /* control endpoint description */
 static const struct usb_endpoint_descriptor
-ctrl_endpt_desc = {
+ctrl_endpt_out_desc = {
        .bLength         = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
+       .bEndpointAddress = USB_DIR_OUT,
+       .bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+       .bLength         = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+
+       .bEndpointAddress = USB_DIR_IN,
        .bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
        .wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
 };
@@ -265,10 +276,10 @@ static int hw_device_init(void __iomem *base)
        hw_bank.size /= sizeof(u32);
 
        reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
-       if (reg == 0 || reg > ENDPT_MAX)
-               return -ENODEV;
+       hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
 
-       hw_ep_max = reg;   /* cache hw ENDPT_MAX */
+       if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
+               return -ENODEV;
 
        /* setup lock mode ? */
 
@@ -1197,16 +1208,17 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
        }
 
        spin_lock_irqsave(udc->lock, flags);
-       for (i = 0; i < hw_ep_max; i++) {
-               struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+       for (i = 0; i < hw_ep_max/2; i++) {
+               struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+               struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
                n += scnprintf(buf + n, PAGE_SIZE - n,
                               "EP=%02i: RX=%08X TX=%08X\n",
-                              i, (u32)mEp->qh[RX].dma, (u32)mEp->qh[TX].dma);
+                              i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
                for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
                        n += scnprintf(buf + n, PAGE_SIZE - n,
                                       " %04X:    %08X    %08X\n", j,
-                                      *((u32 *)mEp->qh[RX].ptr + j),
-                                      *((u32 *)mEp->qh[TX].ptr + j));
+                                      *((u32 *)mEpRx->qh.ptr + j),
+                                      *((u32 *)mEpTx->qh.ptr + j));
                }
        }
        spin_unlock_irqrestore(udc->lock, flags);
@@ -1293,7 +1305,7 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
        unsigned long flags;
        struct list_head   *ptr = NULL;
        struct ci13xxx_req *req = NULL;
-       unsigned i, j, k, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+       unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
        dbg_trace("[%s] %p\n", __func__, buf);
        if (attr == NULL || buf == NULL) {
@@ -1303,22 +1315,20 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
 
        spin_lock_irqsave(udc->lock, flags);
        for (i = 0; i < hw_ep_max; i++)
-               for (k = RX; k <= TX; k++)
-                       list_for_each(ptr, &udc->ci13xxx_ep[i].qh[k].queue)
-                       {
-                               req = list_entry(ptr,
-                                                struct ci13xxx_req, queue);
+               list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+               {
+                       req = list_entry(ptr, struct ci13xxx_req, queue);
+
+                       n += scnprintf(buf + n, PAGE_SIZE - n,
+                                       "EP=%02i: TD=%08X %s\n",
+                                       i % hw_ep_max/2, (u32)req->dma,
+                                       ((i < hw_ep_max/2) ? "RX" : "TX"));
 
+                       for (j = 0; j < qSize; j++)
                                n += scnprintf(buf + n, PAGE_SIZE - n,
-                                              "EP=%02i: TD=%08X %s\n",
-                                              i, (u32)req->dma,
-                                              ((k == RX) ? "RX" : "TX"));
-
-                               for (j = 0; j < qSize; j++)
-                                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                                      " %04X:    %08X\n", j,
-                                                      *((u32 *)req->ptr + j));
-                       }
+                                               " %04X:    %08X\n", j,
+                                               *((u32 *)req->ptr + j));
+               }
        spin_unlock_irqrestore(udc->lock, flags);
 
        return n;
@@ -1467,12 +1477,12 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
         *  At this point it's guaranteed exclusive access to qhead
         *  (endpt is not primed) so it's no need to use tripwire
         */
-       mEp->qh[mEp->dir].ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
-       mEp->qh[mEp->dir].ptr->td.token &= ~TD_STATUS;   /* clear status */
+       mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+       mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
        if (mReq->req.zero == 0)
-               mEp->qh[mEp->dir].ptr->cap |=  QH_ZLT;
+               mEp->qh.ptr->cap |=  QH_ZLT;
        else
-               mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
+               mEp->qh.ptr->cap &= ~QH_ZLT;
 
        wmb();   /* synchronize before ep prime */
 
@@ -1542,11 +1552,11 @@ __acquires(mEp->lock)
 
        hw_ep_flush(mEp->num, mEp->dir);
 
-       while (!list_empty(&mEp->qh[mEp->dir].queue)) {
+       while (!list_empty(&mEp->qh.queue)) {
 
                /* pop oldest request */
                struct ci13xxx_req *mReq = \
-                       list_entry(mEp->qh[mEp->dir].queue.next,
+                       list_entry(mEp->qh.queue.next,
                                   struct ci13xxx_req, queue);
                list_del_init(&mReq->queue);
                mReq->req.status = -ESHUTDOWN;
@@ -1571,8 +1581,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
 {
        struct usb_ep *ep;
        struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
-       struct ci13xxx_ep *mEp = container_of(gadget->ep0,
-                                             struct ci13xxx_ep, ep);
 
        trace("%p", gadget);
 
@@ -1583,7 +1591,8 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
        gadget_for_each_ep(ep, gadget) {
                usb_ep_fifo_flush(ep);
        }
-       usb_ep_fifo_flush(gadget->ep0);
+       usb_ep_fifo_flush(&udc->ep0out.ep);
+       usb_ep_fifo_flush(&udc->ep0in.ep);
 
        udc->driver->disconnect(gadget);
 
@@ -1591,11 +1600,12 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
        gadget_for_each_ep(ep, gadget) {
                usb_ep_disable(ep);
        }
-       usb_ep_disable(gadget->ep0);
+       usb_ep_disable(&udc->ep0out.ep);
+       usb_ep_disable(&udc->ep0in.ep);
 
-       if (mEp->status != NULL) {
-               usb_ep_free_request(gadget->ep0, mEp->status);
-               mEp->status = NULL;
+       if (udc->status != NULL) {
+               usb_ep_free_request(&udc->ep0in.ep, udc->status);
+               udc->status = NULL;
        }
 
        return 0;
@@ -1614,7 +1624,6 @@ static void isr_reset_handler(struct ci13xxx *udc)
 __releases(udc->lock)
 __acquires(udc->lock)
 {
-       struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[0];
        int retval;
 
        trace("%p", udc);
@@ -1635,11 +1644,15 @@ __acquires(udc->lock)
        if (retval)
                goto done;
 
-       retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc);
+       retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
+       if (retval)
+               goto done;
+
+       retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
        if (!retval) {
-               mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_ATOMIC);
-               if (mEp->status == NULL) {
-                       usb_ep_disable(&mEp->ep);
+               udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
+               if (udc->status == NULL) {
+                       usb_ep_disable(&udc->ep0out.ep);
                        retval = -ENOMEM;
                }
        }
@@ -1672,16 +1685,17 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
 
 /**
  * isr_get_status_response: get_status request response
- * @ep:    endpoint
+ * @udc: udc struct
  * @setup: setup request packet
  *
  * This function returns an error code
  */
-static int isr_get_status_response(struct ci13xxx_ep *mEp,
+static int isr_get_status_response(struct ci13xxx *udc,
                                   struct usb_ctrlrequest *setup)
 __releases(mEp->lock)
 __acquires(mEp->lock)
 {
+       struct ci13xxx_ep *mEp = &udc->ep0in;
        struct usb_request *req = NULL;
        gfp_t gfp_flags = GFP_ATOMIC;
        int dir, num, retval;
@@ -1736,27 +1750,23 @@ __acquires(mEp->lock)
 
 /**
  * isr_setup_status_phase: queues the status phase of a setup transation
- * @mEp: endpoint
+ * @udc: udc struct
  *
  * This function returns an error code
  */
-static int isr_setup_status_phase(struct ci13xxx_ep *mEp)
+static int isr_setup_status_phase(struct ci13xxx *udc)
 __releases(mEp->lock)
 __acquires(mEp->lock)
 {
        int retval;
+       struct ci13xxx_ep *mEp;
 
-       trace("%p", mEp);
-
-       /* mEp is always valid & configured */
-
-       if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-               mEp->dir = (mEp->dir == TX) ? RX : TX;
+       trace("%p", udc);
 
-       mEp->status->no_interrupt = 1;
+       mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
 
        spin_unlock(mEp->lock);
-       retval = usb_ep_queue(&mEp->ep, mEp->status, GFP_ATOMIC);
+       retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
        spin_lock(mEp->lock);
 
        return retval;
@@ -1778,11 +1788,11 @@ __acquires(mEp->lock)
 
        trace("%p", mEp);
 
-       if (list_empty(&mEp->qh[mEp->dir].queue))
+       if (list_empty(&mEp->qh.queue))
                return -EINVAL;
 
        /* pop oldest request */
-       mReq = list_entry(mEp->qh[mEp->dir].queue.next,
+       mReq = list_entry(mEp->qh.queue.next,
                          struct ci13xxx_req, queue);
        list_del_init(&mReq->queue);
 
@@ -1794,10 +1804,10 @@ __acquires(mEp->lock)
 
        dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
 
-       if (!list_empty(&mEp->qh[mEp->dir].queue)) {
+       if (!list_empty(&mEp->qh.queue)) {
                struct ci13xxx_req* mReqEnq;
 
-               mReqEnq = list_entry(mEp->qh[mEp->dir].queue.next,
+               mReqEnq = list_entry(mEp->qh.queue.next,
                                  struct ci13xxx_req, queue);
                _hardware_enqueue(mEp, mReqEnq);
        }
@@ -1836,16 +1846,14 @@ __acquires(udc->lock)
                int type, num, err = -EINVAL;
                struct usb_ctrlrequest req;
 
-
                if (mEp->desc == NULL)
                        continue;   /* not configured */
 
-               if ((mEp->dir == RX && hw_test_and_clear_complete(i)) ||
-                   (mEp->dir == TX && hw_test_and_clear_complete(i + 16))) {
+               if (hw_test_and_clear_complete(i)) {
                        err = isr_tr_complete_low(mEp);
                        if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
                                if (err > 0)   /* needs status phase */
-                                       err = isr_setup_status_phase(mEp);
+                                       err = isr_setup_status_phase(udc);
                                if (err < 0) {
                                        dbg_event(_usb_addr(mEp),
                                                  "ERROR", err);
@@ -1866,15 +1874,22 @@ __acquires(udc->lock)
                        continue;
                }
 
+               /*
+                * Flush data and handshake transactions of previous
+                * setup packet.
+                */
+               _ep_nuke(&udc->ep0out);
+               _ep_nuke(&udc->ep0in);
+
                /* read_setup_packet */
                do {
                        hw_test_and_set_setup_guard();
-                       memcpy(&req, &mEp->qh[RX].ptr->setup, sizeof(req));
+                       memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
                } while (!hw_test_and_clear_setup_guard());
 
                type = req.bRequestType;
 
-               mEp->dir = (type & USB_DIR_IN) ? TX : RX;
+               udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
 
                dbg_setup(_usb_addr(mEp), &req);
 
@@ -1895,7 +1910,7 @@ __acquires(udc->lock)
                                if (err)
                                        break;
                        }
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                case USB_REQ_GET_STATUS:
                        if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
@@ -1905,7 +1920,7 @@ __acquires(udc->lock)
                        if (le16_to_cpu(req.wLength) != 2 ||
                            le16_to_cpu(req.wValue)  != 0)
                                break;
-                       err = isr_get_status_response(mEp, &req);
+                       err = isr_get_status_response(udc, &req);
                        break;
                case USB_REQ_SET_ADDRESS:
                        if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
@@ -1916,7 +1931,7 @@ __acquires(udc->lock)
                        err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
                        if (err)
                                break;
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                case USB_REQ_SET_FEATURE:
                        if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@@ -1932,12 +1947,12 @@ __acquires(udc->lock)
                        spin_lock(udc->lock);
                        if (err)
                                break;
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                default:
 delegate:
                        if (req.wLength == 0)   /* no data phase */
-                               mEp->dir = TX;
+                               udc->ep0_dir = TX;
 
                        spin_unlock(udc->lock);
                        err = udc->driver->setup(&udc->gadget, &req);
@@ -1968,7 +1983,7 @@ static int ep_enable(struct usb_ep *ep,
                     const struct usb_endpoint_descriptor *desc)
 {
        struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-       int direction, retval = 0;
+       int retval = 0;
        unsigned long flags;
 
        trace("%p, %p", ep, desc);
@@ -1982,7 +1997,7 @@ static int ep_enable(struct usb_ep *ep,
 
        mEp->desc = desc;
 
-       if (!list_empty(&mEp->qh[mEp->dir].queue))
+       if (!list_empty(&mEp->qh.queue))
                warn("enabling a non-empty endpoint!");
 
        mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
@@ -1991,29 +2006,22 @@ static int ep_enable(struct usb_ep *ep,
 
        mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
 
-       direction = mEp->dir;
-       do {
-               dbg_event(_usb_addr(mEp), "ENABLE", 0);
+       dbg_event(_usb_addr(mEp), "ENABLE", 0);
 
-               mEp->qh[mEp->dir].ptr->cap = 0;
+       mEp->qh.ptr->cap = 0;
 
-               if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-                       mEp->qh[mEp->dir].ptr->cap |=  QH_IOS;
-               else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
-                       mEp->qh[mEp->dir].ptr->cap &= ~QH_MULT;
-               else
-                       mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
-
-               mEp->qh[mEp->dir].ptr->cap |=
-                       (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
-               mEp->qh[mEp->dir].ptr->td.next |= TD_TERMINATE;   /* needed? */
-
-               retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+       if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+               mEp->qh.ptr->cap |=  QH_IOS;
+       else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+               mEp->qh.ptr->cap &= ~QH_MULT;
+       else
+               mEp->qh.ptr->cap &= ~QH_ZLT;
 
-               if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-                       mEp->dir = (mEp->dir == TX) ? RX : TX;
+       mEp->qh.ptr->cap |=
+               (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+       mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
 
-       } while (mEp->dir != direction);
+       retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
 
        spin_unlock_irqrestore(mEp->lock, flags);
        return retval;
@@ -2146,7 +2154,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
        spin_lock_irqsave(mEp->lock, flags);
 
        if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
-           !list_empty(&mEp->qh[mEp->dir].queue)) {
+           !list_empty(&mEp->qh.queue)) {
                _ep_nuke(mEp);
                retval = -EOVERFLOW;
                warn("endpoint ctrl %X nuked", _usb_addr(mEp));
@@ -2170,9 +2178,9 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
        /* push request */
        mReq->req.status = -EINPROGRESS;
        mReq->req.actual = 0;
-       list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
+       list_add_tail(&mReq->queue, &mEp->qh.queue);
 
-       if (list_is_singular(&mEp->qh[mEp->dir].queue))
+       if (list_is_singular(&mEp->qh.queue))
                retval = _hardware_enqueue(mEp, mReq);
 
        if (retval == -EALREADY) {
@@ -2199,7 +2207,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
        trace("%p, %p", ep, req);
 
        if (ep == NULL || req == NULL || mEp->desc == NULL ||
-           list_empty(&mReq->queue)  || list_empty(&mEp->qh[mEp->dir].queue))
+           list_empty(&mReq->queue)  || list_empty(&mEp->qh.queue))
                return -EINVAL;
 
        spin_lock_irqsave(mEp->lock, flags);
@@ -2244,7 +2252,7 @@ static int ep_set_halt(struct usb_ep *ep, int value)
 #ifndef STALL_IN
        /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
        if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
-           !list_empty(&mEp->qh[mEp->dir].queue)) {
+           !list_empty(&mEp->qh.queue)) {
                spin_unlock_irqrestore(mEp->lock, flags);
                return -EAGAIN;
        }
@@ -2355,7 +2363,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
                if (is_active) {
                        pm_runtime_get_sync(&_gadget->dev);
                        hw_device_reset(udc);
-                       hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+                       hw_device_state(udc->ep0out.qh.dma);
                } else {
                        hw_device_state(0);
                        if (udc->udc_driver->notify_event)
@@ -2390,7 +2398,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                int (*bind)(struct usb_gadget *))
 {
        struct ci13xxx *udc = _udc;
-       unsigned long i, k, flags;
+       unsigned long flags;
+       int i, j;
        int retval = -ENOMEM;
 
        trace("%p", driver);
@@ -2427,45 +2436,46 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
        info("hw_ep_max = %d", hw_ep_max);
 
-       udc->driver = driver;
        udc->gadget.dev.driver = NULL;
 
        retval = 0;
-       for (i = 0; i < hw_ep_max; i++) {
-               struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+       for (i = 0; i < hw_ep_max/2; i++) {
+               for (j = RX; j <= TX; j++) {
+                       int k = i + j * hw_ep_max/2;
+                       struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
 
-               scnprintf(mEp->name, sizeof(mEp->name), "ep%i", (int)i);
+                       scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+                                       (j == TX)  ? "in" : "out");
 
-               mEp->lock         = udc->lock;
-               mEp->device       = &udc->gadget.dev;
-               mEp->td_pool      = udc->td_pool;
+                       mEp->lock         = udc->lock;
+                       mEp->device       = &udc->gadget.dev;
+                       mEp->td_pool      = udc->td_pool;
 
-               mEp->ep.name      = mEp->name;
-               mEp->ep.ops       = &usb_ep_ops;
-               mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+                       mEp->ep.name      = mEp->name;
+                       mEp->ep.ops       = &usb_ep_ops;
+                       mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
 
-               /* this allocation cannot be random */
-               for (k = RX; k <= TX; k++) {
-                       INIT_LIST_HEAD(&mEp->qh[k].queue);
+                       INIT_LIST_HEAD(&mEp->qh.queue);
                        spin_unlock_irqrestore(udc->lock, flags);
-                       mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool,
-                                                       GFP_KERNEL,
-                                                       &mEp->qh[k].dma);
+                       mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+                                       &mEp->qh.dma);
                        spin_lock_irqsave(udc->lock, flags);
-                       if (mEp->qh[k].ptr == NULL)
+                       if (mEp->qh.ptr == NULL)
                                retval = -ENOMEM;
                        else
-                               memset(mEp->qh[k].ptr, 0,
-                                      sizeof(*mEp->qh[k].ptr));
-               }
-               if (i == 0)
-                       udc->gadget.ep0 = &mEp->ep;
-               else
+                               memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+                       /* skip ep0 out and in endpoints */
+                       if (i == 0)
+                               continue;
+
                        list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+               }
        }
        if (retval)
                goto done;
 
+       udc->gadget.ep0 = &udc->ep0in.ep;
        /* bind gadget */
        driver->driver.bus     = NULL;
        udc->gadget.dev.driver = &driver->driver;
@@ -2479,6 +2489,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                goto done;
        }
 
+       udc->driver = driver;
        pm_runtime_get_sync(&udc->gadget.dev);
        if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
                if (udc->vbus_active) {
@@ -2490,14 +2501,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                }
        }
 
-       retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+       retval = hw_device_state(udc->ep0out.qh.dma);
        if (retval)
                pm_runtime_put_sync(&udc->gadget.dev);
 
  done:
        spin_unlock_irqrestore(udc->lock, flags);
-       if (retval)
-               usb_gadget_unregister_driver(driver);
        return retval;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -2510,7 +2519,7 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
        struct ci13xxx *udc = _udc;
-       unsigned long i, k, flags;
+       unsigned long i, flags;
 
        trace("%p", driver);
 
@@ -2546,17 +2555,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        for (i = 0; i < hw_ep_max; i++) {
                struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
 
-               if (i == 0)
-                       udc->gadget.ep0 = NULL;
-               else if (!list_empty(&mEp->ep.ep_list))
+               if (!list_empty(&mEp->ep.ep_list))
                        list_del_init(&mEp->ep.ep_list);
 
-               for (k = RX; k <= TX; k++)
-                       if (mEp->qh[k].ptr != NULL)
-                               dma_pool_free(udc->qh_pool,
-                                             mEp->qh[k].ptr, mEp->qh[k].dma);
+               if (mEp->qh.ptr != NULL)
+                       dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
        }
 
+       udc->gadget.ep0 = NULL;
        udc->driver = NULL;
 
        spin_unlock_irqrestore(udc->lock, flags);
index f61fed0..a2492b6 100644 (file)
@@ -20,7 +20,7 @@
  * DEFINE
  *****************************************************************************/
 #define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
-#define ENDPT_MAX          (16)
+#define ENDPT_MAX          (32)
 #define CTRL_PAYLOAD_MAX   (64)
 #define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
 #define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
@@ -88,8 +88,7 @@ struct ci13xxx_ep {
                struct list_head   queue;
                struct ci13xxx_qh *ptr;
                dma_addr_t         dma;
-       }                                      qh[2];
-       struct usb_request                    *status;
+       }                                      qh;
        int                                    wedge;
 
        /* global resources */
@@ -119,9 +118,13 @@ struct ci13xxx {
 
        struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
        struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
+       struct usb_request        *status;    /* ep0 status request */
 
        struct usb_gadget          gadget;     /* USB slave device */
        struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
+       u32                        ep0_dir;    /* ep0 direction */
+#define ep0out ci13xxx_ep[0]
+#define ep0in  ci13xxx_ep[16]
 
        struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
        struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
index f6ff845..1ba4bef 100644 (file)
@@ -928,8 +928,9 @@ unknown:
                 */
                switch (ctrl->bRequestType & USB_RECIP_MASK) {
                case USB_RECIP_INTERFACE:
-                       if (cdev->config)
-                               f = cdev->config->interface[intf];
+                       if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
+                               break;
+                       f = cdev->config->interface[intf];
                        break;
 
                case USB_RECIP_ENDPOINT:
index b5dbb23..6d8e533 100644 (file)
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
 
 #include "gadget_chips.h"
 
@@ -2763,7 +2764,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
                        return ERR_PTR(-ENOMEM);
                common->free_storage_on_release = 1;
        } else {
-               memset(common, 0, sizeof common);
+               memset(common, 0, sizeof *common);
                common->free_storage_on_release = 0;
        }
 
index 3c6e1a0..5e14950 100644 (file)
@@ -346,14 +346,19 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
 
                if (unlikely(!skb))
                        break;
-               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0,
-                               req->actual);
-               page = NULL;
 
-               if (req->actual < req->length) { /* Last fragment */
+               if (skb->len == 0) { /* First fragment */
                        skb->protocol = htons(ETH_P_PHONET);
                        skb_reset_mac_header(skb);
-                       pskb_pull(skb, 1);
+                       /* Can't use pskb_pull() on page in IRQ */
+                       memcpy(skb_put(skb, 1), page_address(page), 1);
+               }
+
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               skb->len == 0, req->actual);
+               page = NULL;
+
+               if (req->actual < req->length) { /* Last fragment */
                        skb->dev = dev;
                        dev->stats.rx_packets++;
                        dev->stats.rx_bytes += skb->len;
index 0c8dd81..b120dbb 100644 (file)
 #define PCH_UDC_BRLEN          0x0F    /* Burst length */
 #define PCH_UDC_THLEN          0x1F    /* Threshold length */
 /* Value of EP Buffer Size */
-#define UDC_EP0IN_BUFF_SIZE    64
-#define UDC_EPIN_BUFF_SIZE     512
-#define UDC_EP0OUT_BUFF_SIZE   64
-#define UDC_EPOUT_BUFF_SIZE    512
+#define UDC_EP0IN_BUFF_SIZE    16
+#define UDC_EPIN_BUFF_SIZE     256
+#define UDC_EP0OUT_BUFF_SIZE   16
+#define UDC_EPOUT_BUFF_SIZE    256
 /* Value of EP maximum packet size */
 #define UDC_EP0IN_MAX_PKT_SIZE 64
 #define UDC_EP0OUT_MAX_PKT_SIZE        64
@@ -351,7 +351,7 @@ struct pch_udc_dev {
        struct pci_pool         *data_requests;
        struct pci_pool         *stp_requests;
        dma_addr_t                      dma_addr;
-       unsigned long                   ep0out_buf[64];
+       void                            *ep0out_buf;
        struct usb_ctrlrequest          setup_data;
        unsigned long                   phys_addr;
        void __iomem                    *base_addr;
@@ -361,6 +361,8 @@ struct pch_udc_dev {
 
 #define PCH_UDC_PCI_BAR                        1
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC  0x8808
+#define PCI_VENDOR_ID_ROHM             0x10DB
+#define PCI_DEVICE_ID_ML7213_IOH_UDC   0x801D
 
 static const char      ep0_string[] = "ep0in";
 static DEFINE_SPINLOCK(udc_stall_spinlock);    /* stall spin lock */
@@ -1219,11 +1221,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
        dev = ep->dev;
        if (req->dma_mapped) {
                if (ep->in)
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_TODEVICE);
+                       dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                        req->req.length, DMA_TO_DEVICE);
                else
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                        req->req.length, DMA_FROM_DEVICE);
                req->dma_mapped = 0;
                req->req.dma = DMA_ADDR_INVALID;
        }
@@ -1414,7 +1416,6 @@ static void pch_udc_start_rxrequest(struct pch_udc_ep *ep,
 
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
        td_data = req->td_data;
-       ep->td_data = req->td_data;
        /* Set the status bits for all descriptors */
        while (1) {
                td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
@@ -1613,15 +1614,19 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
        if (usbreq->length &&
            ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
                if (ep->in)
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_TODEVICE);
+                       usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                    usbreq->buf,
+                                                    usbreq->length,
+                                                    DMA_TO_DEVICE);
                else
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_FROMDEVICE);
+                       usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                    usbreq->buf,
+                                                    usbreq->length,
+                                                    DMA_FROM_DEVICE);
                req->dma_mapped = 1;
        }
        if (usbreq->length > 0) {
-               retval = prepare_dma(ep, req, gfp);
+               retval = prepare_dma(ep, req, GFP_ATOMIC);
                if (retval)
                        goto probe_end;
        }
@@ -1646,7 +1651,6 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                        pch_udc_wait_ep_stall(ep);
                        pch_udc_ep_clear_nak(ep);
                        pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num));
-                       pch_udc_set_dma(dev, DMA_DIR_TX);
                }
        }
        /* Now add this request to the ep's pending requests */
@@ -1926,6 +1930,7 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
            PCH_UDC_BS_DMA_DONE)
                return;
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
+       pch_udc_ep_set_ddptr(ep, 0);
        if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
            PCH_UDC_RTS_SUCC) {
                dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
@@ -1963,7 +1968,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
        u32     epsts;
        struct pch_udc_ep       *ep;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2008,7 +2013,7 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep               *ep;
        struct pch_udc_request          *req = NULL;
 
-       ep = &dev->ep[2*ep_num + 1];
+       ep = &dev->ep[UDC_EPOUT_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2025,10 +2030,11 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        }
        if (epsts & UDC_EPSTS_HE)
                return;
-       if (epsts & UDC_EPSTS_RSS)
+       if (epsts & UDC_EPSTS_RSS) {
                pch_udc_ep_set_stall(ep);
                pch_udc_enable_ep_interrupts(ep->dev,
                                             PCH_UDC_EPINT(ep->in, ep->num));
+       }
        if (epsts & UDC_EPSTS_RCS) {
                if (!dev->prot_stall) {
                        pch_udc_ep_clear_stall(ep);
@@ -2060,8 +2066,10 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
 {
        u32     epsts;
        struct pch_udc_ep       *ep;
+       struct pch_udc_ep       *ep_out;
 
        ep = &dev->ep[UDC_EP0IN_IDX];
+       ep_out = &dev->ep[UDC_EP0OUT_IDX];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2073,8 +2081,16 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
                return;
        if (epsts & UDC_EPSTS_HE)
                return;
-       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall))
+       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) {
                pch_udc_complete_transfer(ep);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               ep_out->td_data->status = (ep_out->td_data->status &
+                                       ~PCH_UDC_BUFF_STS) |
+                                       PCH_UDC_BS_HST_RDY;
+               pch_udc_ep_clear_nak(ep_out);
+               pch_udc_set_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_rrdy(ep_out);
+       }
        /* On IN interrupt, provide data if we have any */
        if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) &&
             !(epsts & UDC_EPSTS_TXEMPTY))
@@ -2102,11 +2118,9 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                dev->stall = 0;
                dev->ep[UDC_EP0IN_IDX].halted = 0;
                dev->ep[UDC_EP0OUT_IDX].halted = 0;
-               /* In data not ready */
-               pch_udc_ep_set_nak(&(dev->ep[UDC_EP0IN_IDX]));
                dev->setup_data = ep->td_stp->request;
                pch_udc_init_setup_buff(ep->td_stp);
-               pch_udc_clear_dma(dev, DMA_DIR_TX);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
                pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]),
                                      dev->ep[UDC_EP0IN_IDX].in);
                if ((dev->setup_data.bRequestType & USB_DIR_IN))
@@ -2122,14 +2136,23 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                setup_supported = dev->driver->setup(&dev->gadget,
                                                     &dev->setup_data);
                spin_lock(&dev->lock);
+
+               if (dev->setup_data.bRequestType & USB_DIR_IN) {
+                       ep->td_data->status = (ep->td_data->status &
+                                               ~PCH_UDC_BUFF_STS) |
+                                               PCH_UDC_BS_HST_RDY;
+                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
+               }
                /* ep0 in returns data on IN phase */
                if (setup_supported >= 0 && setup_supported <
                                            UDC_EP0IN_MAX_PKT_SIZE) {
                        pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX]));
                        /* Gadget would have queued a request when
                         * we called the setup */
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-                       pch_udc_ep_clear_nak(ep);
+                       if (!(dev->setup_data.bRequestType & USB_DIR_IN)) {
+                               pch_udc_set_dma(dev, DMA_DIR_RX);
+                               pch_udc_ep_clear_nak(ep);
+                       }
                } else if (setup_supported < 0) {
                        /* if unsupported request, then stall */
                        pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX]));
@@ -2142,22 +2165,13 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                }
        } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
                     UDC_EPSTS_OUT_DATA) && !dev->stall) {
-               if (list_empty(&ep->queue)) {
-                       dev_err(&dev->pdev->dev, "%s: No request\n", __func__);
-                       ep->td_data->status = (ep->td_data->status &
-                                              ~PCH_UDC_BUFF_STS) |
-                                              PCH_UDC_BS_HST_RDY;
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-               } else {
-                       /* control write */
-                       /* next function will pickuo an clear the status */
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_ddptr(ep, 0);
+               if (!list_empty(&ep->queue)) {
                        ep->epsts = stat;
-
-                       pch_udc_svc_data_out(dev, 0);
-                       /* re-program desc. pointer for possible ZLPs */
-                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
+                       pch_udc_svc_data_out(dev, PCH_UDC_EP0);
                }
+               pch_udc_set_dma(dev, DMA_DIR_RX);
        }
        pch_udc_ep_set_rrdy(ep);
 }
@@ -2174,7 +2188,7 @@ static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep       *ep;
        struct pch_udc_request *req;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        if (!list_empty(&ep->queue)) {
                req = list_entry(ep->queue.next, struct pch_udc_request, queue);
                pch_udc_enable_ep_interrupts(ep->dev,
@@ -2196,13 +2210,13 @@ static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
        for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
                /* IN */
                if (ep_intr & (0x1 << i)) {
-                       ep = &dev->ep[2*i];
+                       ep = &dev->ep[UDC_EPIN_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
                /* OUT */
                if (ep_intr & (0x10000 << i)) {
-                       ep = &dev->ep[2*i+1];
+                       ep = &dev->ep[UDC_EPOUT_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
@@ -2563,9 +2577,6 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
        dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
 
-       dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256,
-                                 PCI_DMA_FROMDEVICE);
-
        /* remove ep0 in and out from the list.  They have own pointer */
        list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
        list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list);
@@ -2637,6 +2648,13 @@ static int init_dma_pools(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0;
        dev->ep[UDC_EP0IN_IDX].td_data = NULL;
        dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
+
+       dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
+       if (!dev->ep0out_buf)
+               return -ENOMEM;
+       dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
+                                      UDC_EP0OUT_BUFF_SIZE * 4,
+                                      DMA_FROM_DEVICE);
        return 0;
 }
 
@@ -2700,7 +2718,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
        pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 
-       /* Assues that there are no pending requets with this driver */
+       /* Assures that there are no pending requests with this driver */
+       driver->disconnect(&dev->gadget);
        driver->unbind(&dev->gadget);
        dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
@@ -2750,6 +2769,11 @@ static void pch_udc_remove(struct pci_dev *pdev)
                pci_pool_destroy(dev->stp_requests);
        }
 
+       if (dev->dma_addr)
+               dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
+                                UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
+       kfree(dev->ep0out_buf);
+
        pch_udc_exit(dev);
 
        if (dev->irq_registered)
@@ -2792,11 +2816,7 @@ static int pch_udc_resume(struct pci_dev *pdev)
        int ret;
 
        pci_set_power_state(pdev, PCI_D0);
-       ret = pci_restore_state(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__);
-               return ret;
-       }
+       pci_restore_state(pdev);
        ret = pci_enable_device(pdev);
        if (ret) {
                dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
@@ -2914,6 +2934,11 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
                .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
                .class_mask = 0xffffffff,
        },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC),
+               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask = 0xffffffff,
+       },
        { 0 },
 };
 
index 2fc8636..12ff6cf 100644 (file)
@@ -131,31 +131,31 @@ static struct printer_dev usb_printer_gadget;
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
-static char *__initdata iSerialNum;
+static char *iSerialNum;
 module_param(iSerialNum, charp, S_IRUGO);
 MODULE_PARM_DESC(iSerialNum, "1");
 
-static char *__initdata iPNPstring;
+static char *iPNPstring;
 module_param(iPNPstring, charp, S_IRUGO);
 MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
 
@@ -1596,13 +1596,12 @@ cleanup(void)
        int status;
 
        mutex_lock(&usb_printer_gadget.lock_printer_io);
-       class_destroy(usb_gadget_class);
-       unregister_chrdev_region(g_printer_devno, 2);
-
        status = usb_gadget_unregister_driver(&printer_driver);
        if (status)
                ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
 
+       unregister_chrdev_region(g_printer_devno, 2);
+       class_destroy(usb_gadget_class);
        mutex_unlock(&usb_printer_gadget.lock_printer_io);
 }
 module_exit(cleanup);
index 20d43da..0151185 100644 (file)
@@ -258,7 +258,7 @@ static int pipe_buffer_setting(struct r8a66597 *r8a66597,
                break;
        case R8A66597_BULK:
                /* isochronous pipes may be used as bulk pipes */
-               if (info->pipe > R8A66597_BASE_PIPENUM_BULK)
+               if (info->pipe >= R8A66597_BASE_PIPENUM_BULK)
                        bufnum = info->pipe - R8A66597_BASE_PIPENUM_BULK;
                else
                        bufnum = info->pipe - R8A66597_BASE_PIPENUM_ISOC;
index 24046c0..0e6afa2 100644 (file)
@@ -151,6 +151,8 @@ config USB_EHCI_MSM
          Qualcomm chipsets. Root Hub has inbuilt TT.
          This driver depends on OTG driver for PHY initialization,
          clock management, powering up VBUS, and power management.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
 config USB_EHCI_HCD_PPC_OF
        bool "EHCI support for PPC USB controller on OF platform bus"
index 2baf8a8..a869e3c 100644 (file)
@@ -227,8 +227,8 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
         * mark HW unaccessible.  The PM and USB cores make sure that
         * the root hub is either suspended or stopped.
         */
-       spin_lock_irqsave(&ehci->lock, flags);
        ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+       spin_lock_irqsave(&ehci->lock, flags);
        ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
index 86e4289..5c761df 100644 (file)
@@ -52,7 +52,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        struct resource *res;
        int irq;
        int retval;
-       unsigned int temp;
 
        pr_debug("initializing FSL-SOC USB Controller\n");
 
@@ -126,18 +125,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
                goto err3;
        }
 
-       /*
-        * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
-        * flag for 83xx or 8536 system interface registers.
-        */
-       if (pdata->big_endian_mmio)
-               temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
-       else
-               temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
-
-       if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
-               pdata->have_sysif_regs = 1;
-
        /* Enable USB controller, 83xx or 8536 */
        if (pdata->have_sysif_regs)
                setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
index 2c83537..3fabed3 100644 (file)
@@ -19,9 +19,6 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
-#define FSL_SOC_USB_ID         0x0
-#define ID_MSK                 0x3f
-#define NID_MSK                        0x3f00
 #define FSL_SOC_USB_ULPIVP     0x170
 #define FSL_SOC_USB_PORTSC1    0x184
 #define PORT_PTS_MSK           (3<<30)
index 6fee3cd..74dcf49 100644 (file)
@@ -572,6 +572,8 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->iaa_watchdog.function = ehci_iaa_watchdog;
        ehci->iaa_watchdog.data = (unsigned long) ehci;
 
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
+
        /*
         * hw default: 1K periodic list heads, one per frame.
         * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -579,11 +581,20 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->periodic_size = DEFAULT_I_TDPS;
        INIT_LIST_HEAD(&ehci->cached_itd_list);
        INIT_LIST_HEAD(&ehci->cached_sitd_list);
+
+       if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+               /* periodic schedule size can be smaller than default */
+               switch (EHCI_TUNE_FLS) {
+               case 0: ehci->periodic_size = 1024; break;
+               case 1: ehci->periodic_size = 512; break;
+               case 2: ehci->periodic_size = 256; break;
+               default:        BUG();
+               }
+       }
        if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
                return retval;
 
        /* controllers may cache some of the periodic schedule ... */
-       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
                ehci->i_thresh = 2 + 8;
        else                                    // N microframes cached
@@ -637,12 +648,6 @@ static int ehci_init(struct usb_hcd *hcd)
                /* periodic schedule size can be smaller than default */
                temp &= ~(3 << 2);
                temp |= (EHCI_TUNE_FLS << 2);
-               switch (EHCI_TUNE_FLS) {
-               case 0: ehci->periodic_size = 1024; break;
-               case 1: ehci->periodic_size = 512; break;
-               case 2: ehci->periodic_size = 256; break;
-               default:        BUG();
-               }
        }
        if (HCC_LPM(hcc_params)) {
                /* support link power management EHCI 1.1 addendum */
index 796ea0c..8a515f0 100644 (file)
@@ -111,6 +111,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 {
        int             port;
        u32             temp;
+       unsigned long   flags;
 
        /* If remote wakeup is enabled for the root hub but disabled
         * for the controller, we must adjust all the port wakeup flags
@@ -120,6 +121,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
                return;
 
+       spin_lock_irqsave(&ehci->lock, flags);
+
        /* clear phy low-power mode before changing wakeup flags */
        if (ehci->has_hostpc) {
                port = HCS_N_PORTS(ehci->hcs_params);
@@ -131,7 +134,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
                        temp = ehci_readl(ehci, hostpc_reg);
                        ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
                }
+               spin_unlock_irqrestore(&ehci->lock, flags);
                msleep(5);
+               spin_lock_irqsave(&ehci->lock, flags);
        }
 
        port = HCS_N_PORTS(ehci->hcs_params);
@@ -170,6 +175,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        /* Does the root hub have a port wakeup pending? */
        if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
                usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
+
+       spin_unlock_irqrestore(&ehci->lock, flags);
 }
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
index fa59b26..c8e360d 100644 (file)
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
 #include <linux/slab.h>
 
 #include <mach/mxc_ehci.h>
 
+#include <asm/mach-types.h>
+
 #define ULPI_VIEWPORT_OFFSET   0x170
 
 struct ehci_mxc_priv {
@@ -114,6 +117,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        struct usb_hcd *hcd;
        struct resource *res;
        int irq, ret;
+       unsigned int flags;
        struct ehci_mxc_priv *priv;
        struct device *dev = &pdev->dev;
        struct ehci_hcd *ehci;
@@ -177,8 +181,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                clk_enable(priv->ahbclk);
        }
 
-       /* "dr" device has its own clock */
-       if (pdev->id == 0) {
+       /* "dr" device has its own clock on i.MX51 */
+       if (cpu_is_mx51() && (pdev->id == 0)) {
                priv->phy1clk = clk_get(dev, "usb_phy1");
                if (IS_ERR(priv->phy1clk)) {
                        ret = PTR_ERR(priv->phy1clk);
@@ -240,6 +244,23 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (ret)
                goto err_add;
 
+       if (pdata->otg) {
+               /*
+                * efikamx and efikasb have some hardware bug which is
+                * preventing usb to work unless CHRGVBUS is set.
+                * It's in violation of USB specs
+                */
+               if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
+                       flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
+                       flags |= ULPI_OTG_CTRL_CHRGVBUS;
+                       ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
+                       if (ret) {
+                               dev_err(dev, "unable to set CHRVBUS\n");
+                               goto err_add;
+                       }
+               }
+       }
+
        return 0;
 
 err_add:
index 680f2ef..f784ceb 100644 (file)
@@ -796,7 +796,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev,
                        dev_name(&pdev->dev));
        if (!hcd) {
-               dev_dbg(&pdev->dev, "failed to create hcd with err %d\n", ret);
+               dev_err(&pdev->dev, "failed to create hcd with err %d\n", ret);
                ret = -ENOMEM;
                goto err_create_hcd;
        }
@@ -864,7 +864,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
        ret = omap_start_ehc(omap, hcd);
        if (ret) {
-               dev_dbg(&pdev->dev, "failed to start ehci\n");
+               dev_err(&pdev->dev, "failed to start ehci with err %d\n", ret);
                goto err_start;
        }
 
@@ -879,7 +879,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
        ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
        if (ret) {
-               dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
+               dev_err(&pdev->dev, "failed to add hcd with err %d\n", ret);
                goto err_add_hcd;
        }
 
index 76179c3..07bb982 100644 (file)
@@ -44,28 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        return 0;
 }
 
-static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci)
+static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci)
 {
        struct pci_dev *amd_smbus_dev;
        u8 rev = 0;
 
        amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
-       if (!amd_smbus_dev)
-               return 0;
-
-       pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
-       if (rev < 0x40) {
-               pci_dev_put(amd_smbus_dev);
-               amd_smbus_dev = NULL;
-               return 0;
+       if (amd_smbus_dev) {
+               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+               if (rev < 0x40) {
+                       pci_dev_put(amd_smbus_dev);
+                       amd_smbus_dev = NULL;
+                       return 0;
+               }
+       } else {
+               amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL);
+               if (!amd_smbus_dev)
+                       return 0;
+               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+               if (rev < 0x11 || rev > 0x18) {
+                       pci_dev_put(amd_smbus_dev);
+                       amd_smbus_dev = NULL;
+                       return 0;
+               }
        }
 
        if (!amd_nb_dev)
                amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
-       if (!amd_nb_dev)
-               ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
 
-       ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n");
+       ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n");
 
        pci_dev_put(amd_smbus_dev);
        amd_smbus_dev = NULL;
@@ -131,7 +138,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
-       if (ehci_quirk_amd_SB800(ehci))
+       if (ehci_quirk_amd_hudson(ehci))
                ehci->amd_l1_fix = 1;
 
        retval = ehci_halt(ehci);
@@ -360,8 +367,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
         * mark HW unaccessible.  The PM and USB cores make sure that
         * the root hub is either suspended or stopped.
         */
-       spin_lock_irqsave (&ehci->lock, flags);
        ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
+       spin_lock_irqsave (&ehci->lock, flags);
        ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
index e8f4f36..a6f21b8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
 
 /**
  * ehci_xilinx_of_setup - Initialize the device for ehci_reset()
index 574b99e..79a66d6 100644 (file)
@@ -262,19 +262,24 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
        }
 }
 
-struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
+static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
        .big_endian_desc = 1,
        .big_endian_mmio = 1,
        .es = 1,
+       .have_sysif_regs = 0,
        .le_setup_buf = 1,
        .init = fsl_usb2_mpc5121_init,
        .exit = fsl_usb2_mpc5121_exit,
 };
 #endif /* CONFIG_PPC_MPC512x */
 
+static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = {
+       .have_sysif_regs = 1,
+};
+
 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
-       { .compatible = "fsl-usb2-mph", },
-       { .compatible = "fsl-usb2-dr", },
+       { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, },
+       { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, },
 #ifdef CONFIG_PPC_MPC512x
        { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
 #endif
index 990f06b..2e9602a 100644 (file)
@@ -861,6 +861,7 @@ static int sl811h_urb_enqueue(
                        DBG("dev %d ep%d maxpacket %d\n",
                                udev->devnum, epnum, ep->maxpacket);
                        retval = -EINVAL;
+                       kfree(ep);
                        goto fail;
                }
 
index fcbf4ab..0231814 100644 (file)
@@ -169,9 +169,10 @@ static void xhci_print_ports(struct xhci_hcd *xhci)
        }
 }
 
-void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num)
+void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)
 {
-       void *addr;
+       struct xhci_intr_reg __iomem *ir_set = &xhci->run_regs->ir_set[set_num];
+       void __iomem *addr;
        u32 temp;
        u64 temp_64;
 
@@ -449,7 +450,7 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
        }
 }
 
-void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
+static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
 {
        /* Fields are 32 bits wide, DMA addresses are in bytes */
        int field_size = 32 / 8;
@@ -488,7 +489,7 @@ void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
                dbg_rsvd64(xhci, (u64 *)slot_ctx, dma);
 }
 
-void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
+static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
                     struct xhci_container_ctx *ctx,
                     unsigned int last_ep)
 {
index 1d0f45f..a953439 100644 (file)
@@ -307,7 +307,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
 
 /***************** Streams structures manipulation *************************/
 
-void xhci_free_stream_ctx(struct xhci_hcd *xhci,
+static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs,
                struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
 {
@@ -335,7 +335,7 @@ void xhci_free_stream_ctx(struct xhci_hcd *xhci,
  * The stream context array must be a power of 2, and can be as small as
  * 64 bytes or as large as 1MB.
  */
-struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
+static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs, dma_addr_t *dma,
                gfp_t mem_flags)
 {
@@ -1900,11 +1900,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        val &= DBOFF_MASK;
        xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
                        " from cap regs base addr\n", val);
-       xhci->dba = (void *) xhci->cap_regs + val;
+       xhci->dba = (void __iomem *) xhci->cap_regs + val;
        xhci_dbg_regs(xhci);
        xhci_print_run_regs(xhci);
        /* Set ir_set to interrupt register set 0 */
-       xhci->ir_set = (void *) xhci->run_regs->ir_set;
+       xhci->ir_set = &xhci->run_regs->ir_set[0];
 
        /*
         * Event ring setup: Allocate a normal ring, but also setup
@@ -1961,7 +1961,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        /* Set the event ring dequeue address */
        xhci_set_hc_event_deq(xhci);
        xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        /*
         * XXX: Might need to set the Interrupter Moderation Register to
index df558f6..3289bf4 100644 (file)
@@ -308,11 +308,8 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 /* Ring the host controller doorbell after placing a command on the ring */
 void xhci_ring_cmd_db(struct xhci_hcd *xhci)
 {
-       u32 temp;
-
        xhci_dbg(xhci, "// Ding dong!\n");
-       temp = xhci_readl(xhci, &xhci->dba->doorbell[0]) & DB_MASK;
-       xhci_writel(xhci, temp | DB_TARGET_HOST, &xhci->dba->doorbell[0]);
+       xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
        /* Flush PCI posted writes */
        xhci_readl(xhci, &xhci->dba->doorbell[0]);
 }
@@ -322,26 +319,24 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
                unsigned int ep_index,
                unsigned int stream_id)
 {
-       struct xhci_virt_ep *ep;
-       unsigned int ep_state;
-       u32 field;
        __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
+       struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
+       unsigned int ep_state = ep->ep_state;
 
-       ep = &xhci->devs[slot_id]->eps[ep_index];
-       ep_state = ep->ep_state;
        /* Don't ring the doorbell for this endpoint if there are pending
-        * cancellations because the we don't want to interrupt processing.
+        * cancellations because we don't want to interrupt processing.
         * We don't want to restart any stream rings if there's a set dequeue
         * pointer command pending because the device can choose to start any
         * stream once the endpoint is on the HW schedule.
         * FIXME - check all the stream rings for pending cancellations.
         */
-       if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
-                       && !(ep_state & EP_HALTED)) {
-               field = xhci_readl(xhci, db_addr) & DB_MASK;
-               field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id);
-               xhci_writel(xhci, field, db_addr);
-       }
+       if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) ||
+           (ep_state & EP_HALTED))
+               return;
+       xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr);
+       /* The CPU has better things to do at this point than wait for a
+        * write-posting flush.  It'll get there soon enough.
+        */
 }
 
 /* Ring the doorbell for any rings with pending URBs */
@@ -479,8 +474,11 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        state->new_deq_seg = find_trb_seg(cur_td->start_seg,
                        dev->eps[ep_index].stopped_trb,
                        &state->new_cycle_state);
-       if (!state->new_deq_seg)
-               BUG();
+       if (!state->new_deq_seg) {
+               WARN_ON(1);
+               return;
+       }
+
        /* Dig out the cycle state saved by the xHC during the stop ep cmd */
        xhci_dbg(xhci, "Finding endpoint context\n");
        ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
@@ -491,8 +489,10 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        state->new_deq_seg = find_trb_seg(state->new_deq_seg,
                        state->new_deq_ptr,
                        &state->new_cycle_state);
-       if (!state->new_deq_seg)
-               BUG();
+       if (!state->new_deq_seg) {
+               WARN_ON(1);
+               return;
+       }
 
        trb = &state->new_deq_ptr->generic;
        if ((trb->field[3] & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK) &&
@@ -1188,7 +1188,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
 
        addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1);
        temp = xhci_readl(xhci, addr);
-       if ((temp & PORT_CONNECT) && (hcd->state == HC_STATE_SUSPENDED)) {
+       if (hcd->state == HC_STATE_SUSPENDED) {
                xhci_dbg(xhci, "resume root hub\n");
                usb_hcd_resume_root_hub(hcd);
        }
@@ -1710,8 +1710,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                /* Others already handled above */
                break;
        }
-       dev_dbg(&td->urb->dev->dev,
-                       "ep %#x - asked for %d bytes, "
+       xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
                        "%d bytes untransferred\n",
                        td->urb->ep->desc.bEndpointAddress,
                        td->urb->transfer_buffer_length,
@@ -2369,12 +2368,13 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
 
                /* Scatter gather list entries may cross 64KB boundaries */
                running_total = TRB_MAX_BUFF_SIZE -
-                       (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+                       (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
+               running_total &= TRB_MAX_BUFF_SIZE - 1;
                if (running_total != 0)
                        num_trbs++;
 
                /* How many more 64KB chunks to transfer, how many more TRBs? */
-               while (running_total < sg_dma_len(sg)) {
+               while (running_total < sg_dma_len(sg) && running_total < temp) {
                        num_trbs++;
                        running_total += TRB_MAX_BUFF_SIZE;
                }
@@ -2389,7 +2389,8 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
        }
        xhci_dbg(xhci, "\n");
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %d, sglist used, num_trbs = %d\n",
+               xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, "
+                               "num_trbs = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
                                num_trbs);
@@ -2399,11 +2400,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
 static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
 {
        if (num_trbs != 0)
-               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
+               dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
                                "TRBs, %d left\n", __func__,
                                urb->ep->desc.bEndpointAddress, num_trbs);
        if (running_total != urb->transfer_buffer_length)
-               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
+               dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
                                "queued %#x (%d), asked for %#x (%d)\n",
                                __func__,
                                urb->ep->desc.bEndpointAddress,
@@ -2414,14 +2415,17 @@ static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
 
 static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
                unsigned int ep_index, unsigned int stream_id, int start_cycle,
-               struct xhci_generic_trb *start_trb, struct xhci_td *td)
+               struct xhci_generic_trb *start_trb)
 {
        /*
         * Pass all the TRBs to the hardware at once and make sure this write
         * isn't reordered.
         */
        wmb();
-       start_trb->field[3] |= start_cycle;
+       if (start_cycle)
+               start_trb->field[3] |= start_cycle;
+       else
+               start_trb->field[3] &= ~0x1;
        xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
 }
 
@@ -2449,7 +2453,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
         * to set the polling interval (once the API is added).
         */
        if (xhci_interval != ep_interval) {
-               if (!printk_ratelimit())
+               if (printk_ratelimit())
                        dev_dbg(&urb->dev->dev, "Driver uses different interval"
                                        " (%d microframe%s) than xHCI "
                                        "(%d microframe%s)\n",
@@ -2535,8 +2539,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        sg = urb->sg;
        addr = (u64) sg_dma_address(sg);
        this_sg_len = sg_dma_len(sg);
-       trb_buff_len = TRB_MAX_BUFF_SIZE -
-               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
        trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
        if (trb_buff_len > urb->transfer_buffer_length)
                trb_buff_len = urb->transfer_buffer_length;
@@ -2551,9 +2554,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                u32 remainder = 0;
 
                /* Don't change the cycle bit of the first TRB until later */
-               if (first_trb)
+               if (first_trb) {
                        first_trb = false;
-               else
+                       if (start_cycle == 0)
+                               field |= 0x1;
+               } else
                        field |= ep_ring->cycle_state;
 
                /* Chain all the TRBs together; clear the chain bit in the last
@@ -2572,7 +2577,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
                                (unsigned int) addr + trb_buff_len);
                if (TRB_MAX_BUFF_SIZE -
-                               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)) < trb_buff_len) {
+                               (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
                        xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
                        xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
                                        (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
@@ -2616,7 +2621,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                }
 
                trb_buff_len = TRB_MAX_BUFF_SIZE -
-                       (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+                       (addr & (TRB_MAX_BUFF_SIZE - 1));
                trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
                if (running_total + trb_buff_len > urb->transfer_buffer_length)
                        trb_buff_len =
@@ -2625,7 +2630,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        check_trb_math(urb, num_trbs, running_total);
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2656,7 +2661,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        num_trbs = 0;
        /* How much data is (potentially) left before the 64KB boundary? */
        running_total = TRB_MAX_BUFF_SIZE -
-               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+               (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
+       running_total &= TRB_MAX_BUFF_SIZE - 1;
 
        /* If there's some data on this 64KB chunk, or we have to send a
         * zero-length transfer, we need at least one TRB
@@ -2671,7 +2677,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
 
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d), addr = %#llx, num_trbs = %d\n",
+               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), "
+                               "addr = %#llx, num_trbs = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
                                urb->transfer_buffer_length,
@@ -2699,8 +2706,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* How much data is in the first TRB? */
        addr = (u64) urb->transfer_dma;
        trb_buff_len = TRB_MAX_BUFF_SIZE -
-               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
-       if (urb->transfer_buffer_length < trb_buff_len)
+               (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
+       if (trb_buff_len > urb->transfer_buffer_length)
                trb_buff_len = urb->transfer_buffer_length;
 
        first_trb = true;
@@ -2711,9 +2718,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                field = 0;
 
                /* Don't change the cycle bit of the first TRB until later */
-               if (first_trb)
+               if (first_trb) {
                        first_trb = false;
-               else
+                       if (start_cycle == 0)
+                               field |= 0x1;
+               } else
                        field |= ep_ring->cycle_state;
 
                /* Chain all the TRBs together; clear the chain bit in the last
@@ -2757,7 +2766,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        check_trb_math(urb, num_trbs, running_total);
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2818,13 +2827,17 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* Queue setup TRB - see section 6.4.1.2.1 */
        /* FIXME better way to translate setup_packet into two u32 fields? */
        setup = (struct usb_ctrlrequest *) urb->setup_packet;
+       field = 0;
+       field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
+       if (start_cycle == 0)
+               field |= 0x1;
        queue_trb(xhci, ep_ring, false, true,
                        /* FIXME endianness is probably going to bite my ass here. */
                        setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
                        setup->wIndex | setup->wLength << 16,
                        TRB_LEN(8) | TRB_INTR_TARGET(0),
                        /* Immediate data in pointer */
-                       TRB_IDT | TRB_TYPE(TRB_SETUP));
+                       field);
 
        /* If there's data, queue data TRBs */
        field = 0;
@@ -2859,7 +2872,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
 
        giveback_first_trb(xhci, slot_id, ep_index, 0,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2872,8 +2885,8 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
        addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
        td_len = urb->iso_frame_desc[i].length;
 
-       running_total = TRB_MAX_BUFF_SIZE -
-                       (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
+       running_total &= TRB_MAX_BUFF_SIZE - 1;
        if (running_total != 0)
                num_trbs++;
 
@@ -2900,6 +2913,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        int running_total, trb_buff_len, td_len, td_remain_len, ret;
        u64 start_addr, addr;
        int i, j;
+       bool more_trbs_coming;
 
        ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
 
@@ -2910,7 +2924,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        }
 
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d),"
+               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d),"
                                " addr = %#llx, num_tds = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
@@ -2950,7 +2964,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                field |= TRB_TYPE(TRB_ISOC);
                                /* Assume URB_ISO_ASAP is set */
                                field |= TRB_SIA;
-                               if (i > 0)
+                               if (i == 0) {
+                                       if (start_cycle == 0)
+                                               field |= 0x1;
+                               } else
                                        field |= ep_ring->cycle_state;
                                first_trb = false;
                        } else {
@@ -2965,9 +2982,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                         */
                        if (j < trbs_per_td - 1) {
                                field |= TRB_CHAIN;
+                               more_trbs_coming = true;
                        } else {
                                td->last_trb = ep_ring->enqueue;
                                field |= TRB_IOC;
+                               more_trbs_coming = false;
                        }
 
                        /* Calculate TRB length */
@@ -2980,7 +2999,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        length_field = TRB_LEN(trb_buff_len) |
                                remainder |
                                TRB_INTR_TARGET(0);
-                       queue_trb(xhci, ep_ring, false, false,
+                       queue_trb(xhci, ep_ring, false, more_trbs_coming,
                                lower_32_bits(addr),
                                upper_32_bits(addr),
                                length_field,
@@ -3003,10 +3022,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                }
        }
 
-       wmb();
-       start_trb->field[3] |= start_cycle;
-
-       xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
+       giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -3064,7 +3081,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
         * to set the polling interval (once the API is added).
         */
        if (xhci_interval != ep_interval) {
-               if (!printk_ratelimit())
+               if (printk_ratelimit())
                        dev_dbg(&urb->dev->dev, "Driver uses different interval"
                                        " (%d microframe%s) than xHCI "
                                        "(%d microframe%s)\n",
index 45e4a31..2083fc2 100644 (file)
@@ -109,7 +109,7 @@ int xhci_halt(struct xhci_hcd *xhci)
 /*
  * Set the run bit and wait for the host to be running.
  */
-int xhci_start(struct xhci_hcd *xhci)
+static int xhci_start(struct xhci_hcd *xhci)
 {
        u32 temp;
        int ret;
@@ -226,7 +226,8 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
 static int xhci_setup_msix(struct xhci_hcd *xhci)
 {
        int i, ret = 0;
-       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       struct usb_hcd *hcd = xhci_to_hcd(xhci);
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
        /*
         * calculate number of msi-x vectors supported.
@@ -265,6 +266,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
                        goto disable_msix;
        }
 
+       hcd->msix_enabled = 1;
        return ret;
 
 disable_msix:
@@ -280,7 +282,8 @@ free_entries:
 /* Free any IRQs and disable MSI-X */
 static void xhci_cleanup_msix(struct xhci_hcd *xhci)
 {
-       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       struct usb_hcd *hcd = xhci_to_hcd(xhci);
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
        xhci_free_irq(xhci);
 
@@ -292,6 +295,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
                pci_disable_msi(pdev);
        }
 
+       hcd->msix_enabled = 0;
        return;
 }
 
@@ -325,7 +329,7 @@ int xhci_init(struct usb_hcd *hcd)
 
 
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-void xhci_event_ring_work(unsigned long arg)
+static void xhci_event_ring_work(unsigned long arg)
 {
        unsigned long flags;
        int temp;
@@ -469,7 +473,7 @@ int xhci_run(struct usb_hcd *hcd)
                        xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
        xhci_writel(xhci, ER_IRQ_ENABLE(temp),
                        &xhci->ir_set->irq_pending);
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        if (NUM_TEST_NOOPS > 0)
                doorbell = xhci_setup_one_noop(xhci);
@@ -508,9 +512,10 @@ void xhci_stop(struct usb_hcd *hcd)
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
        xhci_reset(xhci);
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       xhci_cleanup_msix(xhci);
+
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
        /* Tell the event ring poll function not to reschedule */
        xhci->zombie = 1;
@@ -523,7 +528,7 @@ void xhci_stop(struct usb_hcd *hcd)
        temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
        xhci_writel(xhci, ER_IRQ_DISABLE(temp),
                        &xhci->ir_set->irq_pending);
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        xhci_dbg(xhci, "cleaning up memory\n");
        xhci_mem_cleanup(xhci);
@@ -544,9 +549,10 @@ void xhci_shutdown(struct usb_hcd *hcd)
 
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       xhci_cleanup_msix(xhci);
+
        xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
                    xhci_readl(xhci, &xhci->op_regs->status));
 }
@@ -647,6 +653,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
        int                     rc = 0;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
+       int                     i;
 
        spin_lock_irq(&xhci->lock);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -677,10 +684,15 @@ int xhci_suspend(struct xhci_hcd *xhci)
                spin_unlock_irq(&xhci->lock);
                return -ETIMEDOUT;
        }
-       /* step 5: remove core well power */
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       /* step 5: remove core well power */
+       /* synchronize irq when using MSI-X */
+       if (xhci->msix_entries) {
+               for (i = 0; i < xhci->msix_count; i++)
+                       synchronize_irq(xhci->msix_entries[i].vector);
+       }
+
        return rc;
 }
 
@@ -694,7 +706,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 {
        u32                     command, temp = 0;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
-       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        int     old_state, retval;
 
        old_state = hcd->state;
@@ -729,9 +740,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                xhci_dbg(xhci, "Stop HCD\n");
                xhci_halt(xhci);
                xhci_reset(xhci);
-               if (hibernated)
-                       xhci_cleanup_msix(xhci);
                spin_unlock_irq(&xhci->lock);
+               xhci_cleanup_msix(xhci);
 
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
                /* Tell the event ring poll function not to reschedule */
@@ -745,7 +755,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
                xhci_writel(xhci, ER_IRQ_DISABLE(temp),
                                &xhci->ir_set->irq_pending);
-               xhci_print_ir_set(xhci, xhci->ir_set, 0);
+               xhci_print_ir_set(xhci, 0);
 
                xhci_dbg(xhci, "cleaning up memory\n");
                xhci_mem_cleanup(xhci);
@@ -765,30 +775,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                return retval;
        }
 
-       spin_unlock_irq(&xhci->lock);
-       /* Re-setup MSI-X */
-       if (hcd->irq)
-               free_irq(hcd->irq, hcd);
-       hcd->irq = -1;
-
-       retval = xhci_setup_msix(xhci);
-       if (retval)
-               /* fall back to msi*/
-               retval = xhci_setup_msi(xhci);
-
-       if (retval) {
-               /* fall back to legacy interrupt*/
-               retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
-                                       hcd->irq_descr, hcd);
-               if (retval) {
-                       xhci_err(xhci, "request interrupt %d failed\n",
-                                       pdev->irq);
-                       return retval;
-               }
-               hcd->irq = pdev->irq;
-       }
-
-       spin_lock_irq(&xhci->lock);
        /* step 4: set Run/Stop bit */
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command |= CMD_RUN;
@@ -871,7 +857,7 @@ unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
 /* Returns 1 if the arguments are OK;
  * returns 0 this is a root hub; returns -EINVAL for NULL pointers.
  */
-int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
+static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev,
                const char *func) {
        struct xhci_hcd *xhci;
@@ -1707,7 +1693,7 @@ static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
        xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
 }
 
-void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
+static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                struct xhci_dequeue_state *deq_state)
 {
@@ -2445,8 +2431,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
                xhci_err(xhci, "Error while assigning device slot ID\n");
                return 0;
        }
-       /* xhci_alloc_virt_device() does not touch rings; no need to lock */
-       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) {
+       /* xhci_alloc_virt_device() does not touch rings; no need to lock.
+        * Use GFP_NOIO, since this function can be called from
+        * xhci_discover_or_reset_device(), which may be called as part of
+        * mass storage driver error handling.
+        */
+       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
                /* Disable slot, if we can do it without mem alloc */
                xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
                spin_lock_irqsave(&xhci->lock, flags);
index 170c367..7f127df 100644 (file)
@@ -436,22 +436,18 @@ struct xhci_run_regs {
 /**
  * struct doorbell_array
  *
+ * Bits  0 -  7: Endpoint target
+ * Bits  8 - 15: RsvdZ
+ * Bits 16 - 31: Stream ID
+ *
  * Section 5.6
  */
 struct xhci_doorbell_array {
        u32     doorbell[256];
 };
 
-#define        DB_TARGET_MASK          0xFFFFFF00
-#define        DB_STREAM_ID_MASK       0x0000FFFF
-#define        DB_TARGET_HOST          0x0
-#define        DB_STREAM_ID_HOST       0x0
-#define        DB_MASK                 (0xff << 8)
-
-/* Endpoint Target - bits 0:7 */
-#define EPI_TO_DB(p)           (((p) + 1) & 0xff)
-#define STREAM_ID_TO_DB(p)     (((p) & 0xffff) << 16)
-
+#define DB_VALUE(ep, stream)   ((((ep) + 1) & 0xff) | ((stream) << 16))
+#define DB_VALUE_HOST          0x00000000
 
 /**
  * struct xhci_protocol_caps
@@ -1352,7 +1348,7 @@ static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
 }
 
 /* xHCI debugging */
-void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
+void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num);
 void xhci_print_registers(struct xhci_hcd *xhci);
 void xhci_dbg_regs(struct xhci_hcd *xhci);
 void xhci_print_run_regs(struct xhci_hcd *xhci);
index 1732d9b..1616ad1 100644 (file)
@@ -45,7 +45,7 @@ struct usb_led {
 
 static void change_color(struct usb_led *led)
 {
-       int retval;
+       int retval = 0;
        unsigned char *buffer;
 
        buffer = kmalloc(8, GFP_KERNEL);
index 4ff2158..f7a2057 100644 (file)
@@ -776,7 +776,6 @@ static const struct usb_device_id uss720_table[] = {
        { USB_DEVICE(0x0557, 0x2001) },
        { USB_DEVICE(0x0729, 0x1284) },
        { USB_DEVICE(0x1293, 0x0002) },
-       { USB_DEVICE(0x1293, 0x0002) },
        { USB_DEVICE(0x050d, 0x0002) },
        { }                                             /* Terminating entry */
 };
index eeba228..9d49d1c 100644 (file)
@@ -404,6 +404,7 @@ static int bfin_musb_init(struct musb *musb)
                musb->xceiv->set_power = bfin_musb_set_power;
 
        musb->isr = blackfin_interrupt;
+       musb->double_buffer_not_ok = true;
 
        return 0;
 }
index 07cf394..c292d5c 100644 (file)
@@ -128,12 +128,7 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
 
 static inline struct musb *dev_to_musb(struct device *dev)
 {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-       /* usbcore insists dev->driver_data is a "struct hcd *" */
-       return hcd_to_musb(dev_get_drvdata(dev));
-#else
        return dev_get_drvdata(dev);
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1869,6 +1864,7 @@ allocate_instance(struct device *dev,
        INIT_LIST_HEAD(&musb->out_bulk);
 
        hcd->uses_new_polling = 1;
+       hcd->has_tt = 1;
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
        musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -1876,10 +1872,9 @@ allocate_instance(struct device *dev,
        musb = kzalloc(sizeof *musb, GFP_KERNEL);
        if (!musb)
                return NULL;
-       dev_set_drvdata(dev, musb);
 
 #endif
-
+       dev_set_drvdata(dev, musb);
        musb->mregs = mbase;
        musb->ctrl_base = mbase;
        musb->nIrq = -ENODEV;
@@ -2191,7 +2186,7 @@ static int __init musb_probe(struct platform_device *pdev)
        void __iomem    *base;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem || irq == 0)
+       if (!iomem || irq <= 0)
                return -ENODEV;
 
        base = ioremap(iomem->start, resource_size(iomem));
index d0c236f..e6400be 100644 (file)
@@ -497,6 +497,19 @@ struct musb {
        struct usb_gadget_driver *gadget_driver;        /* its driver */
 #endif
 
+       /*
+        * FIXME: Remove this flag.
+        *
+        * This is only added to allow Blackfin to work
+        * with current driver. For some unknown reason
+        * Blackfin doesn't work with double buffering
+        * and that's enabled by default.
+        *
+        * We added this flag to forcefully disable double
+        * buffering until we get it working.
+        */
+       unsigned                double_buffer_not_ok:1 __deprecated;
+
        struct musb_hdrc_config *config;
 
 #ifdef MUSB_CONFIG_PROC_FS
index 916065b..3a97c4e 100644 (file)
@@ -169,6 +169,9 @@ struct dma_controller {
                                                        dma_addr_t dma_addr,
                                                        u32 length);
        int                     (*channel_abort)(struct dma_channel *);
+       int                     (*is_compatible)(struct dma_channel *channel,
+                                                       u16 maxpacket,
+                                                       void *buf, u32 length);
 };
 
 /* called after channel_program(), may indicate a fault */
index ed58c6c..2fe3046 100644 (file)
 
 /* ----------------------------------------------------------------------- */
 
+#define is_buffer_mapped(req) (is_dma_capable() && \
+                                       (req->map_state != UN_MAPPED))
+
 /* Maps the buffer to dma  */
 
 static inline void map_dma_buffer(struct musb_request *request,
-                               struct musb *musb)
+                       struct musb *musb, struct musb_ep *musb_ep)
 {
+       int compatible = true;
+       struct dma_controller *dma = musb->dma_controller;
+
+       request->map_state = UN_MAPPED;
+
+       if (!is_dma_capable() || !musb_ep->dma)
+               return;
+
+       /* Check if DMA engine can handle this request.
+        * DMA code must reject the USB request explicitly.
+        * Default behaviour is to map the request.
+        */
+       if (dma->is_compatible)
+               compatible = dma->is_compatible(musb_ep->dma,
+                               musb_ep->packet_sz, request->request.buf,
+                               request->request.length);
+       if (!compatible)
+               return;
+
        if (request->request.dma == DMA_ADDR_INVALID) {
                request->request.dma = dma_map_single(
                                musb->controller,
@@ -105,7 +127,7 @@ static inline void map_dma_buffer(struct musb_request *request,
                                request->tx
                                        ? DMA_TO_DEVICE
                                        : DMA_FROM_DEVICE);
-               request->mapped = 1;
+               request->map_state = MUSB_MAPPED;
        } else {
                dma_sync_single_for_device(musb->controller,
                        request->request.dma,
@@ -113,7 +135,7 @@ static inline void map_dma_buffer(struct musb_request *request,
                        request->tx
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
-               request->mapped = 0;
+               request->map_state = PRE_MAPPED;
        }
 }
 
@@ -121,11 +143,14 @@ static inline void map_dma_buffer(struct musb_request *request,
 static inline void unmap_dma_buffer(struct musb_request *request,
                                struct musb *musb)
 {
+       if (!is_buffer_mapped(request))
+               return;
+
        if (request->request.dma == DMA_ADDR_INVALID) {
                DBG(20, "not unmapping a never mapped buffer\n");
                return;
        }
-       if (request->mapped) {
+       if (request->map_state == MUSB_MAPPED) {
                dma_unmap_single(musb->controller,
                        request->request.dma,
                        request->request.length,
@@ -133,16 +158,15 @@ static inline void unmap_dma_buffer(struct musb_request *request,
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
                request->request.dma = DMA_ADDR_INVALID;
-               request->mapped = 0;
-       } else {
+       } else { /* PRE_MAPPED */
                dma_sync_single_for_cpu(musb->controller,
                        request->request.dma,
                        request->request.length,
                        request->tx
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
-
        }
+       request->map_state = UN_MAPPED;
 }
 
 /*
@@ -172,8 +196,7 @@ __acquires(ep->musb->lock)
 
        ep->busy = 1;
        spin_unlock(&musb->lock);
-       if (is_dma_capable() && ep->dma)
-               unmap_dma_buffer(req, musb);
+       unmap_dma_buffer(req, musb);
        if (request->status == 0)
                DBG(5, "%s done request %p,  %d/%d\n",
                                ep->end_point.name, request,
@@ -335,7 +358,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                        csr);
 
 #ifndef        CONFIG_MUSB_PIO_ONLY
-       if (is_dma_capable() && musb_ep->dma) {
+       if (is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                size_t request_size;
 
@@ -436,8 +459,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                 * Unmap the dma buffer back to cpu if dma channel
                 * programming fails
                 */
-               if (is_dma_capable() && musb_ep->dma)
-                       unmap_dma_buffer(req, musb);
+               unmap_dma_buffer(req, musb);
 
                musb_write_fifo(musb_ep->hw_ep, fifo_count,
                                (u8 *) (request->buf + request->actual));
@@ -627,7 +649,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                return;
        }
 
-       if (is_cppi_enabled() && musb_ep->dma) {
+       if (is_cppi_enabled() && is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                struct dma_channel      *channel = musb_ep->dma;
 
@@ -658,7 +680,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                len = musb_readw(epio, MUSB_RXCOUNT);
                if (request->actual < request->length) {
 #ifdef CONFIG_USB_INVENTRA_DMA
-                       if (is_dma_capable() && musb_ep->dma) {
+                       if (is_buffer_mapped(req)) {
                                struct dma_controller   *c;
                                struct dma_channel      *channel;
                                int                     use_dma = 0;
@@ -742,7 +764,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        fifo_count = min_t(unsigned, len, fifo_count);
 
 #ifdef CONFIG_USB_TUSB_OMAP_DMA
-                       if (tusb_dma_omap() && musb_ep->dma) {
+                       if (tusb_dma_omap() && is_buffer_mapped(req)) {
                                struct dma_controller *c = musb->dma_controller;
                                struct dma_channel *channel = musb_ep->dma;
                                u32 dma_addr = request->dma + request->actual;
@@ -762,7 +784,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                         * programming fails. This buffer is mapped if the
                         * channel allocation is successful
                         */
-                        if (is_dma_capable() && musb_ep->dma) {
+                        if (is_buffer_mapped(req)) {
                                unmap_dma_buffer(req, musb);
 
                                /*
@@ -989,7 +1011,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set TXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               if (musb->double_buffer_not_ok)
+                       musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+               else
+                       musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
+                                       | (musb_ep->hb_mult << 11));
 
                csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
                if (musb_readw(regs, MUSB_TXCSR)
@@ -1025,7 +1051,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set RXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               if (musb->double_buffer_not_ok)
+                       musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx);
+               else
+                       musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz
+                                       | (musb_ep->hb_mult << 11));
 
                /* force shared fifo to OUT-only mode */
                if (hw_ep->is_shared_fifo) {
@@ -1214,10 +1244,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        request->epnum = musb_ep->current_epnum;
        request->tx = musb_ep->is_in;
 
-       if (is_dma_capable() && musb_ep->dma)
-               map_dma_buffer(request, musb);
-       else
-               request->mapped = 0;
+       map_dma_buffer(request, musb, musb_ep);
 
        spin_lock_irqsave(&musb->lock, lockflags);
 
index dec8dc0..a55354f 100644 (file)
 #ifndef __MUSB_GADGET_H
 #define __MUSB_GADGET_H
 
+enum buffer_map_state {
+       UN_MAPPED = 0,
+       PRE_MAPPED,
+       MUSB_MAPPED
+};
+
 struct musb_request {
        struct usb_request      request;
        struct musb_ep          *ep;
        struct musb             *musb;
        u8 tx;                  /* endpoint direction */
        u8 epnum;
-       u8 mapped;
+       enum buffer_map_state map_state;
 };
 
 static inline struct musb_request *to_musb_request(struct usb_request *req)
index 4d5bcb4..0f523d7 100644 (file)
@@ -609,7 +609,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
        /* Set RXMAXP with the FIFO size of the endpoint
         * to disable double buffer mode.
         */
-       if (musb->hwvers < MUSB_HWVERS_2000)
+       if (musb->double_buffer_not_ok)
                musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
        else
                musb_writew(ep->regs, MUSB_RXMAXP,
@@ -784,14 +784,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
                /* protocol/endpoint/interval/NAKlimit */
                if (epnum) {
                        musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
-                       if (can_bulk_split(musb, qh->type))
+                       if (musb->double_buffer_not_ok)
                                musb_writew(epio, MUSB_TXMAXP,
-                                       packet_sz
-                                       | ((hw_ep->max_packet_sz_tx /
-                                               packet_sz) - 1) << 11);
+                                               hw_ep->max_packet_sz_tx);
                        else
                                musb_writew(epio, MUSB_TXMAXP,
-                                       packet_sz);
+                                               qh->maxpacket |
+                                               ((qh->hb_mult - 1) << 11));
                        musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
                } else {
                        musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
index f763d62..21056c9 100644 (file)
@@ -94,24 +94,33 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
 {
        musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW),
-               ((u16)((u32) dma_addr & 0xFFFF)));
+               dma_addr);
        musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH),
-               ((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
+               (dma_addr >> 16));
 }
 
 static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
 {
-       return musb_readl(mbase,
+       u32 count = musb_readw(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+       count = count << 16;
+
+       count |= musb_readw(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+       return count;
 }
 
 static inline void musb_write_hsdma_count(void __iomem *mbase,
                                u8 bchannel, u32 len)
 {
-       musb_writel(mbase,
+       musb_writew(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len);
+       musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
-               len);
+               (len >> 16));
 }
 
 #endif /* CONFIG_BLACKFIN */
index a3f1233..bc8badd 100644 (file)
@@ -362,6 +362,7 @@ static int omap2430_musb_init(struct musb *musb)
 
 static int omap2430_musb_exit(struct musb *musb)
 {
+       del_timer_sync(&musb_idle_timer);
 
        omap2430_low_level_exit(musb);
        otg_put_transceiver(musb->xceiv);
index 9fb875d..9ffc823 100644 (file)
@@ -103,6 +103,8 @@ config USB_MSM_OTG_72K
          required after resetting the hardware and power management.
          This driver is required even for peripheral only or host only
          mode configurations.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
 config AB8500_USB
         tristate "AB8500 USB Transceiver Driver"
index e70014a..8acf165 100644 (file)
@@ -132,6 +132,8 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, nop);
 
+       BLOCKING_INIT_NOTIFIER_HEAD(&nop->otg.notifier);
+
        return 0;
 exit:
        kfree(nop);
index 059d9ac..770d799 100644 (file)
@@ -45,7 +45,7 @@ struct ulpi_info {
 /* ULPI hardcoded IDs, used for probing */
 static struct ulpi_info ulpi_ids[] = {
        ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
-       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB3319"),
+       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
 };
 
 static int ulpi_set_otg_flags(struct otg_transceiver *otg)
index 63f7cc4..7b8815d 100644 (file)
@@ -486,12 +486,22 @@ static void ch341_read_int_callback(struct urb *urb)
        if (actual_length >= 4) {
                struct ch341_private *priv = usb_get_serial_port_data(port);
                unsigned long flags;
+               u8 prev_line_status = priv->line_status;
 
                spin_lock_irqsave(&priv->lock, flags);
                priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT;
                if ((data[1] & CH341_MULT_STAT))
                        priv->multi_status_change = 1;
                spin_unlock_irqrestore(&priv->lock, flags);
+
+               if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) {
+                       struct tty_struct *tty = tty_port_tty_get(&port->port);
+                       if (tty)
+                               usb_serial_handle_dcd_change(port, tty,
+                                           priv->line_status & CH341_BIT_DCD);
+                       tty_kref_put(tty);
+               }
+
                wake_up_interruptible(&priv->delta_msr_wait);
        }
 
index 8d7731d..735ea03 100644 (file)
@@ -49,7 +49,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
-static int cp210x_carrier_raised(struct usb_serial_port *p);
 
 static int debug;
 
@@ -87,7 +86,6 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
        { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
        { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
-       { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */
        { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
        { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
        { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
@@ -110,7 +108,9 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
        { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
        { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+       { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
        { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
+       { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
@@ -165,8 +165,7 @@ static struct usb_serial_driver cp210x_device = {
        .tiocmget               = cp210x_tiocmget,
        .tiocmset               = cp210x_tiocmset,
        .attach                 = cp210x_startup,
-       .dtr_rts                = cp210x_dtr_rts,
-       .carrier_raised         = cp210x_carrier_raised
+       .dtr_rts                = cp210x_dtr_rts
 };
 
 /* Config request types */
@@ -765,15 +764,6 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
        return result;
 }
 
-static int cp210x_carrier_raised(struct usb_serial_port *p)
-{
-       unsigned int control;
-       cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1);
-       if (control & CONTROL_DCD)
-               return 1;
-       return 0;
-}
-
 static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
index b92070c..666e5a6 100644 (file)
@@ -455,7 +455,6 @@ static int digi_write_room(struct tty_struct *tty);
 static int digi_chars_in_buffer(struct tty_struct *tty);
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
 static void digi_close(struct usb_serial_port *port);
-static int digi_carrier_raised(struct usb_serial_port *port);
 static void digi_dtr_rts(struct usb_serial_port *port, int on);
 static int digi_startup_device(struct usb_serial *serial);
 static int digi_startup(struct usb_serial *serial);
@@ -511,7 +510,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
        .open =                         digi_open,
        .close =                        digi_close,
        .dtr_rts =                      digi_dtr_rts,
-       .carrier_raised =               digi_carrier_raised,
        .write =                        digi_write,
        .write_room =                   digi_write_room,
        .write_bulk_callback =          digi_write_bulk_callback,
@@ -1339,14 +1337,6 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on)
        digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
 }
 
-static int digi_carrier_raised(struct usb_serial_port *port)
-{
-       struct digi_port *priv = usb_get_serial_port_data(port);
-       if (priv->dp_modem_signals & TIOCM_CD)
-               return 1;
-       return 0;
-}
-
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        int ret;
index a2668d0..f349a36 100644 (file)
@@ -100,6 +100,7 @@ struct ftdi_sio_quirk {
 static int   ftdi_jtag_probe(struct usb_serial *serial);
 static int   ftdi_mtxorb_hack_setup(struct usb_serial *serial);
 static int   ftdi_NDI_device_setup(struct usb_serial *serial);
+static int   ftdi_stmclite_probe(struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
 
@@ -123,6 +124,10 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
        .port_probe = ftdi_HE_TIRA1_setup,
 };
 
+static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
+       .probe  = ftdi_stmclite_probe,
+};
+
 /*
  * The 8U232AM has the same API as the sio except for:
  * - it can support MUCH higher baudrates; up to:
@@ -616,6 +621,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
        { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
+       { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
        { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
@@ -676,7 +682,17 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
-       { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
@@ -800,6 +816,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
        { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1699,6 +1717,25 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
 }
 
 /*
+ * First and second port on STMCLiteadaptors is reserved for JTAG interface
+ * and the forth port for pio
+ */
+static int ftdi_stmclite_probe(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       struct usb_interface *interface = serial->interface;
+
+       dbg("%s", __func__);
+
+       if (interface == udev->actconfig->interface[2])
+               return 0;
+
+       dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+
+       return -ENODEV;
+}
+
+/*
  * The Matrix Orbital VK204-25-USB has an invalid IN endpoint.
  * We have to correct it if we want to read from it.
  */
index bf08672..117e8e6 100644 (file)
 #define RATOC_PRODUCT_ID_USB60F        0xb020
 
 /*
+ * Acton Research Corp.
+ */
+#define ACTON_VID              0x0647  /* Vendor ID */
+#define ACTON_SPECTRAPRO_PID   0x0100
+
+/*
  * Contec products (http://www.contec.com)
  * Submitted by Daniel Sangorrin
  */
 #define OCT_US101_PID          0x0421  /* OCT US101 USB to RS-232 */
 
 /*
- * Icom ID-1 digital transceiver
+ * Definitions for Icom Inc. devices
  */
-
-#define ICOM_ID1_VID            0x0C26
-#define ICOM_ID1_PID            0x0004
+#define ICOM_VID               0x0C26 /* Icom vendor ID */
+/* Note: ID-1 is a communications tranceiver for HAM-radio operators */
+#define ICOM_ID_1_PID          0x0004 /* ID-1 USB to RS-232 */
+/* Note: OPC is an Optional cable to connect an Icom Tranceiver */
+#define ICOM_OPC_U_UC_PID      0x0018 /* OPC-478UC, OPC-1122U cloning cable */
+/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */
+#define ICOM_ID_RP2C1_PID      0x0009 /* ID-RP2C Asset 1 to RS-232 */
+#define ICOM_ID_RP2C2_PID      0x000A /* ID-RP2C Asset 2 to RS-232 */
+#define ICOM_ID_RP2D_PID       0x000B /* ID-RP2D configuration port*/
+#define ICOM_ID_RP2VT_PID      0x000C /* ID-RP2V Transmit config port */
+#define ICOM_ID_RP2VR_PID      0x000D /* ID-RP2V Receive config port */
+#define ICOM_ID_RP4KVT_PID     0x0010 /* ID-RP4000V Transmit config port */
+#define ICOM_ID_RP4KVR_PID     0x0011 /* ID-RP4000V Receive config port */
+#define ICOM_ID_RP2KVT_PID     0x0012 /* ID-RP2000V Transmit config port */
+#define ICOM_ID_RP2KVR_PID     0x0013 /* ID-RP2000V Receive config port */
 
 /*
  * GN Otometrics (http://www.otometrics.com)
 #define WHT_PID                        0x0004 /* Wireless Handheld Terminal */
 
 /*
+ * STMicroelectonics
+ */
+#define ST_VID                 0x0483
+#define ST_STMCLT1030_PID      0x3747 /* ST Micro Connect Lite STMCLT1030 */
+
+/*
  * Papouch products (http://www.papouch.com/)
  * Submitted by Folkert van Heusden
  */
index e6833e2..e4db5ad 100644 (file)
@@ -479,6 +479,26 @@ int usb_serial_handle_break(struct usb_serial_port *port)
 }
 EXPORT_SYMBOL_GPL(usb_serial_handle_break);
 
+/**
+ *     usb_serial_handle_dcd_change - handle a change of carrier detect state
+ *     @port: usb_serial_port structure for the open port
+ *     @tty: tty_struct structure for the port
+ *     @status: new carrier detect status, nonzero if active
+ */
+void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
+                               struct tty_struct *tty, unsigned int status)
+{
+       struct tty_port *port = &usb_port->port;
+
+       dbg("%s - port %d, status %d", __func__, usb_port->number, status);
+
+       if (status)
+               wake_up_interruptible(&port->open_wait);
+       else if (tty && !C_CLOCAL(tty))
+               tty_hangup(tty);
+}
+EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change);
+
 int usb_serial_generic_resume(struct usb_serial *serial)
 {
        struct usb_serial_port *port;
index cd769ef..3b246d9 100644 (file)
@@ -2889,8 +2889,8 @@ static void load_application_firmware(struct edgeport_serial *edge_serial)
 
        dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build);
 
-       edge_serial->product_info.FirmwareMajorVersion = fw->data[0];
-       edge_serial->product_info.FirmwareMinorVersion = fw->data[1];
+       edge_serial->product_info.FirmwareMajorVersion = rec->data[0];
+       edge_serial->product_info.FirmwareMinorVersion = rec->data[1];
        edge_serial->product_info.FirmwareBuildNumber = cpu_to_le16(build);
 
        for (rec = ihex_next_binrec(rec); rec;
index 6ab2a3f..178b22e 100644 (file)
@@ -199,6 +199,7 @@ static struct usb_serial_driver epic_device = {
                .name           = "epic",
        },
        .description            = "EPiC device",
+       .usb_driver             = &io_driver,
        .id_table               = Epic_port_id_table,
        .num_ports              = 1,
        .open                   = edge_open,
index 12ed594..99b97c0 100644 (file)
@@ -1275,6 +1275,7 @@ static struct usb_serial_driver iuu_device = {
                   .name = "iuu_phoenix",
                   },
        .id_table = id_table,
+       .usb_driver = &iuu_driver,
        .num_ports = 1,
        .bulk_in_size = 512,
        .bulk_out_size = 512,
index 2d8baf6..ce134dc 100644 (file)
@@ -546,6 +546,7 @@ static struct usb_serial_driver keyspan_pre_device = {
                .name           = "keyspan_no_firm",
        },
        .description            = "Keyspan - (without firmware)",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_pre_ids,
        .num_ports              = 1,
        .attach                 = keyspan_fake_startup,
@@ -557,6 +558,7 @@ static struct usb_serial_driver keyspan_1port_device = {
                .name           = "keyspan_1",
        },
        .description            = "Keyspan 1 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_1port_ids,
        .num_ports              = 1,
        .open                   = keyspan_open,
@@ -579,6 +581,7 @@ static struct usb_serial_driver keyspan_2port_device = {
                .name           = "keyspan_2",
        },
        .description            = "Keyspan 2 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_2port_ids,
        .num_ports              = 2,
        .open                   = keyspan_open,
@@ -601,6 +604,7 @@ static struct usb_serial_driver keyspan_4port_device = {
                .name           = "keyspan_4",
        },
        .description            = "Keyspan 4 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_4port_ids,
        .num_ports              = 4,
        .open                   = keyspan_open,
index a10dd56..554a869 100644 (file)
@@ -679,22 +679,6 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
        }
 }
 
-static int keyspan_pda_carrier_raised(struct usb_serial_port *port)
-{
-       struct usb_serial *serial = port->serial;
-       unsigned char modembits;
-
-       /* If we can read the modem status and the DCD is low then
-          carrier is not raised yet */
-       if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) {
-               if (!(modembits & (1>>6)))
-                       return 0;
-       }
-       /* Carrier raised, or we failed (eg disconnected) so
-          progress accordingly */
-       return 1;
-}
-
 
 static int keyspan_pda_open(struct tty_struct *tty,
                                        struct usb_serial_port *port)
@@ -881,7 +865,6 @@ static struct usb_serial_driver keyspan_pda_device = {
        .id_table =             id_table_std,
        .num_ports =            1,
        .dtr_rts =              keyspan_pda_dtr_rts,
-       .carrier_raised =       keyspan_pda_carrier_raised,
        .open =                 keyspan_pda_open,
        .close =                keyspan_pda_close,
        .write =                keyspan_pda_write,
index cf17183..653465f 100644 (file)
@@ -44,6 +44,7 @@ static struct usb_serial_driver moto_device = {
                .name =         "moto-modem",
        },
        .id_table =             id_table,
+       .usb_driver =           &moto_driver,
        .num_ports =            1,
 };
 
index 7487782..5f46838 100644 (file)
@@ -382,7 +382,16 @@ static void option_instat_callback(struct urb *urb);
 #define HAIER_VENDOR_ID                                0x201e
 #define HAIER_PRODUCT_CE100                    0x2009
 
-#define CINTERION_VENDOR_ID                    0x0681
+/* Cinterion (formerly Siemens) products */
+#define SIEMENS_VENDOR_ID                              0x0681
+#define CINTERION_VENDOR_ID                            0x1e2d
+#define CINTERION_PRODUCT_HC25_MDM             0x0047
+#define CINTERION_PRODUCT_HC25_MDMNET  0x0040
+#define CINTERION_PRODUCT_HC28_MDM             0x004C
+#define CINTERION_PRODUCT_HC28_MDMNET  0x004A /* same for HC28J */
+#define CINTERION_PRODUCT_EU3_E                        0x0051
+#define CINTERION_PRODUCT_EU3_P                        0x0052
+#define CINTERION_PRODUCT_PH8                  0x0053
 
 /* Olivetti products */
 #define OLIVETTI_VENDOR_ID                     0x0b3c
@@ -944,7 +953,17 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) },
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)},
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
-       { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
+       /* Cinterion */
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, 
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
        { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
index 5be866b..7361320 100644 (file)
@@ -157,6 +157,7 @@ static struct usb_serial_driver oti6858_device = {
                .name =         "oti6858",
        },
        .id_table =             id_table,
+       .usb_driver =           &oti6858_driver,
        .num_ports =            1,
        .open =                 oti6858_open,
        .close =                oti6858_close,
index 8ae4c6c..08c9181 100644 (file)
@@ -50,6 +50,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
@@ -677,9 +678,11 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 {
 
        struct pl2303_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
        unsigned long flags;
        u8 status_idx = UART_STATE;
        u8 length = UART_STATE + 1;
+       u8 prev_line_status;
        u16 idv, idp;
 
        idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
@@ -701,11 +704,20 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 
        /* Save off the uart status for others to look at */
        spin_lock_irqsave(&priv->lock, flags);
+       prev_line_status = priv->line_status;
        priv->line_status = data[status_idx];
        spin_unlock_irqrestore(&priv->lock, flags);
        if (priv->line_status & UART_BREAK_ERROR)
                usb_serial_handle_break(port);
        wake_up_interruptible(&priv->delta_msr_wait);
+
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+       if ((priv->line_status ^ prev_line_status) & UART_DCD)
+               usb_serial_handle_dcd_change(port, tty,
+                               priv->line_status & UART_DCD);
+       tty_kref_put(tty);
 }
 
 static void pl2303_read_int_callback(struct urb *urb)
index 43eb9bd..1b025f7 100644 (file)
@@ -21,6 +21,7 @@
 #define PL2303_PRODUCT_ID_MMX          0x0612
 #define PL2303_PRODUCT_ID_GPRS         0x0609
 #define PL2303_PRODUCT_ID_HCR331       0x331a
+#define PL2303_PRODUCT_ID_MOTOROLA     0x0307
 
 #define ATEN_VENDOR_ID         0x0557
 #define ATEN_VENDOR_ID2                0x0547
index 214a3e5..30b73e6 100644 (file)
@@ -36,6 +36,7 @@
 #define UTSTARCOM_PRODUCT_UM175_V1             0x3712
 #define UTSTARCOM_PRODUCT_UM175_V2             0x3714
 #define UTSTARCOM_PRODUCT_UM175_ALLTEL         0x3715
+#define PANTECH_PRODUCT_UML290_VZW             0x3718
 
 /* CMOTECH devices */
 #define CMOTECH_VENDOR_ID                      0x16d8
@@ -66,6 +67,7 @@ static struct usb_device_id id_table[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -84,6 +86,7 @@ static struct usb_serial_driver qcaux_device = {
                .name =         "qcaux",
        },
        .id_table =             id_table,
+       .usb_driver =           &qcaux_driver,
        .num_ports =            1,
 };
 
index cb8195c..74cd4cc 100644 (file)
@@ -42,6 +42,7 @@ static struct usb_serial_driver siemens_usb_mpi_device = {
                .name =         "siemens_mpi",
        },
        .id_table =             id_table,
+       .usb_driver =           &siemens_usb_mpi_driver,
        .num_ports =            1,
 };
 
index 7481ff8..0457813 100644 (file)
@@ -301,6 +301,9 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x0f3d, 0x68A3),   /* Airprime/Sierra Wireless Direct IP modems */
+         .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
+       },
        { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
 
        { }
index 765aa98..cbfb70b 100644 (file)
@@ -133,7 +133,7 @@ struct spcp8x5_usb_ctrl_arg {
 
 /* how come ??? */
 #define UART_STATE                     0x08
-#define UART_STATE_TRANSIENT_MASK      0x74
+#define UART_STATE_TRANSIENT_MASK      0x75
 #define UART_DCD                       0x01
 #define UART_DSR                       0x02
 #define UART_BREAK_ERROR               0x04
@@ -525,6 +525,10 @@ static void spcp8x5_process_read_urb(struct urb *urb)
                /* overrun is special, not associated with a char */
                if (status & UART_OVERRUN_ERROR)
                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+               if (status & UART_DCD)
+                       usb_serial_handle_dcd_change(port, tty,
+                                  priv->line_status & MSR_STATUS_LINE_DCD);
        }
 
        tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
@@ -645,6 +649,7 @@ static struct usb_serial_driver spcp8x5_device = {
                .name =         "SPCP8x5",
        },
        .id_table               = id_table,
+       .usb_driver             = &spcp8x5_driver,
        .num_ports              = 1,
        .open                   = spcp8x5_open,
        .dtr_rts                = spcp8x5_dtr_rts,
index b2902f3..a910004 100644 (file)
@@ -369,9 +369,9 @@ failed_1port:
 
 static void __exit ti_exit(void)
 {
+       usb_deregister(&ti_usb_driver);
        usb_serial_deregister(&ti_1port_device);
        usb_serial_deregister(&ti_2port_device);
-       usb_deregister(&ti_usb_driver);
 }
 
 
index 6954de5..546a521 100644 (file)
@@ -1344,11 +1344,15 @@ int usb_serial_register(struct usb_serial_driver *driver)
                return -ENODEV;
 
        fixup_generic(driver);
-       if (driver->usb_driver)
-               driver->usb_driver->supports_autosuspend = 1;
 
        if (!driver->description)
                driver->description = driver->driver.name;
+       if (!driver->usb_driver) {
+               WARN(1, "Serial driver %s has no usb_driver\n",
+                               driver->description);
+               return -EINVAL;
+       }
+       driver->usb_driver->supports_autosuspend = 1;
 
        /* Add this device to our list of devices */
        mutex_lock(&table_lock);
index f2ed6a3..95a8214 100644 (file)
@@ -75,6 +75,7 @@ static struct usb_serial_driver debug_device = {
                .name =         "debug",
        },
        .id_table =             id_table,
+       .usb_driver =           &debug_driver,
        .num_ports =            1,
        .bulk_out_size =        USB_DEBUG_MAX_PACKET_SIZE,
        .break_ctl =            usb_debug_break_ctl,
index b004b2a..9c014e2 100644 (file)
@@ -295,12 +295,15 @@ static void usb_wwan_indat_callback(struct urb *urb)
                    __func__, status, endpoint);
        } else {
                tty = tty_port_tty_get(&port->port);
-               if (urb->actual_length) {
-                       tty_insert_flip_string(tty, data, urb->actual_length);
-                       tty_flip_buffer_push(tty);
-               } else
-                       dbg("%s: empty read urb received", __func__);
-               tty_kref_put(tty);
+               if (tty) {
+                       if (urb->actual_length) {
+                               tty_insert_flip_string(tty, data,
+                                               urb->actual_length);
+                               tty_flip_buffer_push(tty);
+                       } else
+                               dbg("%s: empty read urb received", __func__);
+                       tty_kref_put(tty);
+               }
 
                /* Resubmit urb so we continue receiving */
                if (status != -ESHUTDOWN) {
index 15a5d89..1c11959 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/usb/cdc.h>
 #include "visor.h"
 
 /*
@@ -479,6 +480,17 @@ static int visor_probe(struct usb_serial *serial,
 
        dbg("%s", __func__);
 
+       /*
+        * some Samsung Android phones in modem mode have the same ID
+        * as SPH-I500, but they are ACM devices, so dont bind to them
+        */
+       if (id->idVendor == SAMSUNG_VENDOR_ID &&
+               id->idProduct == SAMSUNG_SPH_I500_ID &&
+               serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM &&
+               serial->dev->descriptor.bDeviceSubClass ==
+                       USB_CDC_SUBCLASS_ACM)
+               return -ENODEV;
+
        if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
                dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
                        serial->dev->actconfig->desc.bConfigurationValue);
index c854fde..2c85530 100644 (file)
@@ -31,4 +31,9 @@ UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
                "Cypress ISD-300LP",
                USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
 
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x9999,
+               "Super Top",
+               "USB 2.0  SATA BRIDGE",
+               USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
 #endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */
index fcc1e32..c1602b8 100644 (file)
@@ -1044,6 +1044,15 @@ UNUSUAL_DEV(  0x084d, 0x0011, 0x0110, 0x0110,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BULK32),
 
+/* Reported by <ttkspam@free.fr>
+ * The device reports a vendor-specific device class, requiring an
+ * explicit vendor/product match.
+ */
+UNUSUAL_DEV(  0x0851, 0x1542, 0x0002, 0x0002,
+               "MagicPixel",
+               "FW_Omega2",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
 /* Andrew Lunn <andrew@lunn.ch>
  * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
  * on LUN 4.
@@ -1388,6 +1397,13 @@ UNUSUAL_DEV(  0x0f19, 0x0105, 0x0100, 0x0100,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Submitted by Nick Holloway */
+UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
+               "VTech",
+               "Kidizoom",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY ),
+
 /* Reported by Michael Stattmann <michael@stattmann.com> */
 UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
                "Sony Ericsson",
@@ -1872,6 +1888,22 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/* Patch by Richard Schütz <r.schtz@t-online.de>
+ * This external hard drive enclosure uses a JMicron chip which
+ * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
+UNUSUAL_DEV(  0x1e68, 0x001b, 0x0000, 0x0000,
+               "TrekStor GmbH & Co. KG",
+               "DataStation maxi g.u",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Jasper Mackenzie <scarletpimpernal@hotmail.com> */
+UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000,
+               "Coby Electronics",
+               "MP3 Player",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index 9b3ca10..f616cef 100644 (file)
@@ -128,8 +128,7 @@ static void handle_tx(struct vhost_net *net)
        size_t hdr_size;
        struct socket *sock;
 
-       /* TODO: check that we are running from vhost_worker?
-        * Not sure it's worth it, it's straight-forward enough. */
+       /* TODO: check that we are running from vhost_worker? */
        sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock)
                return;
@@ -306,7 +305,8 @@ static void handle_rx_big(struct vhost_net *net)
        size_t len, total_len = 0;
        int err;
        size_t hdr_size;
-       struct socket *sock = rcu_dereference(vq->private_data);
+       /* TODO: check that we are running from vhost_worker? */
+       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
                return;
 
@@ -415,7 +415,8 @@ static void handle_rx_mergeable(struct vhost_net *net)
        int err, headcount;
        size_t vhost_hlen, sock_hlen;
        size_t vhost_len, sock_len;
-       struct socket *sock = rcu_dereference(vq->private_data);
+       /* TODO: check that we are running from vhost_worker? */
+       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
                return;
 
index 2af44b7..b3363ae 100644 (file)
@@ -173,9 +173,9 @@ static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
 {
        unsigned acked_features;
 
-       acked_features =
-               rcu_dereference_index_check(dev->acked_features,
-                                           lockdep_is_held(&dev->mutex));
+       /* TODO: check that we are running from vhost_worker or dev mutex is
+        * held? */
+       acked_features = rcu_dereference_index_check(dev->acked_features, 1);
        return acked_features & (1 << bit);
 }
 
index d916ac0..6bafb51 100644 (file)
@@ -1227,7 +1227,7 @@ config FB_CARILLO_RANCH
 
 config FB_INTEL
        tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EMBEDDED
+       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EXPERT
        select FB_MODE_HELPERS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
index d583bea..391ac93 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -1091,12 +1091,12 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1107,7 +1107,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1122,7 +1122,7 @@ static int ark_pci_resume (struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0)
@@ -1141,7 +1141,7 @@ static int ark_pci_resume (struct pci_dev* dev)
 
 fail:
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index dd9de2e..4cb6a57 100644 (file)
@@ -1860,11 +1860,11 @@ static void aty128_early_resume(void *data)
 {
         struct aty128fb_par *par = data;
 
-       if (try_acquire_console_sem())
+       if (!console_trylock())
                return;
        pci_restore_state(par->pdev);
        aty128_do_resume(par->pdev);
-       release_console_sem();
+       console_unlock();
 }
 #endif /* CONFIG_PPC_PMAC */
 
@@ -2438,7 +2438,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
        printk(KERN_DEBUG "aty128fb: suspending...\n");
        
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2470,7 +2470,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (state.event != PM_EVENT_ON)
                aty128_set_suspend(par, 1);
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = state;
 
@@ -2527,9 +2527,9 @@ static int aty128_pci_resume(struct pci_dev *pdev)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = aty128_do_resume(pdev);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
index 767ab4f..94e293f 100644 (file)
@@ -2069,7 +2069,7 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (state.event == pdev->dev.power.power_state.event)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2097,14 +2097,14 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
                par->lock_blank = 0;
                atyfb_blank(FB_BLANK_UNBLANK, info);
                fb_set_suspend(info, 0);
-               release_console_sem();
+               console_unlock();
                return -EIO;
        }
 #else
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 #endif
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = state;
 
@@ -2133,7 +2133,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        if (pdev->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
 
        /*
         * PCI state will have been restored by the core, so
@@ -2161,7 +2161,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        par->lock_blank = 0;
        atyfb_blank(FB_BLANK_UNBLANK, info);
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = PMSG_ON;
 
index c4e1764..92bda58 100644 (file)
@@ -2626,7 +2626,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
                goto done;
        }
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2690,7 +2690,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
        if (rinfo->pm_mode & radeon_pm_d2)
                radeon_set_suspend(rinfo, 1);
 
-       release_console_sem();
+       console_unlock();
 
  done:
        pdev->dev.power.power_state = mesg;
@@ -2715,10 +2715,10 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
                return 0;
 
        if (rinfo->no_schedule) {
-               if (try_acquire_console_sem())
+               if (!console_trylock())
                        return 0;
        } else
-               acquire_console_sem();
+               console_lock();
 
        printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
               pci_name(pdev), pdev->dev.power.power_state.event);
@@ -2783,7 +2783,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
        pdev->dev.power.power_state = PMSG_ON;
 
  bail:
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
index c789c46..b224396 100644 (file)
@@ -21,7 +21,7 @@
 #define MAX_BRIGHTNESS         (0xFF)
 #define MIN_BRIGHTNESS         (0)
 
-#define CURRENT_MASK           (0x1F << 1)
+#define CURRENT_BITMASK                (0x1F << 1)
 
 struct pm860x_backlight_data {
        struct pm860x_chip *chip;
@@ -85,7 +85,7 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
        if ((data->current_brightness == 0) && brightness) {
                if (data->iset) {
                        ret = pm860x_set_bits(data->i2c, wled_idc(data->port),
-                                             CURRENT_MASK, data->iset);
+                                             CURRENT_BITMASK, data->iset);
                        if (ret < 0)
                                goto out;
                }
index 8010aae..dd0e84a 100644 (file)
@@ -239,11 +239,15 @@ static int __devinit ltv350qv_probe(struct spi_device *spi)
        lcd->spi = spi;
        lcd->power = FB_BLANK_POWERDOWN;
        lcd->buffer = kzalloc(8, GFP_KERNEL);
+       if (!lcd->buffer) {
+               ret = -ENOMEM;
+               goto out_free_lcd;
+       }
 
        ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
        if (IS_ERR(ld)) {
                ret = PTR_ERR(ld);
-               goto out_free_lcd;
+               goto out_free_buffer;
        }
        lcd->ld = ld;
 
@@ -257,6 +261,8 @@ static int __devinit ltv350qv_probe(struct spi_device *spi)
 
 out_unregister:
        lcd_device_unregister(ld);
+out_free_buffer:
+       kfree(lcd->buffer);
 out_free_lcd:
        kfree(lcd);
        return ret;
@@ -268,6 +274,7 @@ static int __devexit ltv350qv_remove(struct spi_device *spi)
 
        ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
        lcd_device_unregister(lcd->ld);
+       kfree(lcd->buffer);
        kfree(lcd);
 
        return 0;
index 18c5078..47c21fb 100644 (file)
@@ -696,6 +696,7 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 {
        struct backlight_properties props;
        dma_addr_t dma_handle;
+       int ret;
 
        if (request_dma(CH_PPI, KBUILD_MODNAME)) {
                pr_err("couldn't request PPI DMA\n");
@@ -704,17 +705,16 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        if (request_ports()) {
                pr_err("couldn't request gpio port\n");
-               free_dma(CH_PPI);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out_ports;
        }
 
        fb_buffer = dma_alloc_coherent(NULL, TOTAL_VIDEO_MEM_SIZE,
                                       &dma_handle, GFP_KERNEL);
        if (fb_buffer == NULL) {
                pr_err("couldn't allocate dma buffer\n");
-               free_dma(CH_PPI);
-               free_ports();
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_dma_coherent;
        }
 
        if (L1_DATA_A_LENGTH)
@@ -725,10 +725,8 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        if (dma_desc_table == NULL) {
                pr_err("couldn't allocate dma descriptor\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_table;
        }
 
        bfin_lq035_fb.screen_base = (void *)fb_buffer;
@@ -771,31 +769,21 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
        bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
        if (bfin_lq035_fb.pseudo_palette == NULL) {
                pr_err("failed to allocate pseudo_palette\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_palette;
        }
 
        if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) {
                pr_err("failed to allocate colormap (%d entries)\n",
                        NBR_PALETTE);
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               kfree(bfin_lq035_fb.pseudo_palette);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out_cmap;
        }
 
        if (register_framebuffer(&bfin_lq035_fb) < 0) {
                pr_err("unable to register framebuffer\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               fb_buffer = NULL;
-               kfree(bfin_lq035_fb.pseudo_palette);
-               fb_dealloc_cmap(&bfin_lq035_fb.cmap);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_reg;
        }
 
        i2c_add_driver(&ad5280_driver);
@@ -807,11 +795,31 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        lcd_dev = lcd_device_register(KBUILD_MODNAME, &pdev->dev, NULL,
                                      &bfin_lcd_ops);
+       if (IS_ERR(lcd_dev)) {
+               pr_err("unable to register lcd\n");
+               ret = PTR_ERR(lcd_dev);
+               goto out_lcd;
+       }
        lcd_dev->props.max_contrast = 255,
 
        pr_info("initialized");
 
        return 0;
+out_lcd:
+       unregister_framebuffer(&bfin_lq035_fb);
+out_reg:
+       fb_dealloc_cmap(&bfin_lq035_fb.cmap);
+out_cmap:
+       kfree(bfin_lq035_fb.pseudo_palette);
+out_palette:
+out_table:
+       dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+       fb_buffer = NULL;
+out_dma_coherent:
+       free_ports();
+out_ports:
+       free_dma(CH_PPI);
+       return ret;
 }
 
 static int __devexit bfin_lq035_remove(struct platform_device *pdev)
index d637e1f..cff742a 100644 (file)
@@ -460,10 +460,10 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!(state.event & PM_EVENT_SLEEP))
                goto done;
 
-       acquire_console_sem();
+       console_lock();
        chipsfb_blank(1, p);
        fb_set_suspend(p, 1);
-       release_console_sem();
+       console_unlock();
  done:
        pdev->dev.power.power_state = state;
        return 0;
@@ -473,10 +473,10 @@ static int chipsfb_pci_resume(struct pci_dev *pdev)
 {
         struct fb_info *p = pci_get_drvdata(pdev);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(p, 0);
        chipsfb_blank(0, p);
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = PMSG_ON;
        return 0;
index 5a35f22..2209e35 100644 (file)
@@ -5,7 +5,7 @@
 menu "Console display driver support"
 
 config VGA_CONSOLE
-       bool "VGA text console" if EMBEDDED || !X86
+       bool "VGA text console" if EXPERT || !X86
        depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
        default y
        help
index 7ccc967..9c092b8 100644 (file)
@@ -375,14 +375,14 @@ static void fb_flashcursor(struct work_struct *work)
        int c;
        int mode;
 
-       acquire_console_sem();
+       console_lock();
        if (ops && ops->currcon != -1)
                vc = vc_cons[ops->currcon].d;
 
        if (!vc || !CON_IS_VISIBLE(vc) ||
            registered_fb[con2fb_map[vc->vc_num]] != info ||
            vc->vc_deccm != 1) {
-               release_console_sem();
+               console_unlock();
                return;
        }
 
@@ -392,7 +392,7 @@ static void fb_flashcursor(struct work_struct *work)
                CM_ERASE : CM_DRAW;
        ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
-       release_console_sem();
+       console_unlock();
 }
 
 static void cursor_timer_handler(unsigned long dev_addr)
@@ -836,7 +836,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
 
        found = search_fb_in_map(newidx);
 
-       acquire_console_sem();
+       console_lock();
        con2fb_map[unit] = newidx;
        if (!err && !found)
                err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
@@ -863,7 +863,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
        if (!search_fb_in_map(info_idx))
                info_idx = newidx;
 
-       release_console_sem();
+       console_unlock();
        return err;
 }
 
@@ -3321,7 +3321,7 @@ static ssize_t store_rotate(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3331,7 +3331,7 @@ static ssize_t store_rotate(struct device *device,
        rotate = simple_strtoul(buf, last, 0);
        fbcon_rotate(info, rotate);
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3346,7 +3346,7 @@ static ssize_t store_rotate_all(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3356,7 +3356,7 @@ static ssize_t store_rotate_all(struct device *device,
        rotate = simple_strtoul(buf, last, 0);
        fbcon_rotate_all(info, rotate);
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3369,7 +3369,7 @@ static ssize_t show_rotate(struct device *device,
        if (fbcon_has_exited)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3378,7 +3378,7 @@ static ssize_t show_rotate(struct device *device,
        info = registered_fb[idx];
        rotate = fbcon_get_rotate(info);
 err:
-       release_console_sem();
+       console_unlock();
        return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
 }
 
@@ -3392,7 +3392,7 @@ static ssize_t show_cursor_blink(struct device *device,
        if (fbcon_has_exited)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3406,7 +3406,7 @@ static ssize_t show_cursor_blink(struct device *device,
 
        blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
 err:
-       release_console_sem();
+       console_unlock();
        return snprintf(buf, PAGE_SIZE, "%d\n", blink);
 }
 
@@ -3421,7 +3421,7 @@ static ssize_t store_cursor_blink(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3443,7 +3443,7 @@ static ssize_t store_cursor_blink(struct device *device,
        }
 
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3482,7 +3482,7 @@ static void fbcon_start(void)
        if (num_registered_fb) {
                int i;
 
-               acquire_console_sem();
+               console_lock();
 
                for (i = 0; i < FB_MAX; i++) {
                        if (registered_fb[i] != NULL) {
@@ -3491,7 +3491,7 @@ static void fbcon_start(void)
                        }
                }
 
-               release_console_sem();
+               console_unlock();
                fbcon_takeover(0);
        }
 }
@@ -3552,7 +3552,7 @@ static int __init fb_console_init(void)
 {
        int i;
 
-       acquire_console_sem();
+       console_lock();
        fb_register_client(&fbcon_event_notifier);
        fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL,
                                     "fbcon");
@@ -3568,7 +3568,7 @@ static int __init fb_console_init(void)
        for (i = 0; i < MAX_NR_CONSOLES; i++)
                con2fb_map[i] = -1;
 
-       release_console_sem();
+       console_unlock();
        fbcon_start();
        return 0;
 }
@@ -3591,12 +3591,12 @@ static void __exit fbcon_deinit_device(void)
 
 static void __exit fb_console_exit(void)
 {
-       acquire_console_sem();
+       console_lock();
        fb_unregister_client(&fbcon_event_notifier);
        fbcon_deinit_device();
        device_destroy(fb_class, MKDEV(0, 0));
        fbcon_exit();
-       release_console_sem();
+       console_unlock();
        unregister_con_driver(&fb_con);
 }      
 
index c97491b..915fd74 100644 (file)
@@ -202,11 +202,7 @@ static void vgacon_scrollback_init(int pitch)
        }
 }
 
-/*
- * Called only duing init so call of alloc_bootmen is ok.
- * Marked __init_refok to silence modpost.
- */
-static void __init_refok vgacon_scrollback_startup(void)
+static void vgacon_scrollback_startup(void)
 {
        vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
        vgacon_scrollback_init(vga_video_num_columns * 2);
index c265aed..8d61ef9 100644 (file)
@@ -1092,9 +1092,10 @@ static int __init fb_probe(struct platform_device *device)
 
 irq_freq:
 #ifdef CONFIG_CPU_FREQ
+       lcd_da8xx_cpufreq_deregister(par);
+#endif
 err_cpu_freq:
        unregister_framebuffer(da8xx_fb_info);
-#endif
 
 err_dealloc_cmap:
        fb_dealloc_cmap(&da8xx_fb_info->cmap);
@@ -1130,14 +1131,14 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state)
        struct fb_info *info = platform_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        if (par->panel_power_ctrl)
                par->panel_power_ctrl(0);
 
        fb_set_suspend(info, 1);
        lcd_disable_raster();
        clk_disable(par->lcdc_clk);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1146,14 +1147,14 @@ static int fb_resume(struct platform_device *dev)
        struct fb_info *info = platform_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        if (par->panel_power_ctrl)
                par->panel_power_ctrl(1);
 
        clk_enable(par->lcdc_clk);
        lcd_enable_raster();
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 4ac1201..e2bf953 100644 (file)
@@ -1036,11 +1036,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_set_var(info, &var);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                if (!ret && copy_to_user(argp, &var, sizeof(var)))
                        ret = -EFAULT;
@@ -1072,9 +1072,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                ret = fb_pan_display(info, &var);
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
                        return -EFAULT;
@@ -1119,11 +1119,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case FBIOBLANK:
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_blank(info, arg);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                break;
        default:
index 0a08f13..f4a3277 100644 (file)
@@ -90,11 +90,11 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
        int err;
 
        var->activate |= FB_ACTIVATE_FORCE;
-       acquire_console_sem();
+       console_lock();
        fb_info->flags |= FBINFO_MISC_USEREVENT;
        err = fb_set_var(fb_info, var);
        fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       release_console_sem();
+       console_unlock();
        if (err)
                return err;
        return 0;
@@ -175,7 +175,7 @@ static ssize_t store_modes(struct device *device,
        if (i * sizeof(struct fb_videomode) != count)
                return -EINVAL;
 
-       acquire_console_sem();
+       console_lock();
        list_splice(&fb_info->modelist, &old_list);
        fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
                                 &fb_info->modelist);
@@ -185,7 +185,7 @@ static ssize_t store_modes(struct device *device,
        } else
                fb_destroy_modelist(&old_list);
 
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -301,11 +301,11 @@ static ssize_t store_blank(struct device *device,
        char *last = NULL;
        int err;
 
-       acquire_console_sem();
+       console_lock();
        fb_info->flags |= FBINFO_MISC_USEREVENT;
        err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
        fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       release_console_sem();
+       console_unlock();
        if (err < 0)
                return err;
        return count;
@@ -364,9 +364,9 @@ static ssize_t store_pan(struct device *device,
                return -EINVAL;
        var.yoffset = simple_strtoul(last, &last, 0);
 
-       acquire_console_sem();
+       console_lock();
        err = fb_pan_display(fb_info, &var);
-       release_console_sem();
+       console_unlock();
 
        if (err < 0)
                return err;
@@ -399,9 +399,9 @@ static ssize_t store_fbstate(struct device *device,
 
        state = simple_strtoul(buf, &last, 0);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fb_info, (int)state);
-       release_console_sem();
+       console_unlock();
 
        return count;
 }
index 70b1d9d..b4f19db 100644 (file)
@@ -344,10 +344,10 @@ static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        struct fb_info *info = pci_get_drvdata(pdev);
 
        if (state.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                gx_powerdown(info);
                fb_set_suspend(info, 1);
-               release_console_sem();
+               console_unlock();
        }
 
        /* there's no point in setting PCI states; we emulate PCI, so
@@ -361,7 +361,7 @@ static int gxfb_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = gx_powerup(info);
        if (ret) {
                printk(KERN_ERR "gxfb:  power up failed!\n");
@@ -369,7 +369,7 @@ static int gxfb_resume(struct pci_dev *pdev)
        }
 
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #endif
index 39bdbed..416851c 100644 (file)
@@ -465,10 +465,10 @@ static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        struct fb_info *info = pci_get_drvdata(pdev);
 
        if (state.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                lx_powerdown(info);
                fb_set_suspend(info, 1);
-               release_console_sem();
+               console_unlock();
        }
 
        /* there's no point in setting PCI states; we emulate PCI, so
@@ -482,7 +482,7 @@ static int lxfb_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = lx_powerup(info);
        if (ret) {
                printk(KERN_ERR "lxfb:  power up failed!\n");
@@ -490,7 +490,7 @@ static int lxfb_resume(struct pci_dev *pdev)
        }
 
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index 5743ea2..318f6fb 100644 (file)
@@ -1574,7 +1574,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(info, 1);
 
        if (info->fbops->fb_sync)
@@ -1587,7 +1587,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
        pci_save_state(dev);
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, mesg));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1605,7 +1605,7 @@ static int i810fb_resume(struct pci_dev *dev)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
 
@@ -1621,7 +1621,7 @@ static int i810fb_resume(struct pci_dev *dev)
        fb_set_suspend (info, 0);
        info->fbops->fb_blank(VESA_NO_BLANKING, info);
 fail:
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 /***********************************************************************
index 670ecaa..de36693 100644 (file)
@@ -778,9 +778,9 @@ static int jzfb_suspend(struct device *dev)
 {
        struct jzfb *jzfb = dev_get_drvdata(dev);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(jzfb->fb, 1);
-       release_console_sem();
+       console_unlock();
 
        mutex_lock(&jzfb->lock);
        if (jzfb->is_enabled)
@@ -800,9 +800,9 @@ static int jzfb_resume(struct device *dev)
                jzfb_enable(jzfb);
        mutex_unlock(&jzfb->lock);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(jzfb->fb, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index cb01391..7e3a490 100644 (file)
@@ -1177,9 +1177,9 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
        struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
        struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mx3fb->fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
                sdc_disable_channel(mx3_fbi);
@@ -1202,9 +1202,9 @@ static int mx3fb_resume(struct platform_device *pdev)
                sdc_set_brightness(mx3fb, mx3fb->backlight_level);
        }
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mx3fb->fbi, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 62498bd..f838d9e 100644 (file)
@@ -696,6 +696,8 @@ static int nuc900fb_remove(struct platform_device *pdev)
        nuc900fb_stop_lcd(fbinfo);
        msleep(1);
 
+       unregister_framebuffer(fbinfo);
+       nuc900fb_cpufreq_deregister(fbi);
        nuc900fb_unmap_video_memory(fbinfo);
 
        iounmap(fbi->io);
@@ -723,7 +725,7 @@ static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state)
        struct fb_info     *fbinfo = platform_get_drvdata(dev);
        struct nuc900fb_info *info = fbinfo->par;
 
-       nuc900fb_stop_lcd();
+       nuc900fb_stop_lcd(fbinfo);
        msleep(1);
        clk_disable(info->clk);
        return 0;
@@ -740,7 +742,7 @@ static int nuc900fb_resume(struct platform_device *dev)
        msleep(1);
 
        nuc900fb_init_registers(fbinfo);
-       nuc900fb_activate_var(bfinfo);
+       nuc900fb_activate_var(fbinfo);
 
        return 0;
 }
index efe10ff..081dc47 100644 (file)
@@ -1057,7 +1057,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
 
        if (mesg.event == PM_EVENT_PRETHAW)
                mesg.event = PM_EVENT_FREEZE;
-       acquire_console_sem();
+       console_lock();
        par->pm_state = mesg.event;
 
        if (mesg.event & PM_EVENT_SLEEP) {
@@ -1070,7 +1070,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
        }
        dev->dev.power.power_state = mesg;
 
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
@@ -1079,7 +1079,7 @@ static int nvidiafb_resume(struct pci_dev *dev)
        struct fb_info *info = pci_get_drvdata(dev);
        struct nvidia_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev, PCI_D0);
 
        if (par->pm_state != PM_EVENT_FREEZE) {
@@ -1097,7 +1097,7 @@ static int nvidiafb_resume(struct pci_dev *dev)
        nvidiafb_blank(FB_BLANK_UNBLANK, info);
 
 fail:
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index 9c0144e..65560a1 100644 (file)
@@ -513,9 +513,9 @@ static int ps3fb_release(struct fb_info *info, int user)
        if (atomic_dec_and_test(&ps3fb.f_count)) {
                if (atomic_read(&ps3fb.ext_flip)) {
                        atomic_set(&ps3fb.ext_flip, 0);
-                       if (!try_acquire_console_sem()) {
+                       if (console_trylock()) {
                                ps3fb_sync(info, 0);    /* single buffer */
-                               release_console_sem();
+                               console_unlock();
                        }
                }
        }
@@ -830,14 +830,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        if (vmode) {
                                var = info->var;
                                fb_videomode_to_var(&var, vmode);
-                               acquire_console_sem();
+                               console_lock();
                                info->flags |= FBINFO_MISC_USEREVENT;
                                /* Force, in case only special bits changed */
                                var.activate |= FB_ACTIVATE_FORCE;
                                par->new_mode_id = val;
                                retval = fb_set_var(info, &var);
                                info->flags &= ~FBINFO_MISC_USEREVENT;
-                               release_console_sem();
+                               console_unlock();
                        }
                        break;
                }
@@ -881,9 +881,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
 
                dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
-               acquire_console_sem();
+               console_lock();
                retval = ps3fb_sync(info, val);
-               release_console_sem();
+               console_unlock();
                break;
 
        default:
@@ -903,9 +903,9 @@ static int ps3fbd(void *arg)
                set_current_state(TASK_INTERRUPTIBLE);
                if (ps3fb.is_kicked) {
                        ps3fb.is_kicked = 0;
-                       acquire_console_sem();
+                       console_lock();
                        ps3fb_sync(info, 0);    /* single buffer */
-                       release_console_sem();
+                       console_unlock();
                }
                schedule();
        }
index cea6403..35f61dd 100644 (file)
@@ -701,16 +701,12 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev)
         */
        pxa168fb_init_mode(info, mi);
 
-       ret = pxa168fb_check_var(&info->var, info);
-       if (ret)
-               goto failed_free_fbmem;
-
        /*
         * Fill in sane defaults.
         */
        ret = pxa168fb_check_var(&info->var, info);
        if (ret)
-               goto failed;
+               goto failed_free_fbmem;
 
        /*
         * enable controller clock
index b81168d..cf4beb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers
+ *  pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers
  *
  *  This driver needs a DirectFB counterpart in user space, communication
  *  is handled via mmap()ed memory areas and an ioctl.
@@ -421,7 +421,7 @@ pxa3xx_gcu_misc_write(struct file *filp, const char *buff,
                buffer->next = priv->free;
                priv->free = buffer;
                spin_unlock_irqrestore(&priv->spinlock, flags);
-               return ret;
+               return -EFAULT;
        }
 
        buffer->length = words;
index dce8c97..75738a9 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -1113,12 +1113,12 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1129,7 +1129,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1145,12 +1145,12 @@ static int s3_pci_resume(struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1159,7 +1159,7 @@ static int s3_pci_resume(struct pci_dev* dev)
        err = pci_enable_device(dev);
        if (err) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                dev_err(info->device, "error %d enabling device for resume\n", err);
                return err;
        }
@@ -1169,7 +1169,7 @@ static int s3_pci_resume(struct pci_dev* dev)
        fb_set_suspend(info, 0);
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 842d157..487911e 100644 (file)
@@ -2373,7 +2373,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        if (mesg.event == PM_EVENT_FREEZE)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(info, 1);
 
        if (info->fbops->fb_sync)
@@ -2385,7 +2385,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        pci_save_state(dev);
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, mesg));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -2409,7 +2409,7 @@ static int savagefb_resume(struct pci_dev* dev)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
 
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
@@ -2423,7 +2423,7 @@ static int savagefb_resume(struct pci_dev* dev)
        savagefb_set_par(info);
        fb_set_suspend(info, 0);
        savagefb_blank(FB_BLANK_UNBLANK, info);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 74d9f54..2b9e56a 100644 (file)
@@ -1151,7 +1151,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 
                ch = info->par;
 
-               acquire_console_sem();
+               console_lock();
 
                /* HDMI plug in */
                if (!sh_hdmi_must_reconfigure(hdmi) &&
@@ -1171,7 +1171,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                        fb_set_suspend(info, 0);
                }
 
-               release_console_sem();
+               console_unlock();
        } else {
                ret = 0;
                if (!hdmi->info)
@@ -1181,12 +1181,12 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                fb_destroy_modedb(hdmi->monspec.modedb);
                hdmi->monspec.modedb = NULL;
 
-               acquire_console_sem();
+               console_lock();
 
                /* HDMI disconnect */
                fb_set_suspend(hdmi->info, 1);
 
-               release_console_sem();
+               console_unlock();
                pm_runtime_put(hdmi->dev);
        }
 
index bd4840a..bf12e53 100644 (file)
@@ -912,9 +912,9 @@ static int sh_mobile_release(struct fb_info *info, int user)
 
        /* Nothing to reconfigure, when called from fbcon */
        if (user) {
-               acquire_console_sem();
+               console_lock();
                sh_mobile_fb_reconfig(info);
-               release_console_sem();
+               console_unlock();
        }
 
        mutex_unlock(&ch->open_lock);
index b7dc180..bcb44a5 100644 (file)
@@ -2010,9 +2010,9 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
 
        /* tell console/fb driver we are suspending */
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        /* backup copies in case chip is powered down over suspend */
 
@@ -2069,9 +2069,9 @@ static void sm501fb_resume_fb(struct sm501fb_info *info,
                memcpy_toio(par->cursor.k_addr, par->store_cursor,
                            par->cursor.size);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fbi, 0);
-       release_console_sem();
+       console_unlock();
 
        vfree(par->store_fb);
        vfree(par->store_cursor);
index 6913fe1..dfef88c 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/fb.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-/* Why should fb driver call console functions? because acquire_console_sem() */
+/* Why should fb driver call console functions? because console_lock() */
 #include <linux/console.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
@@ -944,7 +944,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
        struct mfd_cell *cell = dev->dev.platform_data;
        int retval = 0;
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -965,7 +965,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
        if (cell->suspend)
                retval = cell->suspend(dev);
 
-       release_console_sem();
+       console_unlock();
 
        return retval;
 }
@@ -976,7 +976,7 @@ static int tmiofb_resume(struct platform_device *dev)
        struct mfd_cell *cell = dev->dev.platform_data;
        int retval = 0;
 
-       acquire_console_sem();
+       console_lock();
 
        if (cell->resume) {
                retval = cell->resume(dev);
@@ -992,7 +992,7 @@ static int tmiofb_resume(struct platform_device *dev)
 
        fb_set_suspend(info, 0);
 out:
-       release_console_sem();
+       console_unlock();
        return retval;
 }
 #else
index 289edd5..4e66349 100644 (file)
@@ -1674,17 +1674,17 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
 #ifdef CONFIG_PM
 static int viafb_suspend(void *unused)
 {
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(viafbinfo, 1);
        viafb_sync(viafbinfo);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
 
 static int viafb_resume(void *unused)
 {
-       acquire_console_sem();
+       console_lock();
        if (viaparinfo->shared->vdev->engine_mmio)
                viafb_reset_engine(viaparinfo);
        viafb_set_par(viafbinfo);
@@ -1692,7 +1692,7 @@ static int viafb_resume(void *unused)
                viafb_set_par(viafbinfo1);
        fb_set_suspend(viafbinfo, 0);
 
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
index 85d76ec..a2965ab 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -819,12 +819,12 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -835,7 +835,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -850,7 +850,7 @@ static int vt8623_pci_resume(struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0)
@@ -869,7 +869,7 @@ static int vt8623_pci_resume(struct pci_dev* dev)
 
 fail:
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 3e6934d..a20218c 100644 (file)
@@ -491,12 +491,12 @@ xenfb_make_preferred_console(void)
        if (console_set_on_cmdline)
                return;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(c) {
                if (!strcmp(c->name, "tty") && c->index == 0)
                        break;
        }
-       release_console_sem();
+       console_unlock();
        if (c) {
                unregister_console(c);
                c->flags |= CON_CONSDEV;
index ef8d9d5..4fb5b2b 100644 (file)
@@ -96,11 +96,6 @@ static struct pci_device_id virtio_pci_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
 
-/* A PCI device has it's own struct device and so does a virtio device so
- * we create a place for the virtio devices to show up in sysfs.  I think it
- * would make more sense for virtio to not insist on having it's own device. */
-static struct device *virtio_pci_root;
-
 /* Convert a generic virtio device to our structure */
 static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
 {
@@ -629,7 +624,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
        if (vp_dev == NULL)
                return -ENOMEM;
 
-       vp_dev->vdev.dev.parent = virtio_pci_root;
+       vp_dev->vdev.dev.parent = &pci_dev->dev;
        vp_dev->vdev.dev.release = virtio_pci_release_dev;
        vp_dev->vdev.config = &virtio_pci_config_ops;
        vp_dev->pci_dev = pci_dev;
@@ -717,17 +712,7 @@ static struct pci_driver virtio_pci_driver = {
 
 static int __init virtio_pci_init(void)
 {
-       int err;
-
-       virtio_pci_root = root_device_register("virtio-pci");
-       if (IS_ERR(virtio_pci_root))
-               return PTR_ERR(virtio_pci_root);
-
-       err = pci_register_driver(&virtio_pci_driver);
-       if (err)
-               root_device_unregister(virtio_pci_root);
-
-       return err;
+       return pci_register_driver(&virtio_pci_driver);
 }
 
 module_init(virtio_pci_init);
@@ -735,7 +720,6 @@ module_init(virtio_pci_init);
 static void __exit virtio_pci_exit(void)
 {
        pci_unregister_driver(&virtio_pci_driver);
-       root_device_unregister(virtio_pci_root);
 }
 
 module_exit(virtio_pci_exit);
index 3a7e9ff..38e96ab 100644 (file)
@@ -593,19 +593,17 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
 
        /* get interface & functional clock objects */
        hdq_data->hdq_ick = clk_get(&pdev->dev, "ick");
-       hdq_data->hdq_fck = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(hdq_data->hdq_ick)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ ick clock object\n");
+               ret = PTR_ERR(hdq_data->hdq_ick);
+               goto err_ick;
+       }
 
-       if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) {
-               dev_dbg(&pdev->dev, "Can't get HDQ clock objects\n");
-               if (IS_ERR(hdq_data->hdq_ick)) {
-                       ret = PTR_ERR(hdq_data->hdq_ick);
-                       goto err_clk;
-               }
-               if (IS_ERR(hdq_data->hdq_fck)) {
-                       ret = PTR_ERR(hdq_data->hdq_fck);
-                       clk_put(hdq_data->hdq_ick);
-                       goto err_clk;
-               }
+       hdq_data->hdq_fck = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ fck clock object\n");
+               ret = PTR_ERR(hdq_data->hdq_fck);
+               goto err_fck;
        }
 
        hdq_data->hdq_usecount = 0;
@@ -665,10 +663,12 @@ err_fnclk:
        clk_disable(hdq_data->hdq_ick);
 
 err_intfclk:
-       clk_put(hdq_data->hdq_ick);
        clk_put(hdq_data->hdq_fck);
 
-err_clk:
+err_fck:
+       clk_put(hdq_data->hdq_ick);
+
+err_ick:
        iounmap(hdq_data->hdq_base);
 
 err_ioremap:
index 2e2400e..31649b7 100644 (file)
@@ -862,12 +862,12 @@ config SBC_EPX_C3_WATCHDOG
 
 # M68K Architecture
 
-config M548x_WATCHDOG
-       tristate "MCF548x watchdog support"
+config M54xx_WATCHDOG
+       tristate "MCF54xx watchdog support"
        depends on M548x
        help
          To compile this driver as a module, choose M here: the
-         module will be called m548x_wdt.
+         module will be called m54xx_wdt.
 
 # MIPS Architecture
 
index dd77665..20e44c4 100644 (file)
@@ -106,7 +106,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 # M32R Architecture
 
 # M68K Architecture
-obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o
+obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
 
 # MIPS Architecture
 obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c
deleted file mode 100644 (file)
index cabbcfe..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * drivers/watchdog/m548x_wdt.c
- *
- * Watchdog driver for ColdFire MCF548x processors
- * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
- *
- * Adapted from the IXP4xx watchdog driver, which carries these notices:
- *
- *  Author: Deepak Saxena <dsaxena@plexity.net>
- *
- *  Copyright 2004 (c) MontaVista, Software, Inc.
- *  Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/uaccess.h>
-
-#include <asm/coldfire.h>
-#include <asm/m548xsim.h>
-#include <asm/m548xgpt.h>
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
-static unsigned long wdt_status;
-
-#define        WDT_IN_USE              0
-#define        WDT_OK_TO_CLOSE         1
-
-static void wdt_enable(void)
-{
-       unsigned int gms0;
-
-       /* preserve GPIO usage, if any */
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       if (gms0 & MCF_GPT_GMS_TMS_GPIO)
-               gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
-                                                       | MCF_GPT_GMS_OD);
-       else
-               gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-       __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
-                       MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
-       gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static void wdt_disable(void)
-{
-       unsigned int gms0;
-
-       /* disable watchdog */
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static void wdt_keepalive(void)
-{
-       unsigned int gms0;
-
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       gms0 |= MCF_GPT_GMS_OCPW(0xA5);
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static int m548x_wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-       wdt_enable();
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t m548x_wdt_write(struct file *file, const char *data,
-                                               size_t len, loff_t *ppos)
-{
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-               wdt_keepalive();
-       }
-       return len;
-}
-
-static const struct watchdog_info ident = {
-       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
-                               WDIOF_KEEPALIVEPING,
-       .identity       = "Coldfire M548x Watchdog",
-};
-
-static long m548x_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                        unsigned long arg)
-{
-       int ret = -ENOTTY;
-       int time;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_keepalive();
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, (int *)arg);
-               if (ret)
-                       break;
-
-               if (time <= 0 || time > 30) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               heartbeat = time;
-               wdt_enable();
-               /* Fall through */
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int m548x_wdt_release(struct inode *inode, struct file *file)
-{
-       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               wdt_disable();
-       else {
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
-               wdt_keepalive();
-       }
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-
-static const struct file_operations m548x_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = m548x_wdt_write,
-       .unlocked_ioctl = m548x_wdt_ioctl,
-       .open           = m548x_wdt_open,
-       .release        = m548x_wdt_release,
-};
-
-static struct miscdevice m548x_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &m548x_wdt_fops,
-};
-
-static int __init m548x_wdt_init(void)
-{
-       if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
-                                               "Coldfire M548x Watchdog")) {
-               printk(KERN_WARNING
-                               "Coldfire M548x Watchdog : I/O region busy\n");
-               return -EBUSY;
-       }
-       printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
-
-       return misc_register(&m548x_wdt_miscdev);
-}
-
-static void __exit m548x_wdt_exit(void)
-{
-       misc_deregister(&m548x_wdt_miscdev);
-       release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
-}
-
-module_init(m548x_wdt_init);
-module_exit(m548x_wdt_exit);
-
-MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
-MODULE_DESCRIPTION("Coldfire M548x Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
-
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/m54xx_wdt.c b/drivers/watchdog/m54xx_wdt.c
new file mode 100644 (file)
index 0000000..4d43286
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * drivers/watchdog/m54xx_wdt.c
+ *
+ * Watchdog driver for ColdFire MCF547x & MCF548x processors
+ * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
+ *
+ * Adapted from the IXP4xx watchdog driver, which carries these notices:
+ *
+ *  Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ *  Copyright 2004 (c) MontaVista, Software, Inc.
+ *  Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+
+#include <asm/coldfire.h>
+#include <asm/m54xxsim.h>
+#include <asm/m54xxgpt.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
+static unsigned long wdt_status;
+
+#define        WDT_IN_USE              0
+#define        WDT_OK_TO_CLOSE         1
+
+static void wdt_enable(void)
+{
+       unsigned int gms0;
+
+       /* preserve GPIO usage, if any */
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       if (gms0 & MCF_GPT_GMS_TMS_GPIO)
+               gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
+                                                       | MCF_GPT_GMS_OD);
+       else
+               gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+       __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
+                       MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
+       gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_disable(void)
+{
+       unsigned int gms0;
+
+       /* disable watchdog */
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_keepalive(void)
+{
+       unsigned int gms0;
+
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       gms0 |= MCF_GPT_GMS_OCPW(0xA5);
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static int m54xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       wdt_enable();
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t m54xx_wdt_write(struct file *file, const char *data,
+                                               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_keepalive();
+       }
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                               WDIOF_KEEPALIVEPING,
+       .identity       = "Coldfire M54xx Watchdog",
+};
+
+static long m54xx_wdt_ioctl(struct file *file, unsigned int cmd,
+                                                        unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > 30) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               heartbeat = time;
+               wdt_enable();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int m54xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               wdt_disable();
+       else {
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                                       "timer will not stop\n");
+               wdt_keepalive();
+       }
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static const struct file_operations m54xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = m54xx_wdt_write,
+       .unlocked_ioctl = m54xx_wdt_ioctl,
+       .open           = m54xx_wdt_open,
+       .release        = m54xx_wdt_release,
+};
+
+static struct miscdevice m54xx_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &m54xx_wdt_fops,
+};
+
+static int __init m54xx_wdt_init(void)
+{
+       if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
+                                               "Coldfire M54xx Watchdog")) {
+               printk(KERN_WARNING
+                               "Coldfire M54xx Watchdog : I/O region busy\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+
+       return misc_register(&m54xx_wdt_miscdev);
+}
+
+static void __exit m54xx_wdt_exit(void)
+{
+       misc_deregister(&m54xx_wdt_miscdev);
+       release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
+}
+
+module_init(m54xx_wdt_init);
+module_exit(m54xx_wdt_exit);
+
+MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
+MODULE_DESCRIPTION("Coldfire M54xx Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index db8c4c4..2417727 100644 (file)
@@ -37,11 +37,19 @@ static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
 #ifdef CONFIG_PM_SLEEP
 static int xen_hvm_suspend(void *data)
 {
+       int err;
        struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
        int *cancelled = data;
 
        BUG_ON(!irqs_disabled());
 
+       err = sysdev_suspend(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n",
+                      err);
+               return err;
+       }
+
        *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
 
        xen_hvm_post_suspend(*cancelled);
@@ -53,6 +61,8 @@ static int xen_hvm_suspend(void *data)
                xen_timer_resume();
        }
 
+       sysdev_resume();
+
        return 0;
 }
 
index 1c12360..bbd000f 100644 (file)
@@ -122,6 +122,7 @@ static ssize_t xenbus_file_read(struct file *filp,
        int ret;
 
        mutex_lock(&u->reply_mutex);
+again:
        while (list_empty(&u->read_buffers)) {
                mutex_unlock(&u->reply_mutex);
                if (filp->f_flags & O_NONBLOCK)
@@ -144,7 +145,7 @@ static ssize_t xenbus_file_read(struct file *filp,
                i += sz - ret;
                rb->cons += sz - ret;
 
-               if (ret != sz) {
+               if (ret != 0) {
                        if (i == 0)
                                i = -EFAULT;
                        goto out;
@@ -160,6 +161,8 @@ static ssize_t xenbus_file_read(struct file *filp,
                                        struct read_buffer, list);
                }
        }
+       if (i == 0)
+               goto again;
 
 out:
        mutex_unlock(&u->reply_mutex);
@@ -407,6 +410,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
 
                mutex_lock(&u->reply_mutex);
                rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
+               wake_up(&u->read_waitq);
                mutex_unlock(&u->reply_mutex);
        }
 
@@ -455,7 +459,7 @@ static ssize_t xenbus_file_write(struct file *filp,
 
        ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
 
-       if (ret == len) {
+       if (ret != 0) {
                rc = -EFAULT;
                goto out;
        }
@@ -488,21 +492,6 @@ static ssize_t xenbus_file_write(struct file *filp,
        msg_type = u->u.msg.type;
 
        switch (msg_type) {
-       case XS_TRANSACTION_START:
-       case XS_TRANSACTION_END:
-       case XS_DIRECTORY:
-       case XS_READ:
-       case XS_GET_PERMS:
-       case XS_RELEASE:
-       case XS_GET_DOMAIN_PATH:
-       case XS_WRITE:
-       case XS_MKDIR:
-       case XS_RM:
-       case XS_SET_PERMS:
-               /* Send out a transaction */
-               ret = xenbus_write_transaction(msg_type, u);
-               break;
-
        case XS_WATCH:
        case XS_UNWATCH:
                /* (Un)Ask for some path to be watched for changes */
@@ -510,7 +499,8 @@ static ssize_t xenbus_file_write(struct file *filp,
                break;
 
        default:
-               ret = -EINVAL;
+               /* Send out a transaction */
+               ret = xenbus_write_transaction(msg_type, u);
                break;
        }
        if (ret != 0)
@@ -555,6 +545,7 @@ static int xenbus_file_release(struct inode *inode, struct file *filp)
        struct xenbus_file_priv *u = filp->private_data;
        struct xenbus_transaction_holder *trans, *tmp;
        struct watch_adapter *watch, *tmp_watch;
+       struct read_buffer *rb, *tmp_rb;
 
        /*
         * No need for locking here because there are no other users,
@@ -573,6 +564,10 @@ static int xenbus_file_release(struct inode *inode, struct file *filp)
                free_watch_adapter(watch);
        }
 
+       list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
+               list_del(&rb->list);
+               kfree(rb);
+       }
        kfree(u);
 
        return 0;
index 9a7921a..3db9caa 100644 (file)
@@ -50,7 +50,7 @@ config EXPORTFS
        tristate
 
 config FILE_LOCKING
-       bool "Enable POSIX file locking API" if EMBEDDED
+       bool "Enable POSIX file locking API" if EXPERT
        default y
        help
          This option enables standard file locking support, required
index 15690bb..789b3af 100644 (file)
@@ -140,6 +140,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
        candidate->first = candidate->last = index;
        candidate->offset_first = from;
        candidate->to_last = to;
+       INIT_LIST_HEAD(&candidate->link);
        candidate->usage = 1;
        candidate->state = AFS_WBACK_PENDING;
        init_waitqueue_head(&candidate->waitq);
index fc557a3..26869cd 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -239,15 +239,23 @@ static void __put_ioctx(struct kioctx *ctx)
        call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
 
-#define get_ioctx(kioctx) do {                                         \
-       BUG_ON(atomic_read(&(kioctx)->users) <= 0);                     \
-       atomic_inc(&(kioctx)->users);                                   \
-} while (0)
-#define put_ioctx(kioctx) do {                                         \
-       BUG_ON(atomic_read(&(kioctx)->users) <= 0);                     \
-       if (unlikely(atomic_dec_and_test(&(kioctx)->users)))            \
-               __put_ioctx(kioctx);                                    \
-} while (0)
+static inline void get_ioctx(struct kioctx *kioctx)
+{
+       BUG_ON(atomic_read(&kioctx->users) <= 0);
+       atomic_inc(&kioctx->users);
+}
+
+static inline int try_get_ioctx(struct kioctx *kioctx)
+{
+       return atomic_inc_not_zero(&kioctx->users);
+}
+
+static inline void put_ioctx(struct kioctx *kioctx)
+{
+       BUG_ON(atomic_read(&kioctx->users) <= 0);
+       if (unlikely(atomic_dec_and_test(&kioctx->users)))
+               __put_ioctx(kioctx);
+}
 
 /* ioctx_alloc
  *     Allocates and initializes an ioctx.  Returns an ERR_PTR if it failed.
@@ -601,8 +609,13 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
        rcu_read_lock();
 
        hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) {
-               if (ctx->user_id == ctx_id && !ctx->dead) {
-                       get_ioctx(ctx);
+               /*
+                * RCU protects us against accessing freed memory but
+                * we have to be careful not to get a reference when the
+                * reference count already dropped to 0 (ctx->dead test
+                * is unreliable because of races).
+                */
+               if (ctx->user_id == ctx_id && !ctx->dead && try_get_ioctx(ctx)){
                        ret = ctx;
                        break;
                }
@@ -1629,6 +1642,23 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                goto out_put_req;
 
        spin_lock_irq(&ctx->ctx_lock);
+       /*
+        * We could have raced with io_destroy() and are currently holding a
+        * reference to ctx which should be destroyed. We cannot submit IO
+        * since ctx gets freed as soon as io_submit() puts its reference.  The
+        * check here is reliable: io_destroy() sets ctx->dead before waiting
+        * for outstanding IO and the barrier between these two is realized by
+        * unlock of mm->ioctx_lock and lock of ctx->ctx_lock.  Analogously we
+        * increment ctx->reqs_active before checking for ctx->dead and the
+        * barrier is realized by unlock and lock of ctx->ctx_lock. Thus if we
+        * don't see ctx->dead set here, io_destroy() waits for our IO to
+        * finish.
+        */
+       if (ctx->dead) {
+               spin_unlock_irq(&ctx->ctx_lock);
+               ret = -EINVAL;
+               goto out_put_req;
+       }
        aio_run_iocb(req);
        if (!list_empty(&ctx->run_list)) {
                /* drain the run list */
index 333a7bb..8892870 100644 (file)
@@ -873,6 +873,11 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
        ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
        if (ret)
                goto out_del;
+       /*
+        * bdev could be deleted beneath us which would implicitly destroy
+        * the holder directory.  Hold on to it.
+        */
+       kobject_get(bdev->bd_part->holder_dir);
 
        list_add(&holder->list, &bdev->bd_holder_disks);
        goto out_unlock;
@@ -909,6 +914,7 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
                del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
                del_symlink(bdev->bd_part->holder_dir,
                            &disk_to_dev(disk)->kobj);
+               kobject_put(bdev->bd_part->holder_dir);
                list_del_init(&holder->list);
                kfree(holder);
        }
@@ -922,14 +928,15 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
  * flush_disk - invalidates all buffer-cache entries on a disk
  *
  * @bdev:      struct block device to be flushed
+ * @kill_dirty: flag to guide handling of dirty inodes
  *
  * Invalidates all buffer-cache entries on a disk. It should be called
  * when a disk has been changed -- either by a media change or online
  * resize.
  */
-static void flush_disk(struct block_device *bdev)
+static void flush_disk(struct block_device *bdev, bool kill_dirty)
 {
-       if (__invalidate_device(bdev)) {
+       if (__invalidate_device(bdev, kill_dirty)) {
                char name[BDEVNAME_SIZE] = "";
 
                if (bdev->bd_disk)
@@ -966,7 +973,7 @@ void check_disk_size_change(struct gendisk *disk, struct block_device *bdev)
                       "%s: detected capacity change from %lld to %lld\n",
                       name, bdev_size, disk_size);
                i_size_write(bdev->bd_inode, disk_size);
-               flush_disk(bdev);
+               flush_disk(bdev, false);
        }
 }
 EXPORT_SYMBOL(check_disk_size_change);
@@ -1019,7 +1026,7 @@ int check_disk_change(struct block_device *bdev)
        if (!(events & DISK_EVENT_MEDIA_CHANGE))
                return 0;
 
-       flush_disk(bdev);
+       flush_disk(bdev, true);
        if (bdops->revalidate_disk)
                bdops->revalidate_disk(bdev->bd_disk);
        return 1;
@@ -1215,12 +1222,6 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
 
        res = __blkdev_get(bdev, mode, 0);
 
-       /* __blkdev_get() may alter read only status, check it afterwards */
-       if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) {
-               __blkdev_put(bdev, mode, 0);
-               res = -EACCES;
-       }
-
        if (whole) {
                /* finish claiming */
                mutex_lock(&bdev->bd_mutex);
@@ -1298,6 +1299,11 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
        if (err)
                return ERR_PTR(err);
 
+       if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
+               blkdev_put(bdev, mode);
+               return ERR_PTR(-EACCES);
+       }
+
        return bdev;
 }
 EXPORT_SYMBOL(blkdev_get_by_path);
@@ -1601,7 +1607,7 @@ fail:
 }
 EXPORT_SYMBOL(lookup_bdev);
 
-int __invalidate_device(struct block_device *bdev)
+int __invalidate_device(struct block_device *bdev, bool kill_dirty)
 {
        struct super_block *sb = get_super(bdev);
        int res = 0;
@@ -1614,7 +1620,7 @@ int __invalidate_device(struct block_device *bdev)
                 * hold).
                 */
                shrink_dcache_sb(sb);
-               res = invalidate_inodes(sb);
+               res = invalidate_inodes(sb, kill_dirty);
                drop_super(sb);
        }
        invalidate_bdev(bdev);
index 15b5ca2..9c94934 100644 (file)
@@ -37,6 +37,9 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
        char *value = NULL;
        struct posix_acl *acl;
 
+       if (!IS_POSIXACL(inode))
+               return NULL;
+
        acl = get_cached_acl(inode, type);
        if (acl != ACL_NOT_CACHED)
                return acl;
@@ -84,6 +87,9 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int ret = 0;
 
+       if (!IS_POSIXACL(dentry->d_inode))
+               return -EOPNOTSUPP;
+
        acl = btrfs_get_acl(dentry->d_inode, type);
 
        if (IS_ERR(acl))
index f745287..4d2110e 100644 (file)
@@ -562,7 +562,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        u64 em_len;
        u64 em_start;
        struct extent_map *em;
-       int ret;
+       int ret = -ENOMEM;
        u32 *sums;
 
        tree = &BTRFS_I(inode)->io_tree;
@@ -577,6 +577,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        compressed_len = em->block_len;
        cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
+       if (!cb)
+               goto out;
+
        atomic_set(&cb->pending_bios, 0);
        cb->errors = 0;
        cb->inode = inode;
@@ -597,13 +600,18 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        nr_pages = (compressed_len + PAGE_CACHE_SIZE - 1) /
                                 PAGE_CACHE_SIZE;
-       cb->compressed_pages = kmalloc(sizeof(struct page *) * nr_pages,
+       cb->compressed_pages = kzalloc(sizeof(struct page *) * nr_pages,
                                       GFP_NOFS);
+       if (!cb->compressed_pages)
+               goto fail1;
+
        bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
 
        for (page_index = 0; page_index < nr_pages; page_index++) {
                cb->compressed_pages[page_index] = alloc_page(GFP_NOFS |
                                                              __GFP_HIGHMEM);
+               if (!cb->compressed_pages[page_index])
+                       goto fail2;
        }
        cb->nr_pages = nr_pages;
 
@@ -614,6 +622,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        cb->len = uncompressed_len;
 
        comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, GFP_NOFS);
+       if (!comp_bio)
+               goto fail2;
        comp_bio->bi_private = cb;
        comp_bio->bi_end_io = end_compressed_bio_read;
        atomic_inc(&cb->pending_bios);
@@ -681,6 +691,17 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        bio_put(comp_bio);
        return 0;
+
+fail2:
+       for (page_index = 0; page_index < nr_pages; page_index++)
+               free_page((unsigned long)cb->compressed_pages[page_index]);
+
+       kfree(cb->compressed_pages);
+fail1:
+       kfree(cb);
+out:
+       free_extent_map(em);
+       return ret;
 }
 
 static struct list_head comp_idle_workspace[BTRFS_COMPRESS_TYPES];
@@ -900,7 +921,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
        return ret;
 }
 
-void __exit btrfs_exit_compress(void)
+void btrfs_exit_compress(void)
 {
        free_workspaces();
 }
index 2c98b3a..6f820fa 100644 (file)
@@ -1254,6 +1254,7 @@ struct btrfs_root {
 #define BTRFS_MOUNT_SPACE_CACHE                (1 << 12)
 #define BTRFS_MOUNT_CLEAR_CACHE                (1 << 13)
 #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14)
+#define BTRFS_MOUNT_ENOSPC_DEBUG        (1 << 15)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -2218,6 +2219,8 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root,
                                   u64 start, u64 end);
 int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
                               u64 num_bytes);
+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 type);
 
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
index b531c36..e1aa8d6 100644 (file)
@@ -359,10 +359,14 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
 
        tree = &BTRFS_I(page->mapping->host)->io_tree;
 
-       if (page->private == EXTENT_PAGE_PRIVATE)
+       if (page->private == EXTENT_PAGE_PRIVATE) {
+               WARN_ON(1);
                goto out;
-       if (!page->private)
+       }
+       if (!page->private) {
+               WARN_ON(1);
                goto out;
+       }
        len = page->private >> 2;
        WARN_ON(len == 0);
 
@@ -1550,6 +1554,7 @@ static int transaction_kthread(void *arg)
                spin_unlock(&root->fs_info->new_trans_lock);
 
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                if (transid == trans->transid) {
                        ret = btrfs_commit_transaction(trans, root);
                        BUG_ON(ret);
@@ -2453,10 +2458,14 @@ int btrfs_commit_super(struct btrfs_root *root)
        up_write(&root->fs_info->cleanup_work_sem);
 
        trans = btrfs_join_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
        /* run commit again to drop the original snapshot */
        trans = btrfs_join_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        btrfs_commit_transaction(trans, root);
        ret = btrfs_write_and_wait_transaction(NULL, root);
        BUG_ON(ret);
@@ -2554,6 +2563,8 @@ int close_ctree(struct btrfs_root *root)
        kfree(fs_info->chunk_root);
        kfree(fs_info->dev_root);
        kfree(fs_info->csum_root);
+       kfree(fs_info);
+
        return 0;
 }
 
index 9786963..ff27d7a 100644 (file)
@@ -171,6 +171,8 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
        int ret;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return ERR_PTR(-ENOMEM);
 
        if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
                key.objectid = root->root_key.objectid;
index b552693..588ff98 100644 (file)
@@ -320,11 +320,6 @@ static int caching_kthread(void *data)
        if (!path)
                return -ENOMEM;
 
-       exclude_super_stripes(extent_root, block_group);
-       spin_lock(&block_group->space_info->lock);
-       block_group->space_info->bytes_readonly += block_group->bytes_super;
-       spin_unlock(&block_group->space_info->lock);
-
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
 
        /*
@@ -467,8 +462,10 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
                        cache->cached = BTRFS_CACHE_NO;
                }
                spin_unlock(&cache->lock);
-               if (ret == 1)
+               if (ret == 1) {
+                       free_excluded_extents(fs_info->extent_root, cache);
                        return 0;
+               }
        }
 
        if (load_cache_only)
@@ -3344,8 +3341,10 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
        u64 reserved;
        u64 max_reclaim;
        u64 reclaimed = 0;
+       long time_left;
        int pause = 1;
        int nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
+       int loops = 0;
 
        block_rsv = &root->fs_info->delalloc_block_rsv;
        space_info = block_rsv->space_info;
@@ -3358,7 +3357,7 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
 
        max_reclaim = min(reserved, to_reclaim);
 
-       while (1) {
+       while (loops < 1024) {
                /* have the flusher threads jump in and do some IO */
                smp_mb();
                nr_pages = min_t(unsigned long, nr_pages,
@@ -3366,8 +3365,12 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
                writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages);
 
                spin_lock(&space_info->lock);
-               if (reserved > space_info->bytes_reserved)
+               if (reserved > space_info->bytes_reserved) {
+                       loops = 0;
                        reclaimed += reserved - space_info->bytes_reserved;
+               } else {
+                       loops++;
+               }
                reserved = space_info->bytes_reserved;
                spin_unlock(&space_info->lock);
 
@@ -3378,7 +3381,12 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
                        return -EAGAIN;
 
                __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(pause);
+               time_left = schedule_timeout(pause);
+
+               /* We were interrupted, exit */
+               if (time_left)
+                       break;
+
                pause <<= 1;
                if (pause > HZ / 10)
                        pause = HZ / 10;
@@ -3588,8 +3596,20 @@ void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
 
        if (num_bytes > 0) {
                if (dest) {
-                       block_rsv_add_bytes(dest, num_bytes, 0);
-               } else {
+                       spin_lock(&dest->lock);
+                       if (!dest->full) {
+                               u64 bytes_to_add;
+
+                               bytes_to_add = dest->size - dest->reserved;
+                               bytes_to_add = min(num_bytes, bytes_to_add);
+                               dest->reserved += bytes_to_add;
+                               if (dest->reserved >= dest->size)
+                                       dest->full = 1;
+                               num_bytes -= bytes_to_add;
+                       }
+                       spin_unlock(&dest->lock);
+               }
+               if (num_bytes) {
                        spin_lock(&space_info->lock);
                        space_info->bytes_reserved -= num_bytes;
                        spin_unlock(&space_info->lock);
@@ -4012,6 +4032,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
        num_bytes = ALIGN(num_bytes, root->sectorsize);
        atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+       WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0);
 
        spin_lock(&BTRFS_I(inode)->accounting_lock);
        nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents);
@@ -5355,7 +5376,7 @@ again:
                               num_bytes, data, 1);
                goto again;
        }
-       if (ret == -ENOSPC) {
+       if (ret == -ENOSPC && btrfs_test_opt(root, ENOSPC_DEBUG)) {
                struct btrfs_space_info *sinfo;
 
                sinfo = __find_space_info(root->fs_info, data);
@@ -5633,6 +5654,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
              struct btrfs_root *root, u32 blocksize)
 {
        struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
        int ret;
 
        block_rsv = get_block_rsv(trans, root);
@@ -5640,14 +5662,39 @@ use_block_rsv(struct btrfs_trans_handle *trans,
        if (block_rsv->size == 0) {
                ret = reserve_metadata_bytes(trans, root, block_rsv,
                                             blocksize, 0);
-               if (ret)
+               /*
+                * If we couldn't reserve metadata bytes try and use some from
+                * the global reserve.
+                */
+               if (ret && block_rsv != global_rsv) {
+                       ret = block_rsv_use_bytes(global_rsv, blocksize);
+                       if (!ret)
+                               return global_rsv;
+                       return ERR_PTR(ret);
+               } else if (ret) {
                        return ERR_PTR(ret);
+               }
                return block_rsv;
        }
 
        ret = block_rsv_use_bytes(block_rsv, blocksize);
        if (!ret)
                return block_rsv;
+       if (ret) {
+               WARN_ON(1);
+               ret = reserve_metadata_bytes(trans, root, block_rsv, blocksize,
+                                            0);
+               if (!ret) {
+                       spin_lock(&block_rsv->lock);
+                       block_rsv->size += blocksize;
+                       spin_unlock(&block_rsv->lock);
+                       return block_rsv;
+               } else if (ret && block_rsv != global_rsv) {
+                       ret = block_rsv_use_bytes(global_rsv, blocksize);
+                       if (!ret)
+                               return global_rsv;
+               }
+       }
 
        return ERR_PTR(-ENOSPC);
 }
@@ -6221,6 +6268,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        BUG_ON(!wc);
 
        trans = btrfs_start_transaction(tree_root, 0);
+       BUG_ON(IS_ERR(trans));
+
        if (block_rsv)
                trans->block_rsv = block_rsv;
 
@@ -6318,6 +6367,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
 
                        btrfs_end_transaction_throttle(trans, tree_root);
                        trans = btrfs_start_transaction(tree_root, 0);
+                       BUG_ON(IS_ERR(trans));
                        if (block_rsv)
                                trans->block_rsv = block_rsv;
                }
@@ -6446,6 +6496,8 @@ static noinline int relocate_inode_pages(struct inode *inode, u64 start,
        int ret = 0;
 
        ra = kzalloc(sizeof(*ra), GFP_NOFS);
+       if (!ra)
+               return -ENOMEM;
 
        mutex_lock(&inode->i_mutex);
        first_index = start >> PAGE_CACHE_SHIFT;
@@ -6531,7 +6583,7 @@ static noinline int relocate_data_extent(struct inode *reloc_inode,
        u64 end = start + extent_key->offset - 1;
 
        em = alloc_extent_map(GFP_NOFS);
-       BUG_ON(!em || IS_ERR(em));
+       BUG_ON(!em);
 
        em->start = start;
        em->len = extent_key->offset;
@@ -7477,7 +7529,7 @@ int btrfs_drop_dead_reloc_roots(struct btrfs_root *root)
                BUG_ON(reloc_root->commit_root != NULL);
                while (1) {
                        trans = btrfs_join_transaction(root, 1);
-                       BUG_ON(!trans);
+                       BUG_ON(IS_ERR(trans));
 
                        mutex_lock(&root->fs_info->drop_mutex);
                        ret = btrfs_drop_snapshot(trans, reloc_root);
@@ -7535,7 +7587,7 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root)
 
        if (found) {
                trans = btrfs_start_transaction(root, 1);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
                ret = btrfs_commit_transaction(trans, root);
                BUG_ON(ret);
        }
@@ -7779,7 +7831,7 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root,
 
 
        trans = btrfs_start_transaction(extent_root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        if (extent_key->objectid == 0) {
                ret = del_extent_zero(trans, extent_root, path, extent_key);
@@ -8013,6 +8065,13 @@ out:
        return ret;
 }
 
+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 type)
+{
+       u64 alloc_flags = get_alloc_profile(root, type);
+       return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+}
+
 /*
  * helper to account the unused space of all the readonly block group in the
  * list. takes mirrors into account.
@@ -8270,6 +8329,13 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                if (block_group->cached == BTRFS_CACHE_STARTED)
                        wait_block_group_cache_done(block_group);
 
+               /*
+                * We haven't cached this block group, which means we could
+                * possibly have excluded extents on this block group.
+                */
+               if (block_group->cached == BTRFS_CACHE_NO)
+                       free_excluded_extents(info->extent_root, block_group);
+
                btrfs_remove_free_space_cache(block_group);
                btrfs_put_block_group(block_group);
 
@@ -8385,6 +8451,13 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                cache->sectorsize = root->sectorsize;
 
                /*
+                * We need to exclude the super stripes now so that the space
+                * info has super bytes accounted for, otherwise we'll think
+                * we have more space than we actually do.
+                */
+               exclude_super_stripes(root, cache);
+
+               /*
                 * check for two cases, either we are full, and therefore
                 * don't need to bother with the caching work since we won't
                 * find any space, or we are empty, and we can just add all
@@ -8392,12 +8465,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                 * time, particularly in the full case.
                 */
                if (found_key.offset == btrfs_block_group_used(&cache->item)) {
-                       exclude_super_stripes(root, cache);
                        cache->last_byte_to_unpin = (u64)-1;
                        cache->cached = BTRFS_CACHE_FINISHED;
                        free_excluded_extents(root, cache);
                } else if (btrfs_block_group_used(&cache->item) == 0) {
-                       exclude_super_stripes(root, cache);
                        cache->last_byte_to_unpin = (u64)-1;
                        cache->cached = BTRFS_CACHE_FINISHED;
                        add_new_free_space(cache, root->fs_info,
index 2e993cf..fd3f172 100644 (file)
@@ -1433,12 +1433,13 @@ int extent_clear_unlock_delalloc(struct inode *inode,
  */
 u64 count_range_bits(struct extent_io_tree *tree,
                     u64 *start, u64 search_end, u64 max_bytes,
-                    unsigned long bits)
+                    unsigned long bits, int contig)
 {
        struct rb_node *node;
        struct extent_state *state;
        u64 cur_start = *start;
        u64 total_bytes = 0;
+       u64 last = 0;
        int found = 0;
 
        if (search_end <= cur_start) {
@@ -1463,7 +1464,9 @@ u64 count_range_bits(struct extent_io_tree *tree,
                state = rb_entry(node, struct extent_state, rb_node);
                if (state->start > search_end)
                        break;
-               if (state->end >= cur_start && (state->state & bits)) {
+               if (contig && found && state->start > last + 1)
+                       break;
+               if (state->end >= cur_start && (state->state & bits) == bits) {
                        total_bytes += min(search_end, state->end) + 1 -
                                       max(cur_start, state->start);
                        if (total_bytes >= max_bytes)
@@ -1472,6 +1475,9 @@ u64 count_range_bits(struct extent_io_tree *tree,
                                *start = state->start;
                                found = 1;
                        }
+                       last = state->end;
+               } else if (contig && found) {
+                       break;
                }
                node = rb_next(node);
                if (!node)
@@ -1865,7 +1871,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
        bio_get(bio);
 
        if (tree->ops && tree->ops->submit_bio_hook)
-               tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
+               ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
                                           mirror_num, bio_flags, start);
        else
                submit_bio(rw, bio);
@@ -1920,6 +1926,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
                nr = bio_get_nr_vecs(bdev);
 
        bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
+       if (!bio)
+               return -ENOMEM;
 
        bio_add_page(bio, page, page_size, offset);
        bio->bi_end_io = end_io_func;
@@ -1944,6 +1952,7 @@ void set_page_extent_mapped(struct page *page)
 
 static void set_page_extent_head(struct page *page, unsigned long len)
 {
+       WARN_ON(!PagePrivate(page));
        set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
 }
 
@@ -2126,7 +2135,7 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
        ret = __extent_read_full_page(tree, page, get_extent, &bio, 0,
                                      &bio_flags);
        if (bio)
-               submit_one_bio(READ, bio, 0, bio_flags);
+               ret = submit_one_bio(READ, bio, 0, bio_flags);
        return ret;
 }
 
@@ -2819,9 +2828,17 @@ int try_release_extent_state(struct extent_map_tree *map,
                 * at this point we can safely clear everything except the
                 * locked bit and the nodatasum bit
                 */
-               clear_extent_bit(tree, start, end,
+               ret = clear_extent_bit(tree, start, end,
                                 ~(EXTENT_LOCKED | EXTENT_NODATASUM),
                                 0, 0, NULL, mask);
+
+               /* if clear_extent_bit failed for enomem reasons,
+                * we can't allow the release to continue.
+                */
+               if (ret < 0)
+                       ret = 0;
+               else
+                       ret = 1;
        }
        return ret;
 }
@@ -2901,6 +2918,46 @@ out:
        return sector;
 }
 
+/*
+ * helper function for fiemap, which doesn't want to see any holes.
+ * This maps until we find something past 'last'
+ */
+static struct extent_map *get_extent_skip_holes(struct inode *inode,
+                                               u64 offset,
+                                               u64 last,
+                                               get_extent_t *get_extent)
+{
+       u64 sectorsize = BTRFS_I(inode)->root->sectorsize;
+       struct extent_map *em;
+       u64 len;
+
+       if (offset >= last)
+               return NULL;
+
+       while(1) {
+               len = last - offset;
+               if (len == 0)
+                       break;
+               len = (len + sectorsize - 1) & ~(sectorsize - 1);
+               em = get_extent(inode, NULL, 0, offset, len, 0);
+               if (!em || IS_ERR(em))
+                       return em;
+
+               /* if this isn't a hole return it */
+               if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags) &&
+                   em->block_start != EXTENT_MAP_HOLE) {
+                       return em;
+               }
+
+               /* this is a hole, advance to the next extent */
+               offset = extent_map_end(em);
+               free_extent_map(em);
+               if (offset >= last)
+                       break;
+       }
+       return NULL;
+}
+
 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len, get_extent_t *get_extent)
 {
@@ -2910,16 +2967,19 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        u32 flags = 0;
        u32 found_type;
        u64 last;
+       u64 last_for_get_extent = 0;
        u64 disko = 0;
+       u64 isize = i_size_read(inode);
        struct btrfs_key found_key;
        struct extent_map *em = NULL;
        struct extent_state *cached_state = NULL;
        struct btrfs_path *path;
        struct btrfs_file_extent_item *item;
        int end = 0;
-       u64 em_start = 0, em_len = 0;
+       u64 em_start = 0;
+       u64 em_len = 0;
+       u64 em_end = 0;
        unsigned long emflags;
-       int hole = 0;
 
        if (len == 0)
                return -EINVAL;
@@ -2929,6 +2989,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                return -ENOMEM;
        path->leave_spinning = 1;
 
+       /*
+        * lookup the last file extent.  We're not using i_size here
+        * because there might be preallocation past i_size
+        */
        ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
                                       path, inode->i_ino, -1, 0);
        if (ret < 0) {
@@ -2942,18 +3006,38 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
        found_type = btrfs_key_type(&found_key);
 
-       /* No extents, just return */
+       /* No extents, but there might be delalloc bits */
        if (found_key.objectid != inode->i_ino ||
            found_type != BTRFS_EXTENT_DATA_KEY) {
-               btrfs_free_path(path);
-               return 0;
+               /* have to trust i_size as the end */
+               last = (u64)-1;
+               last_for_get_extent = isize;
+       } else {
+               /*
+                * remember the start of the last extent.  There are a
+                * bunch of different factors that go into the length of the
+                * extent, so its much less complex to remember where it started
+                */
+               last = found_key.offset;
+               last_for_get_extent = last + 1;
        }
-       last = found_key.offset;
        btrfs_free_path(path);
 
+       /*
+        * we might have some extents allocated but more delalloc past those
+        * extents.  so, we trust isize unless the start of the last extent is
+        * beyond isize
+        */
+       if (last < isize) {
+               last = (u64)-1;
+               last_for_get_extent = isize;
+       }
+
        lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
                         &cached_state, GFP_NOFS);
-       em = get_extent(inode, NULL, 0, off, max - off, 0);
+
+       em = get_extent_skip_holes(inode, off, last_for_get_extent,
+                                  get_extent);
        if (!em)
                goto out;
        if (IS_ERR(em)) {
@@ -2962,19 +3046,14 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        }
 
        while (!end) {
-               hole = 0;
-               off = em->start + em->len;
+               off = extent_map_end(em);
                if (off >= max)
                        end = 1;
 
-               if (em->block_start == EXTENT_MAP_HOLE) {
-                       hole = 1;
-                       goto next;
-               }
-
                em_start = em->start;
                em_len = em->len;
-
+               em_end = extent_map_end(em);
+               emflags = em->flags;
                disko = 0;
                flags = 0;
 
@@ -2993,37 +3072,29 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
                        flags |= FIEMAP_EXTENT_ENCODED;
 
-next:
-               emflags = em->flags;
                free_extent_map(em);
                em = NULL;
-               if (!end) {
-                       em = get_extent(inode, NULL, 0, off, max - off, 0);
-                       if (!em)
-                               goto out;
-                       if (IS_ERR(em)) {
-                               ret = PTR_ERR(em);
-                               goto out;
-                       }
-                       emflags = em->flags;
-               }
-
-               if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
+               if ((em_start >= last) || em_len == (u64)-1 ||
+                  (last == (u64)-1 && isize <= em_end)) {
                        flags |= FIEMAP_EXTENT_LAST;
                        end = 1;
                }
 
-               if (em_start == last) {
+               /* now scan forward to see if this is really the last extent. */
+               em = get_extent_skip_holes(inode, off, last_for_get_extent,
+                                          get_extent);
+               if (IS_ERR(em)) {
+                       ret = PTR_ERR(em);
+                       goto out;
+               }
+               if (!em) {
                        flags |= FIEMAP_EXTENT_LAST;
                        end = 1;
                }
-
-               if (!hole) {
-                       ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
-                                               em_len, flags);
-                       if (ret)
-                               goto out_free;
-               }
+               ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
+                                             em_len, flags);
+               if (ret)
+                       goto out_free;
        }
 out_free:
        free_extent_map(em);
@@ -3192,7 +3263,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                }
                if (!PageUptodate(p))
                        uptodate = 0;
-               unlock_page(p);
+
+               /*
+                * see below about how we avoid a nasty race with release page
+                * and why we unlock later
+                */
+               if (i != 0)
+                       unlock_page(p);
        }
        if (uptodate)
                set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
@@ -3216,9 +3293,26 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
        atomic_inc(&eb->refs);
        spin_unlock(&tree->buffer_lock);
        radix_tree_preload_end();
+
+       /*
+        * there is a race where release page may have
+        * tried to find this extent buffer in the radix
+        * but failed.  It will tell the VM it is safe to
+        * reclaim the, and it will clear the page private bit.
+        * We must make sure to set the page private bit properly
+        * after the extent buffer is in the radix tree so
+        * it doesn't get lost
+        */
+       set_page_extent_mapped(eb->first_page);
+       set_page_extent_head(eb->first_page, eb->len);
+       if (!page0)
+               unlock_page(eb->first_page);
        return eb;
 
 free_eb:
+       if (eb->first_page && !page0)
+               unlock_page(eb->first_page);
+
        if (!atomic_dec_and_test(&eb->refs))
                return exists;
        btrfs_release_extent_buffer(eb);
@@ -3269,10 +3363,11 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                        continue;
 
                lock_page(page);
+               WARN_ON(!PagePrivate(page));
+
+               set_page_extent_mapped(page);
                if (i == 0)
                        set_page_extent_head(page, eb->len);
-               else
-                       set_page_private(page, EXTENT_PAGE_PRIVATE);
 
                clear_page_dirty_for_io(page);
                spin_lock_irq(&page->mapping->tree_lock);
@@ -3462,6 +3557,13 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 
        for (i = start_i; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
+
+               WARN_ON(!PagePrivate(page));
+
+               set_page_extent_mapped(page);
+               if (i == 0)
+                       set_page_extent_head(page, eb->len);
+
                if (inc_all_pages)
                        page_cache_get(page);
                if (!PageUptodate(page)) {
index 7083cfa..9318dfe 100644 (file)
@@ -191,7 +191,7 @@ void extent_io_exit(void);
 
 u64 count_range_bits(struct extent_io_tree *tree,
                     u64 *start, u64 search_end,
-                    u64 max_bytes, unsigned long bits);
+                    u64 max_bytes, unsigned long bits, int contig);
 
 void free_extent_state(struct extent_state *state);
 int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
index b0e1fce..2b6c12e 100644 (file)
@@ -51,8 +51,8 @@ struct extent_map *alloc_extent_map(gfp_t mask)
 {
        struct extent_map *em;
        em = kmem_cache_alloc(extent_map_cache, mask);
-       if (!em || IS_ERR(em))
-               return em;
+       if (!em)
+               return NULL;
        em->in_tree = 0;
        em->flags = 0;
        em->compress_type = BTRFS_COMPRESS_NONE;
index a562a25..4f19a3e 100644 (file)
@@ -536,6 +536,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
        root = root->fs_info->csum_root;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
 
        while (1) {
                key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
@@ -548,7 +550,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                        if (path->slots[0] == 0)
                                goto out;
                        path->slots[0]--;
+               } else if (ret < 0) {
+                       goto out;
                }
+
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 
index c800d58..7084140 100644 (file)
@@ -186,6 +186,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split = alloc_extent_map(GFP_NOFS);
                if (!split2)
                        split2 = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!split || !split2);
 
                write_lock(&em_tree->lock);
                em = lookup_extent_mapping(em_tree, start, len);
@@ -793,8 +794,12 @@ again:
        for (i = 0; i < num_pages; i++) {
                pages[i] = grab_cache_page(inode->i_mapping, index + i);
                if (!pages[i]) {
-                       err = -ENOMEM;
-                       BUG_ON(1);
+                       int c;
+                       for (c = i - 1; c >= 0; c--) {
+                               unlock_page(pages[c]);
+                               page_cache_release(pages[c]);
+                       }
+                       return -ENOMEM;
                }
                wait_on_page_writeback(pages[i]);
        }
@@ -946,6 +951,10 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                     PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
                     (sizeof(struct page *)));
        pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
+       if (!pages) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* generic_write_checks can change our pos */
        start_pos = pos;
@@ -984,8 +993,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                size_t write_bytes = min(iov_iter_count(&i),
                                         nrptrs * (size_t)PAGE_CACHE_SIZE -
                                         offset);
-               size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
-                                       PAGE_CACHE_SHIFT;
+               size_t num_pages = (write_bytes + offset +
+                                   PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
                WARN_ON(num_pages > nrptrs);
                memset(pages, 0, sizeof(struct page *) * nrptrs);
@@ -1015,8 +1024,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
 
                copied = btrfs_copy_from_user(pos, num_pages,
                                           write_bytes, pages, &i);
-               dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >>
-                                       PAGE_CACHE_SHIFT;
+               dirty_pages = (copied + offset + PAGE_CACHE_SIZE - 1) >>
+                               PAGE_CACHE_SHIFT;
 
                if (num_pages > dirty_pages) {
                        if (copied > 0)
index 60d6842..a039065 100644 (file)
@@ -987,11 +987,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,
        return entry;
 }
 
-static void unlink_free_space(struct btrfs_block_group_cache *block_group,
-                             struct btrfs_free_space *info)
+static inline void
+__unlink_free_space(struct btrfs_block_group_cache *block_group,
+                   struct btrfs_free_space *info)
 {
        rb_erase(&info->offset_index, &block_group->free_space_offset);
        block_group->free_extents--;
+}
+
+static void unlink_free_space(struct btrfs_block_group_cache *block_group,
+                             struct btrfs_free_space *info)
+{
+       __unlink_free_space(block_group, info);
        block_group->free_space -= info->bytes;
 }
 
@@ -1016,14 +1023,18 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
        u64 max_bytes;
        u64 bitmap_bytes;
        u64 extent_bytes;
+       u64 size = block_group->key.offset;
 
        /*
         * The goal is to keep the total amount of memory used per 1gb of space
         * at or below 32k, so we need to adjust how much memory we allow to be
         * used by extent based free space tracking
         */
-       max_bytes = MAX_CACHE_BYTES_PER_GIG *
-               (div64_u64(block_group->key.offset, 1024 * 1024 * 1024));
+       if (size < 1024 * 1024 * 1024)
+               max_bytes = MAX_CACHE_BYTES_PER_GIG;
+       else
+               max_bytes = MAX_CACHE_BYTES_PER_GIG *
+                       div64_u64(size, 1024 * 1024 * 1024);
 
        /*
         * we want to account for 1 more bitmap than what we have so we can make
@@ -1171,6 +1182,16 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
        recalculate_thresholds(block_group);
 }
 
+static void free_bitmap(struct btrfs_block_group_cache *block_group,
+                       struct btrfs_free_space *bitmap_info)
+{
+       unlink_free_space(block_group, bitmap_info);
+       kfree(bitmap_info->bitmap);
+       kfree(bitmap_info);
+       block_group->total_bitmaps--;
+       recalculate_thresholds(block_group);
+}
+
 static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,
                              struct btrfs_free_space *bitmap_info,
                              u64 *offset, u64 *bytes)
@@ -1195,6 +1216,7 @@ again:
         */
        search_start = *offset;
        search_bytes = *bytes;
+       search_bytes = min(search_bytes, end - search_start + 1);
        ret = search_bitmap(block_group, bitmap_info, &search_start,
                            &search_bytes);
        BUG_ON(ret < 0 || search_start != *offset);
@@ -1211,13 +1233,8 @@ again:
 
        if (*bytes) {
                struct rb_node *next = rb_next(&bitmap_info->offset_index);
-               if (!bitmap_info->bytes) {
-                       unlink_free_space(block_group, bitmap_info);
-                       kfree(bitmap_info->bitmap);
-                       kfree(bitmap_info);
-                       block_group->total_bitmaps--;
-                       recalculate_thresholds(block_group);
-               }
+               if (!bitmap_info->bytes)
+                       free_bitmap(block_group, bitmap_info);
 
                /*
                 * no entry after this bitmap, but we still have bytes to
@@ -1250,13 +1267,8 @@ again:
                        return -EAGAIN;
 
                goto again;
-       } else if (!bitmap_info->bytes) {
-               unlink_free_space(block_group, bitmap_info);
-               kfree(bitmap_info->bitmap);
-               kfree(bitmap_info);
-               block_group->total_bitmaps--;
-               recalculate_thresholds(block_group);
-       }
+       } else if (!bitmap_info->bytes)
+               free_bitmap(block_group, bitmap_info);
 
        return 0;
 }
@@ -1359,22 +1371,14 @@ out:
        return ret;
 }
 
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 offset, u64 bytes)
+bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
+                         struct btrfs_free_space *info, bool update_stat)
 {
-       struct btrfs_free_space *right_info = NULL;
-       struct btrfs_free_space *left_info = NULL;
-       struct btrfs_free_space *info = NULL;
-       int ret = 0;
-
-       info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
-       if (!info)
-               return -ENOMEM;
-
-       info->offset = offset;
-       info->bytes = bytes;
-
-       spin_lock(&block_group->tree_lock);
+       struct btrfs_free_space *left_info;
+       struct btrfs_free_space *right_info;
+       bool merged = false;
+       u64 offset = info->offset;
+       u64 bytes = info->bytes;
 
        /*
         * first we want to see if there is free space adjacent to the range we
@@ -1388,37 +1392,62 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
        else
                left_info = tree_search_offset(block_group, offset - 1, 0, 0);
 
-       /*
-        * If there was no extent directly to the left or right of this new
-        * extent then we know we're going to have to allocate a new extent, so
-        * before we do that see if we need to drop this into a bitmap
-        */
-       if ((!left_info || left_info->bitmap) &&
-           (!right_info || right_info->bitmap)) {
-               ret = insert_into_bitmap(block_group, info);
-
-               if (ret < 0) {
-                       goto out;
-               } else if (ret) {
-                       ret = 0;
-                       goto out;
-               }
-       }
-
        if (right_info && !right_info->bitmap) {
-               unlink_free_space(block_group, right_info);
+               if (update_stat)
+                       unlink_free_space(block_group, right_info);
+               else
+                       __unlink_free_space(block_group, right_info);
                info->bytes += right_info->bytes;
                kfree(right_info);
+               merged = true;
        }
 
        if (left_info && !left_info->bitmap &&
            left_info->offset + left_info->bytes == offset) {
-               unlink_free_space(block_group, left_info);
+               if (update_stat)
+                       unlink_free_space(block_group, left_info);
+               else
+                       __unlink_free_space(block_group, left_info);
                info->offset = left_info->offset;
                info->bytes += left_info->bytes;
                kfree(left_info);
+               merged = true;
        }
 
+       return merged;
+}
+
+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+                        u64 offset, u64 bytes)
+{
+       struct btrfs_free_space *info;
+       int ret = 0;
+
+       info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
+       if (!info)
+               return -ENOMEM;
+
+       info->offset = offset;
+       info->bytes = bytes;
+
+       spin_lock(&block_group->tree_lock);
+
+       if (try_merge_free_space(block_group, info, true))
+               goto link;
+
+       /*
+        * There was no extent directly to the left or right of this new
+        * extent then we know we're going to have to allocate a new extent, so
+        * before we do that see if we need to drop this into a bitmap
+        */
+       ret = insert_into_bitmap(block_group, info);
+       if (ret < 0) {
+               goto out;
+       } else if (ret) {
+               ret = 0;
+               goto out;
+       }
+link:
        ret = link_free_space(block_group, info);
        if (ret)
                kfree(info);
@@ -1621,6 +1650,7 @@ __btrfs_return_cluster_to_free_space(
                node = rb_next(&entry->offset_index);
                rb_erase(&entry->offset_index, &cluster->root);
                BUG_ON(entry->bitmap);
+               try_merge_free_space(block_group, entry, false);
                tree_insert_offset(&block_group->free_space_offset,
                                   entry->offset, &entry->offset_index, 0);
        }
@@ -1685,13 +1715,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
        ret = offset;
        if (entry->bitmap) {
                bitmap_clear_bits(block_group, entry, offset, bytes);
-               if (!entry->bytes) {
-                       unlink_free_space(block_group, entry);
-                       kfree(entry->bitmap);
-                       kfree(entry);
-                       block_group->total_bitmaps--;
-                       recalculate_thresholds(block_group);
-               }
+               if (!entry->bytes)
+                       free_bitmap(block_group, entry);
        } else {
                unlink_free_space(block_group, entry);
                entry->offset += bytes;
@@ -1789,6 +1814,8 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
 
        ret = search_start;
        bitmap_clear_bits(block_group, entry, ret, bytes);
+       if (entry->bytes == 0)
+               free_bitmap(block_group, entry);
 out:
        spin_unlock(&cluster->lock);
        spin_unlock(&block_group->tree_lock);
@@ -1842,15 +1869,26 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                entry->offset += bytes;
                entry->bytes -= bytes;
 
-               if (entry->bytes == 0) {
+               if (entry->bytes == 0)
                        rb_erase(&entry->offset_index, &cluster->root);
-                       kfree(entry);
-               }
                break;
        }
 out:
        spin_unlock(&cluster->lock);
 
+       if (!ret)
+               return 0;
+
+       spin_lock(&block_group->tree_lock);
+
+       block_group->free_space -= bytes;
+       if (entry->bytes == 0) {
+               block_group->free_extents--;
+               kfree(entry);
+       }
+
+       spin_unlock(&block_group->tree_lock);
+
        return ret;
 }
 
index 160b55b..0efdb65 100644 (file)
@@ -416,7 +416,7 @@ again:
        }
        if (start == 0) {
                trans = btrfs_join_transaction(root, 1);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
                btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -612,6 +612,7 @@ retry:
                            GFP_NOFS);
 
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
@@ -643,6 +644,7 @@ retry:
                                        async_extent->ram_size - 1, 0);
 
                em = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!em);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
                em->orig_start = em->start;
@@ -771,7 +773,7 @@ static noinline int cow_file_range(struct inode *inode,
 
        BUG_ON(root == root->fs_info->tree_root);
        trans = btrfs_join_transaction(root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -819,6 +821,7 @@ static noinline int cow_file_range(struct inode *inode,
                BUG_ON(ret);
 
                em = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!em);
                em->start = start;
                em->orig_start = em->start;
                ram_size = ins.offset;
@@ -1049,7 +1052,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        } else {
                trans = btrfs_join_transaction(root, 1);
        }
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        cow_start = (u64)-1;
        cur_offset = start;
@@ -1168,6 +1171,7 @@ out_check:
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
                        em = alloc_extent_map(GFP_NOFS);
+                       BUG_ON(!em);
                        em->start = cur_offset;
                        em->orig_start = em->start;
                        em->len = num_bytes;
@@ -1557,6 +1561,7 @@ out:
 out_page:
        unlock_page(page);
        page_cache_release(page);
+       kfree(fixup);
 }
 
 /*
@@ -1703,7 +1708,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                trans = btrfs_join_transaction_nolock(root, 1);
                        else
                                trans = btrfs_join_transaction(root, 1);
-                       BUG_ON(!trans);
+                       BUG_ON(IS_ERR(trans));
                        btrfs_set_trans_block_group(trans, inode);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
@@ -1720,6 +1725,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                trans = btrfs_join_transaction_nolock(root, 1);
        else
                trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -1907,7 +1913,7 @@ static int btrfs_clean_io_failures(struct inode *inode, u64 start)
 
        private = 0;
        if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
-                            (u64)-1, 1, EXTENT_DIRTY)) {
+                            (u64)-1, 1, EXTENT_DIRTY, 0)) {
                ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
                                        start, &private_failure);
                if (ret == 0) {
@@ -2354,6 +2360,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                 */
                if (is_bad_inode(inode)) {
                        trans = btrfs_start_transaction(root, 0);
+                       BUG_ON(IS_ERR(trans));
                        btrfs_orphan_del(trans, inode);
                        btrfs_end_transaction(trans, root);
                        iput(inode);
@@ -2381,6 +2388,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
 
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                btrfs_end_transaction(trans, root);
        }
 
@@ -2641,7 +2649,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        if (!path) {
                ret = -ENOMEM;
-               goto err;
+               goto out;
        }
 
        path->leave_spinning = 1;
@@ -2714,9 +2722,10 @@ static int check_path_shared(struct btrfs_root *root,
        struct extent_buffer *eb;
        int level;
        u64 refs = 1;
-       int uninitialized_var(ret);
 
        for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+               int ret;
+
                if (!path->nodes[level])
                        break;
                eb = path->nodes[level];
@@ -2727,7 +2736,7 @@ static int check_path_shared(struct btrfs_root *root,
                if (refs > 1)
                        return 1;
        }
-       return ret; /* XXX callers? */
+       return 0;
 }
 
 /*
@@ -4134,7 +4143,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        }
        srcu_read_unlock(&root->fs_info->subvol_srcu, index);
 
-       if (root != sub_root) {
+       if (!IS_ERR(inode) && root != sub_root) {
                down_read(&root->fs_info->cleanup_work_sem);
                if (!(inode->i_sb->s_flags & MS_RDONLY))
                        btrfs_orphan_cleanup(sub_root);
@@ -4347,6 +4356,8 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
                        trans = btrfs_join_transaction_nolock(root, 1);
                else
                        trans = btrfs_join_transaction(root, 1);
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
                btrfs_set_trans_block_group(trans, inode);
                if (nolock)
                        ret = btrfs_end_transaction_nolock(trans, root);
@@ -4372,6 +4383,7 @@ void btrfs_dirty_inode(struct inode *inode)
                return;
 
        trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
 
        ret = btrfs_update_inode(trans, root, inode);
@@ -5176,6 +5188,8 @@ again:
                                em = NULL;
                                btrfs_release_path(root, path);
                                trans = btrfs_join_transaction(root, 1);
+                               if (IS_ERR(trans))
+                                       return ERR_CAST(trans);
                                goto again;
                        }
                        map = kmap(page);
@@ -5266,6 +5280,128 @@ out:
        return em;
 }
 
+struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
+                                          size_t pg_offset, u64 start, u64 len,
+                                          int create)
+{
+       struct extent_map *em;
+       struct extent_map *hole_em = NULL;
+       u64 range_start = start;
+       u64 end;
+       u64 found;
+       u64 found_end;
+       int err = 0;
+
+       em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
+       if (IS_ERR(em))
+               return em;
+       if (em) {
+               /*
+                * if our em maps to a hole, there might
+                * actually be delalloc bytes behind it
+                */
+               if (em->block_start != EXTENT_MAP_HOLE)
+                       return em;
+               else
+                       hole_em = em;
+       }
+
+       /* check to see if we've wrapped (len == -1 or similar) */
+       end = start + len;
+       if (end < start)
+               end = (u64)-1;
+       else
+               end -= 1;
+
+       em = NULL;
+
+       /* ok, we didn't find anything, lets look for delalloc */
+       found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
+                                end, len, EXTENT_DELALLOC, 1);
+       found_end = range_start + found;
+       if (found_end < range_start)
+               found_end = (u64)-1;
+
+       /*
+        * we didn't find anything useful, return
+        * the original results from get_extent()
+        */
+       if (range_start > end || found_end <= start) {
+               em = hole_em;
+               hole_em = NULL;
+               goto out;
+       }
+
+       /* adjust the range_start to make sure it doesn't
+        * go backwards from the start they passed in
+        */
+       range_start = max(start,range_start);
+       found = found_end - range_start;
+
+       if (found > 0) {
+               u64 hole_start = start;
+               u64 hole_len = len;
+
+               em = alloc_extent_map(GFP_NOFS);
+               if (!em) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               /*
+                * when btrfs_get_extent can't find anything it
+                * returns one huge hole
+                *
+                * make sure what it found really fits our range, and
+                * adjust to make sure it is based on the start from
+                * the caller
+                */
+               if (hole_em) {
+                       u64 calc_end = extent_map_end(hole_em);
+
+                       if (calc_end <= start || (hole_em->start > end)) {
+                               free_extent_map(hole_em);
+                               hole_em = NULL;
+                       } else {
+                               hole_start = max(hole_em->start, start);
+                               hole_len = calc_end - hole_start;
+                       }
+               }
+               em->bdev = NULL;
+               if (hole_em && range_start > hole_start) {
+                       /* our hole starts before our delalloc, so we
+                        * have to return just the parts of the hole
+                        * that go until  the delalloc starts
+                        */
+                       em->len = min(hole_len,
+                                     range_start - hole_start);
+                       em->start = hole_start;
+                       em->orig_start = hole_start;
+                       /*
+                        * don't adjust block start at all,
+                        * it is fixed at EXTENT_MAP_HOLE
+                        */
+                       em->block_start = hole_em->block_start;
+                       em->block_len = hole_len;
+               } else {
+                       em->start = range_start;
+                       em->len = found;
+                       em->orig_start = range_start;
+                       em->block_start = EXTENT_MAP_DELALLOC;
+                       em->block_len = found;
+               }
+       } else if (hole_em) {
+               return hole_em;
+       }
+out:
+
+       free_extent_map(hole_em);
+       if (err) {
+               free_extent_map(em);
+               return ERR_PTR(err);
+       }
+       return em;
+}
+
 static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                                                  u64 start, u64 len)
 {
@@ -5280,8 +5416,8 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
        btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
 
        trans = btrfs_join_transaction(root, 0);
-       if (!trans)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(trans))
+               return ERR_CAST(trans);
 
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -5505,7 +5641,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                 * while we look for nocow cross refs
                 */
                trans = btrfs_join_transaction(root, 0);
-               if (!trans)
+               if (IS_ERR(trans))
                        goto must_cow;
 
                if (can_nocow_odirect(trans, inode, start, len) == 1) {
@@ -5640,7 +5776,7 @@ again:
        BUG_ON(!ordered);
 
        trans = btrfs_join_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                err = -ENOMEM;
                goto out;
        }
@@ -6088,7 +6224,7 @@ out:
 static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len)
 {
-       return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent);
+       return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
 }
 
 int btrfs_readpage(struct file *file, struct page *page)
index a506a22..5fdb2ab 100644 (file)
@@ -203,7 +203,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 
 
        trans = btrfs_join_transaction(root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
@@ -907,6 +907,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
 
        if (new_size > old_size) {
                trans = btrfs_start_transaction(root, 0);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       goto out_unlock;
+               }
                ret = btrfs_grow_device(trans, device, new_size);
                btrfs_commit_transaction(trans, root);
        } else {
@@ -1067,12 +1071,15 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        if (copy_from_user(&flags, arg, sizeof(flags)))
                return -EFAULT;
 
-       if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC)
+       if (flags & BTRFS_SUBVOL_CREATE_ASYNC)
                return -EINVAL;
 
        if (flags & ~BTRFS_SUBVOL_RDONLY)
                return -EOPNOTSUPP;
 
+       if (!is_owner_or_cap(inode))
+               return -EACCES;
+
        down_write(&root->fs_info->subvol_sem);
 
        /* nothing to do */
@@ -1093,7 +1100,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
                goto out_reset;
        }
 
-       ret = btrfs_update_root(trans, root,
+       ret = btrfs_update_root(trans, root->fs_info->tree_root,
                                &root->root_key, &root->root_item);
 
        btrfs_commit_transaction(trans, root);
@@ -1898,7 +1905,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
                        memcpy(&new_key, &key, sizeof(new_key));
                        new_key.objectid = inode->i_ino;
-                       new_key.offset = key.offset + destoff - off;
+                       if (off <= key.offset)
+                               new_key.offset = key.offset + destoff - off;
+                       else
+                               new_key.offset = destoff;
 
                        trans = btrfs_start_transaction(root, 1);
                        if (IS_ERR(trans)) {
@@ -2082,7 +2092,7 @@ static long btrfs_ioctl_trans_start(struct file *file)
 
        ret = -ENOMEM;
        trans = btrfs_start_ioctl_transaction(root, 0);
-       if (!trans)
+       if (IS_ERR(trans))
                goto out_drop;
 
        file->private_data = trans;
@@ -2138,9 +2148,9 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        path->leave_spinning = 1;
 
        trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                btrfs_free_path(path);
-               return -ENOMEM;
+               return PTR_ERR(trans);
        }
 
        dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
@@ -2201,7 +2211,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
        int num_types = 4;
        int alloc_size;
        int ret = 0;
-       int slot_count = 0;
+       u64 slot_count = 0;
        int i, c;
 
        if (copy_from_user(&space_args,
@@ -2240,7 +2250,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                goto out;
        }
 
-       slot_count = min_t(int, space_args.space_slots, slot_count);
+       slot_count = min_t(u64, space_args.space_slots, slot_count);
 
        alloc_size = sizeof(*dest) * slot_count;
 
@@ -2260,6 +2270,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
        for (i = 0; i < num_types; i++) {
                struct btrfs_space_info *tmp;
 
+               if (!slot_count)
+                       break;
+
                info = NULL;
                rcu_read_lock();
                list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
@@ -2281,7 +2294,10 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                                memcpy(dest, &space, sizeof(space));
                                dest++;
                                space_args.total_spaces++;
+                               slot_count--;
                        }
+                       if (!slot_count)
+                               break;
                }
                up_read(&info->groups_sem);
        }
@@ -2334,6 +2350,8 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp
        u64 transid;
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        transid = trans->transid;
        btrfs_commit_transaction_async(trans, root, 0);
 
index cc9b450..a178f5e 100644 (file)
@@ -280,6 +280,7 @@ static int lzo_decompress_biovec(struct list_head *ws,
        unsigned long tot_out;
        unsigned long tot_len;
        char *buf;
+       bool may_late_unmap, need_unmap;
 
        data_in = kmap(pages_in[0]);
        tot_len = read_compress_length(data_in);
@@ -300,11 +301,13 @@ static int lzo_decompress_biovec(struct list_head *ws,
 
                tot_in += in_len;
                working_bytes = in_len;
+               may_late_unmap = need_unmap = false;
 
                /* fast path: avoid using the working buffer */
                if (in_page_bytes_left >= in_len) {
                        buf = data_in + in_offset;
                        bytes = in_len;
+                       may_late_unmap = true;
                        goto cont;
                }
 
@@ -329,14 +332,17 @@ cont:
                                if (working_bytes == 0 && tot_in >= tot_len)
                                        break;
 
-                               kunmap(pages_in[page_in_index]);
-                               page_in_index++;
-                               if (page_in_index >= total_pages_in) {
+                               if (page_in_index + 1 >= total_pages_in) {
                                        ret = -1;
-                                       data_in = NULL;
                                        goto done;
                                }
-                               data_in = kmap(pages_in[page_in_index]);
+
+                               if (may_late_unmap)
+                                       need_unmap = true;
+                               else
+                                       kunmap(pages_in[page_in_index]);
+
+                               data_in = kmap(pages_in[++page_in_index]);
 
                                in_page_bytes_left = PAGE_CACHE_SIZE;
                                in_offset = 0;
@@ -346,6 +352,8 @@ cont:
                out_len = lzo1x_worst_compress(PAGE_CACHE_SIZE);
                ret = lzo1x_decompress_safe(buf, in_len, workspace->buf,
                                            &out_len);
+               if (need_unmap)
+                       kunmap(pages_in[page_in_index - 1]);
                if (ret != LZO_E_OK) {
                        printk(KERN_WARNING "btrfs decompress failed\n");
                        ret = -1;
@@ -363,8 +371,7 @@ cont:
                        break;
        }
 done:
-       if (data_in)
-               kunmap(pages_in[page_in_index]);
+       kunmap(pages_in[page_in_index]);
        return ret;
 }
 
index 2b61e1d..083a554 100644 (file)
@@ -141,7 +141,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
                                          u64 file_offset)
 {
        struct rb_root *root = &tree->tree;
-       struct rb_node *prev;
+       struct rb_node *prev = NULL;
        struct rb_node *ret;
        struct btrfs_ordered_extent *entry;
 
index 0d126be..fb2605d 100644 (file)
@@ -260,6 +260,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 #else
                        BUG();
 #endif
+                       break;
                case BTRFS_BLOCK_GROUP_ITEM_KEY:
                        bi = btrfs_item_ptr(l, i,
                                            struct btrfs_block_group_item);
index 045c9c2..31ade58 100644 (file)
@@ -1157,6 +1157,7 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
        new_node->bytenr = dest->node->start;
        new_node->level = node->level;
        new_node->lowest = node->lowest;
+       new_node->checked = 1;
        new_node->root = dest;
 
        if (!node->lowest) {
@@ -2028,6 +2029,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
 
        while (1) {
                trans = btrfs_start_transaction(root, 0);
+               BUG_ON(IS_ERR(trans));
                trans->block_rsv = rc->block_rsv;
 
                ret = btrfs_block_rsv_check(trans, root, rc->block_rsv,
@@ -2147,6 +2149,12 @@ again:
        }
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       if (IS_ERR(trans)) {
+               if (!err)
+                       btrfs_block_rsv_release(rc->extent_root,
+                                               rc->block_rsv, num_bytes);
+               return PTR_ERR(trans);
+       }
 
        if (!err) {
                if (num_bytes != rc->merging_rsv_size) {
@@ -3222,6 +3230,7 @@ truncate:
        trans = btrfs_join_transaction(root, 0);
        if (IS_ERR(trans)) {
                btrfs_free_path(path);
+               ret = PTR_ERR(trans);
                goto out;
        }
 
@@ -3628,6 +3637,7 @@ int prepare_to_relocate(struct reloc_control *rc)
        set_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_commit_transaction(trans, rc->extent_root);
        return 0;
 }
@@ -3644,6 +3654,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        u32 item_size;
        int ret;
        int err = 0;
+       int progress = 0;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -3656,8 +3667,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        }
 
        while (1) {
+               progress++;
                trans = btrfs_start_transaction(rc->extent_root, 0);
-
+               BUG_ON(IS_ERR(trans));
+restart:
                if (update_backref_cache(trans, &rc->backref_cache)) {
                        btrfs_end_transaction(trans, rc->extent_root);
                        continue;
@@ -3770,6 +3783,15 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
                        }
                }
        }
+       if (trans && progress && err == -ENOSPC) {
+               ret = btrfs_force_chunk_alloc(trans, rc->extent_root,
+                                             rc->block_group->flags);
+               if (ret == 0) {
+                       err = 0;
+                       progress = 0;
+                       goto restart;
+               }
+       }
 
        btrfs_release_path(rc->extent_root, path);
        clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
@@ -3804,7 +3826,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 
        /* get rid of pinned extents */
        trans = btrfs_join_transaction(rc->extent_root, 1);
-       btrfs_commit_transaction(trans, rc->extent_root);
+       if (IS_ERR(trans))
+               err = PTR_ERR(trans);
+       else
+               btrfs_commit_transaction(trans, rc->extent_root);
 out_free:
        btrfs_free_block_rsv(rc->extent_root, rc->block_rsv);
        btrfs_free_path(path);
@@ -4022,6 +4047,7 @@ static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
        int ret;
 
        trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
+       BUG_ON(IS_ERR(trans));
 
        memset(&root->root_item.drop_progress, 0,
                sizeof(root->root_item.drop_progress));
@@ -4125,6 +4151,11 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        set_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       if (IS_ERR(trans)) {
+               unset_reloc_control(rc);
+               err = PTR_ERR(trans);
+               goto out_free;
+       }
 
        rc->merge_reloc_tree = 1;
 
@@ -4154,9 +4185,13 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        unset_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
-       btrfs_commit_transaction(trans, rc->extent_root);
-out:
+       if (IS_ERR(trans))
+               err = PTR_ERR(trans);
+       else
+               btrfs_commit_transaction(trans, rc->extent_root);
+out_free:
        kfree(rc);
+out:
        while (!list_empty(&reloc_roots)) {
                reloc_root = list_entry(reloc_roots.next,
                                        struct btrfs_root, root_list);
index b2130c4..d39a989 100644 (file)
@@ -155,7 +155,8 @@ enum {
        Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress,
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
-       Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, Opt_err,
+       Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
+       Opt_enospc_debug, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -184,6 +185,7 @@ static match_table_t tokens = {
        {Opt_space_cache, "space_cache"},
        {Opt_clear_cache, "clear_cache"},
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
+       {Opt_enospc_debug, "enospc_debug"},
        {Opt_err, NULL},
 };
 
@@ -358,6 +360,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_user_subvol_rm_allowed:
                        btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED);
                        break;
+               case Opt_enospc_debug:
+                       btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
+                       break;
                case Opt_err:
                        printk(KERN_INFO "btrfs: unrecognized mount option "
                               "'%s'\n", p);
@@ -383,7 +388,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                struct btrfs_fs_devices **fs_devices)
 {
        substring_t args[MAX_OPT_ARGS];
-       char *opts, *p;
+       char *opts, *orig, *p;
        int error = 0;
        int intarg;
 
@@ -397,6 +402,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
        opts = kstrdup(options, GFP_KERNEL);
        if (!opts)
                return -ENOMEM;
+       orig = opts;
 
        while ((p = strsep(&opts, ",")) != NULL) {
                int token;
@@ -432,7 +438,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
        }
 
  out_free_opts:
-       kfree(opts);
+       kfree(orig);
  out:
        /*
         * If no subvolume name is specified we use the default one.  Allocate
@@ -623,6 +629,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        btrfs_wait_ordered_extents(root, 0, 0);
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
        return ret;
 }
@@ -761,6 +769,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                }
 
                btrfs_close_devices(fs_devices);
+               kfree(fs_info);
+               kfree(tree_root);
        } else {
                char b[BDEVNAME_SIZE];
 
index bae5c7b..3d73c8d 100644 (file)
@@ -1161,6 +1161,11 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
        INIT_DELAYED_WORK(&ac->work, do_async_commit);
        ac->root = root;
        ac->newtrans = btrfs_join_transaction(root, 0);
+       if (IS_ERR(ac->newtrans)) {
+               int err = PTR_ERR(ac->newtrans);
+               kfree(ac);
+               return err;
+       }
 
        /* take transaction reference */
        mutex_lock(&root->fs_info->trans_mutex);
index 054744a..a4bbb85 100644 (file)
@@ -338,6 +338,12 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                }
                dst_copy = kmalloc(item_size, GFP_NOFS);
                src_copy = kmalloc(item_size, GFP_NOFS);
+               if (!dst_copy || !src_copy) {
+                       btrfs_release_path(root, path);
+                       kfree(dst_copy);
+                       kfree(src_copy);
+                       return -ENOMEM;
+               }
 
                read_extent_buffer(eb, src_copy, src_ptr, item_size);
 
@@ -665,6 +671,9 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        btrfs_dir_item_key_to_cpu(leaf, di, &location);
        name_len = btrfs_dir_name_len(leaf, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
        btrfs_release_path(root, path);
 
@@ -744,6 +753,9 @@ static noinline int backref_in_log(struct btrfs_root *log,
        int match = 0;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        ret = btrfs_search_slot(NULL, log, key, path, 0, 0);
        if (ret != 0)
                goto out;
@@ -967,6 +979,8 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        key.offset = (u64)-1;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
 
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -1178,6 +1192,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
 
        name_len = btrfs_dir_name_len(eb, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        log_type = btrfs_dir_type(eb, di);
        read_extent_buffer(eb, name, (unsigned long)(di + 1),
                   name_len);
@@ -1692,6 +1709,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                root_owner = btrfs_header_owner(parent);
 
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
+               if (!next)
+                       return -ENOMEM;
 
                if (*level == 1) {
                        wc->process_func(root, next, wc, ptr_gen);
@@ -2032,6 +2051,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                wait_log_commit(trans, log_root_tree,
                                log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
+               ret = 0;
                goto out;
        }
        atomic_set(&log_root_tree->log_commit[index2], 1);
@@ -2096,7 +2116,7 @@ out:
        smp_mb();
        if (waitqueue_active(&root->log_commit_wait[index1]))
                wake_up(&root->log_commit_wait[index1]);
-       return 0;
+       return ret;
 }
 
 static void free_log_tree(struct btrfs_trans_handle *trans,
@@ -2194,6 +2214,9 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        log = root->log_root;
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
                                   name, name_len, -1);
        if (IS_ERR(di)) {
@@ -2594,6 +2617,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
 
        ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
                           nr * sizeof(u32), GFP_NOFS);
+       if (!ins_data)
+               return -ENOMEM;
+
        ins_sizes = (u32 *)ins_data;
        ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
@@ -2725,7 +2751,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        log = root->log_root;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        dst_path = btrfs_alloc_path();
+       if (!dst_path) {
+               btrfs_free_path(path);
+               return -ENOMEM;
+       }
 
        min_key.objectid = inode->i_ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
@@ -3080,6 +3112,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
        BUG_ON(!path);
 
        trans = btrfs_start_transaction(fs_info->tree_root, 0);
+       BUG_ON(IS_ERR(trans));
 
        wc.trans = trans;
        wc.pin = 1;
index d158530..dd13eb8 100644 (file)
@@ -1213,6 +1213,10 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
                return -ENOMEM;
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               return PTR_ERR(trans);
+       }
        key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
        key.type = BTRFS_DEV_ITEM_KEY;
        key.offset = device->devid;
@@ -1334,11 +1338,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 
        ret = btrfs_shrink_device(device, 0);
        if (ret)
-               goto error_brelse;
+               goto error_undo;
 
        ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device);
        if (ret)
-               goto error_brelse;
+               goto error_undo;
 
        device->in_fs_metadata = 0;
 
@@ -1412,6 +1416,13 @@ out:
        mutex_unlock(&root->fs_info->volume_mutex);
        mutex_unlock(&uuid_mutex);
        return ret;
+error_undo:
+       if (device->writeable) {
+               list_add(&device->dev_alloc_list,
+                        &root->fs_info->fs_devices->alloc_list);
+               root->fs_info->fs_devices->rw_devices++;
+       }
+       goto error_brelse;
 }
 
 /*
@@ -1601,11 +1612,19 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        ret = find_next_devid(root, &device->devid);
        if (ret) {
+               kfree(device->name);
                kfree(device);
                goto error;
        }
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               kfree(device->name);
+               kfree(device);
+               ret = PTR_ERR(trans);
+               goto error;
+       }
+
        lock_chunks(root);
 
        device->writeable = 1;
@@ -1621,7 +1640,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        device->dev_root = root->fs_info->dev_root;
        device->bdev = bdev;
        device->in_fs_metadata = 1;
-       device->mode = 0;
+       device->mode = FMODE_EXCL;
        set_blocksize(device->bdev, 4096);
 
        if (seeding_dev) {
@@ -1873,7 +1892,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
                return ret;
 
        trans = btrfs_start_transaction(root, 0);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        lock_chunks(root);
 
@@ -2047,7 +2066,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
                BUG_ON(ret);
 
                trans = btrfs_start_transaction(dev_root, 0);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
 
                ret = btrfs_grow_device(trans, device, old_size);
                BUG_ON(ret);
@@ -2213,6 +2232,11 @@ again:
 
        /* Shrinking succeeded, else we would be at "done". */
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto done;
+       }
+
        lock_chunks(root);
 
        device->disk_total_bytes = new_size;
index 60d27bc..6b61ded 100644 (file)
@@ -1560,9 +1560,10 @@ retry_locked:
                /* NOTE: no side-effects allowed, until we take s_mutex */
 
                revoking = cap->implemented & ~cap->issued;
-               if (revoking)
-                       dout(" mds%d revoking %s\n", cap->mds,
-                            ceph_cap_string(revoking));
+               dout(" mds%d cap %p issued %s implemented %s revoking %s\n",
+                    cap->mds, cap, ceph_cap_string(cap->issued),
+                    ceph_cap_string(cap->implemented),
+                    ceph_cap_string(revoking));
 
                if (cap == ci->i_auth_cap &&
                    (cap->issued & CEPH_CAP_FILE_WR)) {
@@ -1658,6 +1659,8 @@ ack:
 
                if (cap == ci->i_auth_cap && ci->i_dirty_caps)
                        flushing = __mark_caps_flushing(inode, session);
+               else
+                       flushing = 0;
 
                mds = cap->mds;  /* remember mds, so we don't repeat */
                sent++;
@@ -1940,6 +1943,35 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
        }
 }
 
+static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
+                                    struct ceph_mds_session *session,
+                                    struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap *cap;
+       int delayed = 0;
+
+       spin_lock(&inode->i_lock);
+       cap = ci->i_auth_cap;
+       dout("kick_flushing_inode_caps %p flushing %s flush_seq %lld\n", inode,
+            ceph_cap_string(ci->i_flushing_caps), ci->i_cap_flush_seq);
+       __ceph_flush_snaps(ci, &session, 1);
+       if (ci->i_flushing_caps) {
+               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                                    __ceph_caps_used(ci),
+                                    __ceph_caps_wanted(ci),
+                                    cap->issued | cap->implemented,
+                                    ci->i_flushing_caps, NULL);
+               if (delayed) {
+                       spin_lock(&inode->i_lock);
+                       __cap_delay_requeue(mdsc, ci);
+                       spin_unlock(&inode->i_lock);
+               }
+       } else {
+               spin_unlock(&inode->i_lock);
+       }
+}
+
 
 /*
  * Take references to capabilities we hold, so that we don't release
@@ -2687,7 +2719,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
        ceph_add_cap(inode, session, cap_id, -1,
                     issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH,
                     NULL /* no caps context */);
-       try_flush_caps(inode, session, NULL);
+       kick_flushing_inode_caps(mdsc, session, inode);
        up_read(&mdsc->snap_rwsem);
 
        /* make sure we re-request max_size, if necessary */
@@ -2785,8 +2817,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        case CEPH_CAP_OP_IMPORT:
                handle_cap_import(mdsc, inode, h, session,
                                  snaptrace, snaptrace_len);
-               ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY,
-                               session);
+               ceph_check_caps(ceph_inode(inode), 0, session);
                goto done_unlocked;
        }
 
index 0bc68de..099a586 100644 (file)
@@ -409,7 +409,7 @@ more:
        spin_lock(&inode->i_lock);
        if (ci->i_release_count == fi->dir_release_count) {
                dout(" marking %p complete\n", inode);
-               ci->i_ceph_flags |= CEPH_I_COMPLETE;
+               /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */
                ci->i_max_offset = filp->f_pos;
        }
        spin_unlock(&inode->i_lock);
@@ -496,6 +496,7 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
 
        /* .snap dir? */
        if (err == -ENOENT &&
+           ceph_snap(parent) == CEPH_NOSNAP &&
            strcmp(dentry->d_name.name,
                   fsc->mount_options->snapdir_name) == 0) {
                struct inode *inode = ceph_get_snapdir(parent);
@@ -1029,28 +1030,8 @@ out_touch:
 static void ceph_dentry_release(struct dentry *dentry)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
-       struct inode *parent_inode = NULL;
-       u64 snapid = CEPH_NOSNAP;
 
-       if (!IS_ROOT(dentry)) {
-               parent_inode = dentry->d_parent->d_inode;
-               if (parent_inode)
-                       snapid = ceph_snap(parent_inode);
-       }
-       dout("dentry_release %p parent %p\n", dentry, parent_inode);
-       if (parent_inode && snapid != CEPH_SNAPDIR) {
-               struct ceph_inode_info *ci = ceph_inode(parent_inode);
-
-               spin_lock(&parent_inode->i_lock);
-               if (ci->i_shared_gen == di->lease_shared_gen ||
-                   snapid <= CEPH_MAXSNAP) {
-                       dout(" clearing %p complete (d_release)\n",
-                            parent_inode);
-                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
-                       ci->i_release_count++;
-               }
-               spin_unlock(&parent_inode->i_lock);
-       }
+       dout("dentry_release %p\n", dentry);
        if (di) {
                ceph_dentry_lru_del(dentry);
                if (di->lease_session)
index e835eff..193bfa5 100644 (file)
@@ -707,13 +707,9 @@ static int fill_inode(struct inode *inode,
                    (issued & CEPH_CAP_FILE_EXCL) == 0 &&
                    (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
                        dout(" marking %p complete (empty)\n", inode);
-                       ci->i_ceph_flags |= CEPH_I_COMPLETE;
+                       /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */
                        ci->i_max_offset = 2;
                }
-
-               /* it may be better to set st_size in getattr instead? */
-               if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
-                       inode->i_size = ci->i_rbytes;
                break;
        default:
                pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
@@ -1819,7 +1815,11 @@ int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
                else
                        stat->dev = 0;
                if (S_ISDIR(inode->i_mode)) {
-                       stat->size = ci->i_rbytes;
+                       if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
+                                               RBYTES))
+                               stat->size = ci->i_rbytes;
+                       else
+                               stat->size = ci->i_files + ci->i_subdirs;
                        stat->blocks = 0;
                        stat->blksize = 65536;
                }
index 1e30d19..a1ee8fa 100644 (file)
@@ -693,9 +693,11 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                                dout("choose_mds %p %llx.%llx "
                                     "frag %u mds%d (%d/%d)\n",
                                     inode, ceph_vinop(inode),
-                                    frag.frag, frag.mds,
+                                    frag.frag, mds,
                                     (int)r, frag.ndist);
-                               return mds;
+                               if (ceph_mdsmap_get_state(mdsc->mdsmap, mds) >=
+                                   CEPH_MDS_STATE_ACTIVE)
+                                       return mds;
                        }
 
                        /* since this file/dir wasn't known to be
@@ -708,7 +710,9 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                                dout("choose_mds %p %llx.%llx "
                                     "frag %u mds%d (auth)\n",
                                     inode, ceph_vinop(inode), frag.frag, mds);
-                               return mds;
+                               if (ceph_mdsmap_get_state(mdsc->mdsmap, mds) >=
+                                   CEPH_MDS_STATE_ACTIVE)
+                                       return mds;
                        }
                }
        }
index 39c243a..f40b913 100644 (file)
@@ -584,10 +584,14 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
        if (lastinode)
                iput(lastinode);
 
-       dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino);
-       list_for_each_entry(child, &realm->children, child_item)
-               queue_realm_cap_snaps(child);
+       list_for_each_entry(child, &realm->children, child_item) {
+               dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n",
+                    realm, realm->ino, child, child->ino);
+               list_del_init(&child->dirty_item);
+               list_add(&child->dirty_item, &realm->dirty_item);
+       }
 
+       list_del_init(&realm->dirty_item);
        dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino);
 }
 
@@ -683,7 +687,9 @@ more:
         * queue cap snaps _after_ we've built the new snap contexts,
         * so that i_head_snapc can be set appropriately.
         */
-       list_for_each_entry(realm, &dirty_realms, dirty_item) {
+       while (!list_empty(&dirty_realms)) {
+               realm = list_first_entry(&dirty_realms, struct ceph_snap_realm,
+                                        dirty_item);
                queue_realm_cap_snaps(realm);
        }
 
index bf6f0f3..9c50854 100644 (file)
@@ -290,6 +290,8 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
 
         fsopt->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
         fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+       fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+       fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
         fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
         fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
         fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
index 6e12a6b..8c9eba6 100644 (file)
@@ -219,6 +219,7 @@ static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
        struct rb_node **p;
        struct rb_node *parent = NULL;
        struct ceph_inode_xattr *xattr = NULL;
+       int name_len = strlen(name);
        int c;
 
        p = &ci->i_xattrs.index.rb_node;
@@ -226,6 +227,8 @@ static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
                parent = *p;
                xattr = rb_entry(parent, struct ceph_inode_xattr, node);
                c = strncmp(name, xattr->name, xattr->name_len);
+               if (c == 0 && name_len > xattr->name_len)
+                       c = 1;
                if (c < 0)
                        p = &(*p)->rb_left;
                else if (c > 0)
index ee45648..7cb0f7f 100644 (file)
@@ -3,6 +3,7 @@ config CIFS
        depends on INET
        select NLS
        select CRYPTO
+       select CRYPTO_MD4
        select CRYPTO_MD5
        select CRYPTO_HMAC
        select CRYPTO_ARC4
index 43b19dd..d875584 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_CIFS) += cifs.o
 
 cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
          link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
-         md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
+         cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
          readdir.o ioctl.o sess.o export.o
 
 cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
index 46af99a..fe16835 100644 (file)
@@ -452,6 +452,11 @@ A partial list of the supported mount options follows:
                if oplock (caching token) is granted and held. Note that
                direct allows write operations larger than page size
                to be sent to the server.
+  strictcache   Use for switching on strict cache mode. In this mode the
+               client read from the cache all the time it has Oplock Level II,
+               otherwise - read from the server. All written data are stored
+               in the cache, but if the client doesn't have Exclusive Oplock,
+               it writes the data to the server.
   acl          Allow setfacl and getfacl to manage posix ACLs if server
                supports them.  (default)
   noacl        Do not allow setfacl and getfacl calls on this mount
index ede9830..65829d3 100644 (file)
@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
        spin_lock(&GlobalMid_Lock);
        list_for_each(tmp, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-               cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+               cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
                        mid_entry->midState,
                        (int)mid_entry->command,
                        mid_entry->pid,
-                       mid_entry->tsk,
+                       mid_entry->callback_data,
                        mid_entry->mid);
 #ifdef CONFIG_CIFS_STATS2
                cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
@@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                mid_entry = list_entry(tmp3, struct mid_q_entry,
                                        qhead);
                                seq_printf(m, "\tState: %d com: %d pid:"
-                                               " %d tsk: %p mid %d\n",
+                                               " %d cbdata: %p mid %d\n",
                                                mid_entry->midState,
                                                (int)mid_entry->command,
                                                mid_entry->pid,
-                                               mid_entry->tsk,
+                                               mid_entry->callback_data,
                                                mid_entry->mid);
                        }
                        spin_unlock(&GlobalMid_Lock);
@@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                                atomic_read(&totSmBufAllocCount));
 #endif /* CONFIG_CIFS_STATS2 */
 
-       seq_printf(m, "Operations (MIDs): %d\n", midCount.counter);
+       seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount));
        seq_printf(m,
                "\n%d session %d share reconnects\n",
                tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
index 7ed3653..0a265ad 100644 (file)
@@ -282,8 +282,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        cFYI(1, "in %s", __func__);
        BUG_ON(IS_ROOT(mntpt));
 
-       xid = GetXid();
-
        /*
         * The MSDFS spec states that paths in DFS referral requests and
         * responses must be prefixed by a single '\' character instead of
@@ -293,20 +291,21 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        mnt = ERR_PTR(-ENOMEM);
        full_path = build_path_from_dentry(mntpt);
        if (full_path == NULL)
-               goto free_xid;
+               goto cdda_exit;
 
        cifs_sb = CIFS_SB(mntpt->d_inode->i_sb);
        tlink = cifs_sb_tlink(cifs_sb);
-       mnt = ERR_PTR(-EINVAL);
        if (IS_ERR(tlink)) {
                mnt = ERR_CAST(tlink);
                goto free_full_path;
        }
        ses = tlink_tcon(tlink)->ses;
 
+       xid = GetXid();
        rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
                &num_referrals, &referrals,
                cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       FreeXid(xid);
 
        cifs_put_tlink(tlink);
 
@@ -339,8 +338,7 @@ success:
        free_dfs_info_array(referrals, num_referrals);
 free_full_path:
        kfree(full_path);
-free_xid:
-       FreeXid(xid);
+cdda_exit:
        cFYI(1, "leaving %s" , __func__);
        return mnt;
 }
index 7852cd6..ac51cd2 100644 (file)
@@ -40,6 +40,7 @@
 #define CIFS_MOUNT_FSCACHE     0x8000 /* local caching enabled */
 #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
+#define CIFS_MOUNT_STRICT_IO   0x40000 /* strict cache mode */
 
 struct cifs_sb_info {
        struct rb_root tlink_tree;
index 430f510..fc0fd4f 100644 (file)
@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
        int charlen, outlen = 0;
        int maxwords = maxbytes / 2;
        char tmp[NLS_MAX_CHARSET_SIZE];
+       __u16 ftmp;
 
-       for (i = 0; i < maxwords && from[i]; i++) {
-               charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp,
-                                            NLS_MAX_CHARSET_SIZE);
+       for (i = 0; i < maxwords; i++) {
+               ftmp = get_unaligned_le16(&from[i]);
+               if (ftmp == 0)
+                       break;
+
+               charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
                if (charlen > 0)
                        outlen += charlen;
                else
@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
 }
 
 /*
- * cifs_mapchar - convert a little-endian char to proper char in codepage
+ * cifs_mapchar - convert a host-endian char to proper char in codepage
  * @target - where converted character should be copied
- * @src_char - 2 byte little-endian source character
+ * @src_char - 2 byte host-endian source character
  * @cp - codepage to which character should be converted
  * @mapchar - should character be mapped according to mapchars mount option?
  *
@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
  * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
  */
 static int
-cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
+cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
             bool mapchar)
 {
        int len = 1;
@@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
         *     build_path_from_dentry are modified, as they use slash as
         *     separator.
         */
-       switch (le16_to_cpu(src_char)) {
+       switch (src_char) {
        case UNI_COLON:
                *target = ':';
                break;
@@ -109,8 +113,7 @@ out:
        return len;
 
 cp_convert:
-       len = cp->uni2char(le16_to_cpu(src_char), target,
-                          NLS_MAX_CHARSET_SIZE);
+       len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
        if (len <= 0) {
                *target = '?';
                len = 1;
@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
        int nullsize = nls_nullsize(codepage);
        int fromwords = fromlen / 2;
        char tmp[NLS_MAX_CHARSET_SIZE];
+       __u16 ftmp;
 
        /*
         * because the chars can be of varying widths, we need to take care
@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
         */
        safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
 
-       for (i = 0; i < fromwords && from[i]; i++) {
+       for (i = 0; i < fromwords; i++) {
+               ftmp = get_unaligned_le16(&from[i]);
+               if (ftmp == 0)
+                       break;
+
                /*
                 * check to see if converting this character might make the
                 * conversion bleed into the null terminator
                 */
                if (outlen >= safelen) {
-                       charlen = cifs_mapchar(tmp, from[i], codepage, mapchar);
+                       charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
                        if ((outlen + charlen) > (tolen - nullsize))
                                break;
                }
 
                /* put converted char into 'to' buffer */
-               charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar);
+               charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
                outlen += charlen;
        }
 
@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
 {
        int charlen;
        int i;
-       wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */
+       wchar_t wchar_to; /* needed to quiet sparse */
 
        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
-
-               /* works for 2.4.0 kernel or later */
-               charlen = codepage->char2uni(from, len, &wchar_to[i]);
+               charlen = codepage->char2uni(from, len, &wchar_to);
                if (charlen < 1) {
-                       cERROR(1, "strtoUCS: char2uni of %d returned %d",
-                               (int)*from, charlen);
+                       cERROR(1, "strtoUCS: char2uni of 0x%x returned %d",
+                               *from, charlen);
                        /* A question mark */
-                       to[i] = cpu_to_le16(0x003f);
+                       wchar_to = 0x003f;
                        charlen = 1;
-               } else
-                       to[i] = cpu_to_le16(wchar_to[i]);
-
+               }
+               put_unaligned_le16(wchar_to, &to[i]);
        }
 
-       to[i] = 0;
+       put_unaligned_le16(0, &to[i]);
        return i;
 }
 
@@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
        return dst;
 }
 
+/*
+ * Convert 16 bit Unicode pathname to wire format from string in current code
+ * page. Conversion may involve remapping up the six characters that are
+ * only legal in POSIX-like OS (if they are present in the string). Path
+ * names are little endian 16 bit Unicode on the wire
+ */
+int
+cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+                const struct nls_table *cp, int mapChars)
+{
+       int i, j, charlen;
+       int len_remaining = maxlen;
+       char src_char;
+       __u16 temp;
+
+       if (!mapChars)
+               return cifs_strtoUCS(target, source, PATH_MAX, cp);
+
+       for (i = 0, j = 0; i < maxlen; j++) {
+               src_char = source[i];
+               switch (src_char) {
+               case 0:
+                       put_unaligned_le16(0, &target[j]);
+                       goto ctoUCS_out;
+               case ':':
+                       temp = UNI_COLON;
+                       break;
+               case '*':
+                       temp = UNI_ASTERIK;
+                       break;
+               case '?':
+                       temp = UNI_QUESTION;
+                       break;
+               case '<':
+                       temp = UNI_LESSTHAN;
+                       break;
+               case '>':
+                       temp = UNI_GRTRTHAN;
+                       break;
+               case '|':
+                       temp = UNI_PIPE;
+                       break;
+               /*
+                * FIXME: We can not handle remapping backslash (UNI_SLASH)
+                * until all the calls to build_path_from_dentry are modified,
+                * as they use backslash as separator.
+                */
+               default:
+                       charlen = cp->char2uni(source+i, len_remaining,
+                                               &temp);
+                       /*
+                        * if no match, use question mark, which at least in
+                        * some cases serves as wild card
+                        */
+                       if (charlen < 1) {
+                               temp = 0x003f;
+                               charlen = 1;
+                       }
+                       len_remaining -= charlen;
+                       /*
+                        * character may take more than one byte in the source
+                        * string, but will take exactly two bytes in the
+                        * target string
+                        */
+                       i += charlen;
+                       continue;
+               }
+               put_unaligned_le16(temp, &target[j]);
+               i++; /* move to next char in source string */
+               len_remaining--;
+       }
+
+ctoUCS_out:
+       return i;
+}
+
index a437ec3..beeebf1 100644 (file)
@@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
 ;
 
 
-/* security id for everyone */
+/* security id for everyone/world system group */
 static const struct cifs_sid sid_everyone = {
        1, 1, {0, 0, 0, 0, 0, 1}, {0} };
+/* security id for Authenticated Users system group */
+static const struct cifs_sid sid_authusers = {
+       1, 1, {0, 0, 0, 0, 0, 5}, {11} };
 /* group users */
 static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
 
@@ -365,10 +368,14 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        if (num_aces  > 0) {
                umode_t user_mask = S_IRWXU;
                umode_t group_mask = S_IRWXG;
-               umode_t other_mask = S_IRWXO;
+               umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
 
                ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
                                GFP_KERNEL);
+               if (!ppace) {
+                       cERROR(1, "DACL memory allocation error");
+                       return;
+               }
 
                for (i = 0; i < num_aces; ++i) {
                        ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
@@ -390,6 +397,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                                                     ppace[i]->type,
                                                     &fattr->cf_mode,
                                                     &other_mask);
+                       if (compare_sids(&(ppace[i]->sid), &sid_authusers))
+                               access_flags_to_mode(ppace[i]->access_req,
+                                                    ppace[i]->type,
+                                                    &fattr->cf_mode,
+                                                    &other_mask);
+
 
 /*                     memcpy((void *)(&(cifscred->aces[i])),
                                (void *)ppace[i],
index 66f3d50..a51585f 100644 (file)
@@ -24,7 +24,6 @@
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
-#include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
 #include "ntlmssp.h"
 /* Note that the smb header signature field on input contains the
        sequence number before this function is called */
 
-extern void mdfour(unsigned char *out, unsigned char *in, int n);
-extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
-                      unsigned char *p24);
-
 static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
                                struct TCP_Server_Info *server, char *signature)
 {
@@ -234,6 +228,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
 /* first calculate 24 bytes ntlm response and then 16 byte session key */
 int setup_ntlm_response(struct cifsSesInfo *ses)
 {
+       int rc = 0;
        unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
        char temp_key[CIFS_SESS_KEY_SIZE];
 
@@ -247,13 +242,26 @@ int setup_ntlm_response(struct cifsSesInfo *ses)
        }
        ses->auth_key.len = temp_len;
 
-       SMBNTencrypt(ses->password, ses->server->cryptkey,
+       rc = SMBNTencrypt(ses->password, ses->server->cryptkey,
                        ses->auth_key.response + CIFS_SESS_KEY_SIZE);
+       if (rc) {
+               cFYI(1, "%s Can't generate NTLM response, error: %d",
+                       __func__, rc);
+               return rc;
+       }
 
-       E_md4hash(ses->password, temp_key);
-       mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
+       rc = E_md4hash(ses->password, temp_key);
+       if (rc) {
+               cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
+               return rc;
+       }
 
-       return 0;
+       rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
+       if (rc)
+               cFYI(1, "%s Can't generate NTLM session key, error: %d",
+                       __func__, rc);
+
+       return rc;
 }
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
@@ -649,9 +657,10 @@ calc_seckey(struct cifsSesInfo *ses)
        get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
 
        tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
-       if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
+       if (IS_ERR(tfm_arc4)) {
+               rc = PTR_ERR(tfm_arc4);
                cERROR(1, "could not allocate crypto API arc4\n");
-               return PTR_ERR(tfm_arc4);
+               return rc;
        }
 
        desc.tfm = tfm_arc4;
@@ -700,14 +709,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        unsigned int size;
 
        server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
-       if (!server->secmech.hmacmd5 ||
-                       IS_ERR(server->secmech.hmacmd5)) {
+       if (IS_ERR(server->secmech.hmacmd5)) {
                cERROR(1, "could not allocate crypto hmacmd5\n");
                return PTR_ERR(server->secmech.hmacmd5);
        }
 
        server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
-       if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
+       if (IS_ERR(server->secmech.md5)) {
                cERROR(1, "could not allocate crypto md5\n");
                rc = PTR_ERR(server->secmech.md5);
                goto crypto_allocate_md5_fail;
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
deleted file mode 100644 (file)
index 15d2ec0..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *   fs/cifs/cifsencrypt.h
- *
- *   Copyright (c) International Business Machines  Corp., 2005
- *   Author(s): Steve French (sfrench@us.ibm.com)
- *
- *   Externs for misc. small encryption routines
- *   so we do not have to put them in cifsproto.h
- *
- *   This library is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published
- *   by the Free Software Foundation; either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This library 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 Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* md4.c */
-extern void mdfour(unsigned char *out, unsigned char *in, int n);
-/* smbdes.c */
-extern void E_P16(unsigned char *p14, unsigned char *p16);
-extern void E_P24(unsigned char *p21, const unsigned char *c8,
-                 unsigned char *p24);
-
-
-
index d9f652a..f297013 100644 (file)
@@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
 module_param(cifs_max_pending, int, 0);
 MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
                                   "Default: 50 Range: 2 to 256");
-
+unsigned short echo_retries = 5;
+module_param(echo_retries, ushort, 0644);
+MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
+                              "reconnecting server. Default: 5. 0 means "
+                              "never reconnect.");
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern mempool_t *cifs_mid_poolp;
@@ -596,10 +600,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
        ssize_t written;
+       int rc;
 
        written = generic_file_aio_write(iocb, iov, nr_segs, pos);
-       if (!CIFS_I(inode)->clientCanCacheAll)
-               filemap_fdatawrite(inode->i_mapping);
+
+       if (CIFS_I(inode)->clientCanCacheAll)
+               return written;
+
+       rc = filemap_fdatawrite(inode->i_mapping);
+       if (rc)
+               cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode);
+
        return written;
 }
 
@@ -729,6 +740,25 @@ const struct file_operations cifs_file_ops = {
        .setlease = cifs_setlease,
 };
 
+const struct file_operations cifs_file_strict_ops = {
+       .read = do_sync_read,
+       .write = do_sync_write,
+       .aio_read = cifs_strict_readv,
+       .aio_write = cifs_strict_writev,
+       .open = cifs_open,
+       .release = cifs_close,
+       .lock = cifs_lock,
+       .fsync = cifs_strict_fsync,
+       .flush = cifs_flush,
+       .mmap = cifs_file_strict_mmap,
+       .splice_read = generic_file_splice_read,
+       .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+       .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+       .setlease = cifs_setlease,
+};
+
 const struct file_operations cifs_file_direct_ops = {
        /* no aio, no readv -
           BB reevaluate whether they can be done with directio, no cache */
@@ -747,6 +777,7 @@ const struct file_operations cifs_file_direct_ops = {
        .llseek = cifs_llseek,
        .setlease = cifs_setlease,
 };
+
 const struct file_operations cifs_file_nobrl_ops = {
        .read = do_sync_read,
        .write = do_sync_write,
@@ -765,6 +796,24 @@ const struct file_operations cifs_file_nobrl_ops = {
        .setlease = cifs_setlease,
 };
 
+const struct file_operations cifs_file_strict_nobrl_ops = {
+       .read = do_sync_read,
+       .write = do_sync_write,
+       .aio_read = cifs_strict_readv,
+       .aio_write = cifs_strict_writev,
+       .open = cifs_open,
+       .release = cifs_close,
+       .fsync = cifs_strict_fsync,
+       .flush = cifs_flush,
+       .mmap = cifs_file_strict_mmap,
+       .splice_read = generic_file_splice_read,
+       .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+       .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+       .setlease = cifs_setlease,
+};
+
 const struct file_operations cifs_file_direct_nobrl_ops = {
        /* no mmap, no aio, no readv -
           BB reevaluate whether they can be done with directio, no cache */
index 851030f..a9371b6 100644 (file)
@@ -61,6 +61,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
                       struct dentry *);
 extern int cifs_revalidate_file(struct file *filp);
 extern int cifs_revalidate_dentry(struct dentry *);
+extern void cifs_invalidate_mapping(struct inode *inode);
 extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int cifs_setattr(struct dentry *, struct iattr *);
 
@@ -72,19 +73,27 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations;
 /* Functions related to files and directories */
 extern const struct file_operations cifs_file_ops;
 extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
-extern const struct file_operations cifs_file_nobrl_ops;
-extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
+extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
+extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */
+extern const struct file_operations cifs_file_direct_nobrl_ops;
+extern const struct file_operations cifs_file_strict_nobrl_ops;
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
 extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
-                        size_t read_size, loff_t *poffset);
+                             size_t read_size, loff_t *poffset);
+extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+                                unsigned long nr_segs, loff_t pos);
 extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
-                        size_t write_size, loff_t *poffset);
+                              size_t write_size, loff_t *poffset);
+extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+                                 unsigned long nr_segs, loff_t pos);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, int);
+extern int cifs_strict_fsync(struct file *, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
 extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
+extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
 extern const struct file_operations cifs_dir_ops;
 extern int cifs_dir_open(struct inode *inode, struct file *file);
 extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
@@ -118,5 +127,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.68"
+#define CIFS_VERSION   "1.71"
 #endif                         /* _CIFSFS_H */
index 606ca8b..17afb0f 100644 (file)
@@ -161,46 +161,41 @@ struct TCP_Server_Info {
        int srv_count; /* reference counter */
        /* 15 character server name + 0x20 16th byte indicating type = srv */
        char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
+       enum statusEnum tcpStatus; /* what we think the status is */
        char *hostname; /* hostname portion of UNC string */
        struct socket *ssocket;
        struct sockaddr_storage dstaddr;
        struct sockaddr_storage srcaddr; /* locally bind to this IP */
+#ifdef CONFIG_NET_NS
+       struct net *net;
+#endif
        wait_queue_head_t response_q;
        wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
        struct list_head pending_mid_q;
-       void *Server_NlsInfo;   /* BB - placeholder for future NLS info  */
-       unsigned short server_codepage; /* codepage for the server    */
-       enum protocolEnum protocolType;
-       char versionMajor;
-       char versionMinor;
-       bool svlocal:1;                 /* local server or remote */
        bool noblocksnd;                /* use blocking sendmsg */
        bool noautotune;                /* do not autotune send buf sizes */
        bool tcp_nodelay;
        atomic_t inFlight;  /* number of requests on the wire to server */
-#ifdef CONFIG_CIFS_STATS2
-       atomic_t inSend; /* requests trying to send */
-       atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
-#endif
-       enum statusEnum tcpStatus; /* what we think the status is */
        struct mutex srv_mutex;
        struct task_struct *tsk;
        char server_GUID[16];
        char secMode;
+       bool session_estab; /* mark when very first sess is established */
+       u16 dialect; /* dialect index that server chose */
        enum securityEnum secType;
        unsigned int maxReq;    /* Clients should submit no more */
        /* than maxReq distinct unanswered SMBs to the server when using  */
        /* multiplexed reads or writes */
        unsigned int maxBuf;    /* maxBuf specifies the maximum */
        /* message size the server can send or receive for non-raw SMBs */
+       /* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */
+       /* when socket is setup (and during reconnect) before NegProt sent */
        unsigned int max_rw;    /* maxRw specifies the maximum */
        /* message size the server can send or receive for */
        /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
        unsigned int max_vcs;   /* maximum number of smb sessions, at least
                                   those that can be specified uniquely with
                                   vcnumbers */
-       char sessid[4];         /* unique token id for this session */
-       /* (returned on Negotiate */
        int capabilities; /* allow selective disabling of caps by smb sess */
        int timeAdj;  /* Adjust for difference in server time zone in sec */
        __u16 CurrentMid;         /* multiplex id - rotating counter */
@@ -210,20 +205,53 @@ struct TCP_Server_Info {
        __u32 sequence_number; /* for signing, protected by srv_mutex */
        struct session_key session_key;
        unsigned long lstrp; /* when we got last response from this server */
-       u16 dialect; /* dialect index that server chose */
        struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
        /* extended security flavors that server supports */
+       bool    sec_ntlmssp;            /* supports NTLMSSP */
+       bool    sec_kerberosu2u;        /* supports U2U Kerberos */
        bool    sec_kerberos;           /* supports plain Kerberos */
        bool    sec_mskerberos;         /* supports legacy MS Kerberos */
-       bool    sec_kerberosu2u;        /* supports U2U Kerberos */
-       bool    sec_ntlmssp;            /* supports NTLMSSP */
-       bool session_estab; /* mark when very first sess is established */
+       struct delayed_work     echo; /* echo ping workqueue job */
 #ifdef CONFIG_CIFS_FSCACHE
        struct fscache_cookie   *fscache; /* client index cache cookie */
 #endif
+#ifdef CONFIG_CIFS_STATS2
+       atomic_t inSend; /* requests trying to send */
+       atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
+#endif
 };
 
 /*
+ * Macros to allow the TCP_Server_Info->net field and related code to drop out
+ * when CONFIG_NET_NS isn't set.
+ */
+
+#ifdef CONFIG_NET_NS
+
+static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv)
+{
+       return srv->net;
+}
+
+static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
+{
+       srv->net = net;
+}
+
+#else
+
+static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv)
+{
+       return &init_net;
+}
+
+static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
+{
+}
+
+#endif
+
+/*
  * Session structure.  One of these for each uid session with a particular host
  */
 struct cifsSesInfo {
@@ -446,11 +474,11 @@ struct cifsInodeInfo {
        /* BB add in lists for dirty pages i.e. write caching info for oplock */
        struct list_head openFileList;
        __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
-       unsigned long time;     /* jiffies of last update/check of inode */
-       bool clientCanCacheRead:1;      /* read oplock */
-       bool clientCanCacheAll:1;       /* read and writebehind oplock */
-       bool delete_pending:1;          /* DELETE_ON_CLOSE is set */
-       bool invalid_mapping:1;         /* pagecache is invalid */
+       bool clientCanCacheRead;        /* read oplock */
+       bool clientCanCacheAll;         /* read and writebehind oplock */
+       bool delete_pending;            /* DELETE_ON_CLOSE is set */
+       bool invalid_mapping;           /* pagecache is invalid */
+       unsigned long time;             /* jiffies of last update of inode */
        u64  server_eof;                /* current file size on server */
        u64  uniqueid;                  /* server inode number */
        u64  createtime;                /* creation time on server */
@@ -508,6 +536,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
 
 #endif
 
+struct mid_q_entry;
+
+/*
+ * This is the prototype for the mid callback function. When creating one,
+ * take special care to avoid deadlocks. Things to bear in mind:
+ *
+ * - it will be called by cifsd
+ * - the GlobalMid_Lock will be held
+ * - the mid will be removed from the pending_mid_q list
+ */
+typedef void (mid_callback_t)(struct mid_q_entry *mid);
+
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
        struct list_head qhead; /* mids waiting on reply from this server */
@@ -519,7 +559,8 @@ struct mid_q_entry {
        unsigned long when_sent; /* time when smb send finished */
        unsigned long when_received; /* when demux complete (taken off wire) */
 #endif
-       struct task_struct *tsk;        /* task waiting for response */
+       mid_callback_t *callback; /* call completion callback */
+       void *callback_data;      /* general purpose pointer for callback */
        struct smb_hdr *resp_buf;       /* response buffer */
        int midState;   /* wish this were enum but can not pass to wait_event */
        __u8 command;   /* smb command code */
@@ -613,7 +654,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   MID_REQUEST_SUBMITTED 2
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
-#define   MID_NO_RESP_NEEDED 0x10
+#define   MID_RESPONSE_MALFORMED 0x10
 
 /* Types of response buffer returned from SendReceive2 */
 #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
@@ -622,12 +663,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
 /* Type of Request to SendReceive2 */
-#define   CIFS_STD_OP          0    /* normal request timeout */
-#define   CIFS_LONG_OP          1    /* long op (up to 45 sec, oplock time) */
-#define   CIFS_VLONG_OP         2    /* sloow op - can take up to 180 seconds */
-#define   CIFS_BLOCKING_OP      4    /* operation can block */
-#define   CIFS_ASYNC_OP         8    /* do not wait for response */
-#define   CIFS_TIMEOUT_MASK 0x00F    /* only one of 5 above set in req */
+#define   CIFS_BLOCKING_OP      1    /* operation can block */
+#define   CIFS_ASYNC_OP         2    /* do not wait for response */
+#define   CIFS_TIMEOUT_MASK 0x003    /* only one of above set in req */
 #define   CIFS_LOG_ERROR    0x010    /* log NT STATUS if non-zero */
 #define   CIFS_LARGE_BUF_OP 0x020    /* large request buffer */
 #define   CIFS_NO_RESP      0x040    /* no response buffer required */
@@ -790,6 +828,9 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
 GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
+/* reconnect after this many failed echo attempts */
+GLOBAL_EXTERN unsigned short echo_retries;
+
 void cifs_oplock_break(struct work_struct *work);
 void cifs_oplock_break_get(struct cifsFileInfo *cfile);
 void cifs_oplock_break_put(struct cifsFileInfo *cfile);
index de36b09..b5c8cc5 100644 (file)
@@ -23,6 +23,7 @@
 #define _CIFSPDU_H
 
 #include <net/sock.h>
+#include <asm/unaligned.h>
 #include "smbfsctl.h"
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
@@ -50,6 +51,7 @@
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_ECHO                  0x2B /* echo request */
 #define SMB_COM_OPEN_ANDX             0x2D /* Legacy open for old servers */
 #define SMB_COM_READ_ANDX             0x2E
 #define SMB_COM_WRITE_ANDX            0x2F
@@ -425,11 +427,49 @@ struct smb_hdr {
        __u16 Mid;
        __u8 WordCount;
 } __attribute__((packed));
-/* given a pointer to an smb_hdr retrieve the value of byte count */
-#define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
-#define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
+
+/* given a pointer to an smb_hdr retrieve a char pointer to the byte count */
+#define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \
+                        (2 * (smb_var)->WordCount))
+
 /* given a pointer to an smb_hdr retrieve the pointer to the byte area */
-#define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2)
+#define pByteArea(smb_var) (BCC(smb_var) + 2)
+
+/* get the converted ByteCount for a SMB packet and return it */
+static inline __u16
+get_bcc(struct smb_hdr *hdr)
+{
+       __u16 *bc_ptr = (__u16 *)BCC(hdr);
+
+       return get_unaligned(bc_ptr);
+}
+
+/* get the unconverted ByteCount for a SMB packet and return it */
+static inline __u16
+get_bcc_le(struct smb_hdr *hdr)
+{
+       __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+       return get_unaligned_le16(bc_ptr);
+}
+
+/* set the ByteCount for a SMB packet in host-byte order */
+static inline void
+put_bcc(__u16 count, struct smb_hdr *hdr)
+{
+       __u16 *bc_ptr = (__u16 *)BCC(hdr);
+
+       put_unaligned(count, bc_ptr);
+}
+
+/* set the ByteCount for a SMB packet in little-endian */
+static inline void
+put_bcc_le(__u16 count, struct smb_hdr *hdr)
+{
+       __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+       put_unaligned_le16(count, bc_ptr);
+}
 
 /*
  * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
@@ -760,6 +800,20 @@ typedef struct smb_com_tconx_rsp_ext {
  *
  */
 
+typedef struct smb_com_echo_req {
+       struct  smb_hdr hdr;
+       __le16  EchoCount;
+       __le16  ByteCount;
+       char    Data[1];
+} __attribute__((packed)) ECHO_REQ;
+
+typedef struct smb_com_echo_rsp {
+       struct  smb_hdr hdr;
+       __le16  SequenceNumber;
+       __le16  ByteCount;
+       char    Data[1];
+} __attribute__((packed)) ECHO_RSP;
+
 typedef struct smb_com_logoff_andx_req {
        struct smb_hdr hdr;     /* wct = 2 */
        __u8 AndXCommand;
index e6d1481..8096f27 100644 (file)
@@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
                const char *fullpath, const struct dfs_info3_param *ref,
                char **devname);
 /* extern void renew_parental_timestamps(struct dentry *direntry);*/
+extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
+                                       struct TCP_Server_Info *server);
+extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern int cifs_call_async(struct TCP_Server_Info *server,
+                          struct smb_hdr *in_buf, mid_callback_t *callback,
+                          void *cbdata);
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        struct smb_hdr * /* input */ ,
                        struct smb_hdr * /* out */ ,
@@ -79,6 +85,8 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern bool is_valid_oplock_break(struct smb_hdr *smb,
                                  struct TCP_Server_Info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
+extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
+                           unsigned int bytes_written);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
@@ -347,12 +355,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 netfid, const __u64 len,
                        const __u64 offset, const __u32 numUnlock,
                        const __u32 numLock, const __u8 lockType,
-                       const bool waitFlag);
+                       const bool waitFlag, const __u8 oplock_level);
 extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 smb_file_id, const int get_flag,
                        const __u64 len, struct file_lock *,
                        const __u16 lock_type, const bool waitFlag);
 extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBEcho(struct TCP_Server_Info *server);
 extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
 
 extern struct cifsSesInfo *sesInfoAlloc(void);
@@ -366,7 +375,7 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
 extern int cifs_verify_signature(struct smb_hdr *,
                                 struct TCP_Server_Info *server,
                                __u32 expected_sequence_number);
-extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
+extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
 extern int setup_ntlm_response(struct cifsSesInfo *);
 extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
@@ -416,4 +425,11 @@ extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
 extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
                const unsigned char *path,
                struct cifs_sb_info *cifs_sb, int xid);
+extern int mdfour(unsigned char *, unsigned char *, int);
+extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
+                       unsigned char *p24);
+extern void E_P16(unsigned char *p14, unsigned char *p16);
+extern void E_P24(unsigned char *p21, const unsigned char *c8,
+                       unsigned char *p24);
 #endif                 /* _CIFSPROTO_H */
index 2f6795e..904aa47 100644 (file)
@@ -136,9 +136,6 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
                }
        }
 
-       if (ses->status == CifsExiting)
-               return -EIO;
-
        /*
         * Give demultiplex thread up to 10 seconds to reconnect, should be
         * greater than cifs socket timeout which is 7 seconds
@@ -156,7 +153,7 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
                 * retrying until process is killed or server comes
                 * back on-line
                 */
-               if (!tcon->retry || ses->status == CifsExiting) {
+               if (!tcon->retry) {
                        cFYI(1, "gave up waiting on reconnect in smb_init");
                        return -EHOSTDOWN;
                }
@@ -331,37 +328,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
 
 static int validate_t2(struct smb_t2_rsp *pSMB)
 {
-       int rc = -EINVAL;
-       int total_size;
-       char *pBCC;
+       unsigned int total_size;
+
+       /* check for plausible wct */
+       if (pSMB->hdr.WordCount < 10)
+               goto vt2_err;
 
-       /* check for plausible wct, bcc and t2 data and parm sizes */
        /* check for parm and data offset going beyond end of smb */
-       if (pSMB->hdr.WordCount >= 10) {
-               if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
-                  (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
-                       /* check that bcc is at least as big as parms + data */
-                       /* check that bcc is less than negotiated smb buffer */
-                       total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
-                       if (total_size < 512) {
-                               total_size +=
-                                       le16_to_cpu(pSMB->t2_rsp.DataCount);
-                               /* BCC le converted in SendReceive */
-                               pBCC = (pSMB->hdr.WordCount * 2) +
-                                       sizeof(struct smb_hdr) +
-                                       (char *)pSMB;
-                               if ((total_size <= (*(u16 *)pBCC)) &&
-                                  (total_size <
-                                       CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
-                                       return 0;
-                               }
-                       }
-               }
-       }
+       if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
+           get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
+               goto vt2_err;
+
+       /* check that bcc is at least as big as parms + data */
+       /* check that bcc is less than negotiated smb buffer */
+       total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
+       if (total_size >= 512)
+               goto vt2_err;
+
+       total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
+       if (total_size > get_bcc(&pSMB->hdr) ||
+           total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
+               goto vt2_err;
+
+       return 0;
+vt2_err:
        cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
                sizeof(struct smb_t2_rsp) + 16);
-       return rc;
+       return -EINVAL;
 }
+
 int
 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 {
@@ -452,7 +447,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
                                (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
                server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
-               GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
                /* even though we do not use raw we might as well set this
                accurately, in case we ever find a need for it */
                if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
@@ -566,7 +560,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
        cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
-       GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
        server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
        server->timeAdj *= 60;
@@ -706,6 +699,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
        return rc;
 }
 
+/*
+ * This is a no-op for now. We're not really interested in the reply, but
+ * rather in the fact that the server sent one and that server->lstrp
+ * gets updated.
+ *
+ * FIXME: maybe we should consider checking that the reply matches request?
+ */
+static void
+cifs_echo_callback(struct mid_q_entry *mid)
+{
+       struct TCP_Server_Info *server = mid->callback_data;
+
+       DeleteMidQEntry(mid);
+       atomic_dec(&server->inFlight);
+       wake_up(&server->request_q);
+}
+
+int
+CIFSSMBEcho(struct TCP_Server_Info *server)
+{
+       ECHO_REQ *smb;
+       int rc = 0;
+
+       cFYI(1, "In echo request");
+
+       rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
+       if (rc)
+               return rc;
+
+       /* set up echo request */
+       smb->hdr.Tid = cpu_to_le16(0xffff);
+       smb->hdr.WordCount = 1;
+       put_unaligned_le16(1, &smb->EchoCount);
+       put_bcc_le(1, &smb->hdr);
+       smb->Data[0] = 'a';
+       smb->hdr.smb_buf_length += 3;
+
+       rc = cifs_call_async(server, (struct smb_hdr *)smb,
+                               cifs_echo_callback, server);
+       if (rc)
+               cFYI(1, "Echo request failed: %d", rc);
+
+       cifs_small_buf_release(smb);
+
+       return rc;
+}
+
 int
 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 {
@@ -1193,7 +1233,7 @@ OldOpenRetry:
        pSMB->ByteCount = cpu_to_le16(count);
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+                       (struct smb_hdr *)pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, "Error in Open = %d", rc);
@@ -1306,7 +1346,7 @@ openRetry:
        pSMB->ByteCount = cpu_to_le16(count);
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+                       (struct smb_hdr *)pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, "Error in Open = %d", rc);
@@ -1388,7 +1428,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        iov[0].iov_base = (char *)pSMB;
        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
        rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-                        &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
+                        &resp_buf_type, CIFS_LOG_ERROR);
        cifs_stats_inc(&tcon->num_reads);
        pSMBr = (READ_RSP *)iov[0].iov_base;
        if (rc) {
@@ -1663,7 +1703,8 @@ int
 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
            const __u16 smb_file_id, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
-           const __u32 numLock, const __u8 lockType, const bool waitFlag)
+           const __u32 numLock, const __u8 lockType,
+           const bool waitFlag, const __u8 oplock_level)
 {
        int rc = 0;
        LOCK_REQ *pSMB = NULL;
@@ -1691,6 +1732,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->NumberOfLocks = cpu_to_le16(numLock);
        pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
        pSMB->LockType = lockType;
+       pSMB->OplockLevel = oplock_level;
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
@@ -3087,7 +3129,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
 
        rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
-                        CIFS_STD_OP);
+                        0);
        cifs_stats_inc(&tcon->num_acl_get);
        if (rc) {
                cFYI(1, "Send error in QuerySecDesc = %d", rc);
@@ -4869,7 +4911,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
                   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-       char *data_offset;
        struct file_end_of_file_info *parm_data;
        int rc = 0;
        __u16 params, param_offset, offset, byte_count, count;
@@ -4893,8 +4934,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-
        count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
        /* BB find exact max SMB PDU from sess structure BB */
@@ -5562,7 +5601,7 @@ QAllEAsRetry:
        }
 
        /* make sure list_len doesn't go past end of SMB */
-       end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
+       end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
        if ((char *)ea_response_data + list_len > end_of_smb) {
                cFYI(1, "EA list appears to go beyond SMB");
                rc = -EIO;
index 9f59887..8d6c17a 100644 (file)
@@ -52,8 +52,8 @@
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 
-extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
-                        unsigned char *p24);
+/* SMB echo "timeout" -- FIXME: tunable? */
+#define SMB_ECHO_INTERVAL (60 * HZ)
 
 extern mempool_t *cifs_req_poolp;
 
@@ -84,6 +84,7 @@ struct smb_vol {
        bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
        bool server_ino:1; /* use inode numbers from server ie UniqueId */
        bool direct_io:1;
+       bool strict_io:1; /* strict cache behavior */
        bool remap:1;      /* set to remap seven reserved chars in filenames */
        bool posix_paths:1; /* unset to not ask for posix pathnames. */
        bool no_linux_ext:1;
@@ -152,6 +153,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
 
        /* before reconnecting the tcp session, mark the smb session (uid)
                and the tid bad so they are not used until reconnected */
+       cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &server->smb_ses_list) {
                ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
@@ -163,7 +165,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        }
        spin_unlock(&cifs_tcp_ses_lock);
+
        /* do not want to be sending data on a socket we are freeing */
+       cFYI(1, "%s: tearing down socket", __func__);
        mutex_lock(&server->srv_mutex);
        if (server->ssocket) {
                cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
@@ -180,22 +184,20 @@ cifs_reconnect(struct TCP_Server_Info *server)
        kfree(server->session_key.response);
        server->session_key.response = NULL;
        server->session_key.len = 0;
+       server->lstrp = jiffies;
+       mutex_unlock(&server->srv_mutex);
 
+       /* mark submitted MIDs for retry and issue callback */
+       cFYI(1, "%s: issuing mid callbacks", __func__);
        spin_lock(&GlobalMid_Lock);
-       list_for_each(tmp, &server->pending_mid_q) {
-               mid_entry = list_entry(tmp, struct
-                                       mid_q_entry,
-                                       qhead);
-               if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
-                               /* Mark other intransit requests as needing
-                                  retry so we do not immediately mark the
-                                  session bad again (ie after we reconnect
-                                  below) as they timeout too */
+       list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+               if (mid_entry->midState == MID_REQUEST_SUBMITTED)
                        mid_entry->midState = MID_RETRY_NEEDED;
-               }
+               list_del_init(&mid_entry->qhead);
+               mid_entry->callback(mid_entry);
        }
        spin_unlock(&GlobalMid_Lock);
-       mutex_unlock(&server->srv_mutex);
 
        while ((server->tcpStatus != CifsExiting) &&
               (server->tcpStatus != CifsGood)) {
@@ -212,10 +214,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        if (server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsGood;
                        spin_unlock(&GlobalMid_Lock);
-       /*              atomic_set(&server->inFlight,0);*/
-                       wake_up(&server->response_q);
                }
        }
+
        return rc;
 }
 
@@ -229,9 +230,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
 static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
 {
        struct smb_t2_rsp *pSMBt;
-       int total_data_size;
-       int data_in_this_rsp;
        int remaining;
+       __u16 total_data_size, data_in_this_rsp;
 
        if (pSMB->Command != SMB_COM_TRANSACTION2)
                return 0;
@@ -245,8 +245,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
 
        pSMBt = (struct smb_t2_rsp *)pSMB;
 
-       total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
-       data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+       total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+       data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
 
        remaining = total_data_size - data_in_this_rsp;
 
@@ -272,21 +272,18 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
 {
        struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
        struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
-       int total_data_size;
-       int total_in_buf;
-       int remaining;
-       int total_in_buf2;
        char *data_area_of_target;
        char *data_area_of_buf2;
-       __u16 byte_count;
+       int remaining;
+       __u16 byte_count, total_data_size, total_in_buf, total_in_buf2;
 
-       total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+       total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
 
-       if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+       if (total_data_size !=
+           get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount))
                cFYI(1, "total data size of primary and secondary t2 differ");
-       }
 
-       total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+       total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
 
        remaining = total_data_size - total_in_buf;
 
@@ -296,28 +293,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
        if (remaining == 0) /* nothing to do, ignore */
                return 0;
 
-       total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+       total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount);
        if (remaining < total_in_buf2) {
                cFYI(1, "transact2 2nd response contains too much data");
        }
 
        /* find end of first SMB data area */
        data_area_of_target = (char *)&pSMBt->hdr.Protocol +
-                               le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+                               get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
        /* validate target area */
 
-       data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
-                                       le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+       data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
+                               get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
 
        data_area_of_target += total_in_buf;
 
        /* copy second buffer into end of first buffer */
        memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
        total_in_buf += total_in_buf2;
-       pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
-       byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
+       put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
+       byte_count = get_bcc_le(pTargetSMB);
        byte_count += total_in_buf2;
-       BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
+       put_bcc_le(byte_count, pTargetSMB);
 
        byte_count = pTargetSMB->smb_buf_length;
        byte_count += total_in_buf2;
@@ -331,7 +328,31 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
                return 0; /* we are done */
        } else /* more responses to go */
                return 1;
+}
+
+static void
+cifs_echo_request(struct work_struct *work)
+{
+       int rc;
+       struct TCP_Server_Info *server = container_of(work,
+                                       struct TCP_Server_Info, echo.work);
+
+       /*
+        * We cannot send an echo until the NEGOTIATE_PROTOCOL request is
+        * done, which is indicated by maxBuf != 0. Also, no need to ping if
+        * we got a response recently
+        */
+       if (server->maxBuf == 0 ||
+           time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
+               goto requeue_echo;
+
+       rc = CIFSSMBEcho(server);
+       if (rc)
+               cFYI(1, "Unable to send echo request to server: %s",
+                       server->hostname);
 
+requeue_echo:
+       queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
 static int
@@ -345,8 +366,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        struct msghdr smb_msg;
        struct kvec iov;
        struct socket *csocket = server->ssocket;
-       struct list_head *tmp;
-       struct cifsSesInfo *ses;
+       struct list_head *tmp, *tmp2;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
        char temp;
@@ -399,7 +419,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                smb_msg.msg_control = NULL;
                smb_msg.msg_controllen = 0;
                pdu_length = 4; /* enough to get RFC1001 header */
+
 incomplete_rcv:
+               if (echo_retries > 0 &&
+                   time_after(jiffies, server->lstrp +
+                                       (echo_retries * SMB_ECHO_INTERVAL))) {
+                       cERROR(1, "Server %s has not responded in %d seconds. "
+                                 "Reconnecting...", server->hostname,
+                                 (echo_retries * SMB_ECHO_INTERVAL / HZ));
+                       cifs_reconnect(server);
+                       csocket = server->ssocket;
+                       wake_up(&server->response_q);
+                       continue;
+               }
+
                length =
                    kernel_recvmsg(csocket, &smb_msg,
                                &iov, 1, pdu_length, 0 /* BB other flags? */);
@@ -550,25 +583,36 @@ incomplete_rcv:
                else if (reconnect == 1)
                        continue;
 
-               length += 4; /* account for rfc1002 hdr */
+               total_read += 4; /* account for rfc1002 hdr */
 
+               dump_smb(smb_buffer, total_read);
 
-               dump_smb(smb_buffer, length);
-               if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
-                       cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
-                       continue;
-               }
+               /*
+                * We know that we received enough to get to the MID as we
+                * checked the pdu_length earlier. Now check to see
+                * if the rest of the header is OK. We borrow the length
+                * var for the rest of the loop to avoid a new stack var.
+                *
+                * 48 bytes is enough to display the header and a little bit
+                * into the payload for debugging purposes.
+                */
+               length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
+               if (length != 0)
+                       cifs_dump_mem("Bad SMB: ", smb_buffer,
+                                       min_t(unsigned int, total_read, 48));
 
+               mid_entry = NULL;
+               server->lstrp = jiffies;
 
-               task_to_wake = NULL;
                spin_lock(&GlobalMid_Lock);
-               list_for_each(tmp, &server->pending_mid_q) {
+               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 
                        if ((mid_entry->mid == smb_buffer->Mid) &&
                            (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
                            (mid_entry->command == smb_buffer->Command)) {
-                               if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
+                               if (length == 0 &&
+                                  check2ndT2(smb_buffer, server->maxBuf) > 0) {
                                        /* We have a multipart transact2 resp */
                                        isMultiRsp = true;
                                        if (mid_entry->resp_buf) {
@@ -603,20 +647,24 @@ incomplete_rcv:
                                mid_entry->resp_buf = smb_buffer;
                                mid_entry->largeBuf = isLargeBuf;
 multi_t2_fnd:
-                               task_to_wake = mid_entry->tsk;
-                               mid_entry->midState = MID_RESPONSE_RECEIVED;
+                               if (length == 0)
+                                       mid_entry->midState =
+                                                       MID_RESPONSE_RECEIVED;
+                               else
+                                       mid_entry->midState =
+                                                       MID_RESPONSE_MALFORMED;
 #ifdef CONFIG_CIFS_STATS2
                                mid_entry->when_received = jiffies;
 #endif
-                               /* so we do not time out requests to  server
-                               which is still responding (since server could
-                               be busy but not dead) */
-                               server->lstrp = jiffies;
+                               list_del_init(&mid_entry->qhead);
+                               mid_entry->callback(mid_entry);
                                break;
                        }
+                       mid_entry = NULL;
                }
                spin_unlock(&GlobalMid_Lock);
-               if (task_to_wake) {
+
+               if (mid_entry != NULL) {
                        /* Was previous buf put in mpx struct for multi-rsp? */
                        if (!isMultiRsp) {
                                /* smb buffer will be freed by user thread */
@@ -625,11 +673,13 @@ multi_t2_fnd:
                                else
                                        smallbuf = NULL;
                        }
-                       wake_up_process(task_to_wake);
+               } else if (length != 0) {
+                       /* response sanity checks failed */
+                       continue;
                } else if (!is_valid_oplock_break(smb_buffer, server) &&
                           !isMultiRsp) {
                        cERROR(1, "No task to wake, unknown frame received! "
-                                  "NumMids %d", midCount.counter);
+                                  "NumMids %d", atomic_read(&midCount));
                        cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
                                      sizeof(struct smb_hdr));
 #ifdef CONFIG_CIFS_DEBUG2
@@ -677,44 +727,16 @@ multi_t2_fnd:
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       /*
-        * BB: we shouldn't have to do any of this. It shouldn't be
-        * possible to exit from the thread with active SMB sessions
-        */
-       spin_lock(&cifs_tcp_ses_lock);
-       if (list_empty(&server->pending_mid_q)) {
-               /* loop through server session structures attached to this and
-                   mark them dead */
-               list_for_each(tmp, &server->smb_ses_list) {
-                       ses = list_entry(tmp, struct cifsSesInfo,
-                                        smb_ses_list);
-                       ses->status = CifsExiting;
-                       ses->server = NULL;
-               }
-               spin_unlock(&cifs_tcp_ses_lock);
-       } else {
-               /* although we can not zero the server struct pointer yet,
-               since there are active requests which may depnd on them,
-               mark the corresponding SMB sessions as exiting too */
-               list_for_each(tmp, &server->smb_ses_list) {
-                       ses = list_entry(tmp, struct cifsSesInfo,
-                                        smb_ses_list);
-                       ses->status = CifsExiting;
-               }
-
+       if (!list_empty(&server->pending_mid_q)) {
                spin_lock(&GlobalMid_Lock);
-               list_for_each(tmp, &server->pending_mid_q) {
-               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
-                               cFYI(1, "Clearing Mid 0x%x - waking up ",
+               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Clearing Mid 0x%x - issuing callback",
                                         mid_entry->mid);
-                               task_to_wake = mid_entry->tsk;
-                               if (task_to_wake)
-                                       wake_up_process(task_to_wake);
-                       }
+                       list_del_init(&mid_entry->qhead);
+                       mid_entry->callback(mid_entry);
                }
                spin_unlock(&GlobalMid_Lock);
-               spin_unlock(&cifs_tcp_ses_lock);
                /* 1/8th of sec is more than enough time for them to exit */
                msleep(125);
        }
@@ -732,18 +754,6 @@ multi_t2_fnd:
                coming home not much else we can do but free the memory */
        }
 
-       /* last chance to mark ses pointers invalid
-       if there are any pointing to this (e.g
-       if a crazy root user tried to kill cifsd
-       kernel thread explicitly this might happen) */
-       /* BB: This shouldn't be necessary, see above */
-       spin_lock(&cifs_tcp_ses_lock);
-       list_for_each(tmp, &server->smb_ses_list) {
-               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
-               ses->server = NULL;
-       }
-       spin_unlock(&cifs_tcp_ses_lock);
-
        kfree(server->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
        kfree(server);
@@ -1355,6 +1365,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio", 13) == 0) {
                        vol->direct_io = 1;
+               } else if (strnicmp(data, "strictcache", 11) == 0) {
+                       vol->strict_io = 1;
                } else if (strnicmp(data, "noac", 4) == 0) {
                        printk(KERN_WARNING "CIFS: Mount option noac not "
                                "supported. Instead set "
@@ -1579,6 +1591,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
+               if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
+                       continue;
+
                if (!match_address(server, addr,
                                   (struct sockaddr *)&vol->srcaddr))
                        continue;
@@ -1609,9 +1624,13 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
                return;
        }
 
+       put_net(cifs_net_ns(server));
+
        list_del_init(&server->tcp_ses_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
+       cancel_delayed_work_sync(&server->echo);
+
        spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
        spin_unlock(&GlobalMid_Lock);
@@ -1681,6 +1700,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                goto out_err;
        }
 
+       cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
        tcp_ses->hostname = extract_hostname(volume_info->UNC);
        if (IS_ERR(tcp_ses->hostname)) {
                rc = PTR_ERR(tcp_ses->hostname);
@@ -1701,8 +1721,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
        tcp_ses->session_estab = false;
        tcp_ses->sequence_number = 0;
+       tcp_ses->lstrp = jiffies;
        INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
        INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+       INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
 
        /*
         * at this point we are the only ones with the pointer
@@ -1751,11 +1773,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 
        cifs_fscache_get_client_cookie(tcp_ses);
 
+       /* queue echo request delayed work */
+       queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
+
        return tcp_ses;
 
 out_err_crypto_release:
        cifs_crypto_shash_release(tcp_ses);
 
+       put_net(cifs_net_ns(tcp_ses));
+
 out_err:
        if (tcp_ses) {
                if (!IS_ERR(tcp_ses->hostname))
@@ -2267,8 +2294,8 @@ generic_ip_connect(struct TCP_Server_Info *server)
        }
 
        if (socket == NULL) {
-               rc = sock_create_kern(sfamily, SOCK_STREAM,
-                                     IPPROTO_TCP, &socket);
+               rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
+                                  IPPROTO_TCP, &socket, 1);
                if (rc < 0) {
                        cERROR(1, "Error %d creating socket", rc);
                        server->ssocket = NULL;
@@ -2580,6 +2607,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
        if (pvolume_info->multiuser)
                cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
                                            CIFS_MOUNT_NO_PERM);
+       if (pvolume_info->strict_io)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
        if (pvolume_info->direct_io) {
                cFYI(1, "mounting share using direct i/o");
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -2936,8 +2965,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        TCONX_RSP *pSMBr;
        unsigned char *bcc_ptr;
        int rc = 0;
-       int length, bytes_left;
-       __u16 count;
+       int length;
+       __u16 bytes_left, count;
 
        if (ses == NULL)
                return -EIO;
@@ -2965,7 +2994,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                bcc_ptr++;              /* skip password */
                /* already aligned so no need to do it below */
        } else {
-               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
                /* BB FIXME add code to fail this if NTLMv2 or Kerberos
                   specified as required (when that support is added to
                   the vfs in the future) as only NTLM or the much
@@ -2981,9 +3010,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                         bcc_ptr);
                else
 #endif /* CIFS_WEAK_PW_HASH */
-               SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr);
+               rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
+                                       bcc_ptr);
 
-               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
                        /* must align unicode strings */
                        *bcc_ptr = 0; /* null byte password */
@@ -3021,7 +3051,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
-                        CIFS_STD_OP);
+                        0);
 
        /* above now done in SendReceive */
        if ((rc == 0) && (tcon != NULL)) {
@@ -3031,7 +3061,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                tcon->need_reconnect = false;
                tcon->tid = smb_buffer_response->Tid;
                bcc_ptr = pByteArea(smb_buffer_response);
-               bytes_left = BCC(smb_buffer_response);
+               bytes_left = get_bcc(smb_buffer_response);
                length = strnlen(bcc_ptr, bytes_left - 2);
                if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
                        is_unicode = true;
index d843631..e964b1c 100644 (file)
@@ -287,6 +287,7 @@ 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(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsLockInfo *li, *tmp;
 
        spin_lock(&cifs_file_list_lock);
@@ -302,6 +303,13 @@ 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);
+
+               /* in strict cache mode we need invalidate mapping on the last
+                  close  because it may cause a error when we open this file
+                  again and get at least level II oplock */
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+                       CIFS_I(inode)->invalid_mapping = true;
+
                cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
@@ -338,7 +346,6 @@ int cifs_open(struct inode *inode, struct file *file)
        struct cifsTconInfo *tcon;
        struct tcon_link *tlink;
        struct cifsFileInfo *pCifsFile = NULL;
-       struct cifsInodeInfo *pCifsInode;
        char *full_path = NULL;
        bool posix_open_ok = false;
        __u16 netfid;
@@ -353,8 +360,6 @@ int cifs_open(struct inode *inode, struct file *file)
        }
        tcon = tlink_tcon(tlink);
 
-       pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
-
        full_path = build_path_from_dentry(file->f_path.dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
@@ -726,12 +731,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
                /* BB we could chain these into one lock request BB */
                rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
-                                0, 1, lockType, 0 /* wait flag */ );
+                                0, 1, lockType, 0 /* wait flag */, 0);
                if (rc == 0) {
                        rc = CIFSSMBLock(xid, tcon, netfid, length,
                                         pfLock->fl_start, 1 /* numUnlock */ ,
                                         0 /* numLock */ , lockType,
-                                        0 /* wait flag */ );
+                                        0 /* wait flag */, 0);
                        pfLock->fl_type = F_UNLCK;
                        if (rc != 0)
                                cERROR(1, "Error unlocking previously locked "
@@ -748,13 +753,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                                rc = CIFSSMBLock(xid, tcon, netfid, length,
                                        pfLock->fl_start, 0, 1,
                                        lockType | LOCKING_ANDX_SHARED_LOCK,
-                                       0 /* wait flag */);
+                                       0 /* wait flag */, 0);
                                if (rc == 0) {
                                        rc = CIFSSMBLock(xid, tcon, netfid,
                                                length, pfLock->fl_start, 1, 0,
                                                lockType |
                                                LOCKING_ANDX_SHARED_LOCK,
-                                               0 /* wait flag */);
+                                               0 /* wait flag */, 0);
                                        pfLock->fl_type = F_RDLCK;
                                        if (rc != 0)
                                                cERROR(1, "Error unlocking "
@@ -797,8 +802,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
                if (numLock) {
                        rc = CIFSSMBLock(xid, tcon, netfid, length,
-                                       pfLock->fl_start,
-                                       0, numLock, lockType, wait_flag);
+                                        pfLock->fl_start, 0, numLock, lockType,
+                                        wait_flag, 0);
 
                        if (rc == 0) {
                                /* For Windows locks we must store them. */
@@ -818,9 +823,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                                                (pfLock->fl_start + length) >=
                                                (li->offset + li->length)) {
                                        stored_rc = CIFSSMBLock(xid, tcon,
-                                                       netfid,
-                                                       li->length, li->offset,
-                                                       1, 0, li->type, false);
+                                                       netfid, li->length,
+                                                       li->offset, 1, 0,
+                                                       li->type, false, 0);
                                        if (stored_rc)
                                                rc = stored_rc;
                                        else {
@@ -839,31 +844,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        return rc;
 }
 
-/*
- * Set the timeout on write requests past EOF. For some servers (Windows)
- * these calls can be very long.
- *
- * If we're writing >10M past the EOF we give a 180s timeout. Anything less
- * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
- * The 10M cutoff is totally arbitrary. A better scheme for this would be
- * welcome if someone wants to suggest one.
- *
- * We may be able to do a better job with this if there were some way to
- * declare that a file should be sparse.
- */
-static int
-cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
-{
-       if (offset <= cifsi->server_eof)
-               return CIFS_STD_OP;
-       else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
-               return CIFS_VLONG_OP;
-       else
-               return CIFS_LONG_OP;
-}
-
 /* update the file size (if needed) after a write */
-static void
+void
 cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                      unsigned int bytes_written)
 {
@@ -882,7 +864,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        unsigned int total_written;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       int xid, long_op;
+       int xid;
        struct cifsFileInfo *open_file;
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
@@ -903,7 +885,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        xid = GetXid();
 
-       long_op = cifs_write_timeout(cifsi, *poffset);
        for (total_written = 0; write_size > total_written;
             total_written += bytes_written) {
                rc = -EAGAIN;
@@ -931,7 +912,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                                min_t(const int, cifs_sb->wsize,
                                      write_size - total_written),
                                *poffset, &bytes_written,
-                               NULL, write_data + total_written, long_op);
+                               NULL, write_data + total_written, 0);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -944,8 +925,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                        cifs_update_eof(cifsi, *poffset, bytes_written);
                        *poffset += bytes_written;
                }
-               long_op = CIFS_STD_OP; /* subsequent writes fast -
-                                   15 seconds is plenty */
        }
 
        cifs_stats_bytes_written(pTcon, total_written);
@@ -974,7 +953,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
        unsigned int total_written;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       int xid, long_op;
+       int xid;
        struct dentry *dentry = open_file->dentry;
        struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
 
@@ -987,7 +966,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
 
        xid = GetXid();
 
-       long_op = cifs_write_timeout(cifsi, *poffset);
        for (total_written = 0; write_size > total_written;
             total_written += bytes_written) {
                rc = -EAGAIN;
@@ -1017,7 +995,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
                                rc = CIFSSMBWrite2(xid, pTcon,
                                                open_file->netfid, len,
                                                *poffset, &bytes_written,
-                                               iov, 1, long_op);
+                                               iov, 1, 0);
                        } else
                                rc = CIFSSMBWrite(xid, pTcon,
                                         open_file->netfid,
@@ -1025,7 +1003,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
                                               write_size - total_written),
                                         *poffset, &bytes_written,
                                         write_data + total_written,
-                                        NULL, long_op);
+                                        NULL, 0);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -1038,8 +1016,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
                        cifs_update_eof(cifsi, *poffset, bytes_written);
                        *poffset += bytes_written;
                }
-               long_op = CIFS_STD_OP; /* subsequent writes fast -
-                                   15 seconds is plenty */
        }
 
        cifs_stats_bytes_written(pTcon, total_written);
@@ -1167,7 +1143,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        char *write_data;
        int rc = -EFAULT;
        int bytes_written = 0;
-       struct cifs_sb_info *cifs_sb;
        struct inode *inode;
        struct cifsFileInfo *open_file;
 
@@ -1175,7 +1150,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
                return -EFAULT;
 
        inode = page->mapping->host;
-       cifs_sb = CIFS_SB(inode->i_sb);
 
        offset += (loff_t)from;
        write_data = kmap(page);
@@ -1239,7 +1213,7 @@ static int cifs_writepages(struct address_space *mapping,
        struct pagevec pvec;
        int rc = 0;
        int scanned = 0;
-       int xid, long_op;
+       int xid;
 
        cifs_sb = CIFS_SB(mapping->host->i_sb);
 
@@ -1377,43 +1351,67 @@ retry:
                                break;
                }
                if (n_iov) {
+retry_write:
                        open_file = find_writable_file(CIFS_I(mapping->host),
                                                        false);
                        if (!open_file) {
                                cERROR(1, "No writable handles for inode");
                                rc = -EBADF;
                        } else {
-                               long_op = cifs_write_timeout(cifsi, offset);
                                rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
                                                   bytes_to_write, offset,
                                                   &bytes_written, iov, n_iov,
-                                                  long_op);
+                                                  0);
                                cifsFileInfo_put(open_file);
-                               cifs_update_eof(cifsi, offset, bytes_written);
                        }
 
-                       if (rc || bytes_written < bytes_to_write) {
-                               cERROR(1, "Write2 ret %d, wrote %d",
-                                         rc, bytes_written);
-                               mapping_set_error(mapping, rc);
-                       } else {
+                       cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
+
+                       /*
+                        * For now, treat a short write as if nothing got
+                        * written. A zero length write however indicates
+                        * ENOSPC or EFBIG. We have no way to know which
+                        * though, so call it ENOSPC for now. EFBIG would
+                        * get translated to AS_EIO anyway.
+                        *
+                        * FIXME: make it take into account the data that did
+                        *        get written
+                        */
+                       if (rc == 0) {
+                               if (bytes_written == 0)
+                                       rc = -ENOSPC;
+                               else if (bytes_written < bytes_to_write)
+                                       rc = -EAGAIN;
+                       }
+
+                       /* retry on data-integrity flush */
+                       if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
+                               goto retry_write;
+
+                       /* fix the stats and EOF */
+                       if (bytes_written > 0) {
                                cifs_stats_bytes_written(tcon, bytes_written);
+                               cifs_update_eof(cifsi, offset, bytes_written);
                        }
 
                        for (i = 0; i < n_iov; i++) {
                                page = pvec.pages[first + i];
-                               /* Should we also set page error on
-                               success rc but too little data written? */
-                               /* BB investigate retry logic on temporary
-                               server crash cases and how recovery works
-                               when page marked as error */
-                               if (rc)
+                               /* on retryable write error, redirty page */
+                               if (rc == -EAGAIN)
+                                       redirty_page_for_writepage(wbc, page);
+                               else if (rc != 0)
                                        SetPageError(page);
                                kunmap(page);
                                unlock_page(page);
                                end_page_writeback(page);
                                page_cache_release(page);
                        }
+
+                       if (rc != -EAGAIN)
+                               mapping_set_error(mapping, rc);
+                       else
+                               rc = 0;
+
                        if ((wbc->nr_to_write -= n_iov) <= 0)
                                done = 1;
                        index = next;
@@ -1525,27 +1523,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
        return rc;
 }
 
-int cifs_fsync(struct file *file, int datasync)
+int cifs_strict_fsync(struct file *file, int datasync)
 {
        int xid;
        int rc = 0;
        struct cifsTconInfo *tcon;
        struct cifsFileInfo *smbfile = file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
        xid = GetXid();
 
        cFYI(1, "Sync file - name: %s datasync: 0x%x",
                file->f_path.dentry->d_name.name, datasync);
 
-       rc = filemap_write_and_wait(inode->i_mapping);
-       if (rc == 0) {
-               struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       if (!CIFS_I(inode)->clientCanCacheRead)
+               cifs_invalidate_mapping(inode);
 
-               tcon = tlink_tcon(smbfile->tlink);
-               if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-                       rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
-       }
+       tcon = tlink_tcon(smbfile->tlink);
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+               rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+
+       FreeXid(xid);
+       return rc;
+}
+
+int cifs_fsync(struct file *file, int datasync)
+{
+       int xid;
+       int rc = 0;
+       struct cifsTconInfo *tcon;
+       struct cifsFileInfo *smbfile = file->private_data;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+
+       xid = GetXid();
+
+       cFYI(1, "Sync file - name: %s datasync: 0x%x",
+               file->f_path.dentry->d_name.name, datasync);
+
+       tcon = tlink_tcon(smbfile->tlink);
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+               rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
 
        FreeXid(xid);
        return rc;
@@ -1596,42 +1614,244 @@ int cifs_flush(struct file *file, fl_owner_t id)
        return rc;
 }
 
-ssize_t cifs_user_read(struct file *file, char __user *read_data,
-       size_t read_size, loff_t *poffset)
+static int
+cifs_write_allocate_pages(struct page **pages, unsigned long num_pages)
 {
-       int rc = -EACCES;
+       int rc = 0;
+       unsigned long i;
+
+       for (i = 0; i < num_pages; i++) {
+               pages[i] = alloc_page(__GFP_HIGHMEM);
+               if (!pages[i]) {
+                       /*
+                        * save number of pages we have already allocated and
+                        * return with ENOMEM error
+                        */
+                       num_pages = i;
+                       rc = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       return rc;
+
+error:
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       return rc;
+}
+
+static inline
+size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
+{
+       size_t num_pages;
+       size_t clen;
+
+       clen = min_t(const size_t, len, wsize);
+       num_pages = clen / PAGE_CACHE_SIZE;
+       if (clen % PAGE_CACHE_SIZE)
+               num_pages++;
+
+       if (cur_len)
+               *cur_len = clen;
+
+       return num_pages;
+}
+
+static ssize_t
+cifs_iovec_write(struct file *file, const struct iovec *iov,
+                unsigned long nr_segs, loff_t *poffset)
+{
+       unsigned int written;
+       unsigned long num_pages, npages, i;
+       size_t copied, len, cur_len;
+       ssize_t total_written = 0;
+       struct kvec *to_send;
+       struct page **pages;
+       struct iov_iter it;
+       struct inode *inode;
+       struct cifsFileInfo *open_file;
+       struct cifsTconInfo *pTcon;
+       struct cifs_sb_info *cifs_sb;
+       int xid, rc;
+
+       len = iov_length(iov, nr_segs);
+       if (!len)
+               return 0;
+
+       rc = generic_write_checks(file, poffset, &len, 0);
+       if (rc)
+               return rc;
+
+       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       num_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
+
+       pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL);
+       if (!to_send) {
+               kfree(pages);
+               return -ENOMEM;
+       }
+
+       rc = cifs_write_allocate_pages(pages, num_pages);
+       if (rc) {
+               kfree(pages);
+               kfree(to_send);
+               return rc;
+       }
+
+       xid = GetXid();
+       open_file = file->private_data;
+       pTcon = tlink_tcon(open_file->tlink);
+       inode = file->f_path.dentry->d_inode;
+
+       iov_iter_init(&it, iov, nr_segs, len, 0);
+       npages = num_pages;
+
+       do {
+               size_t save_len = cur_len;
+               for (i = 0; i < npages; i++) {
+                       copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE);
+                       copied = iov_iter_copy_from_user(pages[i], &it, 0,
+                                                        copied);
+                       cur_len -= copied;
+                       iov_iter_advance(&it, copied);
+                       to_send[i+1].iov_base = kmap(pages[i]);
+                       to_send[i+1].iov_len = copied;
+               }
+
+               cur_len = save_len - cur_len;
+
+               do {
+                       if (open_file->invalidHandle) {
+                               rc = cifs_reopen_file(open_file, false);
+                               if (rc != 0)
+                                       break;
+                       }
+                       rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid,
+                                          cur_len, *poffset, &written,
+                                          to_send, npages, 0);
+               } while (rc == -EAGAIN);
+
+               for (i = 0; i < npages; i++)
+                       kunmap(pages[i]);
+
+               if (written) {
+                       len -= written;
+                       total_written += written;
+                       cifs_update_eof(CIFS_I(inode), *poffset, written);
+                       *poffset += written;
+               } else if (rc < 0) {
+                       if (!total_written)
+                               total_written = rc;
+                       break;
+               }
+
+               /* get length and number of kvecs of the next write */
+               npages = get_numpages(cifs_sb->wsize, len, &cur_len);
+       } while (len > 0);
+
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
+       }
+
+       cifs_stats_bytes_written(pTcon, total_written);
+       mark_inode_dirty_sync(inode);
+
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       kfree(to_send);
+       kfree(pages);
+       FreeXid(xid);
+       return total_written;
+}
+
+static ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
+{
+       ssize_t written;
+       struct inode *inode;
+
+       inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+       /*
+        * BB - optimize the way when signing is disabled. We can drop this
+        * extra memory-to-memory copying and use iovec buffers for constructing
+        * write request.
+        */
+
+       written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos);
+       if (written > 0) {
+               CIFS_I(inode)->invalid_mapping = true;
+               iocb->ki_pos = pos;
+       }
+
+       return written;
+}
+
+ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+                          unsigned long nr_segs, loff_t pos)
+{
+       struct inode *inode;
+
+       inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+       if (CIFS_I(inode)->clientCanCacheAll)
+               return generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+       /*
+        * In strict cache mode we need to write the data to the server exactly
+        * from the pos to pos+len-1 rather than flush all affected pages
+        * because it may cause a error with mandatory locks on these pages but
+        * not on the region from pos to ppos+len-1.
+        */
+
+       return cifs_user_writev(iocb, iov, nr_segs, pos);
+}
+
+static ssize_t
+cifs_iovec_read(struct file *file, const struct iovec *iov,
+                unsigned long nr_segs, loff_t *poffset)
+{
+       int rc;
+       int xid;
+       ssize_t total_read;
        unsigned int bytes_read = 0;
-       unsigned int total_read = 0;
-       unsigned int current_read_size;
+       size_t len, cur_len;
+       int iov_offset = 0;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       int xid;
        struct cifsFileInfo *open_file;
-       char *smb_read_data;
-       char __user *current_offset;
        struct smb_com_read_rsp *pSMBr;
+       char *read_data;
+
+       if (!nr_segs)
+               return 0;
+
+       len = iov_length(iov, nr_segs);
+       if (!len)
+               return 0;
 
        xid = GetXid();
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
-       if (file->private_data == NULL) {
-               rc = -EBADF;
-               FreeXid(xid);
-               return rc;
-       }
        open_file = file->private_data;
        pTcon = tlink_tcon(open_file->tlink);
 
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
 
-       for (total_read = 0, current_offset = read_data;
-            read_size > total_read;
-            total_read += bytes_read, current_offset += bytes_read) {
-               current_read_size = min_t(const int, read_size - total_read,
-                                         cifs_sb->rsize);
+       for (total_read = 0; total_read < len; total_read += bytes_read) {
+               cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize);
                rc = -EAGAIN;
-               smb_read_data = NULL;
+               read_data = NULL;
+
                while (rc == -EAGAIN) {
                        int buf_type = CIFS_NO_BUFFER;
                        if (open_file->invalidHandle) {
@@ -1639,27 +1859,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                                if (rc != 0)
                                        break;
                        }
-                       rc = CIFSSMBRead(xid, pTcon,
-                                        open_file->netfid,
-                                        current_read_size, *poffset,
-                                        &bytes_read, &smb_read_data,
-                                        &buf_type);
-                       pSMBr = (struct smb_com_read_rsp *)smb_read_data;
-                       if (smb_read_data) {
-                               if (copy_to_user(current_offset,
-                                               smb_read_data +
-                                               4 /* RFC1001 length field */ +
-                                               le16_to_cpu(pSMBr->DataOffset),
-                                               bytes_read))
+                       rc = CIFSSMBRead(xid, pTcon, open_file->netfid,
+                                        cur_len, *poffset, &bytes_read,
+                                        &read_data, &buf_type);
+                       pSMBr = (struct smb_com_read_rsp *)read_data;
+                       if (read_data) {
+                               char *data_offset = read_data + 4 +
+                                               le16_to_cpu(pSMBr->DataOffset);
+                               if (memcpy_toiovecend(iov, data_offset,
+                                                     iov_offset, bytes_read))
                                        rc = -EFAULT;
-
                                if (buf_type == CIFS_SMALL_BUFFER)
-                                       cifs_small_buf_release(smb_read_data);
+                                       cifs_small_buf_release(read_data);
                                else if (buf_type == CIFS_LARGE_BUFFER)
-                                       cifs_buf_release(smb_read_data);
-                               smb_read_data = NULL;
+                                       cifs_buf_release(read_data);
+                               read_data = NULL;
+                               iov_offset += bytes_read;
                        }
                }
+
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
                                break;
@@ -1672,13 +1890,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                        *poffset += bytes_read;
                }
        }
+
        FreeXid(xid);
        return total_read;
 }
 
+ssize_t cifs_user_read(struct file *file, char __user *read_data,
+                      size_t read_size, loff_t *poffset)
+{
+       struct iovec iov;
+       iov.iov_base = read_data;
+       iov.iov_len = read_size;
+
+       return cifs_iovec_read(file, &iov, 1, poffset);
+}
+
+static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
+                              unsigned long nr_segs, loff_t pos)
+{
+       ssize_t read;
+
+       read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos);
+       if (read > 0)
+               iocb->ki_pos = pos;
+
+       return read;
+}
+
+ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+                         unsigned long nr_segs, loff_t pos)
+{
+       struct inode *inode;
+
+       inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+       if (CIFS_I(inode)->clientCanCacheRead)
+               return generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+       /*
+        * In strict cache mode we need to read from the server all the time
+        * if we don't have level II oplock because the server can delay mtime
+        * change - so we can't make a decision about inode invalidating.
+        * And we can also fail with pagereading if there are mandatory locks
+        * on pages affected by this read but not on the region from pos to
+        * pos+len-1.
+        */
+
+       return cifs_user_readv(iocb, iov, nr_segs, pos);
+}
 
 static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
-       loff_t *poffset)
+                        loff_t *poffset)
 {
        int rc = -EACCES;
        unsigned int bytes_read = 0;
@@ -1746,6 +2008,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        return total_read;
 }
 
+int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       int rc, xid;
+       struct inode *inode = file->f_path.dentry->d_inode;
+
+       xid = GetXid();
+
+       if (!CIFS_I(inode)->clientCanCacheRead)
+               cifs_invalidate_mapping(inode);
+
+       rc = generic_file_mmap(file, vma);
+       FreeXid(xid);
+       return rc;
+}
+
 int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int rc, xid;
@@ -2192,7 +2469,8 @@ void cifs_oplock_break(struct work_struct *work)
         */
        if (!cfile->oplock_break_cancelled) {
                rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
-                                0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
+                                0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
+                                cinode->clientCanCacheRead ? 1 : 0);
                cFYI(1, "Oplock release rc = %d", rc);
        }
 
index 6c9ee80..8852470 100644 (file)
@@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode)
                                inode->i_fop = &cifs_file_direct_nobrl_ops;
                        else
                                inode->i_fop = &cifs_file_direct_ops;
+               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
+                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                               inode->i_fop = &cifs_file_strict_nobrl_ops;
+                       else
+                               inode->i_fop = &cifs_file_strict_ops;
                } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                        inode->i_fop = &cifs_file_nobrl_ops;
                else { /* not direct, send byte range locks */
                        inode->i_fop = &cifs_file_ops;
                }
 
-
                /* check if server can support readpages */
                if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
                                PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
@@ -1679,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode)
 /*
  * Zap the cache. Called when invalid_mapping flag is set.
  */
-static void
+void
 cifs_invalidate_mapping(struct inode *inode)
 {
        int rc;
index 306769d..e8804d3 100644 (file)
@@ -28,7 +28,6 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
-#include "md5.h"
 
 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
        md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
 
 static int
+symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
+{
+       int rc;
+       unsigned int size;
+       struct crypto_shash *md5;
+       struct sdesc *sdescmd5;
+
+       md5 = crypto_alloc_shash("md5", 0, 0);
+       if (IS_ERR(md5)) {
+               rc = PTR_ERR(md5);
+               cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
+               return rc;
+       }
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
+       sdescmd5 = kmalloc(size, GFP_KERNEL);
+       if (!sdescmd5) {
+               rc = -ENOMEM;
+               cERROR(1, "%s: Memory allocation failure\n", __func__);
+               goto symlink_hash_err;
+       }
+       sdescmd5->shash.tfm = md5;
+       sdescmd5->shash.flags = 0x0;
+
+       rc = crypto_shash_init(&sdescmd5->shash);
+       if (rc) {
+               cERROR(1, "%s: Could not init md5 shash\n", __func__);
+               goto symlink_hash_err;
+       }
+       crypto_shash_update(&sdescmd5->shash, link_str, link_len);
+       rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
+
+symlink_hash_err:
+       crypto_free_shash(md5);
+       kfree(sdescmd5);
+
+       return rc;
+}
+
+static int
 CIFSParseMFSymlink(const u8 *buf,
                   unsigned int buf_len,
                   unsigned int *_link_len,
@@ -56,7 +94,6 @@ CIFSParseMFSymlink(const u8 *buf,
        unsigned int link_len;
        const char *md5_str1;
        const char *link_str;
-       struct MD5Context md5_ctx;
        u8 md5_hash[16];
        char md5_str2[34];
 
@@ -70,9 +107,11 @@ CIFSParseMFSymlink(const u8 *buf,
        if (rc != 1)
                return -EINVAL;
 
-       cifs_MD5_init(&md5_ctx);
-       cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len);
-       cifs_MD5_final(md5_hash, &md5_ctx);
+       rc = symlink_hash(link_len, link_str, md5_hash);
+       if (rc) {
+               cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
+               return rc;
+       }
 
        snprintf(md5_str2, sizeof(md5_str2),
                 CIFS_MF_SYMLINK_MD5_FORMAT,
@@ -94,9 +133,9 @@ CIFSParseMFSymlink(const u8 *buf,
 static int
 CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
 {
+       int rc;
        unsigned int link_len;
        unsigned int ofs;
-       struct MD5Context md5_ctx;
        u8 md5_hash[16];
 
        if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
@@ -107,9 +146,11 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
        if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
                return -ENAMETOOLONG;
 
-       cifs_MD5_init(&md5_ctx);
-       cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len);
-       cifs_MD5_final(md5_hash, &md5_ctx);
+       rc = symlink_hash(link_len, link_str, md5_hash);
+       if (rc) {
+               cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
+               return rc;
+       }
 
        snprintf(buf, buf_len,
                 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c
deleted file mode 100644 (file)
index a725c26..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-   Unix SMB/Netbios implementation.
-   Version 1.9.
-   a implementation of MD4 designed for use in the SMB authentication protocol
-   Copyright (C) Andrew Tridgell 1997-1998.
-   Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-#include <linux/module.h>
-#include <linux/fs.h>
-#include "cifsencrypt.h"
-
-/* NOTE: This code makes no attempt to be fast! */
-
-static __u32
-F(__u32 X, __u32 Y, __u32 Z)
-{
-       return (X & Y) | ((~X) & Z);
-}
-
-static __u32
-G(__u32 X, __u32 Y, __u32 Z)
-{
-       return (X & Y) | (X & Z) | (Y & Z);
-}
-
-static __u32
-H(__u32 X, __u32 Y, __u32 Z)
-{
-       return X ^ Y ^ Z;
-}
-
-static __u32
-lshift(__u32 x, int s)
-{
-       x &= 0xFFFFFFFF;
-       return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
-}
-
-#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s)
-#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s)
-#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s)
-
-/* this applies md4 to 64 byte chunks */
-static void
-mdfour64(__u32 *M, __u32 *A, __u32 *B, __u32 *C, __u32 *D)
-{
-       int j;
-       __u32 AA, BB, CC, DD;
-       __u32 X[16];
-
-
-       for (j = 0; j < 16; j++)
-               X[j] = M[j];
-
-       AA = *A;
-       BB = *B;
-       CC = *C;
-       DD = *D;
-
-       ROUND1(A, B, C, D, 0, 3);
-       ROUND1(D, A, B, C, 1, 7);
-       ROUND1(C, D, A, B, 2, 11);
-       ROUND1(B, C, D, A, 3, 19);
-       ROUND1(A, B, C, D, 4, 3);
-       ROUND1(D, A, B, C, 5, 7);
-       ROUND1(C, D, A, B, 6, 11);
-       ROUND1(B, C, D, A, 7, 19);
-       ROUND1(A, B, C, D, 8, 3);
-       ROUND1(D, A, B, C, 9, 7);
-       ROUND1(C, D, A, B, 10, 11);
-       ROUND1(B, C, D, A, 11, 19);
-       ROUND1(A, B, C, D, 12, 3);
-       ROUND1(D, A, B, C, 13, 7);
-       ROUND1(C, D, A, B, 14, 11);
-       ROUND1(B, C, D, A, 15, 19);
-
-       ROUND2(A, B, C, D, 0, 3);
-       ROUND2(D, A, B, C, 4, 5);
-       ROUND2(C, D, A, B, 8, 9);
-       ROUND2(B, C, D, A, 12, 13);
-       ROUND2(A, B, C, D, 1, 3);
-       ROUND2(D, A, B, C, 5, 5);
-       ROUND2(C, D, A, B, 9, 9);
-       ROUND2(B, C, D, A, 13, 13);
-       ROUND2(A, B, C, D, 2, 3);
-       ROUND2(D, A, B, C, 6, 5);
-       ROUND2(C, D, A, B, 10, 9);
-       ROUND2(B, C, D, A, 14, 13);
-       ROUND2(A, B, C, D, 3, 3);
-       ROUND2(D, A, B, C, 7, 5);
-       ROUND2(C, D, A, B, 11, 9);
-       ROUND2(B, C, D, A, 15, 13);
-
-       ROUND3(A, B, C, D, 0, 3);
-       ROUND3(D, A, B, C, 8, 9);
-       ROUND3(C, D, A, B, 4, 11);
-       ROUND3(B, C, D, A, 12, 15);
-       ROUND3(A, B, C, D, 2, 3);
-       ROUND3(D, A, B, C, 10, 9);
-       ROUND3(C, D, A, B, 6, 11);
-       ROUND3(B, C, D, A, 14, 15);
-       ROUND3(A, B, C, D, 1, 3);
-       ROUND3(D, A, B, C, 9, 9);
-       ROUND3(C, D, A, B, 5, 11);
-       ROUND3(B, C, D, A, 13, 15);
-       ROUND3(A, B, C, D, 3, 3);
-       ROUND3(D, A, B, C, 11, 9);
-       ROUND3(C, D, A, B, 7, 11);
-       ROUND3(B, C, D, A, 15, 15);
-
-       *A += AA;
-       *B += BB;
-       *C += CC;
-       *D += DD;
-
-       *A &= 0xFFFFFFFF;
-       *B &= 0xFFFFFFFF;
-       *C &= 0xFFFFFFFF;
-       *D &= 0xFFFFFFFF;
-
-       for (j = 0; j < 16; j++)
-               X[j] = 0;
-}
-
-static void
-copy64(__u32 *M, unsigned char *in)
-{
-       int i;
-
-       for (i = 0; i < 16; i++)
-               M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
-                   (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
-}
-
-static void
-copy4(unsigned char *out, __u32 x)
-{
-       out[0] = x & 0xFF;
-       out[1] = (x >> 8) & 0xFF;
-       out[2] = (x >> 16) & 0xFF;
-       out[3] = (x >> 24) & 0xFF;
-}
-
-/* produce a md4 message digest from data of length n bytes */
-void
-mdfour(unsigned char *out, unsigned char *in, int n)
-{
-       unsigned char buf[128];
-       __u32 M[16];
-       __u32 b = n * 8;
-       int i;
-       __u32 A = 0x67452301;
-       __u32 B = 0xefcdab89;
-       __u32 C = 0x98badcfe;
-       __u32 D = 0x10325476;
-
-       while (n > 64) {
-               copy64(M, in);
-               mdfour64(M, &A, &B, &C, &D);
-               in += 64;
-               n -= 64;
-       }
-
-       for (i = 0; i < 128; i++)
-               buf[i] = 0;
-       memcpy(buf, in, n);
-       buf[n] = 0x80;
-
-       if (n <= 55) {
-               copy4(buf + 56, b);
-               copy64(M, buf);
-               mdfour64(M, &A, &B, &C, &D);
-       } else {
-               copy4(buf + 120, b);
-               copy64(M, buf);
-               mdfour64(M, &A, &B, &C, &D);
-               copy64(M, buf + 64);
-               mdfour64(M, &A, &B, &C, &D);
-       }
-
-       for (i = 0; i < 128; i++)
-               buf[i] = 0;
-       copy64(M, buf);
-
-       copy4(out, A);
-       copy4(out + 4, B);
-       copy4(out + 8, C);
-       copy4(out + 12, D);
-
-       A = B = C = D = 0;
-}
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
deleted file mode 100644 (file)
index 98b66a5..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to cifs_MD5_init, call cifs_MD5_update as
- * needed on buffers full of bytes, and then call cifs_MD5_final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-/* This code slightly modified to fit into Samba by
-   abartlet@samba.org Jun 2001
-   and to fit the cifs vfs by
-   Steve French sfrench@us.ibm.com */
-
-#include <linux/string.h>
-#include "md5.h"
-
-static void MD5Transform(__u32 buf[4], __u32 const in[16]);
-
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void
-byteReverse(unsigned char *buf, unsigned longs)
-{
-       __u32 t;
-       do {
-               t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-                   ((unsigned) buf[1] << 8 | buf[0]);
-               *(__u32 *) buf = t;
-               buf += 4;
-       } while (--longs);
-}
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void
-cifs_MD5_init(struct MD5Context *ctx)
-{
-       ctx->buf[0] = 0x67452301;
-       ctx->buf[1] = 0xefcdab89;
-       ctx->buf[2] = 0x98badcfe;
-       ctx->buf[3] = 0x10325476;
-
-       ctx->bits[0] = 0;
-       ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void
-cifs_MD5_update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
-{
-       register __u32 t;
-
-       /* Update bitcount */
-
-       t = ctx->bits[0];
-       if ((ctx->bits[0] = t + ((__u32) len << 3)) < t)
-               ctx->bits[1]++; /* Carry from low to high */
-       ctx->bits[1] += len >> 29;
-
-       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
-
-       /* Handle any leading odd-sized chunks */
-
-       if (t) {
-               unsigned char *p = (unsigned char *) ctx->in + t;
-
-               t = 64 - t;
-               if (len < t) {
-                       memmove(p, buf, len);
-                       return;
-               }
-               memmove(p, buf, t);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-               buf += t;
-               len -= t;
-       }
-       /* Process data in 64-byte chunks */
-
-       while (len >= 64) {
-               memmove(ctx->in, buf, 64);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-               buf += 64;
-               len -= 64;
-       }
-
-       /* Handle any remaining bytes of data. */
-
-       memmove(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void
-cifs_MD5_final(unsigned char digest[16], struct MD5Context *ctx)
-{
-       unsigned int count;
-       unsigned char *p;
-
-       /* Compute number of bytes mod 64 */
-       count = (ctx->bits[0] >> 3) & 0x3F;
-
-       /* Set the first char of padding to 0x80.  This is safe since there is
-          always at least one byte free */
-       p = ctx->in + count;
-       *p++ = 0x80;
-
-       /* Bytes of padding needed to make 64 bytes */
-       count = 64 - 1 - count;
-
-       /* Pad out to 56 mod 64 */
-       if (count < 8) {
-               /* Two lots of padding:  Pad the first block to 64 bytes */
-               memset(p, 0, count);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-
-               /* Now fill the next block with 56 bytes */
-               memset(ctx->in, 0, 56);
-       } else {
-               /* Pad block to 56 bytes */
-               memset(p, 0, count - 8);
-       }
-       byteReverse(ctx->in, 14);
-
-       /* Append length in bits and transform */
-       ((__u32 *) ctx->in)[14] = ctx->bits[0];
-       ((__u32 *) ctx->in)[15] = ctx->bits[1];
-
-       MD5Transform(ctx->buf, (__u32 *) ctx->in);
-       byteReverse((unsigned char *) ctx->buf, 4);
-       memmove(digest, ctx->buf, 16);
-       memset(ctx, 0, sizeof(*ctx));   /* In case it's sensitive */
-}
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-       (w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x)
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  cifs_MD5_update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void
-MD5Transform(__u32 buf[4], __u32 const in[16])
-{
-       register __u32 a, b, c, d;
-
-       a = buf[0];
-       b = buf[1];
-       c = buf[2];
-       d = buf[3];
-
-       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-       buf[0] += a;
-       buf[1] += b;
-       buf[2] += c;
-       buf[3] += d;
-}
-
-#if 0   /* currently unused */
-/***********************************************************************
- the rfc 2104 version of hmac_md5 initialisation.
-***********************************************************************/
-static void
-hmac_md5_init_rfc2104(unsigned char *key, int key_len,
-                     struct HMACMD5Context *ctx)
-{
-       int i;
-
-       /* if key is longer than 64 bytes reset it to key=MD5(key) */
-       if (key_len > 64) {
-               unsigned char tk[16];
-               struct MD5Context tctx;
-
-               cifs_MD5_init(&tctx);
-               cifs_MD5_update(&tctx, key, key_len);
-               cifs_MD5_final(tk, &tctx);
-
-               key = tk;
-               key_len = 16;
-       }
-
-       /* start out by storing key in pads */
-       memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
-       memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
-       memcpy(ctx->k_ipad, key, key_len);
-       memcpy(ctx->k_opad, key, key_len);
-
-       /* XOR key with ipad and opad values */
-       for (i = 0; i < 64; i++) {
-               ctx->k_ipad[i] ^= 0x36;
-               ctx->k_opad[i] ^= 0x5c;
-       }
-
-       cifs_MD5_init(&ctx->ctx);
-       cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64);
-}
-#endif
-
-/***********************************************************************
- the microsoft version of hmac_md5 initialisation.
-***********************************************************************/
-void
-hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
-                        struct HMACMD5Context *ctx)
-{
-       int i;
-
-       /* if key is longer than 64 bytes truncate it */
-       if (key_len > 64)
-               key_len = 64;
-
-       /* start out by storing key in pads */
-       memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
-       memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
-       memcpy(ctx->k_ipad, key, key_len);
-       memcpy(ctx->k_opad, key, key_len);
-
-       /* XOR key with ipad and opad values */
-       for (i = 0; i < 64; i++) {
-               ctx->k_ipad[i] ^= 0x36;
-               ctx->k_opad[i] ^= 0x5c;
-       }
-
-       cifs_MD5_init(&ctx->ctx);
-       cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64);
-}
-
-/***********************************************************************
- update hmac_md5 "inner" buffer
-***********************************************************************/
-void
-hmac_md5_update(const unsigned char *text, int text_len,
-               struct HMACMD5Context *ctx)
-{
-       cifs_MD5_update(&ctx->ctx, text, text_len);     /* then text of datagram */
-}
-
-/***********************************************************************
- finish off hmac_md5 "inner" buffer and generate outer one.
-***********************************************************************/
-void
-hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
-{
-       struct MD5Context ctx_o;
-
-       cifs_MD5_final(digest, &ctx->ctx);
-
-       cifs_MD5_init(&ctx_o);
-       cifs_MD5_update(&ctx_o, ctx->k_opad, 64);
-       cifs_MD5_update(&ctx_o, digest, 16);
-       cifs_MD5_final(digest, &ctx_o);
-}
-
-/***********************************************************
- single function to calculate an HMAC MD5 digest from data.
- use the microsoft hmacmd5 init method because the key is 16 bytes.
-************************************************************/
-#if 0 /* currently unused */
-static void
-hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
-        unsigned char *digest)
-{
-       struct HMACMD5Context ctx;
-       hmac_md5_init_limK_to_64(key, 16, &ctx);
-       if (data_len != 0)
-               hmac_md5_update(data, data_len, &ctx);
-
-       hmac_md5_final(digest, &ctx);
-}
-#endif
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
deleted file mode 100644 (file)
index 6fba8cb..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef MD5_H
-#define MD5_H
-#ifndef HEADER_MD5_H
-/* Try to avoid clashes with OpenSSL */
-#define HEADER_MD5_H
-#endif
-
-struct MD5Context {
-       __u32 buf[4];
-       __u32 bits[2];
-       unsigned char in[64];
-};
-#endif                         /* !MD5_H */
-
-#ifndef _HMAC_MD5_H
-struct HMACMD5Context {
-       struct MD5Context ctx;
-       unsigned char k_ipad[65];
-       unsigned char k_opad[65];
-};
-#endif                         /* _HMAC_MD5_H */
-
-void cifs_MD5_init(struct MD5Context *context);
-void cifs_MD5_update(struct MD5Context *context, unsigned char const *buf,
-                       unsigned len);
-void cifs_MD5_final(unsigned char digest[16], struct MD5Context *context);
-
-/* The following definitions come from lib/hmacmd5.c  */
-
-/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
-                       struct HMACMD5Context *ctx);*/
-void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
-                       struct HMACMD5Context *ctx);
-void hmac_md5_update(const unsigned char *text, int text_len,
-                       struct HMACMD5Context *ctx);
-void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
-/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
-                       unsigned char *digest);*/
index 43f1028..2a930a7 100644 (file)
@@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
 {
        __u16 mid = 0;
        __u16 last_mid;
-       int   collision;
-
-       if (server == NULL)
-               return mid;
+       bool collision;
 
        spin_lock(&GlobalMid_Lock);
        last_mid = server->CurrentMid; /* we do not want to loop forever */
@@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
        (and it would also have to have been a request that
         did not time out) */
        while (server->CurrentMid != last_mid) {
-               struct list_head *tmp;
                struct mid_q_entry *mid_entry;
+               unsigned int num_mids;
 
-               collision = 0;
+               collision = false;
                if (server->CurrentMid == 0)
                        server->CurrentMid++;
 
-               list_for_each(tmp, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-
-                       if ((mid_entry->mid == server->CurrentMid) &&
-                           (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+               num_mids = 0;
+               list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
+                       ++num_mids;
+                       if (mid_entry->mid == server->CurrentMid &&
+                           mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                /* This mid is in use, try a different one */
-                               collision = 1;
+                               collision = true;
                                break;
                        }
                }
-               if (collision == 0) {
+
+               /*
+                * if we have more than 32k mids in the list, then something
+                * is very wrong. Possibly a local user is trying to DoS the
+                * box by issuing long-running calls and SIGKILL'ing them. If
+                * we get to 2^16 mids then we're in big trouble as this
+                * function could loop forever.
+                *
+                * Go ahead and assign out the mid in this situation, but force
+                * an eventual reconnect to clean out the pending_mid_q.
+                */
+               if (num_mids > 32768)
+                       server->tcpStatus = CifsNeedReconnect;
+
+               if (!collision) {
                        mid = server->CurrentMid;
                        break;
                }
@@ -381,29 +392,31 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 }
 
 static int
-checkSMBhdr(struct smb_hdr *smb, __u16 mid)
+check_smb_hdr(struct smb_hdr *smb, __u16 mid)
 {
-       /* Make sure that this really is an SMB, that it is a response,
-          and that the message ids match */
-       if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
-               (mid == smb->Mid)) {
-               if (smb->Flags & SMBFLG_RESPONSE)
-                       return 0;
-               else {
-               /* only one valid case where server sends us request */
-                       if (smb->Command == SMB_COM_LOCKING_ANDX)
-                               return 0;
-                       else
-                               cERROR(1, "Received Request not response");
-               }
-       } else { /* bad signature or mid */
-               if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
-                       cERROR(1, "Bad protocol string signature header %x",
-                               *(unsigned int *) smb->Protocol);
-               if (mid != smb->Mid)
-                       cERROR(1, "Mids do not match");
+       /* does it have the right SMB "signature" ? */
+       if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
+               cERROR(1, "Bad protocol string signature header 0x%x",
+                       *(unsigned int *)smb->Protocol);
+               return 1;
        }
-       cERROR(1, "bad smb detected. The Mid=%d", smb->Mid);
+
+       /* Make sure that message ids match */
+       if (mid != smb->Mid) {
+               cERROR(1, "Mids do not match. received=%u expected=%u",
+                       smb->Mid, mid);
+               return 1;
+       }
+
+       /* if it's a response then accept */
+       if (smb->Flags & SMBFLG_RESPONSE)
+               return 0;
+
+       /* only one valid case where server sends us request */
+       if (smb->Command == SMB_COM_LOCKING_ANDX)
+               return 0;
+
+       cERROR(1, "Server sent request, not response. mid=%u", smb->Mid);
        return 1;
 }
 
@@ -448,7 +461,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                return 1;
        }
 
-       if (checkSMBhdr(smb, mid))
+       if (check_smb_hdr(smb, mid))
                return 1;
        clc_len = smbCalcSize_LE(smb);
 
@@ -465,25 +478,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                        if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
                                return 0; /* bcc wrapped */
                }
-               cFYI(1, "Calculated size %d vs length %d mismatch for mid %d",
+               cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u",
                                clc_len, 4 + len, smb->Mid);
-               /* Windows XP can return a few bytes too much, presumably
-               an illegal pad, at the end of byte range lock responses
-               so we allow for that three byte pad, as long as actual
-               received length is as long or longer than calculated length */
-               /* We have now had to extend this more, since there is a
-               case in which it needs to be bigger still to handle a
-               malformed response to transact2 findfirst from WinXP when
-               access denied is returned and thus bcc and wct are zero
-               but server says length is 0x21 bytes too long as if the server
-               forget to reset the smb rfc1001 length when it reset the
-               wct and bcc to minimum size and drop the t2 parms and data */
-               if ((4+len > clc_len) && (len <= clc_len + 512))
-                       return 0;
-               else {
-                       cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d",
+
+               if (4 + len < clc_len) {
+                       cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u",
                                        len, smb->Mid);
                        return 1;
+               } else if (len > clc_len + 512) {
+                       /*
+                        * Some servers (Windows XP in particular) send more
+                        * data than the lengths in the SMB packet would
+                        * indicate on certain calls (byte range locks and
+                        * trans2 find first calls in particular). While the
+                        * client can handle such a frame by ignoring the
+                        * trailing data, we choose limit the amount of extra
+                        * data to 512 bytes.
+                        */
+                       cERROR(1, "RFC1001 size %u more than 512 bytes larger "
+                                 "than SMB for mid=%u", len, smb->Mid);
+                       return 1;
                }
        }
        return 0;
@@ -571,7 +585,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
 
                                cifs_set_oplock_level(pCifsInode,
-                                                     pSMB->OplockLevel);
+                                       pSMB->OplockLevel ? OPLOCK_READ : 0);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing
@@ -637,77 +651,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
        return;
 }
 
-/* Convert 16 bit Unicode pathname to wire format from string in current code
-   page.  Conversion may involve remapping up the seven characters that are
-   only legal in POSIX-like OS (if they are present in the string). Path
-   names are little endian 16 bit Unicode on the wire */
-int
-cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
-                const struct nls_table *cp, int mapChars)
-{
-       int i, j, charlen;
-       int len_remaining = maxlen;
-       char src_char;
-       __u16 temp;
-
-       if (!mapChars)
-               return cifs_strtoUCS(target, source, PATH_MAX, cp);
-
-       for (i = 0, j = 0; i < maxlen; j++) {
-               src_char = source[i];
-               switch (src_char) {
-                       case 0:
-                               target[j] = 0;
-                               goto ctoUCS_out;
-                       case ':':
-                               target[j] = cpu_to_le16(UNI_COLON);
-                               break;
-                       case '*':
-                               target[j] = cpu_to_le16(UNI_ASTERIK);
-                               break;
-                       case '?':
-                               target[j] = cpu_to_le16(UNI_QUESTION);
-                               break;
-                       case '<':
-                               target[j] = cpu_to_le16(UNI_LESSTHAN);
-                               break;
-                       case '>':
-                               target[j] = cpu_to_le16(UNI_GRTRTHAN);
-                               break;
-                       case '|':
-                               target[j] = cpu_to_le16(UNI_PIPE);
-                               break;
-                       /* BB We can not handle remapping slash until
-                          all the calls to build_path_from_dentry
-                          are modified, as they use slash as separator BB */
-                       /* case '\\':
-                               target[j] = cpu_to_le16(UNI_SLASH);
-                               break;*/
-                       default:
-                               charlen = cp->char2uni(source+i,
-                                       len_remaining, &temp);
-                               /* if no match, use question mark, which
-                               at least in some cases servers as wild card */
-                               if (charlen < 1) {
-                                       target[j] = cpu_to_le16(0x003f);
-                                       charlen = 1;
-                               } else
-                                       target[j] = cpu_to_le16(temp);
-                               len_remaining -= charlen;
-                               /* character may take more than one byte in the
-                                  the source string, but will take exactly two
-                                  bytes in the target string */
-                               i += charlen;
-                               continue;
-               }
-               i++; /* move to next char in source string */
-               len_remaining--;
-       }
-
-ctoUCS_out:
-       return i;
-}
-
 void
 cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
 {
index 6783ce6..79f641e 100644 (file)
@@ -170,7 +170,7 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len)
 {
        int rc, alen, slen;
        const char *pct;
-       char *endp, scope_id[13];
+       char scope_id[13];
        struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
        struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
 
@@ -197,9 +197,9 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len)
                memcpy(scope_id, pct + 1, slen);
                scope_id[slen] = '\0';
 
-               s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
-               if (endp != scope_id + slen)
-                       return 0;
+               rc = strict_strtoul(scope_id, 0,
+                                       (unsigned long *)&s6->sin6_scope_id);
+               rc = (rc == 0) ? 1 : 0;
        }
 
        return rc;
@@ -916,14 +916,14 @@ unsigned int
 smbCalcSize(struct smb_hdr *ptr)
 {
        return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
-               2 /* size of the bcc field */ + BCC(ptr));
+               2 /* size of the bcc field */ + get_bcc(ptr));
 }
 
 unsigned int
 smbCalcSize_LE(struct smb_hdr *ptr)
 {
        return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
-               2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
+               2 /* size of the bcc field */ + get_bcc_le(ptr));
 }
 
 /* The following are taken from fs/ntfs/util.c */
index 7f25cc3..f8e4cd2 100644 (file)
@@ -764,7 +764,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
        int rc = 0;
        int xid, i;
-       struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        struct cifsFileInfo *cifsFile = NULL;
        char *current_entry;
@@ -775,8 +774,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 
        xid = GetXid();
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-
        /*
         * Ensure FindFirst doesn't fail before doing filldir() for '.' and
         * '..'. Otherwise we won't be able to notify VFS in case of failure.
index eb74648..1676570 100644 (file)
@@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
 }
 
 static void
-decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
+decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
                      const struct nls_table *nls_cp)
 {
        int len;
@@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
        return;
 }
 
-static int decode_ascii_ssetup(char **pbcc_area, int bleft,
+static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
                               struct cifsSesInfo *ses,
                               const struct nls_table *nls_cp)
 {
@@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
        char *str_area;
        SESSION_SETUP_ANDX *pSMB;
        __u32 capabilities;
-       int count;
+       __u16 count;
        int resp_buf_type;
        struct kvec iov[3];
        enum securityEnum type;
-       __u16 action;
-       int bytes_remaining;
+       __u16 action, bytes_remaining;
        struct key *spnego_key = NULL;
        __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
        u16 blob_len;
@@ -657,13 +656,13 @@ ssetup_ntlmssp_authenticate:
 
        if (type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-               char lnm_session_key[CIFS_SESS_KEY_SIZE];
+               char lnm_session_key[CIFS_AUTH_RESP_SIZE];
 
                pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
 
                /* no capabilities flags in old lanman negotiation */
 
-               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
 
                /* Calculate hash with password and copy into bcc_ptr.
                 * Encryption Key (stored as in cryptkey) gets used if the
@@ -676,8 +675,8 @@ ssetup_ntlmssp_authenticate:
                                        true : false, lnm_session_key);
 
                ses->flags |= CIFS_SES_LANMAN;
-               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
-               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
+               bcc_ptr += CIFS_AUTH_RESP_SIZE;
 
                /* can not sign if LANMAN negotiated so no need
                to calculate signing key? but what if server
@@ -876,10 +875,10 @@ ssetup_ntlmssp_authenticate:
        count = iov[1].iov_len + iov[2].iov_len;
        smb_buf->smb_buf_length += count;
 
-       BCC_LE(smb_buf) = cpu_to_le16(count);
+       put_bcc_le(count, smb_buf);
 
        rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
-                         CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
+                         CIFS_LOG_ERROR);
        /* SMB request buf freed in SendReceive2 */
 
        pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
@@ -910,7 +909,7 @@ ssetup_ntlmssp_authenticate:
        cFYI(1, "UID = %d ", ses->Suid);
        /* response can have either 3 or 4 word count - Samba sends 3 */
        /* and lanman response is 3 */
-       bytes_remaining = BCC(smb_buf);
+       bytes_remaining = get_bcc(smb_buf);
        bcc_ptr = pByteArea(smb_buf);
 
        if (smb_buf->WordCount == 4) {
index b6b6dcb..0472148 100644 (file)
@@ -45,7 +45,6 @@
    up with a different answer to the one above)
 */
 #include <linux/slab.h>
-#include "cifsencrypt.h"
 #define uchar unsigned char
 
 static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
index 192ea51..b5041c8 100644 (file)
@@ -32,9 +32,8 @@
 #include "cifs_unicode.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
-#include "md5.h"
 #include "cifs_debug.h"
-#include "cifsencrypt.h"
+#include "cifsproto.h"
 
 #ifndef false
 #define false 0
 #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
 #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
 
-/*The following definitions come from  libsmb/smbencrypt.c  */
+/* produce a md4 message digest from data of length n bytes */
+int
+mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
+{
+       int rc;
+       unsigned int size;
+       struct crypto_shash *md4;
+       struct sdesc *sdescmd4;
+
+       md4 = crypto_alloc_shash("md4", 0, 0);
+       if (IS_ERR(md4)) {
+               rc = PTR_ERR(md4);
+               cERROR(1, "%s: Crypto md4 allocation error %d\n", __func__, rc);
+               return rc;
+       }
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
+       sdescmd4 = kmalloc(size, GFP_KERNEL);
+       if (!sdescmd4) {
+               rc = -ENOMEM;
+               cERROR(1, "%s: Memory allocation failure\n", __func__);
+               goto mdfour_err;
+       }
+       sdescmd4->shash.tfm = md4;
+       sdescmd4->shash.flags = 0x0;
+
+       rc = crypto_shash_init(&sdescmd4->shash);
+       if (rc) {
+               cERROR(1, "%s: Could not init md4 shash\n", __func__);
+               goto mdfour_err;
+       }
+       crypto_shash_update(&sdescmd4->shash, link_str, link_len);
+       rc = crypto_shash_final(&sdescmd4->shash, md4_hash);
 
-void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
-               unsigned char *p24);
-void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
-                  unsigned char p24[24]);
-void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+mdfour_err:
+       crypto_free_shash(md4);
+       kfree(sdescmd4);
+
+       return rc;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+static void
+SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
+             unsigned char p24[24])
+{
+       unsigned char p21[21];
+
+       memset(p21, '\0', 21);
+
+       memcpy(p21, passwd, 16);
+       E_P24(p21, c8, p24);
+}
 
 /*
    This implements the X/Open SMB password encryption
@@ -118,9 +161,10 @@ _my_mbstowcs(__u16 *dst, const unsigned char *src, int len)
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
 
-void
+int
 E_md4hash(const unsigned char *passwd, unsigned char *p16)
 {
+       int rc;
        int len;
        __u16 wpwd[129];
 
@@ -139,8 +183,10 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
        /* Calculate length in bytes */
        len = _my_wcslen(wpwd) * sizeof(__u16);
 
-       mdfour(p16, (unsigned char *) wpwd, len);
+       rc = mdfour(p16, (unsigned char *) wpwd, len);
        memset(wpwd, 0, 129 * 2);
+
+       return rc;
 }
 
 #if 0 /* currently unused */
@@ -212,19 +258,6 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
 }
 #endif
 
-/* Does the des encryption from the NT or LM MD4 hash. */
-static void
-SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
-             unsigned char p24[24])
-{
-       unsigned char p21[21];
-
-       memset(p21, '\0', 21);
-
-       memcpy(p21, passwd, 16);
-       E_P24(p21, c8, p24);
-}
-
 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
 #if 0 /* currently unused */
 static void
@@ -242,16 +275,21 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
 #endif
 
 /* Does the NT MD4 hash then des encryption. */
-
-void
+int
 SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
 {
+       int rc;
        unsigned char p21[21];
 
        memset(p21, '\0', 21);
 
-       E_md4hash(passwd, p21);
+       rc = E_md4hash(passwd, p21);
+       if (rc) {
+               cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
+               return rc;
+       }
        SMBOWFencrypt(p21, c8, p24);
+       return rc;
 }
 
 
index 59ca81b..46d8756 100644 (file)
 
 extern mempool_t *cifs_mid_poolp;
 
-static struct mid_q_entry *
+static void
+wake_up_task(struct mid_q_entry *mid)
+{
+       wake_up_process(mid->callback_data);
+}
+
+struct mid_q_entry *
 AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 {
        struct mid_q_entry *temp;
@@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        /*      do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
                /* when mid allocated can be before when sent */
                temp->when_alloc = jiffies;
-               temp->tsk = current;
+
+               /*
+                * The default is for the mid to be synchronous, so the
+                * default callback just wakes up the current task.
+                */
+               temp->callback = wake_up_task;
+               temp->callback_data = current;
        }
 
-       spin_lock(&GlobalMid_Lock);
-       list_add_tail(&temp->qhead, &server->pending_mid_q);
        atomic_inc(&midCount);
        temp->midState = MID_REQUEST_ALLOCATED;
-       spin_unlock(&GlobalMid_Lock);
        return temp;
 }
 
-static void
+void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
 #ifdef CONFIG_CIFS_STATS2
        unsigned long now;
 #endif
-       spin_lock(&GlobalMid_Lock);
        midEntry->midState = MID_FREE;
-       list_del(&midEntry->qhead);
        atomic_dec(&midCount);
-       spin_unlock(&GlobalMid_Lock);
        if (midEntry->largeBuf)
                cifs_buf_release(midEntry->resp_buf);
        else
@@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
        mempool_free(midEntry, cifs_mid_poolp);
 }
 
+static void
+delete_mid(struct mid_q_entry *mid)
+{
+       spin_lock(&GlobalMid_Lock);
+       list_del(&mid->qhead);
+       spin_unlock(&GlobalMid_Lock);
+
+       DeleteMidQEntry(mid);
+}
+
 static int
 smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 {
@@ -220,9 +236,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
                server->tcpStatus = CifsNeedReconnect;
        }
 
-       if (rc < 0) {
+       if (rc < 0 && rc != -EINTR)
                cERROR(1, "Error %d sending data on socket to server", rc);
-       } else
+       else
                rc = 0;
 
        /* Don't want to modify the buffer as a
@@ -244,31 +260,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
        return smb_sendv(server, &iov, 1);
 }
 
-static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
+static int wait_for_free_request(struct TCP_Server_Info *server,
+                                const int long_op)
 {
        if (long_op == CIFS_ASYNC_OP) {
                /* oplock breaks must not be held up */
-               atomic_inc(&ses->server->inFlight);
+               atomic_inc(&server->inFlight);
                return 0;
        }
 
        spin_lock(&GlobalMid_Lock);
        while (1) {
-               if (atomic_read(&ses->server->inFlight) >=
-                               cifs_max_pending){
+               if (atomic_read(&server->inFlight) >= cifs_max_pending) {
                        spin_unlock(&GlobalMid_Lock);
 #ifdef CONFIG_CIFS_STATS2
-                       atomic_inc(&ses->server->num_waiters);
+                       atomic_inc(&server->num_waiters);
 #endif
-                       wait_event(ses->server->request_q,
-                                  atomic_read(&ses->server->inFlight)
+                       wait_event(server->request_q,
+                                  atomic_read(&server->inFlight)
                                     < cifs_max_pending);
 #ifdef CONFIG_CIFS_STATS2
-                       atomic_dec(&ses->server->num_waiters);
+                       atomic_dec(&server->num_waiters);
 #endif
                        spin_lock(&GlobalMid_Lock);
                } else {
-                       if (ses->server->tcpStatus == CifsExiting) {
+                       if (server->tcpStatus == CifsExiting) {
                                spin_unlock(&GlobalMid_Lock);
                                return -ENOENT;
                        }
@@ -278,7 +294,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
 
                        /* update # of requests on the wire to server */
                        if (long_op != CIFS_BLOCKING_OP)
-                               atomic_inc(&ses->server->inFlight);
+                               atomic_inc(&server->inFlight);
                        spin_unlock(&GlobalMid_Lock);
                        break;
                }
@@ -308,53 +324,85 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
        *ppmidQ = AllocMidQEntry(in_buf, ses->server);
        if (*ppmidQ == NULL)
                return -ENOMEM;
+       spin_lock(&GlobalMid_Lock);
+       list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
+       spin_unlock(&GlobalMid_Lock);
        return 0;
 }
 
-static int wait_for_response(struct cifsSesInfo *ses,
-                       struct mid_q_entry *midQ,
-                       unsigned long timeout,
-                       unsigned long time_to_wait)
+static int
+wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 {
-       unsigned long curr_timeout;
+       int error;
 
-       for (;;) {
-               curr_timeout = timeout + jiffies;
-               wait_event_timeout(ses->server->response_q,
-                       midQ->midState != MID_REQUEST_SUBMITTED, timeout);
+       error = wait_event_killable(server->response_q,
+                                   midQ->midState != MID_REQUEST_SUBMITTED);
+       if (error < 0)
+               return -ERESTARTSYS;
 
-               if (time_after(jiffies, curr_timeout) &&
-                       (midQ->midState == MID_REQUEST_SUBMITTED) &&
-                       ((ses->server->tcpStatus == CifsGood) ||
-                        (ses->server->tcpStatus == CifsNew))) {
+       return 0;
+}
 
-                       unsigned long lrt;
 
-                       /* We timed out. Is the server still
-                          sending replies ? */
-                       spin_lock(&GlobalMid_Lock);
-                       lrt = ses->server->lstrp;
-                       spin_unlock(&GlobalMid_Lock);
+/*
+ * Send a SMB request and set the callback function in the mid to handle
+ * the result. Caller is responsible for dealing with timeouts.
+ */
+int
+cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
+               mid_callback_t *callback, void *cbdata)
+{
+       int rc;
+       struct mid_q_entry *mid;
 
-                       /* Calculate time_to_wait past last receive time.
-                        Although we prefer not to time out if the
-                        server is still responding - we will time
-                        out if the server takes more than 15 (or 45
-                        or 180) seconds to respond to this request
-                        and has not responded to any request from
-                        other threads on the client within 10 seconds */
-                       lrt += time_to_wait;
-                       if (time_after(jiffies, lrt)) {
-                               /* No replies for time_to_wait. */
-                               cERROR(1, "server not responding");
-                               return -1;
-                       }
-               } else {
-                       return 0;
-               }
+       rc = wait_for_free_request(server, CIFS_ASYNC_OP);
+       if (rc)
+               return rc;
+
+       /* enable signing if server requires it */
+       if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               in_buf->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+       mutex_lock(&server->srv_mutex);
+       mid = AllocMidQEntry(in_buf, server);
+       if (mid == NULL) {
+               mutex_unlock(&server->srv_mutex);
+               return -ENOMEM;
        }
-}
 
+       /* put it on the pending_mid_q */
+       spin_lock(&GlobalMid_Lock);
+       list_add_tail(&mid->qhead, &server->pending_mid_q);
+       spin_unlock(&GlobalMid_Lock);
+
+       rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+       if (rc) {
+               mutex_unlock(&server->srv_mutex);
+               goto out_err;
+       }
+
+       mid->callback = callback;
+       mid->callback_data = cbdata;
+       mid->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+       atomic_inc(&server->inSend);
+#endif
+       rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+#ifdef CONFIG_CIFS_STATS2
+       atomic_dec(&server->inSend);
+       mid->when_sent = jiffies;
+#endif
+       mutex_unlock(&server->srv_mutex);
+       if (rc)
+               goto out_err;
+
+       return rc;
+out_err:
+       delete_mid(mid);
+       atomic_dec(&server->inFlight);
+       wake_up(&server->request_q);
+       return rc;
+}
 
 /*
  *
@@ -382,6 +430,84 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
        return rc;
 }
 
+static int
+sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+{
+       int rc = 0;
+
+       cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
+               mid->mid, mid->midState);
+
+       spin_lock(&GlobalMid_Lock);
+       /* ensure that it's no longer on the pending_mid_q */
+       list_del_init(&mid->qhead);
+
+       switch (mid->midState) {
+       case MID_RESPONSE_RECEIVED:
+               spin_unlock(&GlobalMid_Lock);
+               return rc;
+       case MID_REQUEST_SUBMITTED:
+               /* socket is going down, reject all calls */
+               if (server->tcpStatus == CifsExiting) {
+                       cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
+                              __func__, mid->mid, mid->command, mid->midState);
+                       rc = -EHOSTDOWN;
+                       break;
+               }
+       case MID_RETRY_NEEDED:
+               rc = -EAGAIN;
+               break;
+       case MID_RESPONSE_MALFORMED:
+               rc = -EIO;
+               break;
+       default:
+               cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
+                       mid->mid, mid->midState);
+               rc = -EIO;
+       }
+       spin_unlock(&GlobalMid_Lock);
+
+       DeleteMidQEntry(mid);
+       return rc;
+}
+
+/*
+ * An NT cancel request header looks just like the original request except:
+ *
+ * The Command is SMB_COM_NT_CANCEL
+ * The WordCount is zeroed out
+ * The ByteCount is zeroed out
+ *
+ * This function mangles an existing request buffer into a
+ * SMB_COM_NT_CANCEL request and then sends it.
+ */
+static int
+send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
+               struct mid_q_entry *mid)
+{
+       int rc = 0;
+
+       /* -4 for RFC1001 length and +2 for BCC field */
+       in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4  + 2;
+       in_buf->Command = SMB_COM_NT_CANCEL;
+       in_buf->WordCount = 0;
+       put_bcc_le(0, in_buf);
+
+       mutex_lock(&server->srv_mutex);
+       rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+       if (rc) {
+               mutex_unlock(&server->srv_mutex);
+               return rc;
+       }
+       rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+       mutex_unlock(&server->srv_mutex);
+
+       cFYI(1, "issued NT_CANCEL for mid %u, rc = %d",
+               in_buf->Mid, rc);
+
+       return rc;
+}
+
 int
 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
             struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
@@ -390,7 +516,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        int rc = 0;
        int long_op;
        unsigned int receive_len;
-       unsigned long timeout;
        struct mid_q_entry *midQ;
        struct smb_hdr *in_buf = iov[0].iov_base;
 
@@ -413,7 +538,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
-       rc = wait_for_free_request(ses, long_op);
+       rc = wait_for_free_request(ses->server, long_op);
        if (rc) {
                cifs_small_buf_release(in_buf);
                return rc;
@@ -452,70 +577,41 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 #endif
 
        mutex_unlock(&ses->server->srv_mutex);
-       cifs_small_buf_release(in_buf);
 
-       if (rc < 0)
-               goto out;
-
-       if (long_op == CIFS_STD_OP)
-               timeout = 15 * HZ;
-       else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
-               timeout = 180 * HZ;
-       else if (long_op == CIFS_LONG_OP)
-               timeout = 45 * HZ; /* should be greater than
-                       servers oplock break timeout (about 43 seconds) */
-       else if (long_op == CIFS_ASYNC_OP)
-               goto out;
-       else if (long_op == CIFS_BLOCKING_OP)
-               timeout = 0x7FFFFFFF; /*  large, but not so large as to wrap */
-       else {
-               cERROR(1, "unknown timeout flag %d", long_op);
-               rc = -EIO;
+       if (rc < 0) {
+               cifs_small_buf_release(in_buf);
                goto out;
        }
 
-       /* wait for 15 seconds or until woken up due to response arriving or
-          due to last connection to this server being unmounted */
-       if (signal_pending(current)) {
-               /* if signal pending do not hold up user for full smb timeout
-               but we still give response a chance to complete */
-               timeout = 2 * HZ;
+       if (long_op == CIFS_ASYNC_OP) {
+               cifs_small_buf_release(in_buf);
+               goto out;
        }
 
-       /* No user interrupts in wait - wreaks havoc with performance */
-       wait_for_response(ses, midQ, timeout, 10 * HZ);
-
-       spin_lock(&GlobalMid_Lock);
-
-       if (midQ->resp_buf == NULL) {
-               cERROR(1, "No response to cmd %d mid %d",
-                       midQ->command, midQ->mid);
+       rc = wait_for_response(ses->server, midQ);
+       if (rc != 0) {
+               send_nt_cancel(ses->server, in_buf, midQ);
+               spin_lock(&GlobalMid_Lock);
                if (midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if (ses->server->tcpStatus == CifsExiting)
-                               rc = -EHOSTDOWN;
-                       else {
-                               ses->server->tcpStatus = CifsNeedReconnect;
-                               midQ->midState = MID_RETRY_NEEDED;
-                       }
-               }
-
-               if (rc != -EHOSTDOWN) {
-                       if (midQ->midState == MID_RETRY_NEEDED) {
-                               rc = -EAGAIN;
-                               cFYI(1, "marking request for retry");
-                       } else {
-                               rc = -EIO;
-                       }
+                       midQ->callback = DeleteMidQEntry;
+                       spin_unlock(&GlobalMid_Lock);
+                       cifs_small_buf_release(in_buf);
+                       atomic_dec(&ses->server->inFlight);
+                       wake_up(&ses->server->request_q);
+                       return rc;
                }
                spin_unlock(&GlobalMid_Lock);
-               DeleteMidQEntry(midQ);
-               /* Update # of requests on wire to server */
+       }
+
+       cifs_small_buf_release(in_buf);
+
+       rc = sync_mid_result(midQ, ses->server);
+       if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       spin_unlock(&GlobalMid_Lock);
        receive_len = midQ->resp_buf->smb_buf_length;
 
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
@@ -559,19 +655,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                if (receive_len >= sizeof(struct smb_hdr) - 4
                    /* do not count RFC1001 header */  +
                    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
-                       BCC(midQ->resp_buf) =
-                               le16_to_cpu(BCC_LE(midQ->resp_buf));
+                       put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
                if ((flags & CIFS_NO_RESP) == 0)
                        midQ->resp_buf = NULL;  /* mark it so buf will
                                                   not be freed by
-                                                  DeleteMidQEntry */
+                                                  delete_mid */
        } else {
                rc = -EIO;
                cFYI(1, "Bad MID state?");
        }
 
 out:
-       DeleteMidQEntry(midQ);
+       delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
        wake_up(&ses->server->request_q);
 
@@ -585,7 +680,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 {
        int rc = 0;
        unsigned int receive_len;
-       unsigned long timeout;
        struct mid_q_entry *midQ;
 
        if (ses == NULL) {
@@ -610,7 +704,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                return -EIO;
        }
 
-       rc = wait_for_free_request(ses, long_op);
+       rc = wait_for_free_request(ses->server, long_op);
        if (rc)
                return rc;
 
@@ -649,64 +743,31 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        if (rc < 0)
                goto out;
 
-       if (long_op == CIFS_STD_OP)
-               timeout = 15 * HZ;
-       /* wait for 15 seconds or until woken up due to response arriving or
-          due to last connection to this server being unmounted */
-       else if (long_op == CIFS_ASYNC_OP)
-               goto out;
-       else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
-               timeout = 180 * HZ;
-       else if (long_op == CIFS_LONG_OP)
-               timeout = 45 * HZ; /* should be greater than
-                       servers oplock break timeout (about 43 seconds) */
-       else if (long_op == CIFS_BLOCKING_OP)
-               timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
-       else {
-               cERROR(1, "unknown timeout flag %d", long_op);
-               rc = -EIO;
+       if (long_op == CIFS_ASYNC_OP)
                goto out;
-       }
-
-       if (signal_pending(current)) {
-               /* if signal pending do not hold up user for full smb timeout
-               but we still give response a chance to complete */
-               timeout = 2 * HZ;
-       }
-
-       /* No user interrupts in wait - wreaks havoc with performance */
-       wait_for_response(ses, midQ, timeout, 10 * HZ);
 
-       spin_lock(&GlobalMid_Lock);
-       if (midQ->resp_buf == NULL) {
-               cERROR(1, "No response for cmd %d mid %d",
-                         midQ->command, midQ->mid);
+       rc = wait_for_response(ses->server, midQ);
+       if (rc != 0) {
+               send_nt_cancel(ses->server, in_buf, midQ);
+               spin_lock(&GlobalMid_Lock);
                if (midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if (ses->server->tcpStatus == CifsExiting)
-                               rc = -EHOSTDOWN;
-                       else {
-                               ses->server->tcpStatus = CifsNeedReconnect;
-                               midQ->midState = MID_RETRY_NEEDED;
-                       }
-               }
-
-               if (rc != -EHOSTDOWN) {
-                       if (midQ->midState == MID_RETRY_NEEDED) {
-                               rc = -EAGAIN;
-                               cFYI(1, "marking request for retry");
-                       } else {
-                               rc = -EIO;
-                       }
+                       /* no longer considered to be "in-flight" */
+                       midQ->callback = DeleteMidQEntry;
+                       spin_unlock(&GlobalMid_Lock);
+                       atomic_dec(&ses->server->inFlight);
+                       wake_up(&ses->server->request_q);
+                       return rc;
                }
                spin_unlock(&GlobalMid_Lock);
-               DeleteMidQEntry(midQ);
-               /* Update # of requests on wire to server */
+       }
+
+       rc = sync_mid_result(midQ, ses->server);
+       if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       spin_unlock(&GlobalMid_Lock);
        receive_len = midQ->resp_buf->smb_buf_length;
 
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
@@ -748,43 +809,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                if (receive_len >= sizeof(struct smb_hdr) - 4
                    /* do not count RFC1001 header */  +
                    (2 * out_buf->WordCount) + 2 /* bcc */ )
-                       BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+                       put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
        } else {
                rc = -EIO;
                cERROR(1, "Bad MID state?");
        }
 
 out:
-       DeleteMidQEntry(midQ);
+       delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
        wake_up(&ses->server->request_q);
 
        return rc;
 }
 
-/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
-
-static int
-send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
-               struct mid_q_entry *midQ)
-{
-       int rc = 0;
-       struct cifsSesInfo *ses = tcon->ses;
-       __u16 mid = in_buf->Mid;
-
-       header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
-       in_buf->Mid = mid;
-       mutex_lock(&ses->server->srv_mutex);
-       rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
-       if (rc) {
-               mutex_unlock(&ses->server->srv_mutex);
-               return rc;
-       }
-       rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
-       mutex_unlock(&ses->server->srv_mutex);
-       return rc;
-}
-
 /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
    blocking lock to return. */
 
@@ -807,7 +845,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
        pSMB->hdr.Mid = GetNextMid(ses->server);
 
        return SendReceive(xid, ses, in_buf, out_buf,
-                       &bytes_returned, CIFS_STD_OP);
+                       &bytes_returned, 0);
 }
 
 int
@@ -845,7 +883,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                return -EIO;
        }
 
-       rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
+       rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
        if (rc)
                return rc;
 
@@ -863,7 +901,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
 
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
        if (rc) {
-               DeleteMidQEntry(midQ);
+               delete_mid(midQ);
                mutex_unlock(&ses->server->srv_mutex);
                return rc;
        }
@@ -880,7 +918,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0) {
-               DeleteMidQEntry(midQ);
+               delete_mid(midQ);
                return rc;
        }
 
@@ -899,10 +937,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                if (in_buf->Command == SMB_COM_TRANSACTION2) {
                        /* POSIX lock. We send a NT_CANCEL SMB to cause the
                           blocking lock to return. */
-
-                       rc = send_nt_cancel(tcon, in_buf, midQ);
+                       rc = send_nt_cancel(ses->server, in_buf, midQ);
                        if (rc) {
-                               DeleteMidQEntry(midQ);
+                               delete_mid(midQ);
                                return rc;
                        }
                } else {
@@ -914,47 +951,33 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                        /* If we get -ENOLCK back the lock may have
                           already been removed. Don't exit in this case. */
                        if (rc && rc != -ENOLCK) {
-                               DeleteMidQEntry(midQ);
+                               delete_mid(midQ);
                                return rc;
                        }
                }
 
-               /* Wait 5 seconds for the response. */
-               if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
-                       /* We got the response - restart system call. */
-                       rstart = 1;
-               }
-       }
-
-       spin_lock(&GlobalMid_Lock);
-       if (midQ->resp_buf) {
-               spin_unlock(&GlobalMid_Lock);
-               receive_len = midQ->resp_buf->smb_buf_length;
-       } else {
-               cERROR(1, "No response for cmd %d mid %d",
-                         midQ->command, midQ->mid);
-               if (midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if (ses->server->tcpStatus == CifsExiting)
-                               rc = -EHOSTDOWN;
-                       else {
-                               ses->server->tcpStatus = CifsNeedReconnect;
-                               midQ->midState = MID_RETRY_NEEDED;
+               rc = wait_for_response(ses->server, midQ);
+               if (rc) {
+                       send_nt_cancel(ses->server, in_buf, midQ);
+                       spin_lock(&GlobalMid_Lock);
+                       if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                               /* no longer considered to be "in-flight" */
+                               midQ->callback = DeleteMidQEntry;
+                               spin_unlock(&GlobalMid_Lock);
+                               return rc;
                        }
+                       spin_unlock(&GlobalMid_Lock);
                }
 
-               if (rc != -EHOSTDOWN) {
-                       if (midQ->midState == MID_RETRY_NEEDED) {
-                               rc = -EAGAIN;
-                               cFYI(1, "marking request for retry");
-                       } else {
-                               rc = -EIO;
-                       }
-               }
-               spin_unlock(&GlobalMid_Lock);
-               DeleteMidQEntry(midQ);
-               return rc;
+               /* We got the response - restart system call. */
+               rstart = 1;
        }
 
+       rc = sync_mid_result(midQ, ses->server);
+       if (rc != 0)
+               return rc;
+
+       receive_len = midQ->resp_buf->smb_buf_length;
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
                cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
                        receive_len, xid);
@@ -998,10 +1021,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
        if (receive_len >= sizeof(struct smb_hdr) - 4
            /* do not count RFC1001 header */  +
            (2 * out_buf->WordCount) + 2 /* bcc */ )
-               BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+               put_bcc(get_bcc_le(out_buf), out_buf);
 
 out:
-       DeleteMidQEntry(midQ);
+       delete_mid(midQ);
        if (rstart && rc == -EACCES)
                return -ERESTARTSYS;
        return rc;
index 9f493ee..2a6bd9a 100644 (file)
@@ -176,6 +176,7 @@ static void d_free(struct dentry *dentry)
 
 /**
  * dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups
+ * @dentry: the target dentry
  * After this call, in-progress rcu-walk path lookup will fail. This
  * should be called after unhashing, and after changing d_inode (if
  * the dentry has not already been unhashed).
@@ -281,6 +282,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
 /**
  * d_kill - kill dentry and return parent
  * @dentry: dentry to kill
+ * @parent: parent dentry
  *
  * The dentry must already be unhashed and removed from the LRU.
  *
@@ -1973,7 +1975,7 @@ out:
 /**
  * d_validate - verify dentry provided from insecure source (deprecated)
  * @dentry: The dentry alleged to be valid child of @dparent
- * @parent: The parent dentry (known to be valid)
+ * @dparent: The parent dentry (known to be valid)
  *
  * An insecure source has sent us a dentry, here we verify it and dget() it.
  * This is used by ncpfs in its readdir implementation.
index 85882f6..b044705 100644 (file)
@@ -325,12 +325,16 @@ void dio_end_io(struct bio *bio, int error)
 }
 EXPORT_SYMBOL_GPL(dio_end_io);
 
-static int
+static void
 dio_bio_alloc(struct dio *dio, struct block_device *bdev,
                sector_t first_sector, int nr_vecs)
 {
        struct bio *bio;
 
+       /*
+        * bio_alloc() is guaranteed to return a bio when called with
+        * __GFP_WAIT and we request a valid number of vectors.
+        */
        bio = bio_alloc(GFP_KERNEL, nr_vecs);
 
        bio->bi_bdev = bdev;
@@ -342,7 +346,6 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
 
        dio->bio = bio;
        dio->logical_offset_in_bio = dio->cur_page_fs_offset;
-       return 0;
 }
 
 /*
@@ -583,8 +586,9 @@ static int dio_new_bio(struct dio *dio, sector_t start_sector)
                goto out;
        sector = start_sector << (dio->blkbits - 9);
        nr_pages = min(dio->pages_in_io, bio_get_nr_vecs(dio->map_bh.b_bdev));
+       nr_pages = min(nr_pages, BIO_MAX_PAGES);
        BUG_ON(nr_pages <= 0);
-       ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
+       dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
        dio->boundary = 0;
 out:
        return ret;
index 9c64ae9..2d8c87b 100644 (file)
@@ -1468,15 +1468,13 @@ static void work_stop(void)
 
 static int work_start(void)
 {
-       recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM |
-                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       recv_workqueue = create_singlethread_workqueue("dlm_recv");
        if (!recv_workqueue) {
                log_print("can't start dlm_recv");
                return -ENOMEM;
        }
 
-       send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM |
-                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       send_workqueue = create_singlethread_workqueue("dlm_send");
        if (!send_workqueue) {
                log_print("can't start dlm_send");
                destroy_workqueue(recv_workqueue);
index 6fc4f31..534c1d4 100644 (file)
@@ -46,24 +46,28 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct dentry *lower_dentry;
        struct vfsmount *lower_mnt;
-       struct dentry *dentry_save;
-       struct vfsmount *vfsmount_save;
+       struct dentry *dentry_save = NULL;
+       struct vfsmount *vfsmount_save = NULL;
        int rc = 1;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
        if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
                goto out;
-       dentry_save = nd->path.dentry;
-       vfsmount_save = nd->path.mnt;
-       nd->path.dentry = lower_dentry;
-       nd->path.mnt = lower_mnt;
+       if (nd) {
+               dentry_save = nd->path.dentry;
+               vfsmount_save = nd->path.mnt;
+               nd->path.dentry = lower_dentry;
+               nd->path.mnt = lower_mnt;
+       }
        rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
-       nd->path.dentry = dentry_save;
-       nd->path.mnt = vfsmount_save;
+       if (nd) {
+               nd->path.dentry = dentry_save;
+               nd->path.mnt = vfsmount_save;
+       }
        if (dentry->d_inode) {
                struct inode *lower_inode =
                        ecryptfs_inode_to_lower(dentry->d_inode);
index dbc84ed..e007534 100644 (file)
@@ -632,8 +632,7 @@ int ecryptfs_interpose(struct dentry *hidden_dentry,
                       u32 flags);
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode,
-                                       struct nameidata *ecryptfs_nd);
+                                       struct inode *ecryptfs_dir_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
                                         size_t *decrypted_name_size,
                                         struct dentry *ecryptfs_dentry,
index 81e10e6..7d1050e 100644 (file)
@@ -317,6 +317,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 const struct file_operations ecryptfs_dir_fops = {
        .readdir = ecryptfs_readdir,
+       .read = generic_read_dir,
        .unlocked_ioctl = ecryptfs_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = ecryptfs_compat_ioctl,
index bd33f87..b592938 100644 (file)
@@ -74,16 +74,20 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
        unsigned int flags_save;
        int rc;
 
-       dentry_save = nd->path.dentry;
-       vfsmount_save = nd->path.mnt;
-       flags_save = nd->flags;
-       nd->path.dentry = lower_dentry;
-       nd->path.mnt = lower_mnt;
-       nd->flags &= ~LOOKUP_OPEN;
+       if (nd) {
+               dentry_save = nd->path.dentry;
+               vfsmount_save = nd->path.mnt;
+               flags_save = nd->flags;
+               nd->path.dentry = lower_dentry;
+               nd->path.mnt = lower_mnt;
+               nd->flags &= ~LOOKUP_OPEN;
+       }
        rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
-       nd->path.dentry = dentry_save;
-       nd->path.mnt = vfsmount_save;
-       nd->flags = flags_save;
+       if (nd) {
+               nd->path.dentry = dentry_save;
+               nd->path.mnt = vfsmount_save;
+               nd->flags = flags_save;
+       }
        return rc;
 }
 
@@ -241,8 +245,7 @@ out:
  */
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode,
-                                       struct nameidata *ecryptfs_nd)
+                                       struct inode *ecryptfs_dir_inode)
 {
        struct dentry *lower_dir_dentry;
        struct vfsmount *lower_mnt;
@@ -290,8 +293,6 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                goto out;
        if (special_file(lower_inode->i_mode))
                goto out;
-       if (!ecryptfs_nd)
-               goto out;
        /* Released in this function */
        page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);
        if (!page_virt) {
@@ -349,75 +350,6 @@ out:
 }
 
 /**
- * ecryptfs_new_lower_dentry
- * @name: The name of the new dentry.
- * @lower_dir_dentry: Parent directory of the new dentry.
- * @nd: nameidata from last lookup.
- *
- * Create a new dentry or get it from lower parent dir.
- */
-static struct dentry *
-ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry,
-                         struct nameidata *nd)
-{
-       struct dentry *new_dentry;
-       struct dentry *tmp;
-       struct inode *lower_dir_inode;
-
-       lower_dir_inode = lower_dir_dentry->d_inode;
-
-       tmp = d_alloc(lower_dir_dentry, name);
-       if (!tmp)
-               return ERR_PTR(-ENOMEM);
-
-       mutex_lock(&lower_dir_inode->i_mutex);
-       new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd);
-       mutex_unlock(&lower_dir_inode->i_mutex);
-
-       if (!new_dentry)
-               new_dentry = tmp;
-       else
-               dput(tmp);
-
-       return new_dentry;
-}
-
-
-/**
- * ecryptfs_lookup_one_lower
- * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
- * @lower_dir_dentry: lower parent directory
- * @name: lower file name
- *
- * Get the lower dentry from vfs. If lower dentry does not exist yet,
- * create it.
- */
-static struct dentry *
-ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry,
-                         struct dentry *lower_dir_dentry, struct qstr *name)
-{
-       struct nameidata nd;
-       struct vfsmount *lower_mnt;
-       int err;
-
-       lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
-                                   ecryptfs_dentry->d_parent));
-       err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd);
-       mntput(lower_mnt);
-
-       if (!err) {
-               /* we dont need the mount */
-               mntput(nd.path.mnt);
-               return nd.path.dentry;
-       }
-       if (err != -ENOENT)
-               return ERR_PTR(err);
-
-       /* create a new lower dentry */
-       return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd);
-}
-
-/**
  * ecryptfs_lookup
  * @ecryptfs_dir_inode: The eCryptfs directory inode
  * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
@@ -434,7 +366,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        size_t encrypted_and_encoded_name_size;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
        struct dentry *lower_dir_dentry, *lower_dentry;
-       struct qstr lower_name;
        int rc = 0;
 
        if ((ecryptfs_dentry->d_name.len == 1
@@ -444,20 +375,14 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                goto out_d_drop;
        }
        lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);
-       lower_name.name = ecryptfs_dentry->d_name.name;
-       lower_name.len = ecryptfs_dentry->d_name.len;
-       lower_name.hash = ecryptfs_dentry->d_name.hash;
-       if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
-               rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                               lower_dir_dentry->d_inode, &lower_name);
-               if (rc < 0)
-                       goto out_d_drop;
-       }
-       lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
-                                                lower_dir_dentry, &lower_name);
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
+       lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,
+                                     lower_dir_dentry,
+                                     ecryptfs_dentry->d_name.len);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
                                "[%d] on lower_dentry = [%s]\n", __func__, rc,
                                encrypted_and_encoded_name);
                goto out_d_drop;
@@ -479,28 +404,21 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                       "filename; rc = [%d]\n", __func__, rc);
                goto out_d_drop;
        }
-       lower_name.name = encrypted_and_encoded_name;
-       lower_name.len = encrypted_and_encoded_name_size;
-       lower_name.hash = full_name_hash(lower_name.name, lower_name.len);
-       if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
-               rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                               lower_dir_dentry->d_inode, &lower_name);
-               if (rc < 0)
-                       goto out_d_drop;
-       }
-       lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
-                                                lower_dir_dentry, &lower_name);
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
+       lower_dentry = lookup_one_len(encrypted_and_encoded_name,
+                                     lower_dir_dentry,
+                                     encrypted_and_encoded_name_size);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
                                "[%d] on lower_dentry = [%s]\n", __func__, rc,
                                encrypted_and_encoded_name);
                goto out_d_drop;
        }
 lookup_and_interpose:
        rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
-                                                ecryptfs_dir_inode,
-                                                ecryptfs_nd);
+                                                ecryptfs_dir_inode);
        goto out;
 out_d_drop:
        d_drop(ecryptfs_dentry);
@@ -1092,6 +1010,8 @@ int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        rc = vfs_getattr(ecryptfs_dentry_to_lower_mnt(dentry),
                         ecryptfs_dentry_to_lower(dentry), &lower_stat);
        if (!rc) {
+               fsstack_copy_attr_all(dentry->d_inode,
+                                     ecryptfs_inode_to_lower(dentry->d_inode));
                generic_fillattr(dentry->d_inode, stat);
                stat->blocks = lower_stat.blocks;
        }
index e0194b3..d9a5917 100644 (file)
@@ -99,7 +99,7 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_get);
  * @ctx: [in] Pointer to eventfd context.
  *
  * The eventfd context reference must have been previously acquired either
- * with eventfd_ctx_get() or eventfd_ctx_fdget()).
+ * with eventfd_ctx_get() or eventfd_ctx_fdget().
  */
 void eventfd_ctx_put(struct eventfd_ctx *ctx)
 {
@@ -146,9 +146,9 @@ static void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt)
  * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue.
  * @ctx: [in] Pointer to eventfd context.
  * @wait: [in] Wait queue to be removed.
- * @cnt: [out] Pointer to the 64bit conter value.
+ * @cnt: [out] Pointer to the 64-bit counter value.
  *
- * Returns zero if successful, or the following error codes:
+ * Returns %0 if successful, or the following error codes:
  *
  * -EAGAIN      : The operation would have blocked.
  *
@@ -175,11 +175,11 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue);
  * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero.
  * @ctx: [in] Pointer to eventfd context.
  * @no_wait: [in] Different from zero if the operation should not block.
- * @cnt: [out] Pointer to the 64bit conter value.
+ * @cnt: [out] Pointer to the 64-bit counter value.
  *
- * Returns zero if successful, or the following error codes:
+ * Returns %0 if successful, or the following error codes:
  *
- * -EAGAIN      : The operation would have blocked but @no_wait was nonzero.
+ * -EAGAIN      : The operation would have blocked but @no_wait was non-zero.
  * -ERESTARTSYS : A signal interrupted the wait operation.
  *
  * If @no_wait is zero, the function might sleep until the eventfd internal
index cc8a9b7..4a09af9 100644 (file)
  * cleanup path and it is also acquired by eventpoll_release_file()
  * if a file has been pushed inside an epoll set and it is then
  * close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL).
+ * It is also acquired when inserting an epoll fd onto another epoll
+ * fd. We do this so that we walk the epoll tree and ensure that this
+ * insertion does not create a cycle of epoll file descriptors, which
+ * could lead to deadlock. We need a global mutex to prevent two
+ * simultaneous inserts (A into B and B into A) from racing and
+ * constructing a cycle without either insert observing that it is
+ * going to.
  * It is possible to drop the "ep->mtx" and to use the global
  * mutex "epmutex" (together with "ep->lock") to have it working,
  * but having "ep->mtx" will make the interface more scalable.
@@ -224,6 +231,9 @@ static long max_user_watches __read_mostly;
  */
 static DEFINE_MUTEX(epmutex);
 
+/* Used to check for epoll file descriptor inclusion loops */
+static struct nested_calls poll_loop_ncalls;
+
 /* Used for safe wake up implementation */
 static struct nested_calls poll_safewake_ncalls;
 
@@ -1114,6 +1124,17 @@ static int ep_send_events(struct eventpoll *ep,
        return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
 }
 
+static inline struct timespec ep_set_mstimeout(long ms)
+{
+       struct timespec now, ts = {
+               .tv_sec = ms / MSEC_PER_SEC,
+               .tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC),
+       };
+
+       ktime_get_ts(&now);
+       return timespec_add_safe(now, ts);
+}
+
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout)
 {
@@ -1121,12 +1142,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
        unsigned long flags;
        long slack;
        wait_queue_t wait;
-       struct timespec end_time;
        ktime_t expires, *to = NULL;
 
        if (timeout > 0) {
-               ktime_get_ts(&end_time);
-               timespec_add_ns(&end_time, (u64)timeout * NSEC_PER_MSEC);
+               struct timespec end_time = ep_set_mstimeout(timeout);
+
                slack = select_estimate_accuracy(&end_time);
                to = &expires;
                *to = timespec_to_ktime(end_time);
@@ -1188,6 +1208,62 @@ retry:
        return res;
 }
 
+/**
+ * ep_loop_check_proc - Callback function to be passed to the @ep_call_nested()
+ *                      API, to verify that adding an epoll file inside another
+ *                      epoll structure, does not violate the constraints, in
+ *                      terms of closed loops, or too deep chains (which can
+ *                      result in excessive stack usage).
+ *
+ * @priv: Pointer to the epoll file to be currently checked.
+ * @cookie: Original cookie for this call. This is the top-of-the-chain epoll
+ *          data structure pointer.
+ * @call_nests: Current dept of the @ep_call_nested() call stack.
+ *
+ * Returns: Returns zero if adding the epoll @file inside current epoll
+ *          structure @ep does not violate the constraints, or -1 otherwise.
+ */
+static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
+{
+       int error = 0;
+       struct file *file = priv;
+       struct eventpoll *ep = file->private_data;
+       struct rb_node *rbp;
+       struct epitem *epi;
+
+       mutex_lock(&ep->mtx);
+       for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+               epi = rb_entry(rbp, struct epitem, rbn);
+               if (unlikely(is_file_epoll(epi->ffd.file))) {
+                       error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                                              ep_loop_check_proc, epi->ffd.file,
+                                              epi->ffd.file->private_data, current);
+                       if (error != 0)
+                               break;
+               }
+       }
+       mutex_unlock(&ep->mtx);
+
+       return error;
+}
+
+/**
+ * ep_loop_check - Performs a check to verify that adding an epoll file (@file)
+ *                 another epoll file (represented by @ep) does not create
+ *                 closed loops or too deep chains.
+ *
+ * @ep: Pointer to the epoll private data structure.
+ * @file: Pointer to the epoll file to be checked.
+ *
+ * Returns: Returns zero if adding the epoll @file inside current epoll
+ *          structure @ep does not violate the constraints, or -1 otherwise.
+ */
+static int ep_loop_check(struct eventpoll *ep, struct file *file)
+{
+       return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                             ep_loop_check_proc, file, ep, current);
+}
+
 /*
  * Open an eventpoll file descriptor.
  */
@@ -1236,6 +1312,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                struct epoll_event __user *, event)
 {
        int error;
+       int did_lock_epmutex = 0;
        struct file *file, *tfile;
        struct eventpoll *ep;
        struct epitem *epi;
@@ -1277,6 +1354,25 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
         */
        ep = file->private_data;
 
+       /*
+        * When we insert an epoll file descriptor, inside another epoll file
+        * descriptor, there is the change of creating closed loops, which are
+        * better be handled here, than in more critical paths.
+        *
+        * We hold epmutex across the loop check and the insert in this case, in
+        * order to prevent two separate inserts from racing and each doing the
+        * insert "at the same time" such that ep_loop_check passes on both
+        * before either one does the insert, thereby creating a cycle.
+        */
+       if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) {
+               mutex_lock(&epmutex);
+               did_lock_epmutex = 1;
+               error = -ELOOP;
+               if (ep_loop_check(ep, tfile) != 0)
+                       goto error_tgt_fput;
+       }
+
+
        mutex_lock(&ep->mtx);
 
        /*
@@ -1312,6 +1408,9 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
+       if (unlikely(did_lock_epmutex))
+               mutex_unlock(&epmutex);
+
        fput(tfile);
 error_fput:
        fput(file);
@@ -1431,6 +1530,12 @@ static int __init eventpoll_init(void)
                EP_ITEM_COST;
        BUG_ON(max_user_watches < 0);
 
+       /*
+        * Initialize the structure used to perform epoll file descriptor
+        * inclusion loops checks.
+        */
+       ep_nested_calls_init(&poll_loop_ncalls);
+
        /* Initialize the structure used to perform safe poll wait head wake ups */
        ep_nested_calls_init(&poll_safewake_ncalls);
 
index c62efcb..52a447d 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -120,7 +120,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
                goto out;
 
        file = do_filp_open(AT_FDCWD, tmp,
-                               O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
+                               O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
                                MAY_READ | MAY_EXEC | MAY_OPEN);
        putname(tmp);
        error = PTR_ERR(file);
@@ -723,7 +723,7 @@ struct file *open_exec(const char *name)
        int err;
 
        file = do_filp_open(AT_FDCWD, name,
-                               O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
+                               O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
                                MAY_EXEC | MAY_OPEN);
        if (IS_ERR(file))
                goto out;
index 4268542..a755523 100644 (file)
@@ -1030,7 +1030,6 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
        }
 
-       inode->i_mapping->backing_dev_info = sb->s_bdi;
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &exofs_file_inode_operations;
                inode->i_fop = &exofs_file_operations;
@@ -1131,7 +1130,6 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
 
        sbi = sb->s_fs_info;
 
-       inode->i_mapping->backing_dev_info = sb->s_bdi;
        sb->s_dirt = 1;
        inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
index 264e95d..4d70db1 100644 (file)
@@ -272,7 +272,6 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                err = exofs_set_link(new_dir, new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME;
                if (dir_de)
@@ -286,12 +285,9 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= EXOFS_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = exofs_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -299,7 +295,7 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_inode->i_ctime = CURRENT_TIME;
 
        exofs_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
index 2e1d834..adb9185 100644 (file)
@@ -344,7 +344,6 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -356,12 +355,9 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                        if (new_dir->i_nlink >= EXT2_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = ext2_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -369,12 +365,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
        /*
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
-        * inode_dec_link_count() will mark the inode dirty.
         */
        old_inode->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(old_inode);
 
        ext2_delete_entry (old_de, old_page);
-       inode_dec_link_count(old_inode);
 
        if (dir_de) {
                if (old_dir != new_dir)
index 7aa767d..85c8cc8 100644 (file)
@@ -754,7 +754,7 @@ static int ext3_release_dquot(struct dquot *dquot);
 static int ext3_mark_dquot_dirty(struct dquot *dquot);
 static int ext3_write_info(struct super_block *sb, int type);
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path);
+                        struct path *path);
 static int ext3_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -2877,27 +2877,20 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
  * Standard function to be called on quota_on
  */
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name)
+                        struct path *path)
 {
        int err;
-       struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
 
-       err = kern_path(name, LOOKUP_FOLLOW, &path);
-       if (err)
-               return err;
-
        /* Quotafile not on the same filesystem? */
-       if (path.mnt->mnt_sb != sb) {
-               path_put(&path);
+       if (path->mnt->mnt_sb != sb)
                return -EXDEV;
-       }
        /* Journaling quota? */
        if (EXT3_SB(sb)->s_qf_names[type]) {
                /* Quotafile not of fs root? */
-               if (path.dentry->d_parent != sb->s_root)
+               if (path->dentry->d_parent != sb->s_root)
                        ext3_msg(sb, KERN_WARNING,
                                "warning: Quota file not on filesystem root. "
                                "Journaled quota will not work.");
@@ -2907,7 +2900,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
         * When we journal data on quota file, we have to flush journal to see
         * all updates to the file when we bypass pagecache...
         */
-       if (ext3_should_journal_data(path.dentry->d_inode)) {
+       if (ext3_should_journal_data(path->dentry->d_inode)) {
                /*
                 * We don't need to lock updates but journal_flush() could
                 * otherwise be livelocked...
@@ -2915,15 +2908,11 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
                journal_lock_updates(EXT3_SB(sb)->s_journal);
                err = journal_flush(EXT3_SB(sb)->s_journal);
                journal_unlock_updates(EXT3_SB(sb)->s_journal);
-               if (err) {
-                       path_put(&path);
+               if (err)
                        return err;
-               }
        }
 
-       err = dquot_quota_on_path(sb, type, format_id, &path);
-       path_put(&path);
-       return err;
+       return dquot_quota_on(sb, type, format_id, path);
 }
 
 /* Read data from quotafile - avoid pagecache and such because we cannot afford
index 0c8d97b..3aa0b72 100644 (file)
@@ -848,6 +848,7 @@ struct ext4_inode_info {
        atomic_t i_ioend_count; /* Number of outstanding io_end structs */
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_aiodio_unwritten; /* Nr. of inflight conversions pending */
 
        spinlock_t i_block_reservation_lock;
 
@@ -2119,6 +2120,15 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) <= (first) + (len) - 1)
 
+/* For ioend & aio unwritten conversion wait queues */
+#define EXT4_WQ_HASH_SZ                37
+#define ext4_ioend_wq(v)   (&ext4__ioend_wq[((unsigned long)(v)) %\
+                                           EXT4_WQ_HASH_SZ])
+#define ext4_aio_mutex(v)  (&ext4__aio_mutex[((unsigned long)(v)) %\
+                                            EXT4_WQ_HASH_SZ])
+extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
+extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
+
 #endif /* __KERNEL__ */
 
 #endif /* _EXT4_H */
index 63a7581..ccce8a7 100644 (file)
@@ -3174,9 +3174,10 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                 * that this IO needs to convertion to written when IO is
                 * completed
                 */
-               if (io)
+               if (io && !(io->flag & EXT4_IO_END_UNWRITTEN)) {
                        io->flag = EXT4_IO_END_UNWRITTEN;
-               else
+                       atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+               } else
                        ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
                if (ext4_should_dioread_nolock(inode))
                        map->m_flags |= EXT4_MAP_UNINIT;
@@ -3463,9 +3464,10 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                 * that we need to perform convertion when IO is done.
                 */
                if ((flags & EXT4_GET_BLOCKS_PRE_IO)) {
-                       if (io)
+                       if (io && !(io->flag & EXT4_IO_END_UNWRITTEN)) {
                                io->flag = EXT4_IO_END_UNWRITTEN;
-                       else
+                               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+                       } else
                                ext4_set_inode_state(inode,
                                                     EXT4_STATE_DIO_UNWRITTEN);
                }
index 2e8322c..7b80d54 100644 (file)
@@ -55,11 +55,47 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static void ext4_aiodio_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = ext4_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_aiodio_unwritten) == 0));
+}
+
+/*
+ * This tests whether the IO in question is block-aligned or not.
+ * Ext4 utilizes unwritten extents when hole-filling during direct IO, and they
+ * are converted to written only after the IO is complete.  Until they are
+ * mapped, these blocks appear as holes, so dio_zero_block() will assume that
+ * it needs to zero out portions of the start and/or end block.  If 2 AIO
+ * threads are at work on the same unwritten block, they must be synchronized
+ * or one thread will zero the other's data, causing corruption.
+ */
+static int
+ext4_unaligned_aio(struct inode *inode, const struct iovec *iov,
+                  unsigned long nr_segs, loff_t pos)
+{
+       struct super_block *sb = inode->i_sb;
+       int blockmask = sb->s_blocksize - 1;
+       size_t count = iov_length(iov, nr_segs);
+       loff_t final_size = pos + count;
+
+       if (pos >= inode->i_size)
+               return 0;
+
+       if ((pos & blockmask) || (final_size & blockmask))
+               return 1;
+
+       return 0;
+}
+
 static ssize_t
 ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
                unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+       int unaligned_aio = 0;
+       int ret;
 
        /*
         * If we have encountered a bitmap-format file, the size limit
@@ -78,9 +114,31 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
                        nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
                                              sbi->s_bitmap_maxbytes - pos);
                }
+       } else if (unlikely((iocb->ki_filp->f_flags & O_DIRECT) &&
+                  !is_sync_kiocb(iocb))) {
+               unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos);
        }
 
-       return generic_file_aio_write(iocb, iov, nr_segs, pos);
+       /* Unaligned direct AIO must be serialized; see comment above */
+       if (unaligned_aio) {
+               static unsigned long unaligned_warn_time;
+
+               /* Warn about this once per day */
+               if (printk_timed_ratelimit(&unaligned_warn_time, 60*60*24*HZ))
+                       ext4_msg(inode->i_sb, KERN_WARNING,
+                                "Unaligned AIO/DIO on inode %ld by %s; "
+                                "performance will be poor.",
+                                inode->i_ino, current->comm);
+               mutex_lock(ext4_aio_mutex(inode));
+               ext4_aiodio_wait(inode);
+       }
+
+       ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+       if (unaligned_aio)
+               mutex_unlock(ext4_aio_mutex(inode));
+
+       return ret;
 }
 
 static const struct vm_operations_struct ext4_file_vm_ops = {
index 851f49b..d1fe09a 100644 (file)
@@ -342,10 +342,15 @@ static struct kmem_cache *ext4_free_ext_cachep;
 /* We create slab caches for groupinfo data structures based on the
  * superblock block size.  There will be one per mounted filesystem for
  * each unique s_blocksize_bits */
-#define NR_GRPINFO_CACHES      \
-       (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE + 1)
+#define NR_GRPINFO_CACHES 8
 static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES];
 
+static const char *ext4_groupinfo_slab_names[NR_GRPINFO_CACHES] = {
+       "ext4_groupinfo_1k", "ext4_groupinfo_2k", "ext4_groupinfo_4k",
+       "ext4_groupinfo_8k", "ext4_groupinfo_16k", "ext4_groupinfo_32k",
+       "ext4_groupinfo_64k", "ext4_groupinfo_128k"
+};
+
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
@@ -2414,6 +2419,55 @@ err_freesgi:
        return -ENOMEM;
 }
 
+static void ext4_groupinfo_destroy_slabs(void)
+{
+       int i;
+
+       for (i = 0; i < NR_GRPINFO_CACHES; i++) {
+               if (ext4_groupinfo_caches[i])
+                       kmem_cache_destroy(ext4_groupinfo_caches[i]);
+               ext4_groupinfo_caches[i] = NULL;
+       }
+}
+
+static int ext4_groupinfo_create_slab(size_t size)
+{
+       static DEFINE_MUTEX(ext4_grpinfo_slab_create_mutex);
+       int slab_size;
+       int blocksize_bits = order_base_2(size);
+       int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
+       struct kmem_cache *cachep;
+
+       if (cache_index >= NR_GRPINFO_CACHES)
+               return -EINVAL;
+
+       if (unlikely(cache_index < 0))
+               cache_index = 0;
+
+       mutex_lock(&ext4_grpinfo_slab_create_mutex);
+       if (ext4_groupinfo_caches[cache_index]) {
+               mutex_unlock(&ext4_grpinfo_slab_create_mutex);
+               return 0;       /* Already created */
+       }
+
+       slab_size = offsetof(struct ext4_group_info,
+                               bb_counters[blocksize_bits + 2]);
+
+       cachep = kmem_cache_create(ext4_groupinfo_slab_names[cache_index],
+                                       slab_size, 0, SLAB_RECLAIM_ACCOUNT,
+                                       NULL);
+
+       mutex_unlock(&ext4_grpinfo_slab_create_mutex);
+       if (!cachep) {
+               printk(KERN_EMERG "EXT4: no memory for groupinfo slab cache\n");
+               return -ENOMEM;
+       }
+
+       ext4_groupinfo_caches[cache_index] = cachep;
+
+       return 0;
+}
+
 int ext4_mb_init(struct super_block *sb, int needs_recovery)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2421,9 +2475,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        unsigned offset;
        unsigned max;
        int ret;
-       int cache_index;
-       struct kmem_cache *cachep;
-       char *namep = NULL;
 
        i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets);
 
@@ -2440,30 +2491,9 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                goto out;
        }
 
-       cache_index = sb->s_blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
-       cachep = ext4_groupinfo_caches[cache_index];
-       if (!cachep) {
-               char name[32];
-               int len = offsetof(struct ext4_group_info,
-                                       bb_counters[sb->s_blocksize_bits + 2]);
-
-               sprintf(name, "ext4_groupinfo_%d", sb->s_blocksize_bits);
-               namep = kstrdup(name, GFP_KERNEL);
-               if (!namep) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               /* Need to free the kmem_cache_name() when we
-                * destroy the slab */
-               cachep = kmem_cache_create(namep, len, 0,
-                                            SLAB_RECLAIM_ACCOUNT, NULL);
-               if (!cachep) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               ext4_groupinfo_caches[cache_index] = cachep;
-       }
+       ret = ext4_groupinfo_create_slab(sb->s_blocksize);
+       if (ret < 0)
+               goto out;
 
        /* order 0 is regular bitmap */
        sbi->s_mb_maxs[0] = sb->s_blocksize << 3;
@@ -2520,7 +2550,6 @@ out:
        if (ret) {
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
-               kfree(namep);
        }
        return ret;
 }
@@ -2734,7 +2763,6 @@ int __init ext4_init_mballoc(void)
 
 void ext4_exit_mballoc(void)
 {
-       int i;
        /*
         * Wait for completion of call_rcu()'s on ext4_pspace_cachep
         * before destroying the slab cache.
@@ -2743,15 +2771,7 @@ void ext4_exit_mballoc(void)
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
        kmem_cache_destroy(ext4_free_ext_cachep);
-
-       for (i = 0; i < NR_GRPINFO_CACHES; i++) {
-               struct kmem_cache *cachep = ext4_groupinfo_caches[i];
-               if (cachep) {
-                       char *name = (char *)kmem_cache_name(cachep);
-                       kmem_cache_destroy(cachep);
-                       kfree(name);
-               }
-       }
+       ext4_groupinfo_destroy_slabs();
        ext4_remove_debugfs_entry();
 }
 
index 7270dcf..955cc30 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;
@@ -48,9 +42,6 @@ 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;
 }
 
@@ -62,7 +53,7 @@ void ext4_exit_pageio(void)
 
 void ext4_ioend_wait(struct inode *inode)
 {
-       wait_queue_head_t *wq = to_ioend_wq(inode);
+       wait_queue_head_t *wq = ext4_ioend_wq(inode);
 
        wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
 }
@@ -87,7 +78,7 @@ void ext4_free_io_end(ext4_io_end_t *io)
        for (i = 0; i < io->num_io_pages; i++)
                put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       wq = to_ioend_wq(io->inode);
+       wq = ext4_ioend_wq(io->inode);
        if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
            waitqueue_active(wq))
                wake_up_all(wq);
@@ -102,6 +93,7 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
        struct inode *inode = io->inode;
        loff_t offset = io->offset;
        ssize_t size = io->size;
+       wait_queue_head_t *wq;
        int ret = 0;
 
        ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
@@ -126,7 +118,16 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
        if (io->iocb)
                aio_complete(io->iocb, io->result, 0);
        /* clear the DIO AIO unwritten flag */
-       io->flag &= ~EXT4_IO_END_UNWRITTEN;
+       if (io->flag & EXT4_IO_END_UNWRITTEN) {
+               io->flag &= ~EXT4_IO_END_UNWRITTEN;
+               /* Wake up anyone waiting on unwritten extent conversion */
+               wq = ext4_ioend_wq(io->inode);
+               if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten) &&
+                   waitqueue_active(wq)) {
+                       wake_up_all(wq);
+               }
+       }
+
        return ret;
 }
 
@@ -190,6 +191,7 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct inode *inode;
        unsigned long flags;
        int i;
+       sector_t bi_sector = bio->bi_sector;
 
        BUG_ON(!io_end);
        bio->bi_private = NULL;
@@ -207,9 +209,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                if (error)
                        SetPageError(page);
                BUG_ON(!head);
-               if (head->b_size == PAGE_CACHE_SIZE)
-                       clear_buffer_dirty(head);
-               else {
+               if (head->b_size != PAGE_CACHE_SIZE) {
                        loff_t offset;
                        loff_t io_end_offset = io_end->offset + io_end->size;
 
@@ -221,7 +221,6 @@ static void ext4_end_bio(struct bio *bio, int error)
                                        if (error)
                                                buffer_io_error(bh);
 
-                                       clear_buffer_dirty(bh);
                                }
                                if (buffer_delay(bh))
                                        partial_write = 1;
@@ -257,7 +256,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                             (unsigned long long) io_end->offset,
                             (long) io_end->size,
                             (unsigned long long)
-                            bio->bi_sector >> (inode->i_blkbits - 9));
+                            bi_sector >> (inode->i_blkbits - 9));
        }
 
        /* Add the io_end to per-inode completed io list*/
@@ -380,6 +379,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
 
        blocksize = 1 << inode->i_blkbits;
 
+       BUG_ON(!PageLocked(page));
        BUG_ON(PageWriteback(page));
        set_page_writeback(page);
        ClearPageError(page);
@@ -397,12 +397,14 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
        for (bh = head = page_buffers(page), block_start = 0;
             bh != head || !block_start;
             block_start = block_end, bh = bh->b_this_page) {
+
                block_end = block_start + blocksize;
                if (block_start >= len) {
                        clear_buffer_dirty(bh);
                        set_buffer_uptodate(bh);
                        continue;
                }
+               clear_buffer_dirty(bh);
                ret = io_submit_add_bh(io, io_page, inode, wbc, bh);
                if (ret) {
                        /*
index cb10a06..f6a318f 100644 (file)
@@ -77,6 +77,7 @@ static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
                       const char *dev_name, void *data);
 static void ext4_destroy_lazyinit_thread(void);
 static void ext4_unregister_li_request(struct super_block *sb);
+static void ext4_clear_request_list(void);
 
 #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
 static struct file_system_type ext3_fs_type = {
@@ -832,6 +833,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
        atomic_set(&ei->i_ioend_count, 0);
+       atomic_set(&ei->i_aiodio_unwritten, 0);
 
        return &ei->vfs_inode;
 }
@@ -1161,7 +1163,7 @@ static int ext4_release_dquot(struct dquot *dquot);
 static int ext4_mark_dquot_dirty(struct dquot *dquot);
 static int ext4_write_info(struct super_block *sb, int type);
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path);
+                        struct path *path);
 static int ext4_quota_off(struct super_block *sb, int type);
 static int ext4_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
@@ -2716,6 +2718,8 @@ static void ext4_unregister_li_request(struct super_block *sb)
        mutex_unlock(&ext4_li_info->li_list_mtx);
 }
 
+static struct task_struct *ext4_lazyinit_task;
+
 /*
  * This is the function where ext4lazyinit thread lives. It walks
  * through the request list searching for next scheduled filesystem.
@@ -2784,6 +2788,10 @@ cont_thread:
                if (time_before(jiffies, next_wakeup))
                        schedule();
                finish_wait(&eli->li_wait_daemon, &wait);
+               if (kthread_should_stop()) {
+                       ext4_clear_request_list();
+                       goto exit_thread;
+               }
        }
 
 exit_thread:
@@ -2808,6 +2816,7 @@ exit_thread:
        wake_up(&eli->li_wait_task);
 
        kfree(ext4_li_info);
+       ext4_lazyinit_task = NULL;
        ext4_li_info = NULL;
        mutex_unlock(&ext4_li_mtx);
 
@@ -2830,11 +2839,10 @@ static void ext4_clear_request_list(void)
 
 static int ext4_run_lazyinit_thread(void)
 {
-       struct task_struct *t;
-
-       t = kthread_run(ext4_lazyinit_thread, ext4_li_info, "ext4lazyinit");
-       if (IS_ERR(t)) {
-               int err = PTR_ERR(t);
+       ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread,
+                                        ext4_li_info, "ext4lazyinit");
+       if (IS_ERR(ext4_lazyinit_task)) {
+               int err = PTR_ERR(ext4_lazyinit_task);
                ext4_clear_request_list();
                del_timer_sync(&ext4_li_info->li_timer);
                kfree(ext4_li_info);
@@ -2985,16 +2993,10 @@ static void ext4_destroy_lazyinit_thread(void)
         * If thread exited earlier
         * there's nothing to be done.
         */
-       if (!ext4_li_info)
+       if (!ext4_li_info || !ext4_lazyinit_task)
                return;
 
-       ext4_clear_request_list();
-
-       while (ext4_li_info->li_task) {
-               wake_up(&ext4_li_info->li_wait_daemon);
-               wait_event(ext4_li_info->li_wait_task,
-                          ext4_li_info->li_task == NULL);
-       }
+       kthread_stop(ext4_lazyinit_task);
 }
 
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
@@ -4558,27 +4560,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
  * Standard function to be called on quota_on
  */
 static int ext4_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name)
+                        struct path *path)
 {
        int err;
-       struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
 
-       err = kern_path(name, LOOKUP_FOLLOW, &path);
-       if (err)
-               return err;
-
        /* Quotafile not on the same filesystem? */
-       if (path.mnt->mnt_sb != sb) {
-               path_put(&path);
+       if (path->mnt->mnt_sb != sb)
                return -EXDEV;
-       }
        /* Journaling quota? */
        if (EXT4_SB(sb)->s_qf_names[type]) {
                /* Quotafile not in fs root? */
-               if (path.dentry->d_parent != sb->s_root)
+               if (path->dentry->d_parent != sb->s_root)
                        ext4_msg(sb, KERN_WARNING,
                                "Quota file not on filesystem root. "
                                "Journaled quota will not work");
@@ -4589,7 +4584,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
         * all updates to the file when we bypass pagecache...
         */
        if (EXT4_SB(sb)->s_journal &&
-           ext4_should_journal_data(path.dentry->d_inode)) {
+           ext4_should_journal_data(path->dentry->d_inode)) {
                /*
                 * We don't need to lock updates but journal_flush() could
                 * otherwise be livelocked...
@@ -4597,15 +4592,11 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
                err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
-               if (err) {
-                       path_put(&path);
+               if (err)
                        return err;
-               }
        }
 
-       err = dquot_quota_on_path(sb, type, format_id, &path);
-       path_put(&path);
-       return err;
+       return dquot_quota_on(sb, type, format_id, path);
 }
 
 static int ext4_quota_off(struct super_block *sb, int type)
@@ -4779,7 +4770,7 @@ static struct file_system_type ext4_fs_type = {
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
-int __init ext4_init_feat_adverts(void)
+static int __init ext4_init_feat_adverts(void)
 {
        struct ext4_features *ef;
        int ret = -ENOMEM;
@@ -4803,23 +4794,44 @@ out:
        return ret;
 }
 
+static void ext4_exit_feat_adverts(void)
+{
+       kobject_put(&ext4_feat->f_kobj);
+       wait_for_completion(&ext4_feat->f_kobj_unregister);
+       kfree(ext4_feat);
+}
+
+/* Shared across all ext4 file systems */
+wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
+struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
+
 static int __init ext4_init_fs(void)
 {
-       int err;
+       int i, err;
 
        ext4_check_flag_values();
+
+       for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
+               mutex_init(&ext4__aio_mutex[i]);
+               init_waitqueue_head(&ext4__ioend_wq[i]);
+       }
+
        err = ext4_init_pageio();
        if (err)
                return err;
        err = ext4_init_system_zone();
        if (err)
-               goto out5;
+               goto out7;
        ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
        if (!ext4_kset)
-               goto out4;
+               goto out6;
        ext4_proc_root = proc_mkdir("fs/ext4", NULL);
+       if (!ext4_proc_root)
+               goto out5;
 
        err = ext4_init_feat_adverts();
+       if (err)
+               goto out4;
 
        err = ext4_init_mballoc();
        if (err)
@@ -4849,12 +4861,14 @@ out1:
 out2:
        ext4_exit_mballoc();
 out3:
-       kfree(ext4_feat);
+       ext4_exit_feat_adverts();
+out4:
        remove_proc_entry("fs/ext4", NULL);
+out5:
        kset_unregister(ext4_kset);
-out4:
+out6:
        ext4_exit_system_zone();
-out5:
+out7:
        ext4_exit_pageio();
        return err;
 }
@@ -4868,6 +4882,7 @@ static void __exit ext4_exit_fs(void)
        destroy_inodecache();
        ext4_exit_xattr();
        ext4_exit_mballoc();
+       ext4_exit_feat_adverts();
        remove_proc_entry("fs/ext4", NULL);
        kset_unregister(ext4_kset);
        ext4_exit_system_zone();
index ecc8b39..cb10261 100644 (file)
@@ -815,7 +815,7 @@ static int __init fcntl_init(void)
                __O_SYNC        | O_DSYNC       | FASYNC        |
                O_DIRECT        | O_LARGEFILE   | O_DIRECTORY   |
                O_NOFOLLOW      | O_NOATIME     | O_CLOEXEC     |
-               FMODE_EXEC
+               __FMODE_EXEC
                ));
 
        fasync_cache = kmem_cache_create("fasync_cache",
index c3e89ad..eb36b6b 100644 (file)
@@ -125,13 +125,13 @@ struct file *get_empty_filp(void)
                goto fail;
 
        percpu_counter_inc(&nr_files);
+       f->f_cred = get_cred(cred);
        if (security_file_alloc(f))
                goto fail_sec;
 
        INIT_LIST_HEAD(&f->f_u.fu_list);
        atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
-       f->f_cred = get_cred(cred);
        spin_lock_init(&f->f_lock);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
index bfed844..83543b5 100644 (file)
@@ -1283,8 +1283,11 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
        if (err)
                return err;
 
-       if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
-               return 0;
+       if (attr->ia_valid & ATTR_OPEN) {
+               if (fc->atomic_o_trunc)
+                       return 0;
+               file = NULL;
+       }
 
        if (attr->ia_valid & ATTR_SIZE)
                is_truncate = true;
index 95da1bc..9e0832d 100644 (file)
@@ -86,18 +86,52 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff)
        return ff;
 }
 
+static void fuse_release_async(struct work_struct *work)
+{
+       struct fuse_req *req;
+       struct fuse_conn *fc;
+       struct path path;
+
+       req = container_of(work, struct fuse_req, misc.release.work);
+       path = req->misc.release.path;
+       fc = get_fuse_conn(path.dentry->d_inode);
+
+       fuse_put_request(fc, req);
+       path_put(&path);
+}
+
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       path_put(&req->misc.release.path);
+       if (fc->destroy_req) {
+               /*
+                * If this is a fuseblk mount, then it's possible that
+                * releasing the path will result in releasing the
+                * super block and sending the DESTROY request.  If
+                * the server is single threaded, this would hang.
+                * For this reason do the path_put() in a separate
+                * thread.
+                */
+               atomic_inc(&req->count);
+               INIT_WORK(&req->misc.release.work, fuse_release_async);
+               schedule_work(&req->misc.release.work);
+       } else {
+               path_put(&req->misc.release.path);
+       }
 }
 
-static void fuse_file_put(struct fuse_file *ff)
+static void fuse_file_put(struct fuse_file *ff, bool sync)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
 
-               req->end = fuse_release_end;
-               fuse_request_send_background(ff->fc, req);
+               if (sync) {
+                       fuse_request_send(ff->fc, req);
+                       path_put(&req->misc.release.path);
+                       fuse_put_request(ff->fc, req);
+               } else {
+                       req->end = fuse_release_end;
+                       fuse_request_send_background(ff->fc, req);
+               }
                kfree(ff);
        }
 }
@@ -219,8 +253,12 @@ void fuse_release_common(struct file *file, int opcode)
         * Normally this will send the RELEASE request, however if
         * some asynchronous READ or WRITE requests are outstanding,
         * the sending will be delayed.
+        *
+        * Make the release synchronous if this is a fuseblk mount,
+        * synchronous RELEASE is allowed (and desirable) in this case
+        * because the server can be trusted not to screw up.
         */
-       fuse_file_put(ff);
+       fuse_file_put(ff, ff->fc->destroy_req != NULL);
 }
 
 static int fuse_open(struct inode *inode, struct file *file)
@@ -558,7 +596,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
                page_cache_release(page);
        }
        if (req->ff)
-               fuse_file_put(req->ff);
+               fuse_file_put(req->ff, false);
 }
 
 static void fuse_send_readpages(struct fuse_req *req, struct file *file)
@@ -1137,7 +1175,7 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
 static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
 {
        __free_page(req->pages[0]);
-       fuse_file_put(req->ff);
+       fuse_file_put(req->ff, false);
 }
 
 static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
index ae5744a..d428694 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/rwsem.h>
 #include <linux/rbtree.h>
 #include <linux/poll.h>
+#include <linux/workqueue.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -262,7 +263,10 @@ struct fuse_req {
        /** Data for asynchronous requests */
        union {
                struct {
-                       struct fuse_release_in in;
+                       union {
+                               struct fuse_release_in in;
+                               struct work_struct work;
+                       };
                        struct path path;
                } release;
                struct fuse_init_in init_in;
index 08a8beb..7cd9a5a 100644 (file)
@@ -1779,11 +1779,11 @@ int __init gfs2_glock_init(void)
 #endif
 
        glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM |
-                                         WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+                                         WQ_HIGHPRI | WQ_FREEZABLE, 0);
        if (IS_ERR(glock_workqueue))
                return PTR_ERR(glock_workqueue);
        gfs2_delete_workqueue = alloc_workqueue("delete_workqueue",
-                                               WQ_MEM_RECLAIM | WQ_FREEZEABLE,
+                                               WQ_MEM_RECLAIM | WQ_FREEZABLE,
                                                0);
        if (IS_ERR(gfs2_delete_workqueue)) {
                destroy_workqueue(glock_workqueue);
index 2232b3c..7aa7d4f 100644 (file)
@@ -74,16 +74,14 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
 }
 
 /**
- * GFS2 lookup code fills in vfs inode contents based on info obtained
- * from directory entry inside gfs2_inode_lookup(). This has caused issues
- * with NFS code path since its get_dentry routine doesn't have the relevant
- * directory entry when gfs2_inode_lookup() is invoked. Part of the code
- * segment inside gfs2_inode_lookup code needs to get moved around.
+ * gfs2_set_iop - Sets inode operations
+ * @inode: The inode with correct i_mode filled in
  *
- * Clears I_NEW as well.
- **/
+ * GFS2 lookup code fills in vfs inode contents based on info obtained
+ * from directory entry inside gfs2_inode_lookup().
+ */
 
-void gfs2_set_iop(struct inode *inode)
+static void gfs2_set_iop(struct inode *inode)
 {
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        umode_t mode = inode->i_mode;
@@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode)
                inode->i_op = &gfs2_file_iops;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
        }
-
-       unlock_new_inode(inode);
 }
 
 /**
@@ -119,10 +115,8 @@ void gfs2_set_iop(struct inode *inode)
  * Returns: A VFS inode, or an error
  */
 
-struct inode *gfs2_inode_lookup(struct super_block *sb,
-                               unsigned int type,
-                               u64 no_addr,
-                               u64 no_formal_ino)
+struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
+                               u64 no_addr, u64 no_formal_ino)
 {
        struct inode *inode;
        struct gfs2_inode *ip;
@@ -152,51 +146,37 @@ struct inode *gfs2_inode_lookup(struct super_block *sb,
                error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
                if (unlikely(error))
                        goto fail_iopen;
-               ip->i_iopen_gh.gh_gl->gl_object = ip;
 
+               ip->i_iopen_gh.gh_gl->gl_object = ip;
                gfs2_glock_put(io_gl);
                io_gl = NULL;
 
-               if ((type == DT_UNKNOWN) && (no_formal_ino == 0))
-                       goto gfs2_nfsbypass;
-
-               inode->i_mode = DT2IF(type);
-
-               /*
-                * We must read the inode in order to work out its type in
-                * this case. Note that this doesn't happen often as we normally
-                * know the type beforehand. This code path only occurs during
-                * unlinked inode recovery (where it is safe to do this glock,
-                * which is not true in the general case).
-                */
                if (type == DT_UNKNOWN) {
-                       struct gfs2_holder gh;
-                       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-                       if (unlikely(error))
-                               goto fail_glock;
-                       /* Inode is now uptodate */
-                       gfs2_glock_dq_uninit(&gh);
+                       /* Inode glock must be locked already */
+                       error = gfs2_inode_refresh(GFS2_I(inode));
+                       if (error)
+                               goto fail_refresh;
+               } else {
+                       inode->i_mode = DT2IF(type);
                }
 
                gfs2_set_iop(inode);
+               unlock_new_inode(inode);
        }
 
-gfs2_nfsbypass:
        return inode;
-fail_glock:
-       gfs2_glock_dq(&ip->i_iopen_gh);
+
+fail_refresh:
+       ip->i_iopen_gh.gh_gl->gl_object = NULL;
+       gfs2_glock_dq_uninit(&ip->i_iopen_gh);
 fail_iopen:
        if (io_gl)
                gfs2_glock_put(io_gl);
 fail_put:
-       if (inode->i_state & I_NEW)
-               ip->i_gl->gl_object = NULL;
+       ip->i_gl->gl_object = NULL;
        gfs2_glock_put(ip->i_gl);
 fail:
-       if (inode->i_state & I_NEW)
-               iget_failed(inode);
-       else
-               iput(inode);
+       iget_failed(inode);
        return ERR_PTR(error);
 }
 
@@ -221,14 +201,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
        if (IS_ERR(inode))
                goto fail;
 
-       error = gfs2_inode_refresh(GFS2_I(inode));
-       if (error)
-               goto fail_iput;
-
-       /* Pick up the works we bypass in gfs2_inode_lookup */
-       if (inode->i_state & I_NEW) 
-               gfs2_set_iop(inode);
-
        /* Two extra checks for NFS only */
        if (no_formal_ino) {
                error = -ESTALE;
index 732a183..3e00a66 100644 (file)
@@ -96,7 +96,6 @@ err:
        return -EIO;
 }
 
-extern void gfs2_set_iop(struct inode *inode);
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
                                       u64 no_addr, u64 no_formal_ino);
 extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
index ebef7ab..72c31a3 100644 (file)
@@ -59,14 +59,7 @@ static void gfs2_init_gl_aspace_once(void *foo)
        struct address_space *mapping = (struct address_space *)(gl + 1);
 
        gfs2_init_glock_once(gl);
-       memset(mapping, 0, sizeof(*mapping));
-       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
-       spin_lock_init(&mapping->tree_lock);
-       spin_lock_init(&mapping->i_mmap_lock);
-       INIT_LIST_HEAD(&mapping->private_list);
-       spin_lock_init(&mapping->private_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
-       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
+       address_space_init_once(mapping);
 }
 
 /**
@@ -144,7 +137,7 @@ static int __init init_gfs2_fs(void)
 
        error = -ENOMEM;
        gfs_recovery_wq = alloc_workqueue("gfs_recovery",
-                                         WQ_MEM_RECLAIM | WQ_FREEZEABLE, 0);
+                                         WQ_MEM_RECLAIM | WQ_FREEZABLE, 0);
        if (!gfs_recovery_wq)
                goto fail_wq;
 
index 16c2eca..ec73ed7 100644 (file)
@@ -1336,6 +1336,7 @@ static void gfs2_evict_inode(struct inode *inode)
        if (error)
                goto out_truncate;
 
+       ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
        gfs2_glock_dq_wait(&ip->i_iopen_gh);
        gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
        error = gfs2_glock_nq(&ip->i_iopen_gh);
index afa66aa..b4d70b1 100644 (file)
@@ -238,46 +238,22 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 }
 
 /*
- * hfs_unlink()
+ * hfs_remove()
  *
- * This is the unlink() entry in the inode_operations structure for
- * regular HFS directories.  The purpose is to delete an existing
- * file, given the inode for the parent directory and the name
- * (and its length) of the existing file.
- */
-static int hfs_unlink(struct inode *dir, struct dentry *dentry)
-{
-       struct inode *inode;
-       int res;
-
-       inode = dentry->d_inode;
-       res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
-       if (res)
-               return res;
-
-       drop_nlink(inode);
-       hfs_delete_inode(inode);
-       inode->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(inode);
-
-       return res;
-}
-
-/*
- * hfs_rmdir()
+ * This serves as both unlink() and rmdir() in the inode_operations
+ * structure for regular HFS directories.  The purpose is to delete
+ * an existing child, given the inode for the parent directory and
+ * the name (and its length) of the existing directory.
  *
- * This is the rmdir() entry in the inode_operations structure for
- * regular HFS directories.  The purpose is to delete an existing
- * directory, given the inode for the parent directory and the name
- * (and its length) of the existing directory.
+ * HFS does not have hardlinks, so both rmdir and unlink set the
+ * link count to 0.  The only difference is the emptiness check.
  */
-static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int hfs_remove(struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode;
+       struct inode *inode = dentry->d_inode;
        int res;
 
-       inode = dentry->d_inode;
-       if (inode->i_size != 2)
+       if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
                return -ENOTEMPTY;
        res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
        if (res)
@@ -307,7 +283,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        /* Unlink destination if it already exists */
        if (new_dentry->d_inode) {
-               res = hfs_unlink(new_dir, new_dentry);
+               res = hfs_remove(new_dir, new_dentry);
                if (res)
                        return res;
        }
@@ -332,9 +308,9 @@ const struct file_operations hfs_dir_operations = {
 const struct inode_operations hfs_dir_inode_operations = {
        .create         = hfs_create,
        .lookup         = hfs_lookup,
-       .unlink         = hfs_unlink,
+       .unlink         = hfs_remove,
        .mkdir          = hfs_mkdir,
-       .rmdir          = hfs_rmdir,
+       .rmdir          = hfs_remove,
        .rename         = hfs_rename,
        .setattr        = hfs_inode_setattr,
 };
index 52a0bca..b1991a2 100644 (file)
@@ -397,8 +397,8 @@ int hfsplus_file_extend(struct inode *inode)
        u32 start, len, goal;
        int res;
 
-       if (sbi->total_blocks - sbi->free_blocks + 8 >
-                       sbi->alloc_file->i_size * 8) {
+       if (sbi->alloc_file->i_size * 8 <
+           sbi->total_blocks - sbi->free_blocks + 8) {
                /* extend alloc file */
                printk(KERN_ERR "hfs: extend alloc file! "
                                "(%llu,%u,%u)\n",
index d66ad11..40ad88c 100644 (file)
@@ -134,7 +134,7 @@ int hfs_part_find(struct super_block *sb,
        res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
                                 data, READ);
        if (res)
-               return res;
+               goto out;
 
        switch (be16_to_cpu(*((__be16 *)data))) {
        case HFS_OLD_PMAP_MAGIC:
@@ -147,7 +147,7 @@ int hfs_part_find(struct super_block *sb,
                res = -ENOENT;
                break;
        }
-
+out:
        kfree(data);
        return res;
 }
index 9a3b479..b49b555 100644 (file)
@@ -338,20 +338,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *root, *inode;
        struct qstr str;
        struct nls_table *nls = NULL;
-       int err = -EINVAL;
+       int err;
 
+       err = -EINVAL;
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
-               return -ENOMEM;
+               goto out;
 
        sb->s_fs_info = sbi;
        mutex_init(&sbi->alloc_mutex);
        mutex_init(&sbi->vh_mutex);
        hfsplus_fill_defaults(sbi);
+
+       err = -EINVAL;
        if (!hfsplus_parse_options(data, sbi)) {
                printk(KERN_ERR "hfs: unable to parse mount options\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
 
        /* temporarily use utf8 to correctly find the hidden dir below */
@@ -359,16 +361,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sbi->nls = load_nls("utf8");
        if (!sbi->nls) {
                printk(KERN_ERR "hfs: unable to load nls for utf8\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
 
        /* Grab the volume header */
        if (hfsplus_read_wrapper(sb)) {
                if (!silent)
                        printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
        vhdr = sbi->s_vhdr;
 
@@ -377,7 +377,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
            be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
                printk(KERN_ERR "hfs: wrong filesystem version\n");
-               goto cleanup;
+               goto out_free_vhdr;
        }
        sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
        sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
@@ -421,19 +421,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
        if (!sbi->ext_tree) {
                printk(KERN_ERR "hfs: failed to load extents file\n");
-               goto cleanup;
+               goto out_free_vhdr;
        }
        sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
        if (!sbi->cat_tree) {
                printk(KERN_ERR "hfs: failed to load catalog file\n");
-               goto cleanup;
+               goto out_close_ext_tree;
        }
 
        inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
        if (IS_ERR(inode)) {
                printk(KERN_ERR "hfs: failed to load allocation file\n");
                err = PTR_ERR(inode);
-               goto cleanup;
+               goto out_close_cat_tree;
        }
        sbi->alloc_file = inode;
 
@@ -442,14 +442,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (IS_ERR(root)) {
                printk(KERN_ERR "hfs: failed to load root directory\n");
                err = PTR_ERR(root);
-               goto cleanup;
-       }
-       sb->s_d_op = &hfsplus_dentry_operations;
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
-               err = -ENOMEM;
-               goto cleanup;
+               goto out_put_alloc_file;
        }
 
        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
@@ -459,46 +452,69 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
                hfs_find_exit(&fd);
                if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
-                       goto cleanup;
+                       goto out_put_root;
                inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
-                       goto cleanup;
+                       goto out_put_root;
                }
                sbi->hidden_dir = inode;
        } else
                hfs_find_exit(&fd);
 
-       if (sb->s_flags & MS_RDONLY)
-               goto out;
+       if (!(sb->s_flags & MS_RDONLY)) {
+               /*
+                * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
+                * all three are registered with Apple for our use
+                */
+               vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
+               vhdr->modify_date = hfsp_now2mt();
+               be32_add_cpu(&vhdr->write_count, 1);
+               vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
+               vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
+               hfsplus_sync_fs(sb, 1);
 
-       /* H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
-        * all three are registered with Apple for our use
-        */
-       vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
-       vhdr->modify_date = hfsp_now2mt();
-       be32_add_cpu(&vhdr->write_count, 1);
-       vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
-       vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
-       hfsplus_sync_fs(sb, 1);
-
-       if (!sbi->hidden_dir) {
-               mutex_lock(&sbi->vh_mutex);
-               sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
-               hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
-                                  &str, sbi->hidden_dir);
-               mutex_unlock(&sbi->vh_mutex);
-
-               hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
+               if (!sbi->hidden_dir) {
+                       mutex_lock(&sbi->vh_mutex);
+                       sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
+                       hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
+                                          sbi->hidden_dir);
+                       mutex_unlock(&sbi->vh_mutex);
+
+                       hfsplus_mark_inode_dirty(sbi->hidden_dir,
+                                                HFSPLUS_I_CAT_DIRTY);
+               }
        }
-out:
+
+       sb->s_d_op = &hfsplus_dentry_operations;
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               err = -ENOMEM;
+               goto out_put_hidden_dir;
+       }
+
        unload_nls(sbi->nls);
        sbi->nls = nls;
        return 0;
 
-cleanup:
-       hfsplus_put_super(sb);
+out_put_hidden_dir:
+       iput(sbi->hidden_dir);
+out_put_root:
+       iput(sbi->alloc_file);
+out_put_alloc_file:
+       iput(sbi->alloc_file);
+out_close_cat_tree:
+       hfs_btree_close(sbi->cat_tree);
+out_close_ext_tree:
+       hfs_btree_close(sbi->ext_tree);
+out_free_vhdr:
+       kfree(sbi->s_vhdr);
+       kfree(sbi->s_backup_vhdr);
+out_unload_nls:
+       unload_nls(sbi->nls);
        unload_nls(nls);
+       kfree(sbi);
+out:
        return err;
 }
 
index 1962317..3031d81 100644 (file)
@@ -167,7 +167,7 @@ reread:
                break;
        case cpu_to_be16(HFSP_WRAP_MAGIC):
                if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
-                       goto out;
+                       goto out_free_backup_vhdr;
                wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
                part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
                part_size = wd.embed_count * wd.ablk_size;
@@ -179,7 +179,7 @@ reread:
                 * (should do this only for cdrom/loop though)
                 */
                if (hfs_part_find(sb, &part_start, &part_size))
-                       goto out;
+                       goto out_free_backup_vhdr;
                goto reread;
        }
 
index da85e56..0647d80 100644 (file)
@@ -295,6 +295,20 @@ static void destroy_inode(struct inode *inode)
                call_rcu(&inode->i_rcu, i_callback);
 }
 
+void address_space_init_once(struct address_space *mapping)
+{
+       memset(mapping, 0, sizeof(*mapping));
+       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
+       spin_lock_init(&mapping->tree_lock);
+       spin_lock_init(&mapping->i_mmap_lock);
+       INIT_LIST_HEAD(&mapping->private_list);
+       spin_lock_init(&mapping->private_lock);
+       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
+       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
+       mutex_init(&mapping->unmap_mutex);
+}
+EXPORT_SYMBOL(address_space_init_once);
+
 /*
  * These are initializations that only need to be done
  * once, because the fields are idempotent across use
@@ -308,13 +322,7 @@ void inode_init_once(struct inode *inode)
        INIT_LIST_HEAD(&inode->i_devices);
        INIT_LIST_HEAD(&inode->i_wb_list);
        INIT_LIST_HEAD(&inode->i_lru);
-       INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
-       spin_lock_init(&inode->i_data.tree_lock);
-       spin_lock_init(&inode->i_data.i_mmap_lock);
-       INIT_LIST_HEAD(&inode->i_data.private_list);
-       spin_lock_init(&inode->i_data.private_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
-       INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
+       address_space_init_once(&inode->i_data);
        i_size_ordered_init(inode);
 #ifdef CONFIG_FSNOTIFY
        INIT_HLIST_HEAD(&inode->i_fsnotify_marks);
@@ -540,11 +548,14 @@ void evict_inodes(struct super_block *sb)
 /**
  * invalidate_inodes   - attempt to free all inodes on a superblock
  * @sb:                superblock to operate on
+ * @kill_dirty: flag to guide handling of dirty inodes
  *
  * Attempts to free all inodes for a given superblock.  If there were any
  * busy inodes return a non-zero value, else zero.
+ * If @kill_dirty is set, discard dirty inodes too, otherwise treat
+ * them as busy.
  */
-int invalidate_inodes(struct super_block *sb)
+int invalidate_inodes(struct super_block *sb, bool kill_dirty)
 {
        int busy = 0;
        struct inode *inode, *next;
@@ -556,6 +567,10 @@ int invalidate_inodes(struct super_block *sb)
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
                        continue;
+               if (inode->i_state & I_DIRTY && !kill_dirty) {
+                       busy = 1;
+                       continue;
+               }
                if (atomic_read(&inode->i_count)) {
                        busy = 1;
                        continue;
index 0663568..9b976b5 100644 (file)
@@ -112,4 +112,4 @@ extern void release_open_intent(struct nameidata *);
  */
 extern int get_nr_dirty_inodes(void);
 extern void evict_inodes(struct super_block *);
-extern int invalidate_inodes(struct super_block *);
+extern int invalidate_inodes(struct super_block *, bool);
index a59635e..1eebeb7 100644 (file)
@@ -273,6 +273,13 @@ int __generic_block_fiemap(struct inode *inode,
                len = isize;
        }
 
+       /*
+        * Some filesystems can't deal with being asked to map less than
+        * blocksize, so make sure our len is at least block length.
+        */
+       if (logical_to_blk(inode, len) == 0)
+               len = blk_to_logical(inode, 1);
+
        start_blk = logical_to_blk(inode, start);
        last_blk = logical_to_blk(inode, start + len - 1);
 
index 9e46869..97e7346 100644 (file)
@@ -473,7 +473,8 @@ int __jbd2_log_space_left(journal_t *journal)
 }
 
 /*
- * Called under j_state_lock.  Returns true if a transaction commit was started.
+ * Called with j_state_lock locked for writing.
+ * Returns true if a transaction commit was started.
  */
 int __jbd2_log_start_commit(journal_t *journal, tid_t target)
 {
@@ -520,11 +521,13 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
 {
        transaction_t *transaction = NULL;
        tid_t tid;
+       int need_to_start = 0;
 
        read_lock(&journal->j_state_lock);
        if (journal->j_running_transaction && !current->journal_info) {
                transaction = journal->j_running_transaction;
-               __jbd2_log_start_commit(journal, transaction->t_tid);
+               if (!tid_geq(journal->j_commit_request, transaction->t_tid))
+                       need_to_start = 1;
        } else if (journal->j_committing_transaction)
                transaction = journal->j_committing_transaction;
 
@@ -535,6 +538,8 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
 
        tid = transaction->t_tid;
        read_unlock(&journal->j_state_lock);
+       if (need_to_start)
+               jbd2_log_start_commit(journal, tid);
        jbd2_log_wait_commit(journal, tid);
        return 1;
 }
index faad2bd..1d11910 100644 (file)
@@ -117,10 +117,10 @@ static inline void update_t_max_wait(transaction_t *transaction)
 static int start_this_handle(journal_t *journal, handle_t *handle,
                             int gfp_mask)
 {
-       transaction_t *transaction;
-       int needed;
-       int nblocks = handle->h_buffer_credits;
-       transaction_t *new_transaction = NULL;
+       transaction_t   *transaction, *new_transaction = NULL;
+       tid_t           tid;
+       int             needed, need_to_start;
+       int             nblocks = handle->h_buffer_credits;
 
        if (nblocks > journal->j_max_transaction_buffers) {
                printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
@@ -222,8 +222,11 @@ repeat:
                atomic_sub(nblocks, &transaction->t_outstanding_credits);
                prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
                                TASK_UNINTERRUPTIBLE);
-               __jbd2_log_start_commit(journal, transaction->t_tid);
+               tid = transaction->t_tid;
+               need_to_start = !tid_geq(journal->j_commit_request, tid);
                read_unlock(&journal->j_state_lock);
+               if (need_to_start)
+                       jbd2_log_start_commit(journal, tid);
                schedule();
                finish_wait(&journal->j_wait_transaction_locked, &wait);
                goto repeat;
@@ -442,7 +445,8 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
 {
        transaction_t *transaction = handle->h_transaction;
        journal_t *journal = transaction->t_journal;
-       int ret;
+       tid_t           tid;
+       int             need_to_start, ret;
 
        /* If we've had an abort of any type, don't even think about
         * actually doing the restart! */
@@ -465,8 +469,11 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
        spin_unlock(&transaction->t_handle_lock);
 
        jbd_debug(2, "restarting handle %p\n", handle);
-       __jbd2_log_start_commit(journal, transaction->t_tid);
+       tid = transaction->t_tid;
+       need_to_start = !tid_geq(journal->j_commit_request, tid);
        read_unlock(&journal->j_state_lock);
+       if (need_to_start)
+               jbd2_log_start_commit(journal, tid);
 
        lock_map_release(&handle->h_lockdep_map);
        handle->h_buffer_credits = nblocks;
index 5f1bcb2..b7c99bf 100644 (file)
@@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
                                        struct nsm_handle *nsm,
                                        const struct nlm_reboot *info)
 {
-       struct nlm_host *host = NULL;
+       struct nlm_host *host;
        struct hlist_head *chain;
        struct hlist_node *pos;
 
@@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
                        host->h_state++;
 
                        nlm_get_host(host);
-                       goto out;
+                       mutex_unlock(&nlm_host_mutex);
+                       return host;
                }
        }
-out:
+
        mutex_unlock(&nlm_host_mutex);
-       return host;
+       return NULL;
 }
 
 /**
index ce7337d..6e6777f 100644 (file)
@@ -213,7 +213,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                new_de = minix_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                minix_set_link(new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -225,18 +224,15 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= info->s_link_max)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = minix_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
 
        minix_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                minix_set_link(dir_de, dir_page, new_dir);
index 7d77f24..0087cf9 100644 (file)
@@ -455,14 +455,6 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
 
-       /*
-        * It can be possible to revalidate the dentry that we started
-        * the path walk with. force_reval_path may also revalidate the
-        * dentry already committed to the nameidata.
-        */
-       if (unlikely(parent == dentry))
-               return nameidata_drop_rcu(nd);
-
        BUG_ON(!(nd->flags & LOOKUP_RCU));
        if (nd->root.mnt) {
                spin_lock(&fs->lock);
@@ -561,39 +553,25 @@ static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd)
  */
 void release_open_intent(struct nameidata *nd)
 {
-       if (nd->intent.open.file->f_path.dentry == NULL)
-               put_filp(nd->intent.open.file);
-       else
-               fput(nd->intent.open.file);
-}
-
-/*
- * Call d_revalidate and handle filesystems that request rcu-walk
- * to be dropped. This may be called and return in rcu-walk mode,
- * regardless of success or error. If -ECHILD is returned, the caller
- * must return -ECHILD back up the path walk stack so path walk may
- * be restarted in ref-walk mode.
- */
-static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       int status;
+       struct file *file = nd->intent.open.file;
 
-       status = dentry->d_op->d_revalidate(dentry, nd);
-       if (status == -ECHILD) {
-               if (nameidata_dentry_drop_rcu(nd, dentry))
-                       return status;
-               status = dentry->d_op->d_revalidate(dentry, nd);
+       if (file && !IS_ERR(file)) {
+               if (file->f_path.dentry == NULL)
+                       put_filp(file);
+               else
+                       fput(file);
        }
+}
 
-       return status;
+static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       return dentry->d_op->d_revalidate(dentry, nd);
 }
 
-static inline struct dentry *
+static struct dentry *
 do_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       int status;
-
-       status = d_revalidate(dentry, nd);
+       int status = d_revalidate(dentry, nd);
        if (unlikely(status <= 0)) {
                /*
                 * The dentry failed validation.
@@ -602,24 +580,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
                 * to return a fail status.
                 */
                if (status < 0) {
-                       /* If we're in rcu-walk, we don't have a ref */
-                       if (!(nd->flags & LOOKUP_RCU))
-                               dput(dentry);
+                       dput(dentry);
                        dentry = ERR_PTR(status);
-
-               } else {
-                       /* Don't d_invalidate in rcu-walk mode */
-                       if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
-                               return ERR_PTR(-ECHILD);
-                       if (!d_invalidate(dentry)) {
-                               dput(dentry);
-                               dentry = NULL;
-                       }
+               } else if (!d_invalidate(dentry)) {
+                       dput(dentry);
+                       dentry = NULL;
                }
        }
        return dentry;
 }
 
+static inline struct dentry *
+do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
+{
+       int status = d_revalidate(dentry, nd);
+       if (likely(status > 0))
+               return dentry;
+       if (status == -ECHILD) {
+               if (nameidata_dentry_drop_rcu(nd, dentry))
+                       return ERR_PTR(-ECHILD);
+               return do_revalidate(dentry, nd);
+       }
+       if (status < 0)
+               return ERR_PTR(status);
+       /* Don't d_invalidate in rcu-walk mode */
+       if (nameidata_dentry_drop_rcu(nd, dentry))
+               return ERR_PTR(-ECHILD);
+       if (!d_invalidate(dentry)) {
+               dput(dentry);
+               dentry = NULL;
+       }
+       return dentry;
+}
+
 static inline int need_reval_dot(struct dentry *dentry)
 {
        if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
@@ -664,9 +657,6 @@ force_reval_path(struct path *path, struct nameidata *nd)
                return 0;
 
        if (!status) {
-               /* Don't d_invalidate in rcu-walk mode */
-               if (nameidata_drop_rcu(nd))
-                       return -ECHILD;
                d_invalidate(dentry);
                status = -ESTALE;
        }
@@ -773,6 +763,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
        int error;
        struct dentry *dentry = link->dentry;
 
+       BUG_ON(nd->flags & LOOKUP_RCU);
+
        touch_atime(link->mnt, dentry);
        nd_set_link(nd, NULL);
 
@@ -803,10 +795,16 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
  * Without that kind of total limit, nasty chains of consecutive
  * symlinks can cause almost arbitrarily long lookups. 
  */
-static inline int do_follow_link(struct path *path, struct nameidata *nd)
+static inline int do_follow_link(struct inode *inode, struct path *path, struct nameidata *nd)
 {
        void *cookie;
        int err = -ELOOP;
+
+       /* We drop rcu-walk here */
+       if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
+               return -ECHILD;
+       BUG_ON(inode != path->dentry->d_inode);
+
        if (current->link_count >= MAX_NESTED_LINKS)
                goto loop;
        if (current->total_link_count >= 40)
@@ -1251,9 +1249,15 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
                        return -ECHILD;
 
                nd->seq = seq;
-               if (dentry->d_flags & DCACHE_OP_REVALIDATE)
-                       goto need_revalidate;
-done2:
+               if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+                       dentry = do_revalidate_rcu(dentry, nd);
+                       if (!dentry)
+                               goto need_lookup;
+                       if (IS_ERR(dentry))
+                               goto fail;
+                       if (!(nd->flags & LOOKUP_RCU))
+                               goto done;
+               }
                path->mnt = mnt;
                path->dentry = dentry;
                if (likely(__follow_mount_rcu(nd, path, inode, false)))
@@ -1266,8 +1270,13 @@ done2:
        if (!dentry)
                goto need_lookup;
 found:
-       if (dentry->d_flags & DCACHE_OP_REVALIDATE)
-               goto need_revalidate;
+       if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+               dentry = do_revalidate(dentry, nd);
+               if (!dentry)
+                       goto need_lookup;
+               if (IS_ERR(dentry))
+                       goto fail;
+       }
 done:
        path->mnt = mnt;
        path->dentry = dentry;
@@ -1309,16 +1318,6 @@ need_lookup:
        mutex_unlock(&dir->i_mutex);
        goto found;
 
-need_revalidate:
-       dentry = do_revalidate(dentry, nd);
-       if (!dentry)
-               goto need_lookup;
-       if (IS_ERR(dentry))
-               goto fail;
-       if (nd->flags & LOOKUP_RCU)
-               goto done2;
-       goto done;
-
 fail:
        return PTR_ERR(dentry);
 }
@@ -1415,11 +1414,7 @@ exec_again:
                        goto out_dput;
 
                if (inode->i_op->follow_link) {
-                       /* We commonly drop rcu-walk here */
-                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
-                               return -ECHILD;
-                       BUG_ON(inode != next.dentry->d_inode);
-                       err = do_follow_link(&next, nd);
+                       err = do_follow_link(inode, &next, nd);
                        if (err)
                                goto return_err;
                        nd->inode = nd->path.dentry->d_inode;
@@ -1463,10 +1458,7 @@ last_component:
                        break;
                if (inode && unlikely(inode->i_op->follow_link) &&
                    (lookup_flags & LOOKUP_FOLLOW)) {
-                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
-                               return -ECHILD;
-                       BUG_ON(inode != next.dentry->d_inode);
-                       err = do_follow_link(&next, nd);
+                       err = do_follow_link(inode, &next, nd);
                        if (err)
                                goto return_err;
                        nd->inode = nd->path.dentry->d_inode;
@@ -1500,12 +1492,15 @@ return_reval:
                 * We may need to check the cached dentry for staleness.
                 */
                if (need_reval_dot(nd->path.dentry)) {
+                       if (nameidata_drop_rcu_last_maybe(nd))
+                               return -ECHILD;
                        /* Note: we do not d_invalidate() */
                        err = d_revalidate(nd->path.dentry, nd);
                        if (!err)
                                err = -ESTALE;
                        if (err < 0)
                                break;
+                       return 0;
                }
 return_base:
                if (nameidata_drop_rcu_last_maybe(nd))
@@ -2265,8 +2260,6 @@ static struct file *finish_open(struct nameidata *nd,
        return filp;
 
 exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
        path_put(&nd->path);
        return ERR_PTR(error);
 }
@@ -2389,8 +2382,6 @@ exit_mutex_unlock:
 exit_dput:
        path_put_conditional(path, nd);
 exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
        path_put(&nd->path);
        return ERR_PTR(error);
 }
@@ -2477,6 +2468,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
        }
        audit_inode(pathname, nd.path.dentry);
        filp = finish_open(&nd, open_flag, acc_mode);
+       release_open_intent(&nd);
        return filp;
 
 creat:
@@ -2553,6 +2545,7 @@ out:
                path_put(&nd.root);
        if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL))
                goto reval;
+       release_open_intent(&nd);
        return filp;
 
 exit_dput:
@@ -2560,8 +2553,6 @@ exit_dput:
 out_path:
        path_put(&nd.path);
 out_filp:
-       if (!IS_ERR(nd.intent.open.file))
-               release_open_intent(&nd);
        filp = ERR_PTR(error);
        goto out;
 }
index 7b0b953..d1edf26 100644 (file)
@@ -1244,7 +1244,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
                 */
                br_write_lock(vfsmount_lock);
                if (mnt_get_count(mnt) != 2) {
-                       br_write_lock(vfsmount_lock);
+                       br_write_unlock(vfsmount_lock);
                        return -EBUSY;
                }
                br_write_unlock(vfsmount_lock);
index 1990165..e3d2942 100644 (file)
@@ -135,33 +135,6 @@ out_err:
 
 #if defined(CONFIG_NFS_V4_1)
 /*
- *  * CB_SEQUENCE operations will fail until the callback sessionid is set.
- *   */
-int nfs4_set_callback_sessionid(struct nfs_client *clp)
-{
-       struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv;
-       struct nfs4_sessionid *bc_sid;
-
-       if (!serv->sv_bc_xprt)
-               return -EINVAL;
-
-       /* on success freed in xprt_free */
-       bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL);
-       if (!bc_sid)
-               return -ENOMEM;
-       memcpy(bc_sid->data, &clp->cl_session->sess_id.data,
-               NFS4_MAX_SESSIONID_LEN);
-       spin_lock_bh(&serv->sv_cb_lock);
-       serv->sv_bc_xprt->xpt_bc_sid = bc_sid;
-       spin_unlock_bh(&serv->sv_cb_lock);
-       dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__,
-               ((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1],
-               ((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3],
-               serv->sv_bc_xprt);
-       return 0;
-}
-
-/*
  * The callback service for NFSv4.1 callbacks
  */
 static int
@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
                struct nfs_callback_data *cb_info)
 {
 }
-int nfs4_set_callback_sessionid(struct nfs_client *clp)
-{
-       return 0;
-}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion)
        mutex_unlock(&nfs_callback_mutex);
 }
 
-static int check_gss_callback_principal(struct nfs_client *clp,
-                                       struct svc_rqst *rqstp)
+/* Boolean check of RPC_AUTH_GSS principal */
+int
+check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 {
        struct rpc_clnt *r = clp->cl_rpcclient;
        char *p = svc_gss_principal(rqstp);
 
+       if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
+               return 1;
+
        /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
        if (clp->cl_minorversion != 0)
-               return SVC_DROP;
+               return 0;
        /*
         * It might just be a normal user principal, in which case
         * userspace won't bother to tell us the name at all.
         */
        if (p == NULL)
-               return SVC_DENIED;
+               return 0;
 
        /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
 
        if (memcmp(p, "nfs@", 4) != 0)
-               return SVC_DENIED;
+               return 0;
        p += 4;
        if (strcmp(p, r->cl_server) != 0)
-               return SVC_DENIED;
-       return SVC_OK;
+               return 0;
+       return 1;
 }
 
-/* pg_authenticate method helper */
-static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp)
-{
-       struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp);
-       int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0;
-
-       dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc);
-       if (svc_is_backchannel(rqstp))
-               /* Sessionid (usually) set after CB_NULL ping */
-               return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid,
-                                                 is_cb_compound);
-       else
-               /* No callback identifier in pg_authenticate */
-               return nfs4_find_client_no_ident(svc_addr(rqstp));
-}
-
-/* pg_authenticate method for nfsv4 callback threads. */
+/*
+ * pg_authenticate method for nfsv4 callback threads.
+ *
+ * The authflavor has been negotiated, so an incorrect flavor is a server
+ * bug. Drop packets with incorrect authflavor.
+ *
+ * All other checking done after NFS decoding where the nfs_client can be
+ * found in nfs4_callback_compound
+ */
 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 {
-       struct nfs_client *clp;
-       RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
-       int ret = SVC_OK;
-
-       /* Don't talk to strangers */
-       clp = nfs_cb_find_client(rqstp);
-       if (clp == NULL)
-               return SVC_DROP;
-
-       dprintk("%s: %s NFSv4 callback!\n", __func__,
-                       svc_print_addr(rqstp, buf, sizeof(buf)));
-
        switch (rqstp->rq_authop->flavour) {
-               case RPC_AUTH_NULL:
-                       if (rqstp->rq_proc != CB_NULL)
-                               ret = SVC_DENIED;
-                       break;
-               case RPC_AUTH_UNIX:
-                       break;
-               case RPC_AUTH_GSS:
-                       ret = check_gss_callback_principal(clp, rqstp);
-                       break;
-               default:
-                       ret = SVC_DENIED;
+       case RPC_AUTH_NULL:
+               if (rqstp->rq_proc != CB_NULL)
+                       return SVC_DROP;
+               break;
+       case RPC_AUTH_GSS:
+               /* No RPC_AUTH_GSS support yet in NFSv4.1 */
+                if (svc_is_backchannel(rqstp))
+                       return SVC_DROP;
        }
-       nfs_put_client(clp);
-       return ret;
+       return SVC_OK;
 }
 
 /*
index d3b44f9..46d93ce 100644 (file)
@@ -7,6 +7,7 @@
  */
 #ifndef __LINUX_FS_NFS_CALLBACK_H
 #define __LINUX_FS_NFS_CALLBACK_H
+#include <linux/sunrpc/svc.h>
 
 #define NFS4_CALLBACK 0x40000000
 #define NFS4_CALLBACK_XDRSIZE 2048
@@ -37,7 +38,6 @@ enum nfs4_callback_opnum {
 struct cb_process_state {
        __be32                  drc_status;
        struct nfs_client       *clp;
-       struct nfs4_sessionid   *svc_sid; /* v4.1 callback service sessionid */
 };
 
 struct cb_compound_hdr_arg {
@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall(
 extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
 extern void nfs4_cb_take_slot(struct nfs_client *clp);
 #endif /* CONFIG_NFS_V4_1 */
-
+extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
 extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
                                    struct cb_getattrres *res,
                                    struct cb_process_state *cps);
index 4bb91cb..8958757 100644 (file)
@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
 {
        struct nfs_client *clp;
        int i;
-       __be32 status;
+       __be32 status = htonl(NFS4ERR_BADSESSION);
 
        cps->clp = NULL;
 
-       status = htonl(NFS4ERR_BADSESSION);
-       /* Incoming session must match the callback session */
-       if (memcmp(&args->csa_sessionid, cps->svc_sid, NFS4_MAX_SESSIONID_LEN))
-               goto out;
-
-       clp = nfs4_find_client_sessionid(args->csa_addr,
-                                        &args->csa_sessionid, 1);
+       clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
        if (clp == NULL)
                goto out;
 
@@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
        res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        nfs4_cb_take_slot(clp);
-       cps->clp = clp; /* put in nfs4_callback_compound */
 
 out:
+       cps->clp = clp; /* put in nfs4_callback_compound */
        for (i = 0; i < args->csa_nrclists; i++)
                kfree(args->csa_rclists[i].rcl_refcalls);
        kfree(args->csa_rclists);
index 23112c2..14e0f93 100644 (file)
@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 
        if (hdr_arg.minorversion == 0) {
                cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
-               if (!cps.clp)
+               if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
                        return rpc_drop_reply;
-       } else
-               cps.svc_sid = bc_xprt_sid(rqstp);
+       }
 
        hdr_res.taglen = hdr_arg.taglen;
        hdr_res.tag = hdr_arg.tag;
index 192f2f8..bd3ca32 100644 (file)
@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident)
  * For CB_COMPOUND calls, find a client by IP address, protocol version,
  * minorversion, and sessionID
  *
- * CREATE_SESSION triggers a CB_NULL ping from servers. The callback service
- * sessionid can only be set after the CREATE_SESSION return, so a CB_NULL
- * can arrive before the callback sessionid is set. For CB_NULL calls,
- * find a client by IP address protocol version, and minorversion.
- *
  * Returns NULL if no such client
  */
 struct nfs_client *
 nfs4_find_client_sessionid(const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid, int is_cb_compound)
+                          struct nfs4_sessionid *sid)
 {
        struct nfs_client *clp;
 
@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
                if (!nfs4_has_session(clp))
                        continue;
 
-               /* Match sessionid unless cb_null call*/
-               if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data,
-                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0))
+               /* Match sessionid*/
+               if (memcmp(clp->cl_session->sess_id.data,
+                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
                        continue;
 
                atomic_inc(&clp->cl_count);
@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
 
 struct nfs_client *
 nfs4_find_client_sessionid(const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid, int is_cb_compound)
+                          struct nfs4_sessionid *sid)
 {
        return NULL;
 }
index 364e432..bbbc6bf 100644 (file)
@@ -23,8 +23,6 @@
 
 static void nfs_do_free_delegation(struct nfs_delegation *delegation)
 {
-       if (delegation->cred)
-               put_rpccred(delegation->cred);
        kfree(delegation);
 }
 
@@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head)
 
 static void nfs_free_delegation(struct nfs_delegation *delegation)
 {
+       if (delegation->cred) {
+               put_rpccred(delegation->cred);
+               delegation->cred = NULL;
+       }
        call_rcu(&delegation->rcu, nfs_free_delegation_callback);
 }
 
index e6ace0d..9943a75 100644 (file)
@@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                pos += vec->iov_len;
        }
 
+       /*
+        * If no bytes were started, return the error, and let the
+        * generic layer handle the completion.
+        */
+       if (requested_bytes == 0) {
+               nfs_direct_req_release(dreq);
+               return result < 0 ? result : -EIO;
+       }
+
        if (put_dreq(dreq))
                nfs_direct_complete(dreq);
-
-       if (requested_bytes != 0)
-               return 0;
-
-       if (result < 0)
-               return result;
-       return -EIO;
+       return 0;
 }
 
 static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
@@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                pos += vec->iov_len;
        }
 
+       /*
+        * If no bytes were started, return the error, and let the
+        * generic layer handle the completion.
+        */
+       if (requested_bytes == 0) {
+               nfs_direct_req_release(dreq);
+               return result < 0 ? result : -EIO;
+       }
+
        if (put_dreq(dreq))
                nfs_direct_write_complete(dreq, dreq->inode);
-
-       if (requested_bytes != 0)
-               return 0;
-
-       if (result < 0)
-               return result;
-       return -EIO;
+       return 0;
 }
 
 static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
index d851242..1cc600e 100644 (file)
@@ -881,9 +881,10 @@ out:
        return ret;
 }
 
-static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
+       unsigned long ret = 0;
 
        if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
                        && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
@@ -891,25 +892,32 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfsi->change_attr = fattr->change_attr;
                if (S_ISDIR(inode->i_mode))
                        nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               ret |= NFS_INO_INVALID_ATTR;
        }
        /* If we have atomic WCC data, we may update some attributes */
        if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
-                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
+               memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               ret |= NFS_INO_INVALID_ATTR;
+       }
 
        if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_MTIME)
                        && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
-                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-                       if (S_ISDIR(inode->i_mode))
-                               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+               if (S_ISDIR(inode->i_mode))
+                       nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               ret |= NFS_INO_INVALID_ATTR;
        }
        if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
                        && (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
-                       && nfsi->npages == 0)
-                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
+                       && nfsi->npages == 0) {
+               i_size_write(inode, nfs_size_to_loff_t(fattr->size));
+               ret |= NFS_INO_INVALID_ATTR;
+       }
+       return ret;
 }
 
 /**
@@ -1223,7 +1231,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        | NFS_INO_REVAL_PAGECACHE);
 
        /* Do atomic weak cache consistency updates */
-       nfs_wcc_update_inode(inode, fattr);
+       invalid |= nfs_wcc_update_inode(inode, fattr);
 
        /* More cache consistency checks */
        if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
index 4644f04..cf9fdbd 100644 (file)
@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *);
 extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
 extern struct nfs_client *nfs4_find_client_ident(int);
 extern struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *,
-                          int);
+nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
 extern struct nfs_server *nfs_create_server(
                                        const struct nfs_parsed_mount_data *,
                                        struct nfs_fh *);
index 9f88c5f..2743427 100644 (file)
@@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
        if (!nfs_server_capable(inode, NFS_CAP_ACLS))
                goto out;
 
-       /* We are doing this here, because XDR marshalling can only
-          return -ENOMEM. */
+       /* We are doing this here because XDR marshalling does not
+        * return any results, it BUGs. */
        status = -ENOSPC;
        if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
                goto out;
index 01c5e8b..183c6b1 100644 (file)
@@ -1328,10 +1328,13 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
 
        encode_nfs_fh3(xdr, NFS_FH(args->inode));
        encode_uint32(xdr, args->mask);
+
+       base = req->rq_slen;
        if (args->npages != 0)
                xdr_write_pages(xdr, args->pages, 0, args->len);
+       else
+               xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE);
 
-       base = req->rq_slen;
        error = nfsacl_encode(xdr->buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
                            args->acl_access : NULL, 1, 0);
index 51fe64a..f5c9b12 100644 (file)
@@ -214,7 +214,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
 
        /* ipv6 length plus port is legal */
        if (rlen > INET6_ADDRSTRLEN + 8) {
-               dprintk("%s Invalid address, length %d\n", __func__,
+               dprintk("%s: Invalid address, length %d\n", __func__,
                        rlen);
                goto out_err;
        }
@@ -225,6 +225,11 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
        /* replace the port dots with dashes for the in4_pton() delimiter*/
        for (i = 0; i < 2; i++) {
                char *res = strrchr(buf, '.');
+               if (!res) {
+                       dprintk("%s: Failed finding expected dots in port\n",
+                               __func__);
+                       goto out_free;
+               }
                *res = '-';
        }
 
@@ -240,7 +245,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
        port = htons((tmp[0] << 8) | (tmp[1]));
 
        ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
-       dprintk("%s Decoded address and port %s\n", __func__, buf);
+       dprintk("%s: Decoded address and port %s\n", __func__, buf);
 out_free:
        kfree(buf);
 out_err:
index 9d992b0..1ff76ac 100644 (file)
@@ -50,6 +50,8 @@
 #include <linux/module.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
+#include <linux/utsname.h>
+#include <linux/mm.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -3251,6 +3253,35 @@ static void buf_to_pages(const void *buf, size_t buflen,
        }
 }
 
+static int buf_to_pages_noslab(const void *buf, size_t buflen,
+               struct page **pages, unsigned int *pgbase)
+{
+       struct page *newpage, **spages;
+       int rc = 0;
+       size_t len;
+       spages = pages;
+
+       do {
+               len = min(PAGE_CACHE_SIZE, buflen);
+               newpage = alloc_page(GFP_KERNEL);
+
+               if (newpage == NULL)
+                       goto unwind;
+               memcpy(page_address(newpage), buf, len);
+                buf += len;
+                buflen -= len;
+               *pages++ = newpage;
+               rc++;
+       } while (buflen != 0);
+
+       return rc;
+
+unwind:
+       for(; rc > 0; rc--)
+               __free_page(spages[rc-1]);
+       return -ENOMEM;
+}
+
 struct nfs4_cached_acl {
        int cached;
        size_t len;
@@ -3419,13 +3450,23 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
        };
-       int ret;
+       int ret, i;
 
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
+       i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+       if (i < 0)
+               return i;
        nfs_inode_return_delegation(inode);
-       buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+
+       /*
+        * Free each page after tx, so the only ref left is
+        * held by the network stack
+        */
+       for (; i > 0; i--)
+               put_page(pages[i-1]);
+
        /*
         * Acl update can result in inode attribute update.
         * so mark the attribute cache invalid.
@@ -4572,27 +4613,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
        args.verifier = &verifier;
 
-       while (1) {
-               args.id_len = scnprintf(args.id, sizeof(args.id),
-                                       "%s/%s %u",
-                                       clp->cl_ipaddr,
-                                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                                        RPC_DISPLAY_ADDR),
-                                       clp->cl_id_uniquifier);
-
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
-
-               if (status != -NFS4ERR_CLID_INUSE)
-                       break;
-
-               if (signalled())
-                       break;
-
-               if (++clp->cl_id_uniquifier == 0)
-                       break;
-       }
+       args.id_len = scnprintf(args.id, sizeof(args.id),
+                               "%s/%s.%s/%u",
+                               clp->cl_ipaddr,
+                               init_utsname()->nodename,
+                               init_utsname()->domainname,
+                               clp->cl_rpcclient->cl_auth->au_flavor);
 
-       status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       if (!status)
+               status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
index 2336d53..e6742b5 100644 (file)
@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
        status = nfs4_proc_create_session(clp);
        if (status != 0)
                goto out;
-       status = nfs4_set_callback_sessionid(clp);
-       if (status != 0) {
-               printk(KERN_WARNING "Sessionid not set. No callback service\n");
-               nfs_callback_down(1);
-               status = 0;
-       }
        nfs41_setup_state_renewal(clp);
        nfs_mark_client_ready(clp, NFS_CS_READY);
 out:
index 2ab8e5c..4e2c168 100644 (file)
@@ -6086,11 +6086,11 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       if (!ntohl(*p++)) {
+       if (*p == xdr_zero) {
                p = xdr_inline_decode(xdr, 4);
                if (unlikely(!p))
                        goto out_overflow;
-               if (!ntohl(*p++))
+               if (*p == xdr_zero)
                        return -EAGAIN;
                entry->eof = 1;
                return -EBADCOOKIE;
@@ -6101,7 +6101,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                goto out_overflow;
        entry->prev_cookie = entry->cookie;
        p = xdr_decode_hyper(p, &entry->cookie);
-       entry->len = ntohl(*p++);
+       entry->len = be32_to_cpup(p);
 
        p = xdr_inline_decode(xdr, entry->len);
        if (unlikely(!p))
@@ -6132,9 +6132,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
                entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 
-       if (verify_attr_len(xdr, p, len) < 0)
-               goto out_overflow;
-
        return 0;
 
 out_overflow:
index bc40897..1b1bc1a 100644 (file)
@@ -951,7 +951,7 @@ pnfs_put_deviceid_cache(struct nfs_client *clp)
 {
        struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
 
-       dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache);
+       dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref));
        if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
                int i;
                /* Verify cache is empty */
index 10d648e..c8278f4 100644 (file)
@@ -932,7 +932,7 @@ out_bad:
        while (!list_empty(&list)) {
                data = list_entry(list.next, struct nfs_write_data, pages);
                list_del(&data->pages);
-               nfs_writedata_release(data);
+               nfs_writedata_free(data);
        }
        nfs_redirty_request(req);
        return -ENOMEM;
index fc1c525..84c27d6 100644 (file)
@@ -42,6 +42,11 @@ struct nfsacl_encode_desc {
        gid_t gid;
 };
 
+struct nfsacl_simple_acl {
+       struct posix_acl acl;
+       struct posix_acl_entry ace[4];
+};
+
 static int
 xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
 {
@@ -72,9 +77,20 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
        return 0;
 }
 
-unsigned int
-nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
-             struct posix_acl *acl, int encode_entries, int typeflag)
+/**
+ * nfsacl_encode - Encode an NFSv3 ACL
+ *
+ * @buf: destination xdr_buf to contain XDR encoded ACL
+ * @base: byte offset in xdr_buf where XDR'd ACL begins
+ * @inode: inode of file whose ACL this is
+ * @acl: posix_acl to encode
+ * @encode_entries: whether to encode ACEs as well
+ * @typeflag: ACL type: NFS_ACL_DEFAULT or zero
+ *
+ * Returns size of encoded ACL in bytes or a negative errno value.
+ */
+int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+                 struct posix_acl *acl, int encode_entries, int typeflag)
 {
        int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
        struct nfsacl_encode_desc nfsacl_desc = {
@@ -88,17 +104,22 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
                .uid = inode->i_uid,
                .gid = inode->i_gid,
        };
+       struct nfsacl_simple_acl aclbuf;
        int err;
-       struct posix_acl *acl2 = NULL;
 
        if (entries > NFS_ACL_MAX_ENTRIES ||
            xdr_encode_word(buf, base, entries))
                return -EINVAL;
        if (encode_entries && acl && acl->a_count == 3) {
-               /* Fake up an ACL_MASK entry. */
-               acl2 = posix_acl_alloc(4, GFP_KERNEL);
-               if (!acl2)
-                       return -ENOMEM;
+               struct posix_acl *acl2 = &aclbuf.acl;
+
+               /* Avoid the use of posix_acl_alloc().  nfsacl_encode() is
+                * invoked in contexts where a memory allocation failure is
+                * fatal.  Fortunately this fake ACL is small enough to
+                * construct on the stack. */
+               memset(acl2, 0, sizeof(acl2));
+               posix_acl_init(acl2, 4);
+
                /* Insert entries in canonical order: other orders seem
                 to confuse Solaris VxFS. */
                acl2->a_entries[0] = acl->a_entries[0];  /* ACL_USER_OBJ */
@@ -109,8 +130,6 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
                nfsacl_desc.acl = acl2;
        }
        err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
-       if (acl2)
-               posix_acl_release(acl2);
        if (!err)
                err = 8 + nfsacl_desc.desc.elem_size *
                          nfsacl_desc.desc.array_len;
@@ -224,9 +243,18 @@ posix_acl_from_nfsacl(struct posix_acl *acl)
        return 0;
 }
 
-unsigned int
-nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
-             struct posix_acl **pacl)
+/**
+ * nfsacl_decode - Decode an NFSv3 ACL
+ *
+ * @buf: xdr_buf containing XDR'd ACL data to decode
+ * @base: byte offset in xdr_buf where XDR'd ACL begins
+ * @aclcnt: count of ACEs in decoded posix_acl
+ * @pacl: buffer in which to place decoded posix_acl
+ *
+ * Returns the length of the decoded ACL in bytes, or a negative errno value.
+ */
+int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+                 struct posix_acl **pacl)
 {
        struct nfsacl_decode_desc nfsacl_desc = {
                .desc = {
index 3be975e..cde36cb 100644 (file)
@@ -484,7 +484,7 @@ static int decode_cb_sequence4res(struct xdr_stream *xdr,
 out:
        return status;
 out_default:
-       return nfs_cb_stat_to_errno(status);
+       return nfs_cb_stat_to_errno(nfserr);
 }
 
 /*
@@ -564,11 +564,9 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
        if (unlikely(status))
                goto out;
        if (unlikely(nfserr != NFS4_OK))
-               goto out_default;
+               status = nfs_cb_stat_to_errno(nfserr);
 out:
        return status;
-out_default:
-       return nfs_cb_stat_to_errno(status);
 }
 
 /*
index d98d021..54b60bf 100644 (file)
@@ -230,9 +230,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_client = clp;
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       dp->dl_vfs_file = find_readable_file(fp);
-       get_file(dp->dl_vfs_file);
-       dp->dl_flock = NULL;
        dp->dl_type = type;
        dp->dl_stateid.si_boot = boot_time;
        dp->dl_stateid.si_stateownerid = current_delegid++;
@@ -241,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
-       list_add(&dp->dl_perfile, &fp->fi_delegations);
-       list_add(&dp->dl_perclnt, &clp->cl_delegations);
        INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
        return dp;
 }
@@ -253,36 +248,30 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
                put_nfs4_file(dp->dl_file);
-               fput(dp->dl_vfs_file);
                kmem_cache_free(deleg_slab, dp);
                num_delegations--;
        }
 }
 
-/* Remove the associated file_lock first, then remove the delegation.
- * lease_modify() is called to remove the FS_LEASE file_lock from
- * the i_flock list, eventually calling nfsd's lock_manager
- * fl_release_callback.
- */
-static void
-nfs4_close_delegation(struct nfs4_delegation *dp)
+static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
-       dprintk("NFSD: close_delegation dp %p\n",dp);
-       /* XXX: do we even need this check?: */
-       if (dp->dl_flock)
-               vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
+       if (atomic_dec_and_test(&fp->fi_delegees)) {
+               vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
+               fp->fi_lease = NULL;
+               fp->fi_deleg_file = NULL;
+       }
 }
 
 /* Called under the state lock. */
 static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
-       list_del_init(&dp->dl_perfile);
        list_del_init(&dp->dl_perclnt);
        spin_lock(&recall_lock);
+       list_del_init(&dp->dl_perfile);
        list_del_init(&dp->dl_recall_lru);
        spin_unlock(&recall_lock);
-       nfs4_close_delegation(dp);
+       nfs4_put_deleg_lease(dp->dl_file);
        nfs4_put_delegation(dp);
 }
 
@@ -958,8 +947,6 @@ expire_client(struct nfs4_client *clp)
        spin_lock(&recall_lock);
        while (!list_empty(&clp->cl_delegations)) {
                dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
-               dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
-                               dp->dl_flock);
                list_del_init(&dp->dl_perclnt);
                list_move(&dp->dl_recall_lru, &reaplist);
        }
@@ -2078,6 +2065,7 @@ alloc_init_file(struct inode *ino)
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
                fp->fi_had_conflict = false;
+               fp->fi_lease = NULL;
                memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
                memset(fp->fi_access, 0, sizeof(fp->fi_access));
                spin_lock(&recall_lock);
@@ -2329,23 +2317,8 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
                nfs4_file_put_access(fp, O_RDONLY);
 }
 
-/*
- * Spawn a thread to perform a recall on the delegation represented
- * by the lease (file_lock)
- *
- * Called from break_lease() with lock_flocks() held.
- * Note: we assume break_lease will only call this *once* for any given
- * lease.
- */
-static
-void nfsd_break_deleg_cb(struct file_lock *fl)
+static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 {
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
-
-       dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
-       if (!dp)
-               return;
-
        /* We're assuming the state code never drops its reference
         * without first removing the lease.  Since we're in this lease
         * callback (and since the lease code is serialized by the kernel
@@ -2353,22 +2326,35 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
         * it's safe to take a reference: */
        atomic_inc(&dp->dl_count);
 
-       spin_lock(&recall_lock);
        list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
-       spin_unlock(&recall_lock);
 
        /* only place dl_time is set. protected by lock_flocks*/
        dp->dl_time = get_seconds();
 
+       nfsd4_cb_recall(dp);
+}
+
+/* Called from break_lease() with lock_flocks() held. */
+static void nfsd_break_deleg_cb(struct file_lock *fl)
+{
+       struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
+       struct nfs4_delegation *dp;
+
+       BUG_ON(!fp);
+       /* We assume break_lease is only called once per lease: */
+       BUG_ON(fp->fi_had_conflict);
        /*
         * We don't want the locks code to timeout the lease for us;
-        * we'll remove it ourself if the delegation isn't returned
-        * in time.
+        * we'll remove it ourself if a delegation isn't returned
+        * in time:
         */
        fl->fl_break_time = 0;
 
-       dp->dl_file->fi_had_conflict = true;
-       nfsd4_cb_recall(dp);
+       spin_lock(&recall_lock);
+       fp->fi_had_conflict = true;
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
+               nfsd_break_one_deleg(dp);
+       spin_unlock(&recall_lock);
 }
 
 static
@@ -2459,13 +2445,15 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
 static struct nfs4_delegation *
 find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
 {
-       struct nfs4_delegation *dp;
+       struct nfs4_delegation *dp = NULL;
 
+       spin_lock(&recall_lock);
        list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
                if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
-                       return dp;
+                       break;
        }
-       return NULL;
+       spin_unlock(&recall_lock);
+       return dp;
 }
 
 int share_access_to_flags(u32 share_access)
@@ -2641,6 +2629,66 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
        return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
 }
 
+static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
+{
+       struct file_lock *fl;
+
+       fl = locks_alloc_lock();
+       if (!fl)
+               return NULL;
+       locks_init_lock(fl);
+       fl->fl_lmops = &nfsd_lease_mng_ops;
+       fl->fl_flags = FL_LEASE;
+       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
+       fl->fl_end = OFFSET_MAX;
+       fl->fl_owner = (fl_owner_t)(dp->dl_file);
+       fl->fl_pid = current->tgid;
+       return fl;
+}
+
+static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
+{
+       struct nfs4_file *fp = dp->dl_file;
+       struct file_lock *fl;
+       int status;
+
+       fl = nfs4_alloc_init_lease(dp, flag);
+       if (!fl)
+               return -ENOMEM;
+       fl->fl_file = find_readable_file(fp);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+       status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
+       if (status) {
+               list_del_init(&dp->dl_perclnt);
+               locks_free_lock(fl);
+               return -ENOMEM;
+       }
+       fp->fi_lease = fl;
+       fp->fi_deleg_file = fl->fl_file;
+       get_file(fp->fi_deleg_file);
+       atomic_set(&fp->fi_delegees, 1);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       return 0;
+}
+
+static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
+{
+       struct nfs4_file *fp = dp->dl_file;
+
+       if (!fp->fi_lease)
+               return nfs4_setlease(dp, flag);
+       spin_lock(&recall_lock);
+       if (fp->fi_had_conflict) {
+               spin_unlock(&recall_lock);
+               return -EAGAIN;
+       }
+       atomic_inc(&fp->fi_delegees);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       spin_unlock(&recall_lock);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+       return 0;
+}
+
 /*
  * Attempt to hand out a delegation.
  */
@@ -2650,7 +2698,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        struct nfs4_delegation *dp;
        struct nfs4_stateowner *sop = stp->st_stateowner;
        int cb_up;
-       struct file_lock *fl;
        int status, flag = 0;
 
        cb_up = nfsd4_cb_channel_good(sop->so_client);
@@ -2681,36 +2728,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        }
 
        dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
-       if (dp == NULL) {
-               flag = NFS4_OPEN_DELEGATE_NONE;
-               goto out;
-       }
-       status = -ENOMEM;
-       fl = locks_alloc_lock();
-       if (!fl)
-               goto out;
-       locks_init_lock(fl);
-       fl->fl_lmops = &nfsd_lease_mng_ops;
-       fl->fl_flags = FL_LEASE;
-       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
-       fl->fl_end = OFFSET_MAX;
-       fl->fl_owner =  (fl_owner_t)dp;
-       fl->fl_file = find_readable_file(stp->st_file);
-       BUG_ON(!fl->fl_file);
-       fl->fl_pid = current->tgid;
-       dp->dl_flock = fl;
-
-       /* vfs_setlease checks to see if delegation should be handed out.
-        * the lock_manager callback fl_change is used
-        */
-       if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
-               dprintk("NFSD: setlease failed [%d], no delegation\n", status);
-               dp->dl_flock = NULL;
-               locks_free_lock(fl);
-               unhash_delegation(dp);
-               flag = NFS4_OPEN_DELEGATE_NONE;
-               goto out;
-       }
+       if (dp == NULL)
+               goto out_no_deleg;
+       status = nfs4_set_delegation(dp, flag);
+       if (status)
+               goto out_free;
 
        memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
 
@@ -2722,6 +2744,12 @@ out:
                        && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
                dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
+       return;
+out_free:
+       nfs4_put_delegation(dp);
+out_no_deleg:
+       flag = NFS4_OPEN_DELEGATE_NONE;
+       goto out;
 }
 
 /*
@@ -2916,8 +2944,6 @@ nfs4_laundromat(void)
                                test_val = u;
                        break;
                }
-               dprintk("NFSD: purging unused delegation dp %p, fp %p\n",
-                                   dp, dp->dl_flock);
                list_move(&dp->dl_recall_lru, &reaplist);
        }
        spin_unlock(&recall_lock);
@@ -3128,7 +3154,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                        goto out;
                renew_client(dp->dl_client);
                if (filpp) {
-                       *filpp = find_readable_file(dp->dl_file);
+                       *filpp = dp->dl_file->fi_deleg_file;
                        BUG_ON(!*filpp);
                }
        } else { /* open or lock stateid */
index 956629b..1275b86 100644 (file)
@@ -317,8 +317,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                READ_BUF(dummy32);
                len += (XDR_QUADLEN(dummy32) << 2);
                READMEM(buf, dummy32);
-               if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
-                       goto out_nfserr;
+               if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
+                       return status;
                iattr->ia_valid |= ATTR_UID;
        }
        if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
@@ -328,8 +328,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                READ_BUF(dummy32);
                len += (XDR_QUADLEN(dummy32) << 2);
                READMEM(buf, dummy32);
-               if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
-                       goto out_nfserr;
+               if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
+                       return status;
                iattr->ia_valid |= ATTR_GID;
        }
        if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
index 3074656..2d31224 100644 (file)
@@ -83,8 +83,6 @@ struct nfs4_delegation {
        atomic_t                dl_count;       /* ref count */
        struct nfs4_client      *dl_client;
        struct nfs4_file        *dl_file;
-       struct file             *dl_vfs_file;
-       struct file_lock        *dl_flock;
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
@@ -379,6 +377,9 @@ struct nfs4_file {
         */
        atomic_t                fi_readers;
        atomic_t                fi_writers;
+       struct file             *fi_deleg_file;
+       struct file_lock        *fi_lease;
+       atomic_t                fi_delegees;
        struct inode            *fi_inode;
        u32                     fi_id;      /* used with stateowner->so_id 
                                             * for stateid_hashtbl hash */
index 641117f..da1d970 100644 (file)
@@ -808,7 +808,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
                if (ra->p_count == 0)
                        frap = rap;
        }
-       depth = nfsdstats.ra_size*11/10;
+       depth = nfsdstats.ra_size;
        if (!frap) {    
                spin_unlock(&rab->pb_lock);
                return NULL;
@@ -1744,6 +1744,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        host_err = nfsd_break_lease(odentry->d_inode);
        if (host_err)
                goto out_drop_write;
+       if (ndentry->d_inode) {
+               host_err = nfsd_break_lease(ndentry->d_inode);
+               if (host_err)
+                       goto out_drop_write;
+       }
+       if (host_err)
+               goto out_drop_write;
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
@@ -1812,22 +1819,22 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 
        host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
        if (host_err)
-               goto out_nfserr;
+               goto out_put;
 
        host_err = nfsd_break_lease(rdentry->d_inode);
        if (host_err)
-               goto out_put;
+               goto out_drop_write;
        if (type != S_IFDIR)
                host_err = vfs_unlink(dirp, rdentry);
        else
                host_err = vfs_rmdir(dirp, rdentry);
-out_put:
-       dput(rdentry);
-
        if (!host_err)
                host_err = commit_metadata(fhp);
-
+out_drop_write:
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
+out_put:
+       dput(rdentry);
+
 out_nfserr:
        err = nfserrno(host_err);
 out:
index 388e9e8..85f7baa 100644 (file)
 #include "btnode.h"
 
 
-void nilfs_btnode_cache_init_once(struct address_space *btnc)
-{
-       nilfs_mapping_init_once(btnc);
-}
-
 static const struct address_space_operations def_btnode_aops = {
        .sync_page              = block_sync_page,
 };
index 7903749..1b8ebd8 100644 (file)
@@ -37,7 +37,6 @@ struct nilfs_btnode_chkey_ctxt {
        struct buffer_head *newbh;
 };
 
-void nilfs_btnode_cache_init_once(struct address_space *);
 void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *);
 void nilfs_btnode_cache_clear(struct address_space *);
 struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
index 6a0e2a1..a0babd2 100644 (file)
@@ -454,9 +454,9 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode,
        struct backing_dev_info *bdi = inode->i_sb->s_bdi;
 
        INIT_LIST_HEAD(&shadow->frozen_buffers);
-       nilfs_mapping_init_once(&shadow->frozen_data);
+       address_space_init_once(&shadow->frozen_data);
        nilfs_mapping_init(&shadow->frozen_data, bdi, &shadow_map_aops);
-       nilfs_mapping_init_once(&shadow->frozen_btnodes);
+       address_space_init_once(&shadow->frozen_btnodes);
        nilfs_mapping_init(&shadow->frozen_btnodes, bdi, &shadow_map_aops);
        mi->mi_shadow = shadow;
        return 0;
index 9803427..161791d 100644 (file)
@@ -397,7 +397,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inc_nlink(old_inode);
                nilfs_set_link(new_dir, new_de, new_page, old_inode);
                nilfs_mark_inode_dirty(new_dir);
                new_inode->i_ctime = CURRENT_TIME;
@@ -411,13 +410,9 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= NILFS_LINK_MAX)
                                goto out_dir;
                }
-               inc_nlink(old_inode);
                err = nilfs_add_link(new_dentry, old_inode);
-               if (err) {
-                       drop_nlink(old_inode);
-                       nilfs_mark_inode_dirty(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de) {
                        inc_nlink(new_dir);
                        nilfs_mark_inode_dirty(new_dir);
@@ -431,7 +426,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_inode->i_ctime = CURRENT_TIME;
 
        nilfs_delete_entry(old_de, old_page);
-       drop_nlink(old_inode);
 
        if (dir_de) {
                nilfs_set_link(old_inode, dir_de, dir_page, new_dir);
index 0c43241..a585b35 100644 (file)
@@ -492,19 +492,6 @@ unsigned nilfs_page_count_clean_buffers(struct page *page,
        return nc;
 }
 
-void nilfs_mapping_init_once(struct address_space *mapping)
-{
-       memset(mapping, 0, sizeof(*mapping));
-       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
-       spin_lock_init(&mapping->tree_lock);
-       INIT_LIST_HEAD(&mapping->private_list);
-       spin_lock_init(&mapping->private_lock);
-
-       spin_lock_init(&mapping->i_mmap_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
-       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
-}
-
 void nilfs_mapping_init(struct address_space *mapping,
                        struct backing_dev_info *bdi,
                        const struct address_space_operations *aops)
index 622df27..2a00953 100644 (file)
@@ -61,7 +61,6 @@ void nilfs_free_private_page(struct page *);
 int nilfs_copy_dirty_pages(struct address_space *, struct address_space *);
 void nilfs_copy_back_pages(struct address_space *, struct address_space *);
 void nilfs_clear_dirty_pages(struct address_space *);
-void nilfs_mapping_init_once(struct address_space *mapping);
 void nilfs_mapping_init(struct address_space *mapping,
                        struct backing_dev_info *bdi,
                        const struct address_space_operations *aops);
index 55ebae5..2de9f63 100644 (file)
@@ -430,7 +430,8 @@ static void nilfs_segctor_begin_finfo(struct nilfs_sc_info *sci,
        nilfs_segctor_map_segsum_entry(
                sci, &sci->sc_binfo_ptr, sizeof(struct nilfs_finfo));
 
-       if (inode->i_sb && !test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags))
+       if (NILFS_I(inode)->i_root &&
+           !test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags))
                set_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
        /* skip finfo */
 }
index 0994f6a..1673b3d 100644 (file)
@@ -704,7 +704,8 @@ skip_mount_setup:
        sbp[0]->s_state =
                cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
        /* synchronize sbp[1] with sbp[0] */
-       memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
+       if (sbp[1])
+               memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
        return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
 }
 
@@ -1278,7 +1279,7 @@ static void nilfs_inode_init_once(void *obj)
 #ifdef CONFIG_NILFS_XATTR
        init_rwsem(&ii->xattr_sem);
 #endif
-       nilfs_btnode_cache_init_once(&ii->i_btnode_cache);
+       address_space_init_once(&ii->i_btnode_cache);
        ii->i_bmap = &ii->i_bmap_data;
        inode_init_once(&ii->vfs_inode);
 }
index b572b67..326e747 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2011 Anton Altaparmakov and Tuxera Inc.
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -2576,6 +2576,8 @@ mft_rec_already_initialized:
        flush_dcache_page(page);
        SetPageUptodate(page);
        if (base_ni) {
+               MFT_RECORD *m_tmp;
+
                /*
                 * Setup the base mft record in the extent mft record.  This
                 * completes initialization of the allocated extent mft record
@@ -2588,11 +2590,11 @@ mft_rec_already_initialized:
                 * attach it to the base inode @base_ni and map, pin, and lock
                 * its, i.e. the allocated, mft record.
                 */
-               m = map_extent_mft_record(base_ni, bit, &ni);
-               if (IS_ERR(m)) {
+               m_tmp = map_extent_mft_record(base_ni, bit, &ni);
+               if (IS_ERR(m_tmp)) {
                        ntfs_error(vol->sb, "Failed to map allocated extent "
                                        "mft record 0x%llx.", (long long)bit);
-                       err = PTR_ERR(m);
+                       err = PTR_ERR(m_tmp);
                        /* Set the mft record itself not in use. */
                        m->flags &= cpu_to_le16(
                                        ~le16_to_cpu(MFT_RECORD_IN_USE));
@@ -2603,6 +2605,7 @@ mft_rec_already_initialized:
                        ntfs_unmap_page(page);
                        goto undo_mftbmp_alloc;
                }
+               BUG_ON(m != m_tmp);
                /*
                 * Make sure the allocated mft record is written out to disk.
                 * No need to set the inode dirty because the caller is going
index 43e56b9..6180da1 100644 (file)
@@ -405,9 +405,9 @@ static inline int ocfs2_remove_extent_credits(struct super_block *sb)
               ocfs2_quota_trans_credits(sb);
 }
 
-/* data block for new dir/symlink, 2 for bitmap updates (bitmap fe +
- * bitmap block for the new bit) dx_root update for free list */
-#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2 + 1)
+/* data block for new dir/symlink, allocation of directory block, dx_root
+ * update for free list */
+#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + OCFS2_SUBALLOC_ALLOC + 1)
 
 static inline int ocfs2_add_dir_index_credits(struct super_block *sb)
 {
index b5f9160..19ebc5a 100644 (file)
@@ -3228,7 +3228,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
                                        u32 num_clusters, unsigned int e_flags)
 {
        int ret, delete, index, credits =  0;
-       u32 new_bit, new_len;
+       u32 new_bit, new_len, orig_num_clusters;
        unsigned int set_len;
        struct ocfs2_super *osb = OCFS2_SB(sb);
        handle_t *handle;
@@ -3261,6 +3261,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
                goto out;
        }
 
+       orig_num_clusters = num_clusters;
+
        while (num_clusters) {
                ret = ocfs2_get_refcount_rec(ref_ci, context->ref_root_bh,
                                             p_cluster, num_clusters,
@@ -3348,7 +3350,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
         * in write-back mode.
         */
        if (context->get_clusters == ocfs2_di_get_clusters) {
-               ret = ocfs2_cow_sync_writeback(sb, context, cpos, num_clusters);
+               ret = ocfs2_cow_sync_writeback(sb, context, cpos,
+                                              orig_num_clusters);
                if (ret)
                        mlog_errno(ret);
        }
index 06d1f74..36c423f 100644 (file)
@@ -993,8 +993,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 }
 
 /* Handle quota on quotactl */
-static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
-                         char *path)
+static int ocfs2_quota_on(struct super_block *sb, int type, int format_id)
 {
        unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
                                             OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
@@ -1013,7 +1012,7 @@ static int ocfs2_quota_off(struct super_block *sb, int type)
 }
 
 static const struct quotactl_ops ocfs2_quotactl_ops = {
-       .quota_on       = ocfs2_quota_on,
+       .quota_on_meta  = ocfs2_quota_on,
        .quota_off      = ocfs2_quota_off,
        .quota_sync     = dquot_quota_sync,
        .get_info       = dquot_get_dqinfo,
@@ -1317,7 +1316,7 @@ static int ocfs2_parse_options(struct super_block *sb,
                               struct mount_options *mopt,
                               int is_remount)
 {
-       int status;
+       int status, user_stack = 0;
        char *p;
        u32 tmp;
 
@@ -1460,6 +1459,15 @@ static int ocfs2_parse_options(struct super_block *sb,
                        memcpy(mopt->cluster_stack, args[0].from,
                               OCFS2_STACK_LABEL_LEN);
                        mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
+                       /*
+                        * Open code the memcmp here as we don't have
+                        * an osb to pass to
+                        * ocfs2_userspace_stack().
+                        */
+                       if (memcmp(mopt->cluster_stack,
+                                  OCFS2_CLASSIC_CLUSTER_STACK,
+                                  OCFS2_STACK_LABEL_LEN))
+                               user_stack = 1;
                        break;
                case Opt_inode64:
                        mopt->mount_opt |= OCFS2_MOUNT_INODE64;
@@ -1515,13 +1523,16 @@ static int ocfs2_parse_options(struct super_block *sb,
                }
        }
 
-       /* Ensure only one heartbeat mode */
-       tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
-                                OCFS2_MOUNT_HB_NONE);
-       if (hweight32(tmp) != 1) {
-               mlog(ML_ERROR, "Invalid heartbeat mount options\n");
-               status = 0;
-               goto bail;
+       if (user_stack == 0) {
+               /* Ensure only one heartbeat mode */
+               tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
+                                        OCFS2_MOUNT_HB_GLOBAL |
+                                        OCFS2_MOUNT_HB_NONE);
+               if (hweight32(tmp) != 1) {
+                       mlog(ML_ERROR, "Invalid heartbeat mount options\n");
+                       status = 0;
+                       goto bail;
+               }
        }
 
        status = 1;
index e52389e..5a2c6eb 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -790,6 +790,8 @@ struct file *nameidata_to_filp(struct nameidata *nd)
 
        /* Pick up the filp from the open intent */
        filp = nd->intent.open.file;
+       nd->intent.open.file = NULL;
+
        /* Has the filesystem initialised the file for us? */
        if (filp->f_path.dentry == NULL) {
                path_get(&nd->path);
index 789c625..b10e354 100644 (file)
@@ -251,6 +251,11 @@ static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
        }
 
        vm->vblk_size     = get_unaligned_be32(data + 0x08);
+       if (vm->vblk_size == 0) {
+               ldm_error ("Illegal VBLK size");
+               return false;
+       }
+
        vm->vblk_offset   = get_unaligned_be32(data + 0x0C);
        vm->last_vblk_seq = get_unaligned_be32(data + 0x04);
 
index 68d6a21..11f688b 100644 (file)
@@ -29,10 +29,9 @@ static inline void mac_fix_string(char *stg, int len)
 
 int mac_partition(struct parsed_partitions *state)
 {
-       int slot = 1;
        Sector sect;
        unsigned char *data;
-       int blk, blocks_in_map;
+       int slot, blocks_in_map;
        unsigned secsize;
 #ifdef CONFIG_PPC_PMAC
        int found_root = 0;
@@ -59,10 +58,14 @@ int mac_partition(struct parsed_partitions *state)
                put_dev_sector(sect);
                return 0;               /* not a MacOS disk */
        }
-       strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
        blocks_in_map = be32_to_cpu(part->map_count);
-       for (blk = 1; blk <= blocks_in_map; ++blk) {
-               int pos = blk * secsize;
+       if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
+               put_dev_sector(sect);
+               return 0;
+       }
+       strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
+       for (slot = 1; slot <= blocks_in_map; ++slot) {
+               int pos = slot * secsize;
                put_dev_sector(sect);
                data = read_part_sector(state, pos/512, &sect);
                if (!data)
@@ -113,13 +116,11 @@ int mac_partition(struct parsed_partitions *state)
                        }
 
                        if (goodness > found_root_goodness) {
-                               found_root = blk;
+                               found_root = slot;
                                found_root_goodness = goodness;
                        }
                }
 #endif /* CONFIG_PPC_PMAC */
-
-               ++slot;
        }
 #ifdef CONFIG_PPC_PMAC
        if (found_root_goodness)
index 89e9e19..da42f7d 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -441,7 +441,7 @@ redo:
                        break;
                }
                if (do_wakeup) {
-                       wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT);
+                       wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
                        kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
                }
                pipe_wait(pipe);
@@ -450,7 +450,7 @@ redo:
 
        /* Signal writers asynchronously that there is more room. */
        if (do_wakeup) {
-               wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT);
+               wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
        if (ret > 0)
@@ -612,7 +612,7 @@ redo2:
                        break;
                }
                if (do_wakeup) {
-                       wake_up_interruptible_sync_poll(&pipe->wait, POLLIN);
+                       wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
                        kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                        do_wakeup = 0;
                }
@@ -623,7 +623,7 @@ redo2:
 out:
        mutex_unlock(&inode->i_mutex);
        if (do_wakeup) {
-               wake_up_interruptible_sync_poll(&pipe->wait, POLLIN);
+               wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
        }
        if (ret > 0)
@@ -715,7 +715,7 @@ pipe_release(struct inode *inode, int decr, int decw)
        if (!pipe->readers && !pipe->writers) {
                free_pipe_info(inode);
        } else {
-               wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT);
+               wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
index 39df95a..b1cf6bf 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/errno.h>
 
+EXPORT_SYMBOL(posix_acl_init);
 EXPORT_SYMBOL(posix_acl_alloc);
 EXPORT_SYMBOL(posix_acl_clone);
 EXPORT_SYMBOL(posix_acl_valid);
@@ -32,6 +33,16 @@ EXPORT_SYMBOL(posix_acl_chmod_masq);
 EXPORT_SYMBOL(posix_acl_permission);
 
 /*
+ * Init a fresh posix_acl
+ */
+void
+posix_acl_init(struct posix_acl *acl, int count)
+{
+       atomic_set(&acl->a_refcount, 1);
+       acl->a_count = count;
+}
+
+/*
  * Allocate a new ACL with the specified number of entries.
  */
 struct posix_acl *
@@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags)
        const size_t size = sizeof(struct posix_acl) +
                            count * sizeof(struct posix_acl_entry);
        struct posix_acl *acl = kmalloc(size, flags);
-       if (acl) {
-               atomic_set(&acl->a_refcount, 1);
-               acl->a_count = count;
-       }
+       if (acl)
+               posix_acl_init(acl, count);
        return acl;
 }
 
index 6a00688..15af622 100644 (file)
@@ -1,5 +1,5 @@
 config PROC_FS
-       bool "/proc file system support" if EMBEDDED
+       bool "/proc file system support" if EXPERT
        default y
        help
          This is a virtual file system providing information about the status
@@ -40,7 +40,7 @@ config PROC_VMCORE
         Exports the dump image of crashed kernel in ELF format.
 
 config PROC_SYSCTL
-       bool "Sysctl support (/proc/sys)" if EMBEDDED
+       bool "Sysctl support (/proc/sys)" if EXPERT
        depends on PROC_FS
        select SYSCTL
        default y
@@ -61,7 +61,7 @@ config PROC_SYSCTL
 config PROC_PAGE_MONITOR
        default y
        depends on PROC_FS && MMU
-       bool "Enable /proc page monitoring" if EMBEDDED
+       bool "Enable /proc page monitoring" if EXPERT
        help
          Various /proc files exist to monitor process memory utilization:
          /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
index df2b703..7c99c1c 100644 (file)
@@ -353,9 +353,6 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
        task_cap(m, task);
        task_cpus_allowed(m, task);
        cpuset_task_status_allowed(m, task);
-#if defined(CONFIG_S390)
-       task_show_regs(m, task);
-#endif
        task_context_switch_counts(m, task);
        return 0;
 }
index eafc22a..b701eaa 100644 (file)
@@ -67,7 +67,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
        struct console *con;
        loff_t off = 0;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(con)
                if (off++ == *pos)
                        break;
@@ -84,7 +84,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void c_stop(struct seq_file *m, void *v)
 {
-       release_console_sem();
+       console_unlock();
 }
 
 static const struct seq_operations consoles_op = {
index d9396a4..927cbd1 100644 (file)
@@ -233,7 +233,7 @@ void __init proc_device_tree_init(void)
                return;
        root = of_find_node_by_path("/");
        if (root == NULL) {
-               printk(KERN_ERR "/proc/device-tree: can't find root\n");
+               pr_debug("/proc/device-tree: can't find root\n");
                return;
        }
        proc_device_tree_add_node(root, proc_device_tree);
index 84becd3..a2a622e 100644 (file)
@@ -2189,8 +2189,8 @@ int dquot_resume(struct super_block *sb, int type)
 }
 EXPORT_SYMBOL(dquot_resume);
 
-int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
-                     struct path *path)
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
+                  struct path *path)
 {
        int error = security_quota_on(path->dentry);
        if (error)
@@ -2204,20 +2204,6 @@ int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
                                             DQUOT_LIMITS_ENABLED);
        return error;
 }
-EXPORT_SYMBOL(dquot_quota_on_path);
-
-int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name)
-{
-       struct path path;
-       int error;
-
-       error = kern_path(name, LOOKUP_FOLLOW, &path);
-       if (!error) {
-               error = dquot_quota_on_path(sb, type, format_id, &path);
-               path_put(&path);
-       }
-       return error;
-}
 EXPORT_SYMBOL(dquot_quota_on);
 
 /*
index b299961..b34bdb2 100644 (file)
@@ -64,18 +64,15 @@ static int quota_sync_all(int type)
 }
 
 static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
-                        void __user *addr)
+                        struct path *path)
 {
-       char *pathname;
-       int ret = -ENOSYS;
-
-       pathname = getname(addr);
-       if (IS_ERR(pathname))
-               return PTR_ERR(pathname);
-       if (sb->s_qcop->quota_on)
-               ret = sb->s_qcop->quota_on(sb, type, id, pathname);
-       putname(pathname);
-       return ret;
+       if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
+               return -ENOSYS;
+       if (sb->s_qcop->quota_on_meta)
+               return sb->s_qcop->quota_on_meta(sb, type, id);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+       return sb->s_qcop->quota_on(sb, type, id, path);
 }
 
 static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
@@ -241,7 +238,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
 
 /* Copy parameters and call proper function */
 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
-                      void __user *addr)
+                      void __user *addr, struct path *path)
 {
        int ret;
 
@@ -256,7 +253,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
 
        switch (cmd) {
        case Q_QUOTAON:
-               return quota_quotaon(sb, type, cmd, id, addr);
+               return quota_quotaon(sb, type, cmd, id, path);
        case Q_QUOTAOFF:
                if (!sb->s_qcop->quota_off)
                        return -ENOSYS;
@@ -335,6 +332,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
 {
        uint cmds, type;
        struct super_block *sb = NULL;
+       struct path path, *pathp = NULL;
        int ret;
 
        cmds = cmd >> SUBCMDSHIFT;
@@ -351,12 +349,27 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
                return -ENODEV;
        }
 
+       /*
+        * Path for quotaon has to be resolved before grabbing superblock
+        * because that gets s_umount sem which is also possibly needed by path
+        * resolution (think about autofs) and thus deadlocks could arise.
+        */
+       if (cmds == Q_QUOTAON) {
+               ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path);
+               if (ret)
+                       pathp = ERR_PTR(ret);
+               else
+                       pathp = &path;
+       }
+
        sb = quotactl_block(special);
        if (IS_ERR(sb))
                return PTR_ERR(sb);
 
-       ret = do_quotactl(sb, type, cmds, id, addr);
+       ret = do_quotactl(sb, type, cmds, id, addr, pathp);
 
        drop_super(sb);
+       if (pathp && !IS_ERR(pathp))
+               path_put(pathp);
        return ret;
 }
index ba5f51e..68fdf45 100644 (file)
@@ -771,7 +771,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                                        EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
                                        dentry, inode, &security);
        if (retval) {
-               dir->i_nlink--;
+               DEC_DIR_INODE_NLINK(dir)
                goto out_failed;
        }
 
index 2575682..0aab04f 100644 (file)
@@ -632,7 +632,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
 static int reiserfs_release_dquot(struct dquot *);
 static int reiserfs_mark_dquot_dirty(struct dquot *);
 static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *);
+static int reiserfs_quota_on(struct super_block *, int, int, struct path *);
 
 static const struct dquot_operations reiserfs_quota_operations = {
        .write_dquot = reiserfs_write_dquot,
@@ -2048,25 +2048,21 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
  * Standard function to be called on quota_on
  */
 static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
-                            char *name)
+                            struct path *path)
 {
        int err;
-       struct path path;
        struct inode *inode;
        struct reiserfs_transaction_handle th;
 
        if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
                return -EINVAL;
 
-       err = kern_path(name, LOOKUP_FOLLOW, &path);
-       if (err)
-               return err;
        /* Quotafile not on the same filesystem? */
-       if (path.mnt->mnt_sb != sb) {
+       if (path->mnt->mnt_sb != sb) {
                err = -EXDEV;
                goto out;
        }
-       inode = path.dentry->d_inode;
+       inode = path->dentry->d_inode;
        /* We must not pack tails for quota files on reiserfs for quota IO to work */
        if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
                err = reiserfs_unpack(inode, NULL);
@@ -2082,7 +2078,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
        /* Journaling quota? */
        if (REISERFS_SB(sb)->s_qf_names[type]) {
                /* Quotafile not of fs root? */
-               if (path.dentry->d_parent != sb->s_root)
+               if (path->dentry->d_parent != sb->s_root)
                        reiserfs_warning(sb, "super-6521",
                                 "Quota file not on filesystem root. "
                                 "Journalled quota will not work.");
@@ -2101,9 +2097,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
                if (err)
                        goto out;
        }
-       err = dquot_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on(sb, type, format_id, path);
 out:
-       path_put(&path);
        return err;
 }
 
index 2fb2882..8ab48bc 100644 (file)
@@ -63,6 +63,14 @@ static struct buffer_head *get_block_length(struct super_block *sb,
                *length = (unsigned char) bh->b_data[*offset] |
                        (unsigned char) bh->b_data[*offset + 1] << 8;
                *offset += 2;
+
+               if (*offset == msblk->devblksize) {
+                       put_bh(bh);
+                       bh = sb_bread(sb, ++(*cur_index));
+                       if (bh == NULL)
+                               return NULL;
+                       *offset = 0;
+               }
        }
 
        return bh;
index 856756c..c4eb400 100644 (file)
@@ -95,12 +95,6 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
                        if (!buffer_uptodate(bh[k]))
                                goto release_mutex;
 
-                       if (avail == 0) {
-                               offset = 0;
-                               put_bh(bh[k++]);
-                               continue;
-                       }
-
                        stream->buf.in = bh[k]->b_data + offset;
                        stream->buf.in_size = avail;
                        stream->buf.in_pos = 0;
index 818a5e0..4661ae2 100644 (file)
@@ -82,12 +82,6 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
                        if (!buffer_uptodate(bh[k]))
                                goto release_mutex;
 
-                       if (avail == 0) {
-                               offset = 0;
-                               put_bh(bh[k++]);
-                               continue;
-                       }
-
                        stream->next_in = bh[k]->b_data + offset;
                        stream->avail_in = avail;
                        offset = 0;
index 74e149e..7e9dd4c 100644 (file)
@@ -177,6 +177,11 @@ void deactivate_locked_super(struct super_block *s)
        struct file_system_type *fs = s->s_type;
        if (atomic_dec_and_test(&s->s_active)) {
                fs->kill_sb(s);
+               /*
+                * We need to call rcu_barrier so all the delayed rcu free
+                * inodes are flushed before we release the fs module.
+                */
+               rcu_barrier();
                put_filesystem(fs);
                put_super(s);
        } else {
index f4b6758..8c41fea 100644 (file)
@@ -1,5 +1,5 @@
 config SYSFS
-       bool "sysfs file system support" if EMBEDDED
+       bool "sysfs file system support" if EXPERT
        default y
        help
        The sysfs filesystem is a virtual filesystem that the kernel uses to
index b427b12..e474fbc 100644 (file)
@@ -245,7 +245,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
                new_de = sysv_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                sysv_set_link(new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -257,18 +256,15 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
                        if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = sysv_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
 
        sysv_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                sysv_set_link(dir_de, dir_page, new_dir);
index 2be0f9e..b7c338d 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/crc-itu-t.h>
 #include <linux/exportfs.h>
 
+enum { UDF_MAX_LINKS = 0xffff };
+
 static inline int udf_match(int len1, const unsigned char *name1, int len2,
                            const unsigned char *name2)
 {
@@ -650,7 +652,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct udf_inode_info *iinfo;
 
        err = -EMLINK;
-       if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
+       if (dir->i_nlink >= UDF_MAX_LINKS)
                goto out;
 
        err = -EIO;
@@ -1034,9 +1036,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        struct fileIdentDesc cfi, *fi;
        int err;
 
-       if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
+       if (inode->i_nlink >= UDF_MAX_LINKS)
                return -EMLINK;
-       }
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi) {
@@ -1131,9 +1132,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto end_rename;
 
                retval = -EMLINK;
-               if (!new_inode &&
-                       new_dir->i_nlink >=
-                               (256 << sizeof(new_dir->i_nlink)) - 1)
+               if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS)
                        goto end_rename;
        }
        if (!nfi) {
index 12f39b9..d6f6815 100644 (file)
@@ -306,7 +306,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                ufs_set_link(new_dir, new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -318,12 +317,9 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= UFS_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = ufs_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -331,12 +327,11 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
        /*
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
-        * inode_dec_link_count() will mark the inode dirty.
         */
        old_inode->i_ctime = CURRENT_TIME_SEC;
 
        ufs_delete_entry(old_dir, old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                ufs_set_link(old_inode, dir_de, dir_page, new_dir);
index 05201ae..d61611c 100644 (file)
@@ -152,6 +152,8 @@ xfs_ioc_trim(
 
        if (!capable(CAP_SYS_ADMIN))
                return -XFS_ERROR(EPERM);
+       if (!blk_queue_discard(q))
+               return -XFS_ERROR(EOPNOTSUPP);
        if (copy_from_user(&range, urange, sizeof(range)))
                return -XFS_ERROR(EFAULT);
 
index b06ede1..0ca0e3c 100644 (file)
@@ -695,14 +695,19 @@ xfs_ioc_fsgeometry_v1(
        xfs_mount_t             *mp,
        void                    __user *arg)
 {
-       xfs_fsop_geom_v1_t      fsgeo;
+       xfs_fsop_geom_t         fsgeo;
        int                     error;
 
-       error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
+       error = xfs_fs_geometry(mp, &fsgeo, 3);
        if (error)
                return -error;
 
-       if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
+       /*
+        * Caller should have passed an argument of type
+        * xfs_fsop_geom_v1_t.  This is a proper subset of the
+        * xfs_fsop_geom_t that xfs_fs_geometry() fills in.
+        */
+       if (copy_to_user(arg, &fsgeo, sizeof(xfs_fsop_geom_v1_t)))
                return -XFS_ERROR(EFAULT);
        return 0;
 }
@@ -985,10 +990,22 @@ xfs_ioctl_setattr(
 
                /*
                 * Extent size must be a multiple of the appropriate block
-                * size, if set at all.
+                * size, if set at all. It must also be smaller than the
+                * maximum extent size supported by the filesystem.
+                *
+                * Also, for non-realtime files, limit the extent size hint to
+                * half the size of the AGs in the filesystem so alignment
+                * doesn't result in extents larger than an AG.
                 */
                if (fa->fsx_extsize != 0) {
-                       xfs_extlen_t    size;
+                       xfs_extlen_t    size;
+                       xfs_fsblock_t   extsize_fsb;
+
+                       extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
+                       if (extsize_fsb > MAXEXTLEN) {
+                               code = XFS_ERROR(EINVAL);
+                               goto error_return;
+                       }
 
                        if (XFS_IS_REALTIME_INODE(ip) ||
                            ((mask & FSX_XFLAGS) &&
@@ -997,6 +1014,10 @@ xfs_ioctl_setattr(
                                       mp->m_sb.sb_blocklog;
                        } else {
                                size = mp->m_sb.sb_blocksize;
+                               if (extsize_fsb > mp->m_sb.sb_agblocks / 2) {
+                                       code = XFS_ERROR(EINVAL);
+                                       goto error_return;
+                               }
                        }
 
                        if (fa->fsx_extsize % size) {
index f8e854b..206a281 100644 (file)
@@ -1863,12 +1863,14 @@ xfs_qm_dqreclaim_one(void)
        xfs_dquot_t     *dqpout;
        xfs_dquot_t     *dqp;
        int             restarts;
+       int             startagain;
 
        restarts = 0;
        dqpout = NULL;
 
        /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
-startagain:
+again:
+       startagain = 0;
        mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
 
        list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
@@ -1885,13 +1887,10 @@ startagain:
                        ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
 
                        trace_xfs_dqreclaim_want(dqp);
-
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return NULL;
                        XQM_STATS_INC(xqmstats.xs_qm_dqwants);
-                       goto startagain;
+                       restarts++;
+                       startagain = 1;
+                       goto dqunlock;
                }
 
                /*
@@ -1906,23 +1905,20 @@ startagain:
                        ASSERT(list_empty(&dqp->q_mplist));
                        list_del_init(&dqp->q_freelist);
                        xfs_Gqm->qm_dqfrlist_cnt--;
-                       xfs_dqunlock(dqp);
                        dqpout = dqp;
                        XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
-                       break;
+                       goto dqunlock;
                }
 
                ASSERT(dqp->q_hash);
                ASSERT(!list_empty(&dqp->q_mplist));
 
                /*
-                * Try to grab the flush lock. If this dquot is in the process of
-                * getting flushed to disk, we don't want to reclaim it.
+                * Try to grab the flush lock. If this dquot is in the process
+                * of getting flushed to disk, we don't want to reclaim it.
                 */
-               if (!xfs_dqflock_nowait(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
+               if (!xfs_dqflock_nowait(dqp))
+                       goto dqunlock;
 
                /*
                 * We have the flush lock so we know that this is not in the
@@ -1944,8 +1940,7 @@ startagain:
                                xfs_fs_cmn_err(CE_WARN, mp,
                        "xfs_qm_dqreclaim: dquot %p flush failed", dqp);
                        }
-                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-                       continue;
+                       goto dqunlock;
                }
 
                /*
@@ -1967,13 +1962,8 @@ startagain:
                 */
                if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
                        restarts++;
-                       mutex_unlock(&dqp->q_hash->qh_lock);
-                       xfs_dqfunlock(dqp);
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-                       if (restarts++ >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return NULL;
-                       goto startagain;
+                       startagain = 1;
+                       goto qhunlock;
                }
 
                ASSERT(dqp->q_nrefs == 0);
@@ -1986,14 +1976,20 @@ startagain:
                xfs_Gqm->qm_dqfrlist_cnt--;
                dqpout = dqp;
                mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
+qhunlock:
                mutex_unlock(&dqp->q_hash->qh_lock);
 dqfunlock:
                xfs_dqfunlock(dqp);
+dqunlock:
                xfs_dqunlock(dqp);
                if (dqpout)
                        break;
                if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                       return NULL;
+                       break;
+               if (startagain) {
+                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+                       goto again;
+               }
        }
        mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
        return dqpout;
index 0ab56b3..d0b3bc7 100644 (file)
@@ -75,6 +75,22 @@ typedef unsigned int xfs_alloctype_t;
 #define XFS_ALLOC_SET_ASIDE(mp)  (4 + ((mp)->m_sb.sb_agcount * 4))
 
 /*
+ * When deciding how much space to allocate out of an AG, we limit the
+ * allocation maximum size to the size the AG. However, we cannot use all the
+ * blocks in the AG - some are permanently used by metadata. These
+ * blocks are generally:
+ *     - the AG superblock, AGF, AGI and AGFL
+ *     - the AGF (bno and cnt) and AGI btree root blocks
+ *     - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits
+ *
+ * The AG headers are sector sized, so the amount of space they take up is
+ * dependent on filesystem geometry. The others are all single blocks.
+ */
+#define XFS_ALLOC_AG_MAX_USABLE(mp)    \
+       ((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7)
+
+
+/*
  * Argument structure for xfs_alloc routines.
  * This is turned into a structure to avoid having 20 arguments passed
  * down several levels of the stack.
index 4111cd3..dc3afd7 100644 (file)
@@ -1038,17 +1038,34 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the middle part of a previous delayed allocation.
                 * Contiguity is impossible here.
                 * This case is avoided almost all the time.
+                *
+                * We start with a delayed allocation:
+                *
+                * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+
+                *  PREV @ idx
+                *
+                * and we are allocating:
+                *                     +rrrrrrrrrrrrrrrrr+
+                *                            new
+                *
+                * and we set it up for insertion as:
+                * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+
+                *                            new
+                *  PREV @ idx          LEFT              RIGHT
+                *                      inserted at idx + 1
                 */
                temp = new->br_startoff - PREV.br_startoff;
-               trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
-               xfs_bmbt_set_blockcount(ep, temp);
-               r[0] = *new;
-               r[1].br_state = PREV.br_state;
-               r[1].br_startblock = 0;
-               r[1].br_startoff = new_endoff;
                temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
-               r[1].br_blockcount = temp2;
-               xfs_iext_insert(ip, idx + 1, 2, &r[0], state);
+               trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
+               xfs_bmbt_set_blockcount(ep, temp);      /* truncate PREV */
+               LEFT = *new;
+               RIGHT.br_state = PREV.br_state;
+               RIGHT.br_startblock = nullstartblock(
+                               (int)xfs_bmap_worst_indlen(ip, temp2));
+               RIGHT.br_startoff = new_endoff;
+               RIGHT.br_blockcount = temp2;
+               /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
+               xfs_iext_insert(ip, idx + 1, 2, &LEFT, state);
                ip->i_df.if_lastex = idx + 1;
                ip->i_d.di_nextents++;
                if (cur == NULL)
@@ -2430,7 +2447,7 @@ xfs_bmap_btalloc_nullfb(
                startag = ag = 0;
 
        pag = xfs_perag_get(mp, ag);
-       while (*blen < ap->alen) {
+       while (*blen < args->maxlen) {
                if (!pag->pagf_init) {
                        error = xfs_alloc_pagf_init(mp, args->tp, ag,
                                                    XFS_ALLOC_FLAG_TRYLOCK);
@@ -2452,7 +2469,7 @@ xfs_bmap_btalloc_nullfb(
                        notinit = 1;
 
                if (xfs_inode_is_filestream(ap->ip)) {
-                       if (*blen >= ap->alen)
+                       if (*blen >= args->maxlen)
                                break;
 
                        if (ap->userdata) {
@@ -2498,14 +2515,14 @@ xfs_bmap_btalloc_nullfb(
         * If the best seen length is less than the request
         * length, use the best as the minimum.
         */
-       else if (*blen < ap->alen)
+       else if (*blen < args->maxlen)
                args->minlen = *blen;
        /*
-        * Otherwise we've seen an extent as big as alen,
+        * Otherwise we've seen an extent as big as maxlen,
         * use that as the minimum.
         */
        else
-               args->minlen = ap->alen;
+               args->minlen = args->maxlen;
 
        /*
         * set the failure fallback case to look in the selected
@@ -2573,7 +2590,9 @@ xfs_bmap_btalloc(
        args.tp = ap->tp;
        args.mp = mp;
        args.fsbno = ap->rval;
-       args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);
+
+       /* Trim the allocation back to the maximum an AG can fit. */
+       args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));
        args.firstblock = ap->firstblock;
        blen = 0;
        if (nullfb) {
@@ -2621,7 +2640,7 @@ xfs_bmap_btalloc(
                        /*
                         * Adjust for alignment
                         */
-                       if (blen > args.alignment && blen <= ap->alen)
+                       if (blen > args.alignment && blen <= args.maxlen)
                                args.minlen = blen - args.alignment;
                        args.minalignslop = 0;
                } else {
@@ -2640,7 +2659,7 @@ xfs_bmap_btalloc(
                         * of minlen+alignment+slop doesn't go up
                         * between the calls.
                         */
-                       if (blen > mp->m_dalign && blen <= ap->alen)
+                       if (blen > mp->m_dalign && blen <= args.maxlen)
                                nextminlen = blen - mp->m_dalign;
                        else
                                nextminlen = args.minlen;
@@ -4485,6 +4504,16 @@ xfs_bmapi(
                                /* Figure out the extent size, adjust alen */
                                extsz = xfs_get_extsz_hint(ip);
                                if (extsz) {
+                                       /*
+                                        * make sure we don't exceed a single
+                                        * extent length when we align the
+                                        * extent by reducing length we are
+                                        * going to allocate by the maximum
+                                        * amount extent size aligment may
+                                        * require.
+                                        */
+                                       alen = XFS_FILBLKS_MIN(len,
+                                                  MAXEXTLEN - (2 * extsz - 1));
                                        error = xfs_bmap_extsize_align(mp,
                                                        &got, &prev, extsz,
                                                        rt, eof,
index 98c6f73..6f8c21c 100644 (file)
@@ -427,13 +427,15 @@ xfs_buf_item_unpin(
 
                if (remove) {
                        /*
-                        * We have to remove the log item from the transaction
-                        * as we are about to release our reference to the
-                        * buffer.  If we don't, the unlock that occurs later
-                        * in xfs_trans_uncommit() will ry to reference the
+                        * If we are in a transaction context, we have to
+                        * remove the log item from the transaction as we are
+                        * about to release our reference to the buffer.  If we
+                        * don't, the unlock that occurs later in
+                        * xfs_trans_uncommit() will try to reference the
                         * buffer which we no longer have a hold on.
                         */
-                       xfs_trans_del_item(lip);
+                       if (lip->li_desc)
+                               xfs_trans_del_item(lip);
 
                        /*
                         * Since the transaction no longer refers to the buffer,
index 75f2ef6..d22e626 100644 (file)
@@ -138,7 +138,8 @@ xfs_efi_item_unpin(
 
        if (remove) {
                ASSERT(!(lip->li_flags & XFS_LI_IN_AIL));
-               xfs_trans_del_item(lip);
+               if (lip->li_desc)
+                       xfs_trans_del_item(lip);
                xfs_efi_item_free(efip);
                return;
        }
index cec89dd..85668ef 100644 (file)
@@ -53,6 +53,9 @@ xfs_fs_geometry(
        xfs_fsop_geom_t         *geo,
        int                     new_version)
 {
+
+       memset(geo, 0, sizeof(*geo));
+
        geo->blocksize = mp->m_sb.sb_blocksize;
        geo->rtextsize = mp->m_sb.sb_rextsize;
        geo->agblocks = mp->m_sb.sb_agblocks;
index 55582bd..8a0f044 100644 (file)
@@ -337,7 +337,12 @@ xfs_iomap_prealloc_size(
                int shift = 0;
                int64_t freesp;
 
-               alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size);
+               /*
+                * rounddown_pow_of_two() returns an undefined result
+                * if we pass in alloc_blocks = 0. Hence the "+ 1" to
+                * ensure we always pass in a non-zero value.
+                */
+               alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
                alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
                                        rounddown_pow_of_two(alloc_blocks));
 
index 916eb7d..3bd3291 100644 (file)
@@ -191,7 +191,7 @@ void          xfs_log_ticket_put(struct xlog_ticket *ticket);
 
 xlog_tid_t xfs_log_get_trans_ident(struct xfs_trans *tp);
 
-int    xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
+void   xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
                                struct xfs_log_vec *log_vector,
                                xfs_lsn_t *commit_lsn, int flags);
 bool   xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
index 9dc8125..9ca59be 100644 (file)
@@ -543,7 +543,7 @@ xlog_cil_push(
 
        error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0);
        if (error)
-               goto out_abort;
+               goto out_abort_free_ticket;
 
        /*
         * now that we've written the checkpoint into the log, strictly
@@ -569,8 +569,9 @@ restart:
        }
        spin_unlock(&cil->xc_cil_lock);
 
+       /* xfs_log_done always frees the ticket on error. */
        commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, 0);
-       if (error || commit_lsn == -1)
+       if (commit_lsn == -1)
                goto out_abort;
 
        /* attach all the transactions w/ busy extents to iclog */
@@ -600,6 +601,8 @@ out_free_ticket:
        kmem_free(new_ctx);
        return 0;
 
+out_abort_free_ticket:
+       xfs_log_ticket_put(tic);
 out_abort:
        xlog_cil_committed(ctx, XFS_LI_ABORTED);
        return XFS_ERROR(EIO);
@@ -622,7 +625,7 @@ out_abort:
  * background commit, returns without it held once background commits are
  * allowed again.
  */
-int
+void
 xfs_log_commit_cil(
        struct xfs_mount        *mp,
        struct xfs_trans        *tp,
@@ -637,11 +640,6 @@ xfs_log_commit_cil(
        if (flags & XFS_TRANS_RELEASE_LOG_RES)
                log_flags = XFS_LOG_REL_PERM_RESERV;
 
-       if (XLOG_FORCED_SHUTDOWN(log)) {
-               xlog_cil_free_logvec(log_vector);
-               return XFS_ERROR(EIO);
-       }
-
        /*
         * do all the hard work of formatting items (including memory
         * allocation) outside the CIL context lock. This prevents stalling CIL
@@ -701,7 +699,6 @@ xfs_log_commit_cil(
         */
        if (push)
                xlog_cil_push(log, 0);
-       return 0;
 }
 
 /*
index 33dbc4e..7692279 100644 (file)
@@ -1446,6 +1446,14 @@ xfs_log_item_batch_insert(
  * Bulk operation version of xfs_trans_committed that takes a log vector of
  * items to insert into the AIL. This uses bulk AIL insertion techniques to
  * minimise lock traffic.
+ *
+ * If we are called with the aborted flag set, it is because a log write during
+ * a CIL checkpoint commit has failed. In this case, all the items in the
+ * checkpoint have already gone through IOP_COMMITED and IOP_UNLOCK, which
+ * means that checkpoint commit abort handling is treated exactly the same
+ * as an iclog write error even though we haven't started any IO yet. Hence in
+ * this case all we need to do is IOP_COMMITTED processing, followed by an
+ * IOP_UNPIN(aborted) call.
  */
 void
 xfs_trans_committed_bulk(
@@ -1472,6 +1480,16 @@ xfs_trans_committed_bulk(
                if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
                        continue;
 
+               /*
+                * if we are aborting the operation, no point in inserting the
+                * object into the AIL as we are in a shutdown situation.
+                */
+               if (aborted) {
+                       ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount));
+                       IOP_UNPIN(lip, 1);
+                       continue;
+               }
+
                if (item_lsn != commit_lsn) {
 
                        /*
@@ -1503,20 +1521,24 @@ xfs_trans_committed_bulk(
 }
 
 /*
- * Called from the trans_commit code when we notice that
- * the filesystem is in the middle of a forced shutdown.
+ * Called from the trans_commit code when we notice that the filesystem is in
+ * the middle of a forced shutdown.
+ *
+ * When we are called here, we have already pinned all the items in the
+ * transaction. However, neither IOP_COMMITTING or IOP_UNLOCK has been called
+ * so we can simply walk the items in the transaction, unpin them with an abort
+ * flag and then free the items. Note that unpinning the items can result in
+ * them being freed immediately, so we need to use a safe list traversal method
+ * here.
  */
 STATIC void
 xfs_trans_uncommit(
        struct xfs_trans        *tp,
        uint                    flags)
 {
-       struct xfs_log_item_desc *lidp;
+       struct xfs_log_item_desc *lidp, *n;
 
-       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               /*
-                * Unpin all but those that aren't dirty.
-                */
+       list_for_each_entry_safe(lidp, n, &tp->t_items, lid_trans) {
                if (lidp->lid_flags & XFS_LID_DIRTY)
                        IOP_UNPIN(lidp->lid_item, 1);
        }
@@ -1733,7 +1755,6 @@ xfs_trans_commit_cil(
        int                     flags)
 {
        struct xfs_log_vec      *log_vector;
-       int                     error;
 
        /*
         * Get each log item to allocate a vector structure for
@@ -1744,9 +1765,7 @@ xfs_trans_commit_cil(
        if (!log_vector)
                return ENOMEM;
 
-       error = xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
-       if (error)
-               return error;
+       xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
 
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
        xfs_trans_free(tp);
index 17714be..5b6c391 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9cf736e..fc1575f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bc4a6de..ef1cef7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a091cab..de39915 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 65b3f58..a3252a5 100644 (file)
@@ -8,7 +8,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 241b8a0..e46ec95 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20101209
+#define ACPI_CA_VERSION                 0x20110112
 
 #include "actypes.h"
 #include "actbl.h"
index e552635..0a66cc4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ad20016..7e42bfe 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cd77aa7..7504bc9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d4136b2..0fc15df 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 939a431..64f838b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a3e334a..5af3ed5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5dcb953..e228893 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 572189e..5d2a5e9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 31b6188..b4bfe33 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef __ASSEMBLY__
 #ifdef CONFIG_MMU
 
+#include <linux/mm_types.h>
+
 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 extern int ptep_set_access_flags(struct vm_area_struct *vma,
                                 unsigned long address, pte_t *ptep,
index 6864933..fe77e33 100644 (file)
 #endif
 
 #ifdef CONFIG_EVENT_TRACING
-#define FTRACE_EVENTS()        VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
+#define FTRACE_EVENTS()        . = ALIGN(8);                                   \
+                       VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
                        *(_ftrace_events)                               \
                        VMLINUX_SYMBOL(__stop_ftrace_events) = .;
 #else
 #endif
 
 #ifdef CONFIG_FTRACE_SYSCALLS
-#define TRACE_SYSCALLS() VMLINUX_SYMBOL(__start_syscalls_metadata) = .;        \
+#define TRACE_SYSCALLS() . = ALIGN(8);                                 \
+                        VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
                         *(__syscalls_metadata)                         \
                         VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
 #else
        CPU_KEEP(exit.data)                                             \
        MEM_KEEP(init.data)                                             \
        MEM_KEEP(exit.data)                                             \
-       . = ALIGN(32);                                                  \
-       VMLINUX_SYMBOL(__start___tracepoints) = .;                      \
+       STRUCT_ALIGN();                                                 \
        *(__tracepoints)                                                \
-       VMLINUX_SYMBOL(__stop___tracepoints) = .;                       \
        /* implement dynamic printk debug */                            \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__start___verbose) = .;                          \
        VMLINUX_SYMBOL(__stop___verbose) = .;                           \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()                                                \
-       TRACE_PRINTKS()                                                 \
-                                                                       \
-       STRUCT_ALIGN();                                                 \
-       FTRACE_EVENTS()                                                 \
-                                                                       \
-       STRUCT_ALIGN();                                                 \
-       TRACE_SYSCALLS()
+       TRACE_PRINTKS()
 
 /*
  * Data section helpers
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
                *(.rodata) *(.rodata.*)                                 \
                *(__vermagic)           /* Kernel version magic */      \
+               . = ALIGN(8);                                           \
+               VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;         \
+               *(__tracepoints_ptrs)   /* Tracepoints: pointer array */\
+               VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .;          \
                *(__markers_strings)    /* Markers: strings */          \
                *(__tracepoints_strings)/* Tracepoints: strings */      \
        }                                                               \
                VMLINUX_SYMBOL(__start___param) = .;                    \
                *(__param)                                              \
                VMLINUX_SYMBOL(__stop___param) = .;                     \
+       }                                                               \
+                                                                       \
+       /* Built-in module versions. */                                 \
+       __modver : AT(ADDR(__modver) - LOAD_OFFSET) {                   \
+               VMLINUX_SYMBOL(__start___modver) = .;                   \
+               *(__modver)                                             \
+               VMLINUX_SYMBOL(__stop___modver) = .;                    \
                . = ALIGN((align));                                     \
                VMLINUX_SYMBOL(__end_rodata) = .;                       \
        }                                                               \
        KERNEL_CTORS()                                                  \
        *(.init.rodata)                                                 \
        MCOUNT_REC()                                                    \
+       FTRACE_EVENTS()                                                 \
+       TRACE_SYSCALLS()                                                \
        DEV_DISCARD(init.rodata)                                        \
        CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.rodata)                                        \
index a4694c6..348843b 100644 (file)
@@ -1101,7 +1101,7 @@ struct drm_device {
        struct platform_device *platformdev; /**< Platform device struture */
 
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
-       int num_crtcs;                  /**< Number of CRTCs on this device */
+       unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
        void *dev_private;              /**< device private data */
        void *mm_private;
        struct address_space *dev_mapping;
@@ -1367,7 +1367,7 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
-extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern void drm_vblank_off(struct drm_device *dev, int crtc);
index acd7fad..801be59 100644 (file)
@@ -275,6 +275,7 @@ struct drm_pending_vblank_event;
 
 /**
  * drm_crtc_funcs - control CRTCs for a given device
+ * @reset: reset CRTC after state has been invalidate (e.g. resume)
  * @dpms: control display power levels
  * @save: save CRTC state
  * @resore: restore CRTC state
@@ -302,6 +303,8 @@ struct drm_crtc_funcs {
        void (*save)(struct drm_crtc *crtc); /* suspend? */
        /* Restore CRTC state */
        void (*restore)(struct drm_crtc *crtc); /* resume? */
+       /* Reset CRTC state */
+       void (*reset)(struct drm_crtc *crtc);
 
        /* cursor controls */
        int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
@@ -379,6 +382,7 @@ struct drm_crtc {
  * @dpms: set power state (see drm_crtc_funcs above)
  * @save: save connector state
  * @restore: restore connector state
+ * @reset: reset connector after state has been invalidate (e.g. resume)
  * @mode_valid: is this mode valid on the given connector?
  * @mode_fixup: try to fixup proposed mode for this connector
  * @mode_set: set this mode
@@ -396,6 +400,7 @@ struct drm_connector_funcs {
        void (*dpms)(struct drm_connector *connector, int mode);
        void (*save)(struct drm_connector *connector);
        void (*restore)(struct drm_connector *connector);
+       void (*reset)(struct drm_connector *connector);
 
        /* Check to see if anything is attached to the connector.
         * @force is set to false whilst polling, true when checking the
@@ -413,6 +418,7 @@ struct drm_connector_funcs {
 };
 
 struct drm_encoder_funcs {
+       void (*reset)(struct drm_encoder *encoder);
        void (*destroy)(struct drm_encoder *encoder);
 };
 
@@ -656,6 +662,7 @@ extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
                                                   struct drm_display_mode *mode);
 extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
 extern void drm_mode_config_init(struct drm_device *dev);
+extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 extern void drm_mode_set_name(struct drm_display_mode *mode);
 extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
index fe29ae3..5ff1194 100644 (file)
@@ -28,7 +28,6 @@
        {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
        {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
        {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-       {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
index e95a86b..e5c607a 100644 (file)
@@ -907,6 +907,7 @@ struct drm_radeon_cs {
 #define RADEON_INFO_TILING_CONFIG      0x06
 #define RADEON_INFO_WANT_HYPERZ                0x07
 #define RADEON_INFO_WANT_CMASK         0x08 /* get access to CMASK on r300 */
+#define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */
 
 struct drm_radeon_info {
        uint32_t                request;
index 5cb86c3..fc48754 100644 (file)
@@ -99,7 +99,6 @@ struct rxrpc_key_token {
  * structure of raw payloads passed to add_key() or instantiate key
  */
 struct rxrpc_key_data_v1 {
-       u32             kif_version;            /* 1 */
        u16             security_index;
        u16             ticket_length;
        u32             expiry;                 /* time_t */
index 2296d8b..b0ada6f 100644 (file)
@@ -1,5 +1,6 @@
 header-y += byteorder/
 header-y += can/
+header-y += caif/
 header-y += dvb/
 header-y += hdlc/
 header-y += isdn/
index eb176bb..a2e910e 100644 (file)
@@ -306,9 +306,6 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
                                             u32 *mask, u32 req);
 extern void acpi_early_init(void);
 
-int acpi_os_map_generic_address(struct acpi_generic_address *addr);
-void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
-
 #else  /* !CONFIG_ACPI */
 
 #define acpi_disabled 1
diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h
new file mode 100644 (file)
index 0000000..7180013
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _ACPI_IO_H_
+#define _ACPI_IO_H_
+
+#include <linux/io.h>
+#include <acpi/acpi.h>
+
+static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
+                                           acpi_size size)
+{
+       return ioremap_cache(phys, size);
+}
+
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
+#endif
index 4d18ff3..d5063e1 100644 (file)
@@ -699,7 +699,7 @@ extern void blk_start_queue(struct request_queue *q);
 extern void blk_stop_queue(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
-extern void __blk_run_queue(struct request_queue *);
+extern void __blk_run_queue(struct request_queue *q, bool force_kblockd);
 extern void blk_run_queue(struct request_queue *);
 extern int blk_rq_map_user(struct request_queue *, struct request *,
                           struct rq_map_data *, void __user *, unsigned long,
@@ -1088,7 +1088,6 @@ static inline void put_dev_sector(Sector p)
 
 struct work_struct;
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
-int kblockd_schedule_delayed_work(struct request_queue *q, struct delayed_work *dwork, unsigned long delay);
 
 #ifdef CONFIG_BLK_CGROUP
 /*
@@ -1136,7 +1135,6 @@ static inline uint64_t rq_io_start_time_ns(struct request *req)
 extern int blk_throtl_init(struct request_queue *q);
 extern void blk_throtl_exit(struct request_queue *q);
 extern int blk_throtl_bio(struct request_queue *q, struct bio **bio);
-extern void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay);
 extern void throtl_shutdown_timer_wq(struct request_queue *q);
 #else /* CONFIG_BLK_DEV_THROTTLING */
 static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
@@ -1146,7 +1144,6 @@ static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
 
 static inline int blk_throtl_init(struct request_queue *q) { return 0; }
 static inline int blk_throtl_exit(struct request_queue *q) { return 0; }
-static inline void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay) {}
 static inline void throtl_shutdown_timer_wq(struct request_queue *q) {}
 #endif /* CONFIG_BLK_DEV_THROTTLING */
 
index 3395cf7..b22fb0d 100644 (file)
@@ -245,7 +245,6 @@ static inline int blk_cmd_buf_len(struct request *rq)
 
 extern void blk_dump_cmd(char *buf, struct request *rq);
 extern void blk_fill_rwbs(char *rwbs, u32 rw, int bytes);
-extern void blk_fill_rwbs_rq(char *rwbs, struct request *rq);
 
 #endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */
 
diff --git a/include/linux/caif/Kbuild b/include/linux/caif/Kbuild
new file mode 100644 (file)
index 0000000..a9cf250
--- /dev/null
@@ -0,0 +1,2 @@
+header-y += caif_socket.h
+header-y += if_caif.h
index c3011be..31d91a6 100644 (file)
@@ -123,6 +123,7 @@ struct ceph_msg_pos {
 #define SOCK_CLOSED    11 /* socket state changed to closed */
 #define OPENING         13 /* open connection w/ (possibly new) peer */
 #define DEAD            14 /* dead, about to kfree */
+#define BACKOFF         15
 
 /*
  * A single connection with another host.
@@ -160,7 +161,6 @@ struct ceph_connection {
        struct list_head out_queue;
        struct list_head out_sent;   /* sending or sent but unacked */
        u64 out_seq;                 /* last message queued for send */
-       bool out_keepalive_pending;
 
        u64 in_seq, in_seq_acked;  /* last message received, acked */
 
index 9774fe6..7453cfd 100644 (file)
@@ -139,9 +139,9 @@ extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_n
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
 extern struct console *console_drivers;
-extern void acquire_console_sem(void);
-extern int try_acquire_console_sem(void);
-extern void release_console_sem(void);
+extern void console_lock(void);
+extern int console_trylock(void);
+extern void console_unlock(void);
 extern void console_conditional_schedule(void);
 extern void console_unblank(void);
 extern struct tty_driver *console_device(int *);
index 68cd248..66900e3 100644 (file)
@@ -101,8 +101,8 @@ struct ieee_pfc {
  */
 struct dcb_app {
        __u8    selector;
-       __u32   protocol;
        __u8    priority;
+       __u16   protocol;
 };
 
 struct dcbmsg {
index da7e52b..1effc8b 100644 (file)
@@ -109,7 +109,7 @@ static inline void freezer_count(void)
 }
 
 /*
- * Check if the task should be counted as freezeable by the freezer
+ * Check if the task should be counted as freezable by the freezer
  */
 static inline int freezer_should_skip(struct task_struct *p)
 {
index 32b38cd..e38b50a 100644 (file)
@@ -649,6 +649,7 @@ struct address_space {
        spinlock_t              private_lock;   /* for use by the address_space */
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
+       struct mutex            unmap_mutex;    /* to protect unmapping */
 } __attribute__((aligned(sizeof(long))));
        /*
         * On most architectures that alignment is already the case; but
@@ -2139,7 +2140,7 @@ extern void check_disk_size_change(struct gendisk *disk,
                                   struct block_device *bdev);
 extern int revalidate_disk(struct gendisk *);
 extern int check_disk_change(struct block_device *);
-extern int __invalidate_device(struct block_device *);
+extern int __invalidate_device(struct block_device *, bool);
 extern int invalidate_partition(struct gendisk *, int);
 #endif
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
@@ -2225,6 +2226,7 @@ extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin);
 
 extern int inode_init_always(struct super_block *, struct inode *);
 extern void inode_init_once(struct inode *);
+extern void address_space_init_once(struct address_space *mapping);
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -2555,9 +2557,12 @@ int proc_nr_inodes(struct ctl_table *table, int write,
                   void __user *buffer, size_t *lenp, loff_t *ppos);
 int __init get_filesystem_list(char *buf);
 
+#define __FMODE_EXEC           ((__force int) FMODE_EXEC)
+#define __FMODE_NONOTIFY       ((__force int) FMODE_NONOTIFY)
+
 #define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
 #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
-                                           (flag & FMODE_NONOTIFY)))
+                                           (flag & __FMODE_NONOTIFY)))
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index a3b148a..dca3176 100644 (file)
@@ -249,7 +249,7 @@ static inline enum zone_type gfp_zone(gfp_t flags)
                                         ((1 << ZONES_SHIFT) - 1);
 
        if (__builtin_constant_p(bit))
-               MAYBE_BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
+               BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
        else {
 #ifdef CONFIG_DEBUG_VM
                BUG_ON((GFP_ZONE_BAD >> bit) & 1);
@@ -332,16 +332,19 @@ alloc_pages(gfp_t gfp_mask, unsigned int order)
        return alloc_pages_current(gfp_mask, order);
 }
 extern struct page *alloc_pages_vma(gfp_t gfp_mask, int order,
-                       struct vm_area_struct *vma, unsigned long addr);
+                       struct vm_area_struct *vma, unsigned long addr,
+                       int node);
 #else
 #define alloc_pages(gfp_mask, order) \
                alloc_pages_node(numa_node_id(), gfp_mask, order)
-#define alloc_pages_vma(gfp_mask, order, vma, addr)    \
+#define alloc_pages_vma(gfp_mask, order, vma, addr, node)      \
        alloc_pages(gfp_mask, order)
 #endif
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
-#define alloc_page_vma(gfp_mask, vma, addr)    \
-       alloc_pages_vma(gfp_mask, 0, vma, addr)
+#define alloc_page_vma(gfp_mask, vma, addr)                    \
+       alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id())
+#define alloc_page_vma_node(gfp_mask, vma, addr, node)         \
+       alloc_pages_vma(gfp_mask, 0, vma, addr, node)
 
 extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
 extern unsigned long get_zeroed_page(gfp_t gfp_mask);
index 8e6c8c4..df29c8f 100644 (file)
@@ -57,7 +57,8 @@ extern pmd_t *page_check_address_pmd(struct page *page,
          (transparent_hugepage_flags &                                 \
           (1<<TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG) &&                   \
           ((__vma)->vm_flags & VM_HUGEPAGE))) &&                       \
-        !((__vma)->vm_flags & VM_NOHUGEPAGE))
+        !((__vma)->vm_flags & VM_NOHUGEPAGE) &&                        \
+        !is_vma_temporary_stack(__vma))
 #define transparent_hugepage_defrag(__vma)                             \
        ((transparent_hugepage_flags &                                  \
          (1<<TRANSPARENT_HUGEPAGE_DEFRAG_FLAG)) ||                     \
index 6042228..294169e 100644 (file)
@@ -959,7 +959,7 @@ struct ieee80211_ht_info {
 /* block-ack parameters */
 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
 #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
 #define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
 #define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
 
index e470d38..05e0328 100644 (file)
@@ -12,8 +12,6 @@
  * @cs_en:     pointer to the cs enable function
  * @cs_dis:    pointer to the cs disable function
  * @irq_read_val:    pointer to read the pen irq value function
- * @x_max_res: xmax resolution
- * @y_max_res: ymax resolution
  * @touch_x_max: touch x max
  * @touch_y_max: touch y max
  * @cs_pin: chip select pin
@@ -29,8 +27,6 @@ struct bu21013_platform_device {
        int (*cs_en)(int reset_pin);
        int (*cs_dis)(int reset_pin);
        int (*irq_read_val)(void);
-       int x_max_res;
-       int y_max_res;
        int touch_x_max;
        int touch_y_max;
        unsigned int cs_pin;
index 6974746..fe7c4b9 100644 (file)
@@ -4,8 +4,8 @@
 #include <linux/types.h>
 #include <linux/input.h>
 
-#define MATRIX_MAX_ROWS                16
-#define MATRIX_MAX_COLS                16
+#define MATRIX_MAX_ROWS                32
+#define MATRIX_MAX_COLS                32
 
 #define KEY(row, col, val)     ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\
                                 (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\
index abde252..80fcb53 100644 (file)
@@ -74,7 +74,8 @@ typedef       void (*irq_flow_handler_t)(unsigned int irq,
 
 #define IRQF_MODIFY_MASK       \
        (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
-        IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL)
+        IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
+        IRQ_PER_CPU)
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
index 6a64c6f..c1a95b7 100644 (file)
@@ -101,13 +101,6 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
 #define get_irq_desc_msi(desc)         ((desc)->irq_data.msi_desc)
 
 /*
- * Monolithic do_IRQ implementation.
- */
-#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-extern unsigned int __do_IRQ(unsigned int irq);
-#endif
-
-/*
  * Architectures call this to let the generic IRQ layer
  * handle an interrupt. If the descriptor is attached to an
  * irqchip-style controller then we call the ->handle_irq() handler,
@@ -115,14 +108,7 @@ extern unsigned int __do_IRQ(unsigned int irq);
  */
 static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
 {
-#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
        desc->handle_irq(irq, desc);
-#else
-       if (likely(desc->handle_irq))
-               desc->handle_irq(irq, desc);
-       else
-               __do_IRQ(irq);
-#endif
 }
 
 static inline void generic_handle_irq(unsigned int irq)
index 5a9d905..2fe6e84 100644 (file)
@@ -243,6 +243,8 @@ extern int test_taint(unsigned flag);
 extern unsigned long get_taint(void);
 extern int root_mountflags;
 
+extern bool early_boot_irqs_disabled;
+
 /* Values used for system_state */
 extern enum system_states {
        SYSTEM_BOOTING,
@@ -573,12 +575,6 @@ struct sysinfo {
        char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
 };
 
-/* Force a compilation error if condition is true */
-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
-
-/* Force a compilation error if condition is constant and true */
-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
-
 /* Force a compilation error if a constant expression is not a power of 2 */
 #define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
        BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
@@ -590,6 +586,32 @@ struct sysinfo {
 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
 #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
 
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @condition: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions).  So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed".  This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition)                                        \
+       do {                                                    \
+               ((void)sizeof(char[1 - 2*!!(condition)]));      \
+               if (condition) __build_bug_on_failed = 1;       \
+       } while(0)
+#endif
+
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
 
index e91a4e5..a370ce5 100644 (file)
@@ -22,7 +22,7 @@ struct klist {
        struct list_head        k_list;
        void                    (*get)(struct klist_node *);
        void                    (*put)(struct klist_node *);
-} __attribute__ ((aligned (4)));
+} __attribute__ ((aligned (sizeof(void *))));
 
 #define KLIST_INIT(_name, _get, _put)                                  \
        { .k_lock       = __SPIN_LOCK_UNLOCKED(_name.k_lock),           \
index 08d7dc4..39f8453 100644 (file)
@@ -76,7 +76,7 @@ bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);
                                                                        \
                _n = (long) &((ptr)->name##_end)                        \
                        - (long) &((ptr)->name##_begin);                \
-               MAYBE_BUILD_BUG_ON(_n < 0);                             \
+               BUILD_BUG_ON(_n < 0);                                   \
                                                                        \
                kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \
        } while (0)
index 9a5f8a7..3a54266 100644 (file)
@@ -96,6 +96,11 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
  * in an undefined state.
  */
 #ifndef CONFIG_DEBUG_LIST
+static inline void __list_del_entry(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+}
+
 static inline void list_del(struct list_head *entry)
 {
        __list_del(entry->prev, entry->next);
@@ -103,6 +108,7 @@ static inline void list_del(struct list_head *entry)
        entry->prev = LIST_POISON2;
 }
 #else
+extern void __list_del_entry(struct list_head *entry);
 extern void list_del(struct list_head *entry);
 #endif
 
@@ -135,7 +141,7 @@ static inline void list_replace_init(struct list_head *old,
  */
 static inline void list_del_init(struct list_head *entry)
 {
-       __list_del(entry->prev, entry->next);
+       __list_del_entry(entry);
        INIT_LIST_HEAD(entry);
 }
 
@@ -146,7 +152,7 @@ static inline void list_del_init(struct list_head *entry)
  */
 static inline void list_move(struct list_head *list, struct list_head *head)
 {
-       __list_del(list->prev, list->next);
+       __list_del_entry(list);
        list_add(list, head);
 }
 
@@ -158,7 +164,7 @@ static inline void list_move(struct list_head *list, struct list_head *head)
 static inline void list_move_tail(struct list_head *list,
                                  struct list_head *head)
 {
-       __list_del(list->prev, list->next);
+       __list_del_entry(list);
        list_add_tail(list, head);
 }
 
index 71c09b2..4aef1dd 100644 (file)
@@ -436,16 +436,8 @@ do {                                                               \
 #endif /* CONFIG_LOCKDEP */
 
 #ifdef CONFIG_TRACE_IRQFLAGS
-extern void early_boot_irqs_off(void);
-extern void early_boot_irqs_on(void);
 extern void print_irqtrace_events(struct task_struct *curr);
 #else
-static inline void early_boot_irqs_off(void)
-{
-}
-static inline void early_boot_irqs_on(void)
-{
-}
 static inline void print_irqtrace_events(struct task_struct *curr)
 {
 }
@@ -522,12 +514,15 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # ifdef CONFIG_PROVE_LOCKING
 #  define lock_map_acquire(l)          lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_)
+#  define lock_map_acquire_read(l)     lock_acquire(l, 0, 0, 2, 2, NULL, _THIS_IP_)
 # else
 #  define lock_map_acquire(l)          lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
+#  define lock_map_acquire_read(l)     lock_acquire(l, 0, 0, 2, 1, NULL, _THIS_IP_)
 # endif
 # define lock_map_release(l)                   lock_release(l, 1, _THIS_IP_)
 #else
 # define lock_map_acquire(l)                   do { } while (0)
+# define lock_map_acquire_read(l)              do { } while (0)
 # define lock_map_release(l)                   do { } while (0)
 #endif
 
index 6a576f9..f512e18 100644 (file)
@@ -146,6 +146,10 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                                                gfp_t gfp_mask);
 u64 mem_cgroup_get_limit(struct mem_cgroup *mem);
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
+#endif
+
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct mem_cgroup;
 
@@ -335,6 +339,11 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *mem)
        return 0;
 }
 
+static inline void mem_cgroup_split_huge_fixup(struct page *head,
+                                               struct page *tail)
+{
+}
+
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #endif /* _LINUX_MEMCONTROL_H */
index 3fd3684..ef4f0b6 100644 (file)
@@ -71,6 +71,7 @@ struct wm8994 {
        u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
 
        /* Used over suspend/resume */
+       bool suspended;
        u16 ldo_regs[WM8994_NUM_LDO_REGS];
        u16 gpio_regs[WM8994_NUM_GPIO_REGS];
 
index 956a355..f6385fc 100644 (file)
@@ -470,6 +470,7 @@ static inline void set_compound_order(struct page *page, unsigned long order)
        page[1].lru.prev = (void *)order;
 }
 
+#ifdef CONFIG_MMU
 /*
  * Do pte_mkwrite, but only if the vma says VM_WRITE.  We do this when
  * servicing faults for write access.  In the normal case, do always want
@@ -482,6 +483,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
                pte = pte_mkwrite(pte);
        return pte;
 }
+#endif
 
 /*
  * Multiple processes may "see" the same page. E.g. for untouched
index bf17350..38d3930 100644 (file)
@@ -94,12 +94,12 @@ struct sh_mmcif_plat_data {
 
 static inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
 {
-       return readl(addr + reg);
+       return __raw_readl(addr + reg);
 }
 
 static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 {
-       writel(val, addr + reg);
+       __raw_writel(val, addr + reg);
 }
 
 #define SH_MMCIF_BBS 512 /* boot block size */
index 8b17fd8..5de4204 100644 (file)
@@ -58,6 +58,12 @@ struct module_attribute {
        void (*free)(struct module *);
 };
 
+struct module_version_attribute {
+       struct module_attribute mattr;
+       const char *module_name;
+       const char *version;
+} __attribute__ ((__aligned__(sizeof(void *))));
+
 struct module_kobject
 {
        struct kobject kobj;
@@ -161,7 +167,28 @@ extern struct module __this_module;
   Using this automatically adds a checksum of the .c files and the
   local headers in "srcversion".
 */
+
+#if defined(MODULE) || !defined(CONFIG_SYSFS)
 #define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#else
+#define MODULE_VERSION(_version)                                       \
+       extern ssize_t __modver_version_show(struct module_attribute *, \
+                                            struct module *, char *);  \
+       static struct module_version_attribute __modver_version_attr    \
+       __used                                                          \
+    __attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
+       = {                                                             \
+               .mattr  = {                                             \
+                       .attr   = {                                     \
+                               .name   = "version",                    \
+                               .mode   = S_IRUGO,                      \
+                       },                                              \
+                       .show   = __modver_version_show,                \
+               },                                                      \
+               .module_name    = KBUILD_MODNAME,                       \
+               .version        = _version,                             \
+       }
+#endif
 
 /* Optional firmware file (or files) needed by the module
  * format is simply firmware file name.  Multiple firmware
@@ -350,7 +377,7 @@ struct module
           keeping pointers to this stuff */
        char *args;
 #ifdef CONFIG_TRACEPOINTS
-       struct tracepoint *tracepoints;
+       struct tracepoint * const *tracepoints_ptrs;
        unsigned int num_tracepoints;
 #endif
 #ifdef HAVE_JUMP_LABEL
@@ -362,7 +389,7 @@ struct module
        unsigned int num_trace_bprintk_fmt;
 #endif
 #ifdef CONFIG_EVENT_TRACING
-       struct ftrace_event_call *trace_events;
+       struct ftrace_event_call **trace_events;
        unsigned int num_trace_events;
 #endif
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
index 112adf8..07b4195 100644 (file)
 /* Chosen so that structs with an unsigned long line up. */
 #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
 
-#ifdef MODULE
 #define ___module_cat(a,b) __mod_ ## a ## b
 #define __module_cat(a,b) ___module_cat(a,b)
+#ifdef MODULE
 #define __MODULE_INFO(tag, name, info)                                   \
 static const char __module_cat(name,__LINE__)[]                                  \
   __used __attribute__((section(".modinfo"), unused, aligned(1)))        \
   = __stringify(tag) "=" info
 #else  /* !MODULE */
-#define __MODULE_INFO(tag, name, info)
+/* This struct is here for syntactic coherency, it is not used */
+#define __MODULE_INFO(tag, name, info)                                   \
+  struct __module_cat(name,__LINE__) {}
 #endif
 #define __MODULE_PARM_TYPE(name, _type)                                          \
   __MODULE_INFO(parmtype, name##type, #name ":" _type)
index 0fa7a3a..b21d567 100644 (file)
@@ -150,6 +150,7 @@ static inline int ip_mroute_opt(int opt)
 extern int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int);
 extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
+extern int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
 extern int ip_mr_init(void);
 #else
 static inline
index 6091ab7..9d2deb2 100644 (file)
@@ -136,6 +136,7 @@ extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, unsigned int
 extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ip6_mr_input(struct sk_buff *skb);
 extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
+extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
 extern int ip6_mr_init(void);
 extern void ip6_mr_cleanup(void);
 #else
index f321b57..fabcb1e 100644 (file)
@@ -51,10 +51,10 @@ nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
        return w;
 }
 
-extern unsigned int
+extern int
 nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
              struct posix_acl *acl, int encode_entries, int typeflag);
-extern unsigned int
+extern int
 nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
              struct posix_acl **pacl);
 
index 32fb812..1ca6411 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/printk.h>
 #include <asm/atomic.h>
  
 /* Each escaped entry is prefixed by ESCAPE_CODE
@@ -186,10 +188,17 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val);
 int oprofile_add_data64(struct op_entry *entry, u64 val);
 int oprofile_write_commit(struct op_entry *entry);
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_HW_PERF_EVENTS
 int __init oprofile_perf_init(struct oprofile_operations *ops);
 void oprofile_perf_exit(void);
 char *op_name_from_perf_id(void);
-#endif /* CONFIG_PERF_EVENTS */
+#else
+static inline int __init oprofile_perf_init(struct oprofile_operations *ops)
+{
+       pr_info("oprofile: hardware counters not available\n");
+       return -ENODEV;
+}
+static inline void oprofile_perf_exit(void) { }
+#endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* OPROFILE_H */
index dd9c7ab..21415cc 100644 (file)
@@ -431,6 +431,8 @@ struct dev_pm_info {
        struct list_head        entry;
        struct completion       completion;
        struct wakeup_source    *wakeup;
+#else
+       unsigned int            should_wakeup:1;
 #endif
 #ifdef CONFIG_PM_RUNTIME
        struct timer_list       suspend_timer;
index 9cff00d..03a67db 100644 (file)
@@ -109,11 +109,6 @@ static inline bool device_can_wakeup(struct device *dev)
        return dev->power.can_wakeup;
 }
 
-static inline bool device_may_wakeup(struct device *dev)
-{
-       return false;
-}
-
 static inline struct wakeup_source *wakeup_source_create(const char *name)
 {
        return NULL;
@@ -134,24 +129,32 @@ static inline void wakeup_source_unregister(struct wakeup_source *ws) {}
 
 static inline int device_wakeup_enable(struct device *dev)
 {
-       return -EINVAL;
+       dev->power.should_wakeup = true;
+       return 0;
 }
 
 static inline int device_wakeup_disable(struct device *dev)
 {
+       dev->power.should_wakeup = false;
        return 0;
 }
 
-static inline int device_init_wakeup(struct device *dev, bool val)
+static inline int device_set_wakeup_enable(struct device *dev, bool enable)
 {
-       dev->power.can_wakeup = val;
-       return val ? -EINVAL : 0;
+       dev->power.should_wakeup = enable;
+       return 0;
 }
 
+static inline int device_init_wakeup(struct device *dev, bool val)
+{
+       device_set_wakeup_capable(dev, val);
+       device_set_wakeup_enable(dev, val);
+       return 0;
+}
 
-static inline int device_set_wakeup_enable(struct device *dev, bool enable)
+static inline bool device_may_wakeup(struct device *dev)
 {
-       return -EINVAL;
+       return dev->power.can_wakeup && dev->power.should_wakeup;
 }
 
 static inline void __pm_stay_awake(struct wakeup_source *ws) {}
index d68283a..54211c1 100644 (file)
@@ -71,6 +71,7 @@ posix_acl_release(struct posix_acl *acl)
 
 /* posix_acl.c */
 
+extern void posix_acl_init(struct posix_acl *, int);
 extern struct posix_acl *posix_acl_alloc(int, gfp_t);
 extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t);
 extern int posix_acl_valid(const struct posix_acl *);
index 092a04f..a1147e5 100644 (file)
 
 extern long arch_ptrace(struct task_struct *child, long request,
                        unsigned long addr, unsigned long data);
-extern int ptrace_traceme(void);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
-extern int ptrace_attach(struct task_struct *tsk);
-extern int ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 extern int ptrace_request(struct task_struct *child, long request,
index 94c1f03..9a85412 100644 (file)
@@ -322,9 +322,12 @@ struct dquot_operations {
        qsize_t *(*get_reserved_space) (struct inode *);
 };
 
+struct path;
+
 /* Operations handling requests from userspace */
 struct quotactl_ops {
-       int (*quota_on)(struct super_block *, int, int, char *);
+       int (*quota_on)(struct super_block *, int, int, struct path *);
+       int (*quota_on_meta)(struct super_block *, int, int);
        int (*quota_off)(struct super_block *, int);
        int (*quota_sync)(struct super_block *, int, int);
        int (*get_info)(struct super_block *, int, struct if_dqinfo *);
index 223b14c..eb354f6 100644 (file)
@@ -76,11 +76,9 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
 
 int dquot_file_open(struct inode *inode, struct file *file);
 
-int dquot_quota_on(struct super_block *sb, int type, int format_id,
-       char *path);
 int dquot_enable(struct inode *inode, int type, int format_id,
        unsigned int flags);
-int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
        struct path *path);
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        int format_id, int type);
index fcb9884..a5930cb 100644 (file)
@@ -182,6 +182,26 @@ static inline bool res_counter_check_under_limit(struct res_counter *cnt)
        return ret;
 }
 
+/**
+ * res_counter_check_margin - check if the counter allows charging
+ * @cnt: the resource counter to check
+ * @bytes: the number of bytes to check the remaining space against
+ *
+ * Returns a boolean value on whether the counter can be charged
+ * @bytes or whether this would exceed the limit.
+ */
+static inline bool res_counter_check_margin(struct res_counter *cnt,
+                                           unsigned long bytes)
+{
+       bool ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cnt->lock, flags);
+       ret = cnt->limit - cnt->usage >= bytes;
+       spin_unlock_irqrestore(&cnt->lock, flags);
+       return ret;
+}
+
 static inline bool res_counter_check_under_soft_limit(struct res_counter *cnt)
 {
        bool ret;
index d63dcba..9026b30 100644 (file)
 #define LINUX_RIO_REGS_H
 
 /*
- * In RapidIO, each device has a 2MB configuration space that is
+ * In RapidIO, each device has a 16MB configuration space that is
  * accessed via maintenance transactions.  Portions of configuration
  * space are standardized and/or reserved.
  */
+#define RIO_MAINT_SPACE_SZ     0x1000000 /* 16MB of RapidIO mainenance space */
+
 #define RIO_DEV_ID_CAR         0x00    /* [I] Device Identity CAR */
 #define RIO_DEV_INFO_CAR       0x04    /* [I] Device Information CAR */
 #define RIO_ASM_ID_CAR         0x08    /* [I] Assembly Identity CAR */
index 3c995b4..89c3e51 100644 (file)
@@ -203,6 +203,18 @@ struct rtc_device
        struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
        int pie_enabled;
        struct work_struct irqwork;
+
+
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       struct work_struct uie_task;
+       struct timer_list uie_timer;
+       /* Those fields are protected by rtc->irq_lock */
+       unsigned int oldsecs;
+       unsigned int uie_irq_active:1;
+       unsigned int stop_uie_polling:1;
+       unsigned int uie_task_active:1;
+       unsigned int uie_timer_active:1;
+#endif
 };
 #define to_rtc_device(d) container_of(d, struct rtc_device, dev)
 
@@ -238,6 +250,7 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
 extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
                                                unsigned int enabled);
 
+void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode);
 void rtc_aie_update_irq(void *private);
 void rtc_uie_update_irq(void *private);
 enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
@@ -246,8 +259,6 @@ int rtc_register(rtc_task_t *task);
 int rtc_unregister(rtc_task_t *task);
 int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
 
-void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
-void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
 void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
 int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
                        ktime_t expires, ktime_t period);
index d747f94..777d8a5 100644 (file)
@@ -1744,7 +1744,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
-#define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezeable */
+#define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
 #define PF_FREEZER_NOSIG 0x80000000    /* Freezer won't send signals to it */
 
 /*
index c642bb8..b2b7f97 100644 (file)
@@ -1662,7 +1662,7 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(int cap);
+int security_capable(const struct cred *cred, int cap);
 int security_real_capable(struct task_struct *tsk, int cap);
 int security_real_capable_noaudit(struct task_struct *tsk, int cap);
 int security_sysctl(struct ctl_table *table, int op);
@@ -1856,9 +1856,9 @@ static inline int security_capset(struct cred *new,
        return cap_capset(new, old, effective, inheritable, permitted);
 }
 
-static inline int security_capable(int cap)
+static inline int security_capable(const struct cred *cred, int cap)
 {
-       return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
+       return cap_capable(current, cred, cap, SECURITY_CAP_AUDIT);
 }
 
 static inline int security_real_capable(struct task_struct *tsk, int cap)
index c50b458..0828842 100644 (file)
@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
                return 1;
        return 0;
 }
-static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
-{
-       if (svc_is_backchannel(rqstp))
-               return (struct nfs4_sessionid *)
-                       rqstp->rq_server->sv_bc_xprt->xpt_bc_sid;
-       return NULL;
-}
-
 #else /* CONFIG_NFS_V4_1 */
 static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
                                         unsigned int min_reqs)
@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
        return 0;
 }
 
-static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
-{
-       return NULL;
-}
-
 static inline void xprt_free_bc_request(struct rpc_rqst *req)
 {
 }
index 059877b..7ad9751 100644 (file)
@@ -77,7 +77,6 @@ struct svc_xprt {
        size_t                  xpt_remotelen;  /* length of address */
        struct rpc_wait_queue   xpt_bc_pending; /* backchannel wait queue */
        struct list_head        xpt_users;      /* callbacks on free */
-       void                    *xpt_bc_sid;    /* back channel session ID */
 
        struct net              *xpt_net;
        struct rpc_xprt         *xpt_bc_xprt;   /* NFSv4.1 backchannel */
index 18cd068..98664db 100644 (file)
@@ -125,39 +125,37 @@ extern struct trace_event_functions enter_syscall_print_funcs;
 extern struct trace_event_functions exit_syscall_print_funcs;
 
 #define SYSCALL_TRACE_ENTER_EVENT(sname)                               \
-       static struct syscall_metadata                                  \
-       __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call __used                          \
-         __attribute__((__aligned__(4)))                               \
-         __attribute__((section("_ftrace_events")))                    \
          event_enter_##sname = {                                       \
                .name                   = "sys_enter"#sname,            \
                .class                  = &event_class_syscall_enter,   \
                .event.funcs            = &enter_syscall_print_funcs,   \
                .data                   = (void *)&__syscall_meta_##sname,\
        };                                                              \
+       static struct ftrace_event_call __used                          \
+         __attribute__((section("_ftrace_events")))                    \
+        *__event_enter_##sname = &event_enter_##sname;                 \
        __TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY)
 
 #define SYSCALL_TRACE_EXIT_EVENT(sname)                                        \
-       static struct syscall_metadata                                  \
-       __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call __used                          \
-         __attribute__((__aligned__(4)))                               \
-         __attribute__((section("_ftrace_events")))                    \
          event_exit_##sname = {                                        \
                .name                   = "sys_exit"#sname,             \
                .class                  = &event_class_syscall_exit,    \
                .event.funcs            = &exit_syscall_print_funcs,    \
                .data                   = (void *)&__syscall_meta_##sname,\
        };                                                              \
+       static struct ftrace_event_call __used                          \
+         __attribute__((section("_ftrace_events")))                    \
+       *__event_exit_##sname = &event_exit_##sname;                    \
        __TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY)
 
 #define SYSCALL_METADATA(sname, nb)                            \
        SYSCALL_TRACE_ENTER_EVENT(sname);                       \
        SYSCALL_TRACE_EXIT_EVENT(sname);                        \
        static struct syscall_metadata __used                   \
-         __attribute__((__aligned__(4)))                       \
-         __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta_##sname = {                            \
                .name           = "sys"#sname,                  \
                .nb_args        = nb,                           \
@@ -166,14 +164,15 @@ extern struct trace_event_functions exit_syscall_print_funcs;
                .enter_event    = &event_enter_##sname,         \
                .exit_event     = &event_exit_##sname,          \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
-       };
+       };                                                      \
+       static struct syscall_metadata __used                   \
+         __attribute__((section("__syscalls_metadata")))       \
+        *__p_syscall_meta_##sname = &__syscall_meta_##sname;
 
 #define SYSCALL_DEFINE0(sname)                                 \
        SYSCALL_TRACE_ENTER_EVENT(_##sname);                    \
        SYSCALL_TRACE_EXIT_EVENT(_##sname);                     \
        static struct syscall_metadata __used                   \
-         __attribute__((__aligned__(4)))                       \
-         __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta__##sname = {                           \
                .name           = "sys_"#sname,                 \
                .nb_args        = 0,                            \
@@ -181,6 +180,9 @@ extern struct trace_event_functions exit_syscall_print_funcs;
                .exit_event     = &event_exit__##sname,         \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
        };                                                      \
+       static struct syscall_metadata __used                   \
+         __attribute__((section("__syscalls_metadata")))       \
+        *__p_syscall_meta_##sname = &__syscall_meta__##sname;  \
        asmlinkage long sys_##sname(void)
 #else
 #define SYSCALL_DEFINE0(name)     asmlinkage long sys_##name(void)
index 387fa7d..7faf933 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 
+/* Enable/disable SYSRQ support by default (0==no, 1==yes). */
+#define SYSRQ_DEFAULT_ENABLE   1
+
 /* Possible values of bitmask for enabling sysrq functions */
 /* 0x0001 is reserved for enable everything */
 #define SYSRQ_ENABLE_LOG       0x0002
index 8651556..d3ec89f 100644 (file)
@@ -172,6 +172,14 @@ void thermal_zone_device_update(struct thermal_zone_device *);
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
                const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+
+#ifdef CONFIG_NET
 extern int generate_netlink_event(u32 orig, enum events event);
+#else
+static inline int generate_netlink_event(u32 orig, enum events event)
+{
+       return 0;
+}
+#endif
 
 #endif /* __THERMAL_H__ */
index c681461..97c84a5 100644 (file)
@@ -33,12 +33,7 @@ struct tracepoint {
        void (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
-} __attribute__((aligned(32)));                /*
-                                        * Aligned on 32 bytes because it is
-                                        * globally visible and gcc happily
-                                        * align these on the structure size.
-                                        * Keep in sync with vmlinux.lds.h.
-                                        */
+};
 
 /*
  * Connect a probe to a tracepoint.
@@ -61,15 +56,15 @@ extern void tracepoint_probe_update_all(void);
 
 struct tracepoint_iter {
        struct module *module;
-       struct tracepoint *tracepoint;
+       struct tracepoint * const *tracepoint;
 };
 
 extern void tracepoint_iter_start(struct tracepoint_iter *iter);
 extern void tracepoint_iter_next(struct tracepoint_iter *iter);
 extern void tracepoint_iter_stop(struct tracepoint_iter *iter);
 extern void tracepoint_iter_reset(struct tracepoint_iter *iter);
-extern int tracepoint_get_iter_range(struct tracepoint **tracepoint,
-       struct tracepoint *begin, struct tracepoint *end);
+extern int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
+       struct tracepoint * const *begin, struct tracepoint * const *end);
 
 /*
  * tracepoint_synchronize_unregister must be called between the last tracepoint
@@ -84,11 +79,13 @@ static inline void tracepoint_synchronize_unregister(void)
 #define PARAMS(args...) args
 
 #ifdef CONFIG_TRACEPOINTS
-extern void tracepoint_update_probe_range(struct tracepoint *begin,
-       struct tracepoint *end);
+extern
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+       struct tracepoint * const *end);
 #else
-static inline void tracepoint_update_probe_range(struct tracepoint *begin,
-       struct tracepoint *end)
+static inline
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+       struct tracepoint * const *end)
 { }
 #endif /* CONFIG_TRACEPOINTS */
 
@@ -174,12 +171,20 @@ do_trace:                                                         \
        {                                                               \
        }
 
+/*
+ * We have no guarantee that gcc and the linker won't up-align the tracepoint
+ * structures, so we create an array of pointers that will be used for iteration
+ * on the tracepoints.
+ */
 #define DEFINE_TRACE_FN(name, reg, unreg)                              \
        static const char __tpstrtab_##name[]                           \
        __attribute__((section("__tracepoints_strings"))) = #name;      \
        struct tracepoint __tracepoint_##name                           \
-       __attribute__((section("__tracepoints"), aligned(32))) =        \
-               { __tpstrtab_##name, 0, reg, unreg, NULL }
+       __attribute__((section("__tracepoints"))) =                     \
+               { __tpstrtab_##name, 0, reg, unreg, NULL };             \
+       static struct tracepoint * const __tracepoint_ptr_##name __used \
+       __attribute__((section("__tracepoints_ptrs"))) =                \
+               &__tracepoint_##name;
 
 #define DEFINE_TRACE(name)                                             \
        DEFINE_TRACE_FN(name, NULL, NULL);
index 5e86dc7..81a9279 100644 (file)
@@ -89,7 +89,7 @@ struct usb_cdc_acm_descriptor {
 
 #define USB_CDC_COMM_FEATURE   0x01
 #define USB_CDC_CAP_LINE       0x02
-#define USB_CDC_CAP_BRK        0x04
+#define USB_CDC_CAP_BRK                0x04
 #define USB_CDC_CAP_NOTIFY     0x08
 
 /* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
@@ -271,6 +271,11 @@ struct usb_cdc_notification {
        __le16  wLength;
 } __attribute__ ((packed));
 
+struct usb_cdc_speed_change {
+       __le32  DLBitRRate;     /* contains the downlink bit rate (IN pipe) */
+       __le32  ULBitRate;      /* contains the uplink bit rate (OUT pipe) */
+} __attribute__ ((packed));
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -292,7 +297,7 @@ struct usb_cdc_ncm_ntb_parameters {
        __le16  wNdpOutDivisor;
        __le16  wNdpOutPayloadRemainder;
        __le16  wNdpOutAlignment;
-       __le16  wPadding2;
+       __le16  wNtbOutMaxDatagrams;
 } __attribute__ ((packed));
 
 /*
@@ -307,7 +312,7 @@ struct usb_cdc_ncm_nth16 {
        __le16  wHeaderLength;
        __le16  wSequence;
        __le16  wBlockLength;
-       __le16  wFpIndex;
+       __le16  wNdpIndex;
 } __attribute__ ((packed));
 
 struct usb_cdc_ncm_nth32 {
@@ -315,7 +320,7 @@ struct usb_cdc_ncm_nth32 {
        __le16  wHeaderLength;
        __le16  wSequence;
        __le32  dwBlockLength;
-       __le32  dwFpIndex;
+       __le32  dwNdpIndex;
 } __attribute__ ((packed));
 
 /*
@@ -337,7 +342,7 @@ struct usb_cdc_ncm_dpe16 {
 struct usb_cdc_ncm_ndp16 {
        __le32  dwSignature;
        __le16  wLength;
-       __le16  wNextFpIndex;
+       __le16  wNextNdpIndex;
        struct  usb_cdc_ncm_dpe16 dpe16[0];
 } __attribute__ ((packed));
 
@@ -375,6 +380,7 @@ struct usb_cdc_ncm_ndp32 {
 #define USB_CDC_NCM_NCAP_ENCAP_COMMAND                 (1 << 2)
 #define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE             (1 << 3)
 #define USB_CDC_NCM_NCAP_CRC_MODE                      (1 << 4)
+#define        USB_CDC_NCM_NCAP_NTB_INPUT_SIZE                 (1 << 5)
 
 /* CDC NCM subclass Table 6-3: NTB Parameter Structure */
 #define USB_CDC_NCM_NTB16_SUPPORTED                    (1 << 0)
@@ -392,6 +398,13 @@ struct usb_cdc_ncm_ndp32 {
 #define USB_CDC_NCM_NTB_MIN_IN_SIZE                    2048
 #define USB_CDC_NCM_NTB_MIN_OUT_SIZE                   2048
 
+/* NTB Input Size Structure */
+struct usb_cdc_ncm_ndp_input_size {
+       __le32  dwNtbInMaxSize;
+       __le16  wNtbInMaxDatagrams;
+       __le16  wReserved;
+} __attribute__ ((packed));
+
 /* CDC NCM subclass 6.2.11 SetCrcMode */
 #define USB_CDC_NCM_CRC_NOT_APPENDED                   0x00
 #define USB_CDC_NCM_CRC_APPENDED                       0x01
index dd6ee49..a854fe8 100644 (file)
@@ -112,6 +112,7 @@ struct usb_hcd {
        /* Flags that get set only during HCD registration or removal. */
        unsigned                rh_registered:1;/* is root hub registered? */
        unsigned                rh_pollable:1;  /* may we poll the root hub? */
+       unsigned                msix_enabled:1; /* driver has MSI-X enabled? */
 
        /* The next flag is a stopgap, to be removed when all the HCDs
         * support the new root-hub polling mechanism. */
index b92e173..7d1babb 100644 (file)
 #ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__
 #define __LINUX_USB_GADGET_MSM72K_UDC_H__
 
-#ifdef CONFIG_ARCH_MSM7X00A
-#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
-#else
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
-#endif
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
index 16d682f..c904913 100644 (file)
@@ -347,6 +347,9 @@ extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,
 extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
                                        unsigned int ch);
 extern int usb_serial_handle_break(struct usb_serial_port *port);
+extern void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
+                                        struct tty_struct *tty,
+                                        unsigned int status);
 
 
 extern int usb_serial_bus_register(struct usb_serial_driver *device);
index 0093dd7..800617b 100644 (file)
@@ -109,7 +109,10 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
                                      unsigned int fbit)
 {
        /* Did you forget to fix assumptions on max features? */
-       MAYBE_BUILD_BUG_ON(fbit >= 32);
+       if (__builtin_constant_p(fbit))
+               BUILD_BUG_ON(fbit >= 32);
+       else
+               BUG_ON(fbit >= 32);
 
        if (fbit < VIRTIO_TRANSPORT_F_START)
                virtio_check_driver_offered_feature(vdev, fbit);
index a85064d..e4d3335 100644 (file)
@@ -7,7 +7,8 @@
  * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
  * anyone can use the definitions to implement compatible drivers/servers.
  *
- * Copyright (C) Red Hat, Inc., 2009, 2010
+ * Copyright (C) Red Hat, Inc., 2009, 2010, 2011
+ * Copyright (C) Amit Shah <amit.shah@redhat.com>, 2009, 2010, 2011
  */
 
 /* Feature bits */
index 1ac1158..f7998a3 100644 (file)
@@ -250,7 +250,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
 enum {
        WQ_NON_REENTRANT        = 1 << 0, /* guarantee non-reentrance */
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
-       WQ_FREEZEABLE           = 1 << 2, /* freeze during suspend */
+       WQ_FREEZABLE            = 1 << 2, /* freeze during suspend */
        WQ_MEM_RECLAIM          = 1 << 3, /* may be used for memory reclaim */
        WQ_HIGHPRI              = 1 << 4, /* high priority */
        WQ_CPU_INTENSIVE        = 1 << 5, /* cpu instensive workqueue */
@@ -318,7 +318,7 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
 /**
  * alloc_ordered_workqueue - allocate an ordered workqueue
  * @name: name of the workqueue
- * @flags: WQ_* flags (only WQ_FREEZEABLE and WQ_MEM_RECLAIM are meaningful)
+ * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful)
  *
  * Allocate an ordered workqueue.  An ordered workqueue executes at
  * most one work item at any given time in the queued order.  They are
@@ -335,8 +335,8 @@ alloc_ordered_workqueue(const char *name, unsigned int flags)
 
 #define create_workqueue(name)                                 \
        alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
-#define create_freezeable_workqueue(name)                      \
-       alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
+#define create_freezable_workqueue(name)                       \
+       alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
 #define create_singlethread_workqueue(name)                    \
        alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
 
diff --git a/include/media/mt9v011.h b/include/media/mt9v011.h
new file mode 100644 (file)
index 0000000..ea29fc7
--- /dev/null
@@ -0,0 +1,17 @@
+/* mt9v011 sensor
+ *
+ * Copyright (C) 2011 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+ */
+
+#ifndef __MT9V011_H__
+#define __MT9V011_H__
+
+struct mt9v011_platform_data {
+       unsigned xtal;  /* Hz */
+};
+
+#endif
index a23c1fc..2963263 100644 (file)
@@ -183,6 +183,9 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
 }
 
 #define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
+#define US_TO_NS(usec)         ((usec) * 1000)
+#define MS_TO_US(msec)         ((msec) * 1000)
+#define MS_TO_NS(msec)         ((msec) * 1000 * 1000)
 
 void ir_raw_event_handle(struct rc_dev *dev);
 int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
index ac7ce00..7982714 100644 (file)
@@ -115,7 +115,7 @@ struct saa7146_dev
 
        /* different device locks */
        spinlock_t                      slock;
-       struct mutex                    lock;
+       struct mutex                    v4l2_lock;
 
        unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
        u32                             revision;       /* chip revision; needed for bug-workarounds*/
index 2d65b35..a659319 100644 (file)
@@ -138,21 +138,10 @@ struct v4l2_subdev_ops;
 
 /* Load an i2c module and return an initialized v4l2_subdev struct.
    The client_type argument is the name of the chip that's on the adapter. */
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
                struct i2c_adapter *adapter, const char *client_type,
-               int irq, void *platform_data,
                u8 addr, const unsigned short *probe_addrs);
 
-/* Load an i2c module and return an initialized v4l2_subdev struct.
-   The client_type argument is the name of the chip that's on the adapter. */
-static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
-               struct i2c_adapter *adapter, const char *client_type,
-               u8 addr, const unsigned short *probe_addrs)
-{
-       return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL,
-                                      addr, probe_addrs);
-}
-
 struct i2c_board_info;
 
 struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
index d69ab4a..97d0638 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/videodev2.h>
 
 /* forward references */
 struct v4l2_ctrl_handler;
@@ -53,8 +54,10 @@ struct v4l2_ctrl_ops {
   * @handler:  The handler that owns the control.
   * @cluster:  Point to start of cluster array.
   * @ncontrols:        Number of controls in cluster array.
-  * @has_new:  Internal flag: set when there is a valid new value.
   * @done:     Internal flag: set for each processed control.
+  * @is_new:   Set when the user specified a new value for this control. It
+  *            is also set when called from v4l2_ctrl_handler_setup. Drivers
+  *            should never set this flag.
   * @is_private: If set, then this control is private to its handler and it
   *            will not be added to any other handlers. Drivers can set
   *            this flag.
@@ -97,9 +100,9 @@ struct v4l2_ctrl {
        struct v4l2_ctrl_handler *handler;
        struct v4l2_ctrl **cluster;
        unsigned ncontrols;
-       unsigned int has_new:1;
        unsigned int done:1;
 
+       unsigned int is_new:1;
        unsigned int is_private:1;
        unsigned int is_volatile:1;
 
index b0316a7..daf1e57 100644 (file)
@@ -106,10 +106,7 @@ struct v4l2_subdev_io_pin_config {
        u8 strength;    /* Pin drive strength */
 };
 
-/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev*
-       functions after the v4l2_subdev was registered. It is used to pass
-       platform data to the subdev which can be used during initialization.
-
+/*
    s_io_pin_config: configure one or more chip I/O pins for chips that
        multiplex different internal signal pads out to IO pins.  This function
        takes a pointer to an array of 'n' pin configuration entries, one for
@@ -141,7 +138,6 @@ struct v4l2_subdev_io_pin_config {
 struct v4l2_subdev_core_ops {
        int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
        int (*log_status)(struct v4l2_subdev *sd);
-       int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
        int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n,
                                      struct v4l2_subdev_io_pin_config *pincfg);
        int (*init)(struct v4l2_subdev *sd, u32 val);
@@ -415,6 +411,21 @@ struct v4l2_subdev_ops {
        const struct v4l2_subdev_sensor_ops     *sensor;
 };
 
+/*
+ * Internal ops. Never call this from drivers, only the v4l2 framework can call
+ * these ops.
+ *
+ * registered: called when this subdev is registered. When called the v4l2_dev
+ *     field is set to the correct v4l2_device.
+ *
+ * unregistered: called when this subdev is unregistered. When called the
+ *     v4l2_dev field is still set to the correct v4l2_device.
+ */
+struct v4l2_subdev_internal_ops {
+       int (*registered)(struct v4l2_subdev *sd);
+       void (*unregistered)(struct v4l2_subdev *sd);
+};
+
 #define V4L2_SUBDEV_NAME_SIZE 32
 
 /* Set this flag if this subdev is a i2c device. */
@@ -431,6 +442,8 @@ struct v4l2_subdev {
        u32 flags;
        struct v4l2_device *v4l2_dev;
        const struct v4l2_subdev_ops *ops;
+       /* Never call these internal ops from within a driver! */
+       const struct v4l2_subdev_internal_ops *internal_ops;
        /* The control handler of this subdev. May be NULL. */
        struct v4l2_ctrl_handler *ctrl_handler;
        /* name must be unique */
index a29feb0..d2cf884 100644 (file)
@@ -184,6 +184,7 @@ struct hci_conn {
        __u32            link_mode;
        __u8             auth_type;
        __u8             sec_level;
+       __u8             pending_sec_level;
        __u8             power_save;
        __u16            disc_timeout;
        unsigned long    pend;
index 8a64b81..b4c7c1c 100644 (file)
@@ -195,7 +195,8 @@ static inline int genlmsg_end(struct sk_buff *skb, void *hdr)
  */
 static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 {
-       nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
+       if (hdr)
+               nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
 }
 
 /**
index 4a3cd2c..96e50e0 100644 (file)
 #define IPV6_ADDR_SCOPE_GLOBAL         0x0e
 
 /*
+ *     Addr flags
+ */
+#ifdef __KERNEL__
+#define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \
+       ((a)->s6_addr[1] & 0x10)
+#define IPV6_ADDR_MC_FLAG_PREFIX(a)    \
+       ((a)->s6_addr[1] & 0x20)
+#define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a)        \
+       ((a)->s6_addr[1] & 0x40)
+#endif
+
+/*
  *     fragmentation header
  */
 
index 96ba5f7..349cefe 100644 (file)
@@ -77,9 +77,6 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
        if (e == NULL)
                return;
 
-       if (!(e->ctmask & (1 << event)))
-               return;
-
        set_bit(event, &e->cache);
 }
 
index cd85b3b..e505358 100644 (file)
@@ -201,18 +201,8 @@ nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
 }
 #endif
 
-static inline void
-nf_tproxy_put_sock(struct sock *sk)
-{
-       /* TIME_WAIT inet sockets have to be handled differently */
-       if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
-               inet_twsk_put(inet_twsk(sk));
-       else
-               sock_put(sk);
-}
-
 /* assign a socket to the skb -- consumes sk */
-int
+void
 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk);
 
 #endif
index e9eee99..04f8556 100644 (file)
@@ -199,7 +199,7 @@ struct tcf_proto {
 
 struct qdisc_skb_cb {
        unsigned int            pkt_len;
-       char                    data[];
+       long                    data[];
 };
 
 static inline int qdisc_qlen(struct Qdisc *q)
@@ -445,7 +445,6 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 {
        __skb_queue_tail(list, skb);
        sch->qstats.backlog += qdisc_pkt_len(skb);
-       qdisc_bstats_update(sch, skb);
 
        return NET_XMIT_SUCCESS;
 }
@@ -460,8 +459,10 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
 {
        struct sk_buff *skb = __skb_dequeue(list);
 
-       if (likely(skb != NULL))
+       if (likely(skb != NULL)) {
                sch->qstats.backlog -= qdisc_pkt_len(skb);
+               qdisc_bstats_update(sch, skb);
+       }
 
        return skb;
 }
@@ -474,10 +475,11 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
 static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
                                              struct sk_buff_head *list)
 {
-       struct sk_buff *skb = __qdisc_dequeue_head(sch, list);
+       struct sk_buff *skb = __skb_dequeue(list);
 
        if (likely(skb != NULL)) {
                unsigned int len = qdisc_pkt_len(skb);
+               sch->qstats.backlog -= len;
                kfree_skb(skb);
                return len;
        }
index 2a128c8..e73ebda 100644 (file)
@@ -78,6 +78,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_GET_PEER_ADDR_INFO        15
 #define SCTP_DELAYED_ACK_TIME  16
 #define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME
+#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME
 #define SCTP_CONTEXT   17
 #define SCTP_FRAGMENT_INTERLEAVE       18
 #define SCTP_PARTIAL_DELIVERY_POINT    19 /* Set/Get partial delivery point */
index d884d26..bc1cf7d 100644 (file)
@@ -753,6 +753,8 @@ struct proto {
                                        int level,
                                        int optname, char __user *optval,
                                        int __user *option);
+       int                     (*compat_ioctl)(struct sock *sk,
+                                       unsigned int cmd, unsigned long arg);
 #endif
        int                     (*sendmsg)(struct kiocb *iocb, struct sock *sk,
                                           struct msghdr *msg, size_t len);
index 8479b66..3fd5064 100644 (file)
@@ -261,6 +261,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev);
 #define CONF_ENABLE_ESR         0x0008
 #define CONF_ENABLE_IOCARD     0x0010 /* auto-enabled if IO resources or IRQ
                                        * (CONF_ENABLE_IRQ) in use */
+#define CONF_ENABLE_ZVCARD     0x0020
 
 /* flags used by pcmcia_loop_config() autoconfiguration */
 #define CONF_AUTO_CHECK_VCC    0x0100 /* check for matching Vcc? */
index 648d233..b76d400 100644 (file)
@@ -9,6 +9,7 @@
 #define _SCSI_SCSI_H
 
 #include <linux/types.h>
+#include <linux/scatterlist.h>
 
 struct scsi_cmnd;
 
index 07fdfb6..0828b6c 100644 (file)
@@ -8,7 +8,6 @@
 #include <scsi/scsi_cmnd.h>
 #include <net/sock.h>
 #include <net/tcp.h>
-#include "target_core_mib.h"
 
 #define TARGET_CORE_MOD_VERSION                "v4.0.0-rc6"
 #define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
@@ -195,6 +194,21 @@ typedef enum {
        SAM_TASK_ATTR_EMULATED
 } t10_task_attr_index_t;
 
+/*
+ * Used for target SCSI statistics
+ */
+typedef enum {
+       SCSI_INST_INDEX,
+       SCSI_DEVICE_INDEX,
+       SCSI_AUTH_INTR_INDEX,
+       SCSI_INDEX_TYPE_MAX
+} scsi_index_t;
+
+struct scsi_index_table {
+       spinlock_t      lock;
+       u32             scsi_mib_index[SCSI_INDEX_TYPE_MAX];
+} ____cacheline_aligned;
+
 struct se_cmd;
 
 struct t10_alua {
@@ -578,8 +592,6 @@ struct se_node_acl {
        spinlock_t              stats_lock;
        /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
        atomic_t                acl_pr_ref_count;
-       /* Used for MIB access */
-       atomic_t                mib_ref_count;
        struct se_dev_entry     *device_list;
        struct se_session       *nacl_sess;
        struct se_portal_group *se_tpg;
@@ -595,8 +607,6 @@ struct se_node_acl {
 } ____cacheline_aligned;
 
 struct se_session {
-       /* Used for MIB access */
-       atomic_t                mib_ref_count;
        u64                     sess_bin_isid;
        struct se_node_acl      *se_node_acl;
        struct se_portal_group *se_tpg;
@@ -806,7 +816,6 @@ struct se_hba {
        /* Virtual iSCSI devices attached. */
        u32                     dev_count;
        u32                     hba_index;
-       atomic_t                dev_mib_access_count;
        atomic_t                load_balance_queue;
        atomic_t                left_queue_depth;
        /* Maximum queue depth the HBA can handle. */
@@ -845,6 +854,12 @@ struct se_lun {
 
 #define SE_LUN(c)              ((struct se_lun *)(c)->se_lun)
 
+struct scsi_port_stats {
+       u64     cmd_pdus;
+       u64     tx_data_octets;
+       u64     rx_data_octets;
+} ____cacheline_aligned;
+
 struct se_port {
        /* RELATIVE TARGET PORT IDENTIFER */
        u16             sep_rtpi;
@@ -867,6 +882,7 @@ struct se_port {
 } ____cacheline_aligned;
 
 struct se_tpg_np {
+       struct se_portal_group *tpg_np_parent;
        struct config_group     tpg_np_group;
 } ____cacheline_aligned;
 
index 66f44e5..2469405 100644 (file)
@@ -111,6 +111,8 @@ struct se_subsystem_api;
 
 extern int init_se_global(void);
 extern void release_se_global(void);
+extern void init_scsi_index_table(void);
+extern u32 scsi_get_new_index(scsi_index_t);
 extern void transport_init_queue_obj(struct se_queue_obj *);
 extern int transport_subsystem_check_init(void);
 extern int transport_subsystem_register(struct se_subsystem_api *);
index aba421d..78f18ad 100644 (file)
@@ -31,7 +31,7 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                                        0 : blk_rq_sectors(rq);
                __entry->errors    = rq->errors;
 
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
                blk_dump_cmd(__get_str(cmd), rq);
        ),
 
@@ -118,7 +118,7 @@ DECLARE_EVENT_CLASS(block_rq,
                __entry->bytes     = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
                                        blk_rq_bytes(rq) : 0;
 
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
                blk_dump_cmd(__get_str(cmd), rq);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -563,7 +563,7 @@ TRACE_EVENT(block_rq_remap,
                __entry->nr_sector      = blk_rq_sectors(rq);
                __entry->old_dev        = dev;
                __entry->old_sector     = from;
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
        ),
 
        TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
index e16610c..3e68366 100644 (file)
@@ -446,14 +446,16 @@ static inline notrace int ftrace_get_offsets_##call(                      \
  *     .reg                    = ftrace_event_reg,
  * };
  *
- * static struct ftrace_event_call __used
- * __attribute__((__aligned__(4)))
- * __attribute__((section("_ftrace_events"))) event_<call> = {
+ * static struct ftrace_event_call event_<call> = {
  *     .name                   = "<call>",
  *     .class                  = event_class_<template>,
  *     .event                  = &ftrace_event_type_<call>,
  *     .print_fmt              = print_fmt_<call>,
  * };
+ * // its only safe to use pointers when doing linker tricks to
+ * // create an array.
+ * static struct ftrace_event_call __used
+ * __attribute__((section("_ftrace_events"))) *__event_<call> = &event_<call>;
  *
  */
 
@@ -579,28 +581,28 @@ static struct ftrace_event_class __used event_class_##call = {            \
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
                                                                        \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+static struct ftrace_event_call __used event_##call = {                        \
        .name                   = #call,                                \
        .class                  = &event_class_##template,              \
        .event.funcs            = &ftrace_event_type_funcs_##template,  \
        .print_fmt              = print_fmt_##template,                 \
-};
+};                                                                     \
+static struct ftrace_event_call __used                                 \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
                                                                        \
 static const char print_fmt_##call[] = print;                          \
                                                                        \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+static struct ftrace_event_call __used event_##call = {                        \
        .name                   = #call,                                \
        .class                  = &event_class_##template,              \
        .event.funcs            = &ftrace_event_type_funcs_##call,      \
        .print_fmt              = print_fmt_##call,                     \
-}
+};                                                                     \
+static struct ftrace_event_call __used                                 \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
index 4e33790..be788c0 100644 (file)
@@ -745,8 +745,8 @@ config DEBUG_BLK_CGROUP
 endif # CGROUPS
 
 menuconfig NAMESPACES
-       bool "Namespaces support" if EMBEDDED
-       default !EMBEDDED
+       bool "Namespaces support" if EXPERT
+       default !EXPERT
        help
          Provides the way to make tasks work with different objects using
          the same id. For example same IPC id may refer to different objects
@@ -899,23 +899,31 @@ config SYSCTL
 config ANON_INODES
        bool
 
-menuconfig EMBEDDED
-       bool "Configure standard kernel features (for small systems)"
+menuconfig EXPERT
+       bool "Configure standard kernel features (expert users)"
        help
          This option allows certain base kernel options and settings
           to be disabled or tweaked. This is for specialized
           environments which can tolerate a "non-standard" kernel.
           Only use this if you really know what you are doing.
 
+config EMBEDDED
+       bool "Embedded system"
+       select EXPERT
+       help
+         This option should be enabled if compiling the kernel for
+         an embedded system so certain expert options are available
+         for configuration.
+
 config UID16
-       bool "Enable 16-bit UID system calls" if EMBEDDED
+       bool "Enable 16-bit UID system calls" if EXPERT
        depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION)
        default y
        help
          This enables the legacy 16-bit UID syscall wrappers.
 
 config SYSCTL_SYSCALL
-       bool "Sysctl syscall support" if EMBEDDED
+       bool "Sysctl syscall support" if EXPERT
        depends on PROC_SYSCTL
        default y
        select SYSCTL
@@ -932,7 +940,7 @@ config SYSCTL_SYSCALL
          If unsure say Y here.
 
 config KALLSYMS
-        bool "Load all symbols for debugging/ksymoops" if EMBEDDED
+        bool "Load all symbols for debugging/ksymoops" if EXPERT
         default y
         help
           Say Y here to let the kernel print out symbolic crash information and
@@ -963,7 +971,7 @@ config KALLSYMS_EXTRA_PASS
 
 
 config HOTPLUG
-       bool "Support for hot-pluggable devices" if EMBEDDED
+       bool "Support for hot-pluggable devices" if EXPERT
        default y
        help
          This option is provided for the case where no hotplug or uevent
@@ -973,7 +981,7 @@ config HOTPLUG
 
 config PRINTK
        default y
-       bool "Enable support for printk" if EMBEDDED
+       bool "Enable support for printk" if EXPERT
        help
          This option enables normal printk support. Removing it
          eliminates most of the message strings from the kernel image
@@ -982,7 +990,7 @@ config PRINTK
          strongly discouraged.
 
 config BUG
-       bool "BUG() support" if EMBEDDED
+       bool "BUG() support" if EXPERT
        default y
        help
           Disabling this option eliminates support for BUG and WARN, reducing
@@ -993,12 +1001,12 @@ config BUG
 
 config ELF_CORE
        default y
-       bool "Enable ELF core dumps" if EMBEDDED
+       bool "Enable ELF core dumps" if EXPERT
        help
          Enable support for generating core dumps. Disabling saves about 4k.
 
 config PCSPKR_PLATFORM
-       bool "Enable PC-Speaker support" if EMBEDDED
+       bool "Enable PC-Speaker support" if EXPERT
        depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
        default y
        help
@@ -1007,14 +1015,14 @@ config PCSPKR_PLATFORM
 
 config BASE_FULL
        default y
-       bool "Enable full-sized data structures for core" if EMBEDDED
+       bool "Enable full-sized data structures for core" if EXPERT
        help
          Disabling this option reduces the size of miscellaneous core
          kernel data structures. This saves memory on small machines,
          but may reduce performance.
 
 config FUTEX
-       bool "Enable futex support" if EMBEDDED
+       bool "Enable futex support" if EXPERT
        default y
        select RT_MUTEXES
        help
@@ -1023,7 +1031,7 @@ config FUTEX
          run glibc-based applications correctly.
 
 config EPOLL
-       bool "Enable eventpoll support" if EMBEDDED
+       bool "Enable eventpoll support" if EXPERT
        default y
        select ANON_INODES
        help
@@ -1031,7 +1039,7 @@ config EPOLL
          support for epoll family of system calls.
 
 config SIGNALFD
-       bool "Enable signalfd() system call" if EMBEDDED
+       bool "Enable signalfd() system call" if EXPERT
        select ANON_INODES
        default y
        help
@@ -1041,7 +1049,7 @@ config SIGNALFD
          If unsure, say Y.
 
 config TIMERFD
-       bool "Enable timerfd() system call" if EMBEDDED
+       bool "Enable timerfd() system call" if EXPERT
        select ANON_INODES
        default y
        help
@@ -1051,7 +1059,7 @@ config TIMERFD
          If unsure, say Y.
 
 config EVENTFD
-       bool "Enable eventfd() system call" if EMBEDDED
+       bool "Enable eventfd() system call" if EXPERT
        select ANON_INODES
        default y
        help
@@ -1061,7 +1069,7 @@ config EVENTFD
          If unsure, say Y.
 
 config SHMEM
-       bool "Use full shmem filesystem" if EMBEDDED
+       bool "Use full shmem filesystem" if EXPERT
        default y
        depends on MMU
        help
@@ -1072,7 +1080,7 @@ config SHMEM
          which may be appropriate on small systems without swap.
 
 config AIO
-       bool "Enable AIO support" if EMBEDDED
+       bool "Enable AIO support" if EXPERT
        default y
        help
          This option enables POSIX asynchronous I/O which may by used
@@ -1149,16 +1157,16 @@ endmenu
 
 config VM_EVENT_COUNTERS
        default y
-       bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
+       bool "Enable VM event counters for /proc/vmstat" if EXPERT
        help
          VM event counters are needed for event counts to be shown.
          This option allows the disabling of the VM event counters
-         on EMBEDDED systems.  /proc/vmstat will only show page counts
+         on EXPERT systems.  /proc/vmstat will only show page counts
          if VM event counters are disabled.
 
 config PCI_QUIRKS
        default y
-       bool "Enable PCI quirk workarounds" if EMBEDDED
+       bool "Enable PCI quirk workarounds" if EXPERT
        depends on PCI
        help
          This enables workarounds for various PCI chipset
@@ -1167,7 +1175,7 @@ config PCI_QUIRKS
 
 config SLUB_DEBUG
        default y
-       bool "Enable SLUB debugging support" if EMBEDDED
+       bool "Enable SLUB debugging support" if EXPERT
        depends on SLUB && SYSFS
        help
          SLUB has extensive debug support features. Disabling these can
@@ -1211,7 +1219,7 @@ config SLUB
           a slab allocator.
 
 config SLOB
-       depends on EMBEDDED
+       depends on EXPERT
        bool "SLOB (Simple Allocator)"
        help
           SLOB replaces the stock allocator with a drastically simpler
@@ -1222,7 +1230,7 @@ endchoice
 
 config MMAP_ALLOW_UNINITIALIZED
        bool "Allow mmapped anonymous memory to be uninitialized"
-       depends on EMBEDDED && !MMU
+       depends on EXPERT && !MMU
        default n
        help
          Normally, and according to the Linux spec, anonymous memory obtained
index 6eb48e5..24fe022 100644 (file)
@@ -66,7 +66,7 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
                pre_start = 0;
                read_current_timer(&start);
                start_jiffies = jiffies;
-               while (jiffies <= (start_jiffies + 1)) {
+               while (time_before_eq(jiffies, start_jiffies + 1)) {
                        pre_start = start;
                        read_current_timer(&start);
                }
@@ -74,8 +74,8 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
 
                pre_end = 0;
                end = post_start;
-               while (jiffies <=
-                      (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) {
+               while (time_before_eq(jiffies, start_jiffies + 1 +
+                                              DELAY_CALIBRATION_TICKS)) {
                        pre_end = end;
                        read_current_timer(&end);
                }
index 00799c1..33c37c3 100644 (file)
@@ -96,6 +96,15 @@ static inline void mark_rodata_ro(void) { }
 extern void tc_init(void);
 #endif
 
+/*
+ * Debug helper: via this flag we know that we are in 'early bootup code'
+ * where only the boot processor is running with IRQ disabled.  This means
+ * two things - IRQ must not be enabled before the flag is cleared and some
+ * operations which are not allowed with IRQ disabled are allowed while the
+ * flag is set.
+ */
+bool early_boot_irqs_disabled __read_mostly;
+
 enum system_states system_state __read_mostly;
 EXPORT_SYMBOL(system_state);
 
@@ -554,7 +563,7 @@ asmlinkage void __init start_kernel(void)
        cgroup_init_early();
 
        local_irq_disable();
-       early_boot_irqs_off();
+       early_boot_irqs_disabled = true;
 
 /*
  * Interrupts are still disabled. Do necessary setups, then
@@ -621,7 +630,7 @@ asmlinkage void __init start_kernel(void)
        if (!irqs_disabled())
                printk(KERN_CRIT "start_kernel(): bug: interrupts were "
                                 "enabled early\n");
-       early_boot_irqs_on();
+       early_boot_irqs_disabled = false;
        local_irq_enable();
 
        /* Interrupts are enabled now so all GFP allocations are safe. */
index 2f05303..9e9385f 100644 (file)
@@ -306,7 +306,7 @@ int capable(int cap)
                BUG();
        }
 
-       if (security_capable(cap) == 0) {
+       if (security_capable(current_cred(), cap) == 0) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
index 4349935..e92e981 100644 (file)
@@ -1575,8 +1575,10 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
                return -ENODEV;
 
        trialcs = alloc_trial_cpuset(cs);
-       if (!trialcs)
-               return -ENOMEM;
+       if (!trialcs) {
+               retval = -ENOMEM;
+               goto out;
+       }
 
        switch (cft->private) {
        case FILE_CPULIST:
@@ -1591,6 +1593,7 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
        }
 
        free_trial_cpuset(trialcs);
+out:
        cgroup_unlock();
        return retval;
 }
index 6a1aa00..3a9d6dd 100644 (file)
@@ -252,13 +252,13 @@ struct cred *cred_alloc_blank(void)
 #endif
 
        atomic_set(&new->usage, 1);
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       new->magic = CRED_MAGIC;
+#endif
 
        if (security_cred_alloc_blank(new, GFP_KERNEL) < 0)
                goto error;
 
-#ifdef CONFIG_DEBUG_CREDENTIALS
-       new->magic = CRED_MAGIC;
-#endif
        return new;
 
 error:
@@ -657,6 +657,8 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        validate_creds(old);
 
        *new = *old;
+       atomic_set(&new->usage, 1);
+       set_cred_subscribers(new, 0);
        get_uid(new->user);
        get_group_info(new->group_info);
 
@@ -674,8 +676,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
                goto error;
 
-       atomic_set(&new->usage, 1);
-       set_cred_subscribers(new, 0);
        put_cred(old);
        validate_creds(new);
        return new;
@@ -748,7 +748,11 @@ bool creds_are_invalid(const struct cred *cred)
        if (cred->magic != CRED_MAGIC)
                return true;
 #ifdef CONFIG_SECURITY_SELINUX
-       if (selinux_is_enabled()) {
+       /*
+        * cred->security == NULL if security_cred_alloc_blank() or
+        * security_prepare_creds() returned an error.
+        */
+       if (selinux_is_enabled() && cred->security) {
                if ((unsigned long) cred->security < PAGE_SIZE)
                        return true;
                if ((*(u32 *)cred->security & 0xffffff00) ==
index 31d766b..8e42fec 100644 (file)
@@ -9,9 +9,6 @@ menu "IRQ subsystem"
 config GENERIC_HARDIRQS
        def_bool y
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
 # Select this to disable the deprecated stuff
 config GENERIC_HARDIRQS_NO_DEPRECATED
        def_bool n
index e2347eb..3540a71 100644 (file)
@@ -118,114 +118,3 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
 
        return retval;
 }
-
-#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-
-#ifdef CONFIG_ENABLE_WARN_DEPRECATED
-# warning __do_IRQ is deprecated. Please convert to proper flow handlers
-#endif
-
-/**
- * __do_IRQ - original all in one highlevel IRQ handler
- * @irq:       the interrupt number
- *
- * __do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
- * This is the original x86 implementation which is used for every
- * interrupt type.
- */
-unsigned int __do_IRQ(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irqaction *action;
-       unsigned int status;
-
-       kstat_incr_irqs_this_cpu(irq, desc);
-
-       if (CHECK_IRQ_PER_CPU(desc->status)) {
-               irqreturn_t action_ret;
-
-               /*
-                * No locking required for CPU-local interrupts:
-                */
-               if (desc->irq_data.chip->ack)
-                       desc->irq_data.chip->ack(irq);
-               if (likely(!(desc->status & IRQ_DISABLED))) {
-                       action_ret = handle_IRQ_event(irq, desc->action);
-                       if (!noirqdebug)
-                               note_interrupt(irq, desc, action_ret);
-               }
-               desc->irq_data.chip->end(irq);
-               return 1;
-       }
-
-       raw_spin_lock(&desc->lock);
-       if (desc->irq_data.chip->ack)
-               desc->irq_data.chip->ack(irq);
-       /*
-        * REPLAY is when Linux resends an IRQ that was dropped earlier
-        * WAITING is used by probe to mark irqs that are being tested
-        */
-       status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
-       status |= IRQ_PENDING; /* we _want_ to handle it */
-
-       /*
-        * If the IRQ is disabled for whatever reason, we cannot
-        * use the action we have.
-        */
-       action = NULL;
-       if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
-               action = desc->action;
-               status &= ~IRQ_PENDING; /* we commit to handling */
-               status |= IRQ_INPROGRESS; /* we are handling it */
-       }
-       desc->status = status;
-
-       /*
-        * If there is no IRQ handler or it was disabled, exit early.
-        * Since we set PENDING, if another processor is handling
-        * a different instance of this same irq, the other processor
-        * will take care of it.
-        */
-       if (unlikely(!action))
-               goto out;
-
-       /*
-        * Edge triggered interrupts need to remember
-        * pending events.
-        * This applies to any hw interrupts that allow a second
-        * instance of the same irq to arrive while we are in do_IRQ
-        * or in the handler. But the code here only handles the _second_
-        * instance of the irq, not the third or fourth. So it is mostly
-        * useful for irq hardware that does not mask cleanly in an
-        * SMP environment.
-        */
-       for (;;) {
-               irqreturn_t action_ret;
-
-               raw_spin_unlock(&desc->lock);
-
-               action_ret = handle_IRQ_event(irq, action);
-               if (!noirqdebug)
-                       note_interrupt(irq, desc, action_ret);
-
-               raw_spin_lock(&desc->lock);
-               if (likely(!(desc->status & IRQ_PENDING)))
-                       break;
-               desc->status &= ~IRQ_PENDING;
-       }
-       desc->status &= ~IRQ_INPROGRESS;
-
-out:
-       /*
-        * The ->end() handler has to deal with interrupts which got
-        * disabled while the handler was running.
-        */
-       desc->irq_data.chip->end(irq);
-       raw_spin_unlock(&desc->lock);
-
-       return 1;
-}
-#endif
index 4571ae7..99c3bc8 100644 (file)
@@ -3,6 +3,12 @@
  */
 #include <linux/irqdesc.h>
 
+#ifdef CONFIG_SPARSE_IRQ
+# define IRQ_BITMAP_BITS       (NR_IRQS + 8196)
+#else
+# define IRQ_BITMAP_BITS       NR_IRQS
+#endif
+
 extern int noirqdebug;
 
 #define irq_data_to_desc(data) container_of(data, struct irq_desc, irq_data)
index 282f202..2039bea 100644 (file)
@@ -94,7 +94,7 @@ int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
 static DEFINE_MUTEX(sparse_irq_lock);
-static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
+static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);
 
 #ifdef CONFIG_SPARSE_IRQ
 
@@ -217,6 +217,15 @@ int __init early_irq_init(void)
        initcnt = arch_probe_nr_irqs();
        printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
 
+       if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
+               nr_irqs = IRQ_BITMAP_BITS;
+
+       if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
+               initcnt = IRQ_BITMAP_BITS;
+
+       if (initcnt > nr_irqs)
+               nr_irqs = initcnt;
+
        for (i = 0; i < initcnt; i++) {
                desc = alloc_desc(i, node);
                set_bit(i, allocated_irqs);
index 0caa59f..9033c1c 100644 (file)
@@ -1100,7 +1100,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
        if (retval)
                kfree(action);
 
-#ifdef CONFIG_DEBUG_SHIRQ
+#ifdef CONFIG_DEBUG_SHIRQ_FIXME
        if (!retval && (irqflags & IRQF_SHARED)) {
                /*
                 * It's a shared IRQ -- the driver ought to be prepared for it
index 1d25419..441fd62 100644 (file)
@@ -56,6 +56,7 @@ void move_masked_irq(int irq)
 void move_native_irq(int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       bool masked;
 
        if (likely(!(desc->status & IRQ_MOVE_PENDING)))
                return;
@@ -63,8 +64,15 @@ void move_native_irq(int irq)
        if (unlikely(desc->status & IRQ_DISABLED))
                return;
 
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
+       /*
+        * Be careful vs. already masked interrupts. If this is a
+        * threaded interrupt with ONESHOT set, we can end up with an
+        * interrupt storm.
+        */
+       masked = desc->status & IRQ_MASKED;
+       if (!masked)
+               desc->irq_data.chip->irq_mask(&desc->irq_data);
        move_masked_irq(irq);
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+       if (!masked)
+               desc->irq_data.chip->irq_unmask(&desc->irq_data);
 }
-
index 891115a..dc49358 100644 (file)
@@ -23,7 +23,7 @@
 #ifdef CONFIG_HARDIRQS_SW_RESEND
 
 /* Bitmap to handle software resend of interrupts: */
-static DECLARE_BITMAP(irqs_resend, NR_IRQS);
+static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
 
 /*
  * Run software resends of IRQ's
index 42ba65d..0d2058d 100644 (file)
@@ -2292,22 +2292,6 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
 }
 
 /*
- * Debugging helper: via this flag we know that we are in
- * 'early bootup code', and will warn about any invalid irqs-on event:
- */
-static int early_boot_irqs_enabled;
-
-void early_boot_irqs_off(void)
-{
-       early_boot_irqs_enabled = 0;
-}
-
-void early_boot_irqs_on(void)
-{
-       early_boot_irqs_enabled = 1;
-}
-
-/*
  * Hardirqs will be enabled:
  */
 void trace_hardirqs_on_caller(unsigned long ip)
@@ -2319,7 +2303,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
        if (unlikely(!debug_locks || current->lockdep_recursion))
                return;
 
-       if (DEBUG_LOCKS_WARN_ON(unlikely(!early_boot_irqs_enabled)))
+       if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
                return;
 
        if (unlikely(curr->hardirqs_enabled)) {
index 34e00b7..efa290e 100644 (file)
@@ -2460,9 +2460,9 @@ static void find_module_sections(struct module *mod, struct load_info *info)
 #endif
 
 #ifdef CONFIG_TRACEPOINTS
-       mod->tracepoints = section_objs(info, "__tracepoints",
-                                       sizeof(*mod->tracepoints),
-                                       &mod->num_tracepoints);
+       mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
+                                            sizeof(*mod->tracepoints_ptrs),
+                                            &mod->num_tracepoints);
 #endif
 #ifdef HAVE_JUMP_LABEL
        mod->jump_entries = section_objs(info, "__jump_table",
@@ -3393,7 +3393,7 @@ void module_layout(struct module *mod,
                   struct modversion_info *ver,
                   struct kernel_param *kp,
                   struct kernel_symbol *ks,
-                  struct tracepoint *tp)
+                  struct tracepoint * const *tp)
 {
 }
 EXPORT_SYMBOL(module_layout);
@@ -3407,8 +3407,8 @@ void module_update_tracepoints(void)
        mutex_lock(&module_mutex);
        list_for_each_entry(mod, &modules, list)
                if (!mod->taints)
-                       tracepoint_update_probe_range(mod->tracepoints,
-                               mod->tracepoints + mod->num_tracepoints);
+                       tracepoint_update_probe_range(mod->tracepoints_ptrs,
+                               mod->tracepoints_ptrs + mod->num_tracepoints);
        mutex_unlock(&module_mutex);
 }
 
@@ -3432,8 +3432,8 @@ int module_get_iter_tracepoints(struct tracepoint_iter *iter)
                        else if (iter_mod > iter->module)
                                iter->tracepoint = NULL;
                        found = tracepoint_get_iter_range(&iter->tracepoint,
-                               iter_mod->tracepoints,
-                               iter_mod->tracepoints
+                               iter_mod->tracepoints_ptrs,
+                               iter_mod->tracepoints_ptrs
                                        + iter_mod->num_tracepoints);
                        if (found) {
                                iter->module = iter_mod;
index 08107d1..0da1411 100644 (file)
@@ -719,9 +719,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
                        params[i].ops->free(params[i].arg);
 }
 
-static void __init kernel_add_sysfs_param(const char *name,
-                                         struct kernel_param *kparam,
-                                         unsigned int name_skip)
+static struct module_kobject * __init locate_module_kobject(const char *name)
 {
        struct module_kobject *mk;
        struct kobject *kobj;
@@ -729,10 +727,7 @@ static void __init kernel_add_sysfs_param(const char *name,
 
        kobj = kset_find_obj(module_kset, name);
        if (kobj) {
-               /* We already have one.  Remove params so we can add more. */
                mk = to_module_kobject(kobj);
-               /* We need to remove it before adding parameters. */
-               sysfs_remove_group(&mk->kobj, &mk->mp->grp);
        } else {
                mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
                BUG_ON(!mk);
@@ -743,15 +738,36 @@ static void __init kernel_add_sysfs_param(const char *name,
                                           "%s", name);
                if (err) {
                        kobject_put(&mk->kobj);
-                       printk(KERN_ERR "Module '%s' failed add to sysfs, "
-                              "error number %d\n", name, err);
-                       printk(KERN_ERR "The system will be unstable now.\n");
-                       return;
+                       printk(KERN_ERR
+                               "Module '%s' failed add to sysfs, error number %d\n",
+                               name, err);
+                       printk(KERN_ERR
+                               "The system will be unstable now.\n");
+                       return NULL;
                }
-               /* So that exit path is even. */
+
+               /* So that we hold reference in both cases. */
                kobject_get(&mk->kobj);
        }
 
+       return mk;
+}
+
+static void __init kernel_add_sysfs_param(const char *name,
+                                         struct kernel_param *kparam,
+                                         unsigned int name_skip)
+{
+       struct module_kobject *mk;
+       int err;
+
+       mk = locate_module_kobject(name);
+       if (!mk)
+               return;
+
+       /* We need to remove old parameters before adding more. */
+       if (mk->mp)
+               sysfs_remove_group(&mk->kobj, &mk->mp->grp);
+
        /* These should not fail at boot. */
        err = add_sysfs_param(mk, kparam, kparam->name + name_skip);
        BUG_ON(err);
@@ -796,6 +812,32 @@ static void __init param_sysfs_builtin(void)
        }
 }
 
+ssize_t __modver_version_show(struct module_attribute *mattr,
+                             struct module *mod, char *buf)
+{
+       struct module_version_attribute *vattr =
+               container_of(mattr, struct module_version_attribute, mattr);
+
+       return sprintf(buf, "%s\n", vattr->version);
+}
+
+extern struct module_version_attribute __start___modver[], __stop___modver[];
+
+static void __init version_sysfs_builtin(void)
+{
+       const struct module_version_attribute *vattr;
+       struct module_kobject *mk;
+       int err;
+
+       for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
+               mk = locate_module_kobject(vattr->module_name);
+               if (mk) {
+                       err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
+                       kobject_uevent(&mk->kobj, KOBJ_ADD);
+                       kobject_put(&mk->kobj);
+               }
+       }
+}
 
 /* module-related sysfs stuff */
 
@@ -875,6 +917,7 @@ static int __init param_sysfs_init(void)
        }
        module_sysfs_initialized = 1;
 
+       version_sysfs_builtin();
        param_sysfs_builtin();
 
        return 0;
index 84522c7..656222f 100644 (file)
@@ -782,6 +782,10 @@ retry:
        raw_spin_unlock_irq(&ctx->lock);
 }
 
+#define MAX_INTERRUPTS (~0ULL)
+
+static void perf_log_throttle(struct perf_event *event, int enable);
+
 static int
 event_sched_in(struct perf_event *event,
                 struct perf_cpu_context *cpuctx,
@@ -794,6 +798,17 @@ event_sched_in(struct perf_event *event,
 
        event->state = PERF_EVENT_STATE_ACTIVE;
        event->oncpu = smp_processor_id();
+
+       /*
+        * Unthrottle events, since we scheduled we might have missed several
+        * ticks already, also for a heavily scheduling task there is little
+        * guarantee it'll get a tick in a timely manner.
+        */
+       if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) {
+               perf_log_throttle(event, 1);
+               event->hw.interrupts = 0;
+       }
+
        /*
         * The new state must be visible before we turn it on in the hardware:
         */
@@ -1596,10 +1611,6 @@ void __perf_event_task_sched_in(struct task_struct *task)
        }
 }
 
-#define MAX_INTERRUPTS (~0ULL)
-
-static void perf_log_throttle(struct perf_event *event, int enable);
-
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
 {
        u64 frequency = event->attr.sample_freq;
@@ -1901,11 +1912,12 @@ static void __perf_event_read(void *info)
                return;
 
        raw_spin_lock(&ctx->lock);
-       update_context_time(ctx);
+       if (ctx->is_active)
+               update_context_time(ctx);
        update_event_times(event);
+       if (event->state == PERF_EVENT_STATE_ACTIVE)
+               event->pmu->read(event);
        raw_spin_unlock(&ctx->lock);
-
-       event->pmu->read(event);
 }
 
 static inline u64 perf_event_count(struct perf_event *event)
@@ -1999,8 +2011,7 @@ static int alloc_callchain_buffers(void)
         * accessed from NMI. Use a temporary manual per cpu allocation
         * until that gets sorted out.
         */
-       size = sizeof(*entries) + sizeof(struct perf_callchain_entry *) *
-               num_possible_cpus();
+       size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
 
        entries = kzalloc(size, GFP_KERNEL);
        if (!entries)
@@ -2201,13 +2212,6 @@ find_lively_task_by_vpid(pid_t vpid)
        if (!task)
                return ERR_PTR(-ESRCH);
 
-       /*
-        * Can't attach events to a dying task.
-        */
-       err = -ESRCH;
-       if (task->flags & PF_EXITING)
-               goto errout;
-
        /* Reuse ptrace permission checks for now. */
        err = -EACCES;
        if (!ptrace_may_access(task, PTRACE_MODE_READ))
@@ -2268,14 +2272,27 @@ retry:
 
                get_ctx(ctx);
 
-               if (cmpxchg(&task->perf_event_ctxp[ctxn], NULL, ctx)) {
-                       /*
-                        * We raced with some other task; use
-                        * the context they set.
-                        */
+               err = 0;
+               mutex_lock(&task->perf_event_mutex);
+               /*
+                * If it has already passed perf_event_exit_task().
+                * we must see PF_EXITING, it takes this mutex too.
+                */
+               if (task->flags & PF_EXITING)
+                       err = -ESRCH;
+               else if (task->perf_event_ctxp[ctxn])
+                       err = -EAGAIN;
+               else
+                       rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx);
+               mutex_unlock(&task->perf_event_mutex);
+
+               if (unlikely(err)) {
                        put_task_struct(task);
                        kfree(ctx);
-                       goto retry;
+
+                       if (err == -EAGAIN)
+                               goto retry;
+                       goto errout;
                }
        }
 
@@ -5374,6 +5391,8 @@ free_dev:
        goto out;
 }
 
+static struct lock_class_key cpuctx_mutex;
+
 int perf_pmu_register(struct pmu *pmu, char *name, int type)
 {
        int cpu, ret;
@@ -5422,6 +5441,7 @@ skip_type:
 
                cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
                __perf_event_init_context(&cpuctx->ctx);
+               lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
                cpuctx->ctx.type = cpu_context;
                cpuctx->ctx.pmu = pmu;
                cpuctx->jiffies_interval = 1;
@@ -6127,7 +6147,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
         * scheduled, so we are now safe from rescheduling changing
         * our context.
         */
-       child_ctx = child->perf_event_ctxp[ctxn];
+       child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]);
        task_ctx_sched_out(child_ctx, EVENT_ALL);
 
        /*
@@ -6440,11 +6460,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
        unsigned long flags;
        int ret = 0;
 
-       child->perf_event_ctxp[ctxn] = NULL;
-
-       mutex_init(&child->perf_event_mutex);
-       INIT_LIST_HEAD(&child->perf_event_list);
-
        if (likely(!parent->perf_event_ctxp[ctxn]))
                return 0;
 
@@ -6533,6 +6548,10 @@ int perf_event_init_task(struct task_struct *child)
 {
        int ctxn, ret;
 
+       memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp));
+       mutex_init(&child->perf_event_mutex);
+       INIT_LIST_HEAD(&child->perf_event_list);
+
        for_each_task_context_nr(ctxn) {
                ret = perf_event_init_context(child, ctxn);
                if (ret)
index 7b5db6a..7018530 100644 (file)
@@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq);
 
 static int __init pm_start_workqueue(void)
 {
-       pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0);
+       pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
 
        return pm_wq ? 0 : -ENOMEM;
 }
index d6d2a10..0cf3a27 100644 (file)
@@ -22,7 +22,7 @@
  */
 #define TIMEOUT        (20 * HZ)
 
-static inline int freezeable(struct task_struct * p)
+static inline int freezable(struct task_struct * p)
 {
        if ((p == current) ||
            (p->flags & PF_NOFREEZE) ||
@@ -53,7 +53,7 @@ static int try_to_freeze_tasks(bool sig_only)
                todo = 0;
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
-                       if (frozen(p) || !freezeable(p))
+                       if (frozen(p) || !freezable(p))
                                continue;
 
                        if (!freeze_task(p, sig_only))
@@ -167,7 +167,7 @@ static void thaw_tasks(bool nosig_only)
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
-               if (!freezeable(p))
+               if (!freezable(p))
                        continue;
 
                if (nosig_only && should_send_signal(p))
index 0dac75e..64db648 100644 (file)
@@ -1519,11 +1519,8 @@ static int
 swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
                unsigned int nr_pages, unsigned int nr_highmem)
 {
-       int error = 0;
-
        if (nr_highmem > 0) {
-               error = get_highmem_buffer(PG_ANY);
-               if (error)
+               if (get_highmem_buffer(PG_ANY))
                        goto err_out;
                if (nr_highmem > alloc_highmem) {
                        nr_highmem -= alloc_highmem;
@@ -1546,7 +1543,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
 
  err_out:
        swsusp_free();
-       return error;
+       return -ENOMEM;
 }
 
 asmlinkage int swsusp_save(void)
index 53d9a9e..3623152 100644 (file)
@@ -97,7 +97,7 @@ static int console_locked, console_suspended;
 /*
  * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
  * It is also used in interesting ways to provide interlocking in
- * release_console_sem().
+ * console_unlock();.
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
@@ -262,25 +262,47 @@ int dmesg_restrict = 1;
 int dmesg_restrict;
 #endif
 
+static int syslog_action_restricted(int type)
+{
+       if (dmesg_restrict)
+               return 1;
+       /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
+       return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
+}
+
+static int check_syslog_permissions(int type, bool from_file)
+{
+       /*
+        * If this is from /proc/kmsg and we've already opened it, then we've
+        * already done the capabilities checks at open time.
+        */
+       if (from_file && type != SYSLOG_ACTION_OPEN)
+               return 0;
+
+       if (syslog_action_restricted(type)) {
+               if (capable(CAP_SYSLOG))
+                       return 0;
+               /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
+               if (capable(CAP_SYS_ADMIN)) {
+                       WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
+                                "but no CAP_SYSLOG (deprecated).\n");
+                       return 0;
+               }
+               return -EPERM;
+       }
+       return 0;
+}
+
 int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
        unsigned i, j, limit, count;
        int do_clear = 0;
        char c;
-       int error = 0;
+       int error;
 
-       /*
-        * If this is from /proc/kmsg we only do the capabilities checks
-        * at open time.
-        */
-       if (type == SYSLOG_ACTION_OPEN || !from_file) {
-               if (dmesg_restrict && !capable(CAP_SYSLOG))
-                       goto warn; /* switch to return -EPERM after 2.6.39 */
-               if ((type != SYSLOG_ACTION_READ_ALL &&
-                    type != SYSLOG_ACTION_SIZE_BUFFER) &&
-                   !capable(CAP_SYSLOG))
-                       goto warn; /* switch to return -EPERM after 2.6.39 */
-       }
+       error = check_syslog_permissions(type, from_file);
+       if (error)
+               goto out;
 
        error = security_syslog(type);
        if (error)
@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
        }
 out:
        return error;
-warn:
-       /* remove after 2.6.39 */
-       if (capable(CAP_SYS_ADMIN))
-               WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
-                 "but no CAP_SYSLOG (deprecated and denied).\n");
-       return -EPERM;
 }
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
@@ -501,7 +517,7 @@ static void _call_console_drivers(unsigned start,
 /*
  * Call the console drivers, asking them to write out
  * log_buf[start] to log_buf[end - 1].
- * The console_sem must be held.
+ * The console_lock must be held.
  */
 static void call_console_drivers(unsigned start, unsigned end)
 {
@@ -604,11 +620,11 @@ static int have_callable_console(void)
  *
  * This is printk().  It can be called from any context.  We want it to work.
  *
- * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
+ * We try to grab the console_lock.  If we succeed, it's easy - we log the output and
  * call the console drivers.  If we fail to get the semaphore we place the output
  * into the log buffer and return.  The current holder of the console_sem will
- * notice the new output in release_console_sem() and will send it to the
- * consoles before releasing the semaphore.
+ * notice the new output in console_unlock(); and will send it to the
+ * consoles before releasing the lock.
  *
  * One effect of this deferred printing is that code which calls printk() and
  * then changes console_loglevel may break. This is because console_loglevel
@@ -659,19 +675,19 @@ static inline int can_use_console(unsigned int cpu)
 /*
  * Try to get console ownership to actually show the kernel
  * messages from a 'printk'. Return true (and with the
- * console_semaphore held, and 'console_locked' set) if it
+ * console_lock held, and 'console_locked' set) if it
  * is successful, false otherwise.
  *
  * This gets called with the 'logbuf_lock' spinlock held and
  * interrupts disabled. It should return with 'lockbuf_lock'
  * released but interrupts still disabled.
  */
-static int acquire_console_semaphore_for_printk(unsigned int cpu)
+static int console_trylock_for_printk(unsigned int cpu)
        __releases(&logbuf_lock)
 {
        int retval = 0;
 
-       if (!try_acquire_console_sem()) {
+       if (console_trylock()) {
                retval = 1;
 
                /*
@@ -827,12 +843,12 @@ asmlinkage int vprintk(const char *fmt, va_list args)
         * actual magic (print out buffers, wake up klogd,
         * etc). 
         *
-        * The acquire_console_semaphore_for_printk() function
+        * The console_trylock_for_printk() function
         * will release 'logbuf_lock' regardless of whether it
         * actually gets the semaphore or not.
         */
-       if (acquire_console_semaphore_for_printk(this_cpu))
-               release_console_sem();
+       if (console_trylock_for_printk(this_cpu))
+               console_unlock();
 
        lockdep_on();
 out_restore_irqs:
@@ -993,7 +1009,7 @@ void suspend_console(void)
        if (!console_suspend_enabled)
                return;
        printk("Suspending console(s) (use no_console_suspend to debug)\n");
-       acquire_console_sem();
+       console_lock();
        console_suspended = 1;
        up(&console_sem);
 }
@@ -1004,7 +1020,7 @@ void resume_console(void)
                return;
        down(&console_sem);
        console_suspended = 0;
-       release_console_sem();
+       console_unlock();
 }
 
 /**
@@ -1027,21 +1043,21 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self,
        case CPU_DYING:
        case CPU_DOWN_FAILED:
        case CPU_UP_CANCELED:
-               acquire_console_sem();
-               release_console_sem();
+               console_lock();
+               console_unlock();
        }
        return NOTIFY_OK;
 }
 
 /**
- * acquire_console_sem - lock the console system for exclusive use.
+ * console_lock - lock the console system for exclusive use.
  *
- * Acquires a semaphore which guarantees that the caller has
+ * Acquires a lock which guarantees that the caller has
  * exclusive access to the console system and the console_drivers list.
  *
  * Can sleep, returns nothing.
  */
-void acquire_console_sem(void)
+void console_lock(void)
 {
        BUG_ON(in_interrupt());
        down(&console_sem);
@@ -1050,21 +1066,29 @@ void acquire_console_sem(void)
        console_locked = 1;
        console_may_schedule = 1;
 }
-EXPORT_SYMBOL(acquire_console_sem);
+EXPORT_SYMBOL(console_lock);
 
-int try_acquire_console_sem(void)
+/**
+ * console_trylock - try to lock the console system for exclusive use.
+ *
+ * Tried to acquire a lock which guarantees that the caller has
+ * exclusive access to the console system and the console_drivers list.
+ *
+ * returns 1 on success, and 0 on failure to acquire the lock.
+ */
+int console_trylock(void)
 {
        if (down_trylock(&console_sem))
-               return -1;
+               return 0;
        if (console_suspended) {
                up(&console_sem);
-               return -1;
+               return 0;
        }
        console_locked = 1;
        console_may_schedule = 0;
-       return 0;
+       return 1;
 }
-EXPORT_SYMBOL(try_acquire_console_sem);
+EXPORT_SYMBOL(console_trylock);
 
 int is_console_locked(void)
 {
@@ -1095,20 +1119,20 @@ void wake_up_klogd(void)
 }
 
 /**
- * release_console_sem - unlock the console system
+ * console_unlock - unlock the console system
  *
- * Releases the semaphore which the caller holds on the console system
+ * Releases the console_lock which the caller holds on the console system
  * and the console driver list.
  *
- * While the semaphore was held, console output may have been buffered
- * by printk().  If this is the case, release_console_sem() emits
- * the output prior to releasing the semaphore.
+ * While the console_lock was held, console output may have been buffered
+ * by printk().  If this is the case, console_unlock(); emits
+ * the output prior to releasing the lock.
  *
  * If there is output waiting for klogd, we wake it up.
  *
- * release_console_sem() may be called from any context.
+ * console_unlock(); may be called from any context.
  */
-void release_console_sem(void)
+void console_unlock(void)
 {
        unsigned long flags;
        unsigned _con_start, _log_end;
@@ -1141,7 +1165,7 @@ void release_console_sem(void)
        if (wake_klogd)
                wake_up_klogd();
 }
-EXPORT_SYMBOL(release_console_sem);
+EXPORT_SYMBOL(console_unlock);
 
 /**
  * console_conditional_schedule - yield the CPU if required
@@ -1150,7 +1174,7 @@ EXPORT_SYMBOL(release_console_sem);
  * if this CPU should yield the CPU to another task, do
  * so here.
  *
- * Must be called within acquire_console_sem().
+ * Must be called within console_lock();.
  */
 void __sched console_conditional_schedule(void)
 {
@@ -1171,14 +1195,14 @@ void console_unblank(void)
                if (down_trylock(&console_sem) != 0)
                        return;
        } else
-               acquire_console_sem();
+               console_lock();
 
        console_locked = 1;
        console_may_schedule = 0;
        for_each_console(c)
                if ((c->flags & CON_ENABLED) && c->unblank)
                        c->unblank();
-       release_console_sem();
+       console_unlock();
 }
 
 /*
@@ -1189,7 +1213,7 @@ struct tty_driver *console_device(int *index)
        struct console *c;
        struct tty_driver *driver = NULL;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(c) {
                if (!c->device)
                        continue;
@@ -1197,7 +1221,7 @@ struct tty_driver *console_device(int *index)
                if (driver)
                        break;
        }
-       release_console_sem();
+       console_unlock();
        return driver;
 }
 
@@ -1208,17 +1232,17 @@ struct tty_driver *console_device(int *index)
  */
 void console_stop(struct console *console)
 {
-       acquire_console_sem();
+       console_lock();
        console->flags &= ~CON_ENABLED;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(console_stop);
 
 void console_start(struct console *console)
 {
-       acquire_console_sem();
+       console_lock();
        console->flags |= CON_ENABLED;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(console_start);
 
@@ -1340,7 +1364,7 @@ void register_console(struct console *newcon)
         *      Put this console in the list - keep the
         *      preferred driver at the head of the list.
         */
-       acquire_console_sem();
+       console_lock();
        if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
                newcon->next = console_drivers;
                console_drivers = newcon;
@@ -1352,14 +1376,14 @@ void register_console(struct console *newcon)
        }
        if (newcon->flags & CON_PRINTBUFFER) {
                /*
-                * release_console_sem() will print out the buffered messages
+                * console_unlock(); will print out the buffered messages
                 * for us.
                 */
                spin_lock_irqsave(&logbuf_lock, flags);
                con_start = log_start;
                spin_unlock_irqrestore(&logbuf_lock, flags);
        }
-       release_console_sem();
+       console_unlock();
        console_sysfs_notify();
 
        /*
@@ -1396,7 +1420,7 @@ int unregister_console(struct console *console)
                return braille_unregister_console(console);
 #endif
 
-       acquire_console_sem();
+       console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
                res = 0;
@@ -1418,7 +1442,7 @@ int unregister_console(struct console *console)
        if (console_drivers != NULL && console->flags & CON_CONSDEV)
                console_drivers->flags |= CON_CONSDEV;
 
-       release_console_sem();
+       console_unlock();
        console_sysfs_notify();
        return res;
 }
index 99bbaa3..e2302e4 100644 (file)
@@ -163,7 +163,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
        return !err;
 }
 
-int ptrace_attach(struct task_struct *task)
+static int ptrace_attach(struct task_struct *task)
 {
        int retval;
 
@@ -219,7 +219,7 @@ out:
  * Performs checks and sets PT_PTRACED.
  * Should be used by all ptrace implementations for PTRACE_TRACEME.
  */
-int ptrace_traceme(void)
+static int ptrace_traceme(void)
 {
        int ret = -EPERM;
 
@@ -293,7 +293,7 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
        return false;
 }
 
-int ptrace_detach(struct task_struct *child, unsigned int data)
+static int ptrace_detach(struct task_struct *child, unsigned int data)
 {
        bool dead = false;
 
@@ -313,7 +313,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
                child->exit_code = data;
                dead = __ptrace_detach(current, child);
                if (!child->exit_state)
-                       wake_up_process(child);
+                       wake_up_state(child, TASK_TRACED | TASK_STOPPED);
        }
        write_unlock_irq(&tasklist_lock);
 
index ea3e5ef..18d38e4 100644 (file)
@@ -553,9 +553,6 @@ struct rq {
        /* try_to_wake_up() stats */
        unsigned int ttwu_count;
        unsigned int ttwu_local;
-
-       /* BKL stats */
-       unsigned int bkl_count;
 #endif
 };
 
@@ -609,6 +606,9 @@ static inline struct task_group *task_group(struct task_struct *p)
        struct task_group *tg;
        struct cgroup_subsys_state *css;
 
+       if (p->flags & PF_EXITING)
+               return &root_task_group;
+
        css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
                        lockdep_is_held(&task_rq(p)->lock));
        tg = container_of(css, struct task_group, css);
@@ -3887,7 +3887,7 @@ static inline void schedule_debug(struct task_struct *prev)
        schedstat_inc(this_rq(), sched_count);
 #ifdef CONFIG_SCHEDSTATS
        if (unlikely(prev->lock_depth >= 0)) {
-               schedstat_inc(this_rq(), bkl_count);
+               schedstat_inc(this_rq(), rq_sched_info.bkl_count);
                schedstat_inc(prev, sched_info.bkl_count);
        }
 #endif
@@ -4871,7 +4871,8 @@ recheck:
                 * assigned.
                 */
                if (rt_bandwidth_enabled() && rt_policy(policy) &&
-                               task_group(p)->rt_bandwidth.rt_runtime == 0) {
+                               task_group(p)->rt_bandwidth.rt_runtime == 0 &&
+                               !task_group_is_autogroup(task_group(p))) {
                        __task_rq_unlock(rq);
                        raw_spin_unlock_irqrestore(&p->pi_lock, flags);
                        return -EPERM;
@@ -8882,6 +8883,20 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
        }
 }
 
+static void
+cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task)
+{
+       /*
+        * cgroup_exit() is called in the copy_process() failure path.
+        * Ignore this case since the task hasn't ran yet, this avoids
+        * trying to poke a half freed task state from generic code.
+        */
+       if (!(task->flags & PF_EXITING))
+               return;
+
+       sched_move_task(task);
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
                                u64 shareval)
@@ -8954,6 +8969,7 @@ struct cgroup_subsys cpu_cgroup_subsys = {
        .destroy        = cpu_cgroup_destroy,
        .can_attach     = cpu_cgroup_can_attach,
        .attach         = cpu_cgroup_attach,
+       .exit           = cpu_cgroup_exit,
        .populate       = cpu_cgroup_populate,
        .subsys_id      = cpu_cgroup_subsys_id,
        .early_init     = 1,
index 32a723b..9fb6562 100644 (file)
@@ -27,6 +27,11 @@ static inline void autogroup_destroy(struct kref *kref)
 {
        struct autogroup *ag = container_of(kref, struct autogroup, kref);
 
+#ifdef CONFIG_RT_GROUP_SCHED
+       /* We've redirected RT tasks to the root task group... */
+       ag->tg->rt_se = NULL;
+       ag->tg->rt_rq = NULL;
+#endif
        sched_destroy_group(ag->tg);
 }
 
@@ -55,6 +60,10 @@ static inline struct autogroup *autogroup_task_get(struct task_struct *p)
        return ag;
 }
 
+#ifdef CONFIG_RT_GROUP_SCHED
+static void free_rt_sched_group(struct task_group *tg);
+#endif
+
 static inline struct autogroup *autogroup_create(void)
 {
        struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL);
@@ -72,6 +81,19 @@ static inline struct autogroup *autogroup_create(void)
        init_rwsem(&ag->lock);
        ag->id = atomic_inc_return(&autogroup_seq_nr);
        ag->tg = tg;
+#ifdef CONFIG_RT_GROUP_SCHED
+       /*
+        * Autogroup RT tasks are redirected to the root task group
+        * so we don't have to move tasks around upon policy change,
+        * or flail around trying to allocate bandwidth on the fly.
+        * A bandwidth exception in __sched_setscheduler() allows
+        * the policy change to proceed.  Thereafter, task_group()
+        * returns &root_task_group, so zero bandwidth is required.
+        */
+       free_rt_sched_group(tg);
+       tg->rt_se = root_task_group.rt_se;
+       tg->rt_rq = root_task_group.rt_rq;
+#endif
        tg->autogroup = ag;
 
        return ag;
@@ -106,6 +128,11 @@ task_wants_autogroup(struct task_struct *p, struct task_group *tg)
        return true;
 }
 
+static inline bool task_group_is_autogroup(struct task_group *tg)
+{
+       return tg != &root_task_group && tg->autogroup;
+}
+
 static inline struct task_group *
 autogroup_task_group(struct task_struct *p, struct task_group *tg)
 {
@@ -231,6 +258,11 @@ void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
 #ifdef CONFIG_SCHED_DEBUG
 static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
 {
+       int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
+
+       if (!enabled || !tg->autogroup)
+               return 0;
+
        return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
 }
 #endif /* CONFIG_SCHED_DEBUG */
index 5358e24..7b859ff 100644 (file)
@@ -15,6 +15,10 @@ autogroup_task_group(struct task_struct *p, struct task_group *tg);
 
 static inline void autogroup_init(struct task_struct *init_task) {  }
 static inline void autogroup_free(struct task_group *tg) { }
+static inline bool task_group_is_autogroup(struct task_group *tg)
+{
+       return 0;
+}
 
 static inline struct task_group *
 autogroup_task_group(struct task_struct *p, struct task_group *tg)
index 1dfae3d..eb6cb8e 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/kallsyms.h>
 #include <linux/utsname.h>
 
+static DEFINE_SPINLOCK(sched_debug_lock);
+
 /*
  * This allows printing both to /proc/sched_debug and
  * to the console
@@ -86,6 +88,26 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
 }
 #endif
 
+#ifdef CONFIG_CGROUP_SCHED
+static char group_path[PATH_MAX];
+
+static char *task_group_path(struct task_group *tg)
+{
+       if (autogroup_path(tg, group_path, PATH_MAX))
+               return group_path;
+
+       /*
+        * May be NULL if the underlying cgroup isn't fully-created yet
+        */
+       if (!tg->css.cgroup) {
+               group_path[0] = '\0';
+               return group_path;
+       }
+       cgroup_path(tg->css.cgroup, group_path, PATH_MAX);
+       return group_path;
+}
+#endif
+
 static void
 print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 {
@@ -108,6 +130,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
        SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
                0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
 #endif
+#ifdef CONFIG_CGROUP_SCHED
+       SEQ_printf(m, " %s", task_group_path(task_group(p)));
+#endif
 
        SEQ_printf(m, "\n");
 }
@@ -144,7 +169,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
        struct sched_entity *last;
        unsigned long flags;
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
+#else
        SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
+#endif
        SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
                        SPLIT_NS(cfs_rq->exec_clock));
 
@@ -191,7 +220,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 
 void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
 {
+#ifdef CONFIG_RT_GROUP_SCHED
+       SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
+#else
        SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
+#endif
 
 #define P(x) \
        SEQ_printf(m, "  .%-30s: %Ld\n", #x, (long long)(rt_rq->x))
@@ -212,6 +245,7 @@ extern __read_mostly int sched_clock_running;
 static void print_cpu(struct seq_file *m, int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
+       unsigned long flags;
 
 #ifdef CONFIG_X86
        {
@@ -262,14 +296,20 @@ static void print_cpu(struct seq_file *m, int cpu)
        P(ttwu_count);
        P(ttwu_local);
 
-       P(bkl_count);
+       SEQ_printf(m, "  .%-30s: %d\n", "bkl_count",
+                               rq->rq_sched_info.bkl_count);
 
 #undef P
+#undef P64
 #endif
+       spin_lock_irqsave(&sched_debug_lock, flags);
        print_cfs_stats(m, cpu);
        print_rt_stats(m, cpu);
 
+       rcu_read_lock();
        print_rq(m, rq, cpu);
+       rcu_read_unlock();
+       spin_unlock_irqrestore(&sched_debug_lock, flags);
 }
 
 static const char *sched_tunable_scaling_names[] = {
index c62ebae..0c26e2d 100644 (file)
@@ -699,7 +699,8 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
        cfs_rq->nr_running--;
 }
 
-#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
+#ifdef CONFIG_FAIR_GROUP_SCHED
+# ifdef CONFIG_SMP
 static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
                                            int global_update)
 {
@@ -721,10 +722,10 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
        u64 now, delta;
        unsigned long load = cfs_rq->load.weight;
 
-       if (!cfs_rq)
+       if (cfs_rq->tg == &root_task_group)
                return;
 
-       now = rq_of(cfs_rq)->clock;
+       now = rq_of(cfs_rq)->clock_task;
        delta = now - cfs_rq->load_stamp;
 
        /* truncate load history at 4 idle periods */
@@ -762,6 +763,51 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
                list_del_leaf_cfs_rq(cfs_rq);
 }
 
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+                               long weight_delta)
+{
+       long load_weight, load, shares;
+
+       load = cfs_rq->load.weight + weight_delta;
+
+       load_weight = atomic_read(&tg->load_weight);
+       load_weight -= cfs_rq->load_contribution;
+       load_weight += load;
+
+       shares = (tg->shares * load);
+       if (load_weight)
+               shares /= load_weight;
+
+       if (shares < MIN_SHARES)
+               shares = MIN_SHARES;
+       if (shares > tg->shares)
+               shares = tg->shares;
+
+       return shares;
+}
+
+static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+       if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
+               update_cfs_load(cfs_rq, 0);
+               update_cfs_shares(cfs_rq, 0);
+       }
+}
+# else /* CONFIG_SMP */
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
+{
+}
+
+static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+                               long weight_delta)
+{
+       return tg->shares;
+}
+
+static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+}
+# endif /* CONFIG_SMP */
 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                            unsigned long weight)
 {
@@ -782,41 +828,20 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
 {
        struct task_group *tg;
        struct sched_entity *se;
-       long load_weight, load, shares;
-
-       if (!cfs_rq)
-               return;
+       long shares;
 
        tg = cfs_rq->tg;
        se = tg->se[cpu_of(rq_of(cfs_rq))];
        if (!se)
                return;
-
-       load = cfs_rq->load.weight + weight_delta;
-
-       load_weight = atomic_read(&tg->load_weight);
-       load_weight -= cfs_rq->load_contribution;
-       load_weight += load;
-
-       shares = (tg->shares * load);
-       if (load_weight)
-               shares /= load_weight;
-
-       if (shares < MIN_SHARES)
-               shares = MIN_SHARES;
-       if (shares > tg->shares)
-               shares = tg->shares;
+#ifndef CONFIG_SMP
+       if (likely(se->load.weight == tg->shares))
+               return;
+#endif
+       shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
 
        reweight_entity(cfs_rq_of(se), se, shares);
 }
-
-static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
-{
-       if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
-               update_cfs_load(cfs_rq, 0);
-               update_cfs_shares(cfs_rq, 0);
-       }
-}
 #else /* CONFIG_FAIR_GROUP_SCHED */
 static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
 {
@@ -1062,6 +1087,9 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
                struct sched_entity *se = __pick_next_entity(cfs_rq);
                s64 delta = curr->vruntime - se->vruntime;
 
+               if (delta < 0)
+                       return;
+
                if (delta > ideal_runtime)
                        resched_task(rq_of(cfs_rq)->curr);
        }
@@ -1362,27 +1390,27 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
                return wl;
 
        for_each_sched_entity(se) {
-               long S, rw, s, a, b;
+               long lw, w;
 
-               S = se->my_q->tg->shares;
-               s = se->load.weight;
-               rw = se->my_q->load.weight;
+               tg = se->my_q->tg;
+               w = se->my_q->load.weight;
 
-               a = S*(rw + wl);
-               b = S*rw + s*wg;
+               /* use this cpu's instantaneous contribution */
+               lw = atomic_read(&tg->load_weight);
+               lw -= se->my_q->load_contribution;
+               lw += w + wg;
 
-               wl = s*(a-b);
+               wl += w;
 
-               if (likely(b))
-                       wl /= b;
+               if (lw > 0 && wl < lw)
+                       wl = (wl * tg->shares) / lw;
+               else
+                       wl = tg->shares;
 
-               /*
-                * Assume the group is already running and will
-                * thus already be accounted for in the weight.
-                *
-                * That is, moving shares between CPUs, does not
-                * alter the group weight.
-                */
+               /* zero point is MIN_SHARES */
+               if (wl < MIN_SHARES)
+                       wl = MIN_SHARES;
+               wl -= se->load.weight;
                wg = 0;
        }
 
@@ -1401,7 +1429,7 @@ static inline unsigned long effective_load(struct task_group *tg, int cpu,
 
 static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
-       unsigned long this_load, load;
+       s64 this_load, load;
        int idx, this_cpu, prev_cpu;
        unsigned long tl_per_task;
        struct task_group *tg;
@@ -1440,8 +1468,8 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
         * Otherwise check if either cpus are near enough in load to allow this
         * task to be woken on this_cpu.
         */
-       if (this_load) {
-               unsigned long this_eff_load, prev_eff_load;
+       if (this_load > 0) {
+               s64 this_eff_load, prev_eff_load;
 
                this_eff_load = 100;
                this_eff_load *= power_of(prev_cpu);
index c914ec7..ad62677 100644 (file)
@@ -625,7 +625,7 @@ static void update_curr_rt(struct rq *rq)
        struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
        u64 delta_exec;
 
-       if (!task_has_rt_policy(curr))
+       if (curr->sched_class != &rt_sched_class)
                return;
 
        delta_exec = rq->clock_task - curr->se.exec_start;
index 4ec30e0..9910744 100644 (file)
@@ -194,23 +194,52 @@ void generic_smp_call_function_interrupt(void)
         */
        list_for_each_entry_rcu(data, &call_function.queue, csd.list) {
                int refs;
+               void (*func) (void *info);
 
-               if (!cpumask_test_and_clear_cpu(cpu, data->cpumask))
+               /*
+                * Since we walk the list without any locks, we might
+                * see an entry that was completed, removed from the
+                * list and is in the process of being reused.
+                *
+                * We must check that the cpu is in the cpumask before
+                * checking the refs, and both must be set before
+                * executing the callback on this cpu.
+                */
+
+               if (!cpumask_test_cpu(cpu, data->cpumask))
+                       continue;
+
+               smp_rmb();
+
+               if (atomic_read(&data->refs) == 0)
                        continue;
 
+               func = data->csd.func;                  /* for later warn */
                data->csd.func(data->csd.info);
 
+               /*
+                * If the cpu mask is not still set then it enabled interrupts,
+                * we took another smp interrupt, and executed the function
+                * twice on this cpu.  In theory that copy decremented refs.
+                */
+               if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) {
+                       WARN(1, "%pS enabled interrupts and double executed\n",
+                            func);
+                       continue;
+               }
+
                refs = atomic_dec_return(&data->refs);
                WARN_ON(refs < 0);
-               if (!refs) {
-                       raw_spin_lock(&call_function.lock);
-                       list_del_rcu(&data->csd.list);
-                       raw_spin_unlock(&call_function.lock);
-               }
 
                if (refs)
                        continue;
 
+               WARN_ON(!cpumask_empty(data->cpumask));
+
+               raw_spin_lock(&call_function.lock);
+               list_del_rcu(&data->csd.list);
+               raw_spin_unlock(&call_function.lock);
+
                csd_unlock(&data->csd);
        }
 
@@ -430,7 +459,7 @@ void smp_call_function_many(const struct cpumask *mask,
         * can't happen.
         */
        WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
-                    && !oops_in_progress);
+                    && !oops_in_progress && !early_boot_irqs_disabled);
 
        /* So, what's a CPU they want? Ignoring this one. */
        cpu = cpumask_first_and(mask, cpu_online_mask);
@@ -454,11 +483,21 @@ void smp_call_function_many(const struct cpumask *mask,
 
        data = &__get_cpu_var(cfd_data);
        csd_lock(&data->csd);
+       BUG_ON(atomic_read(&data->refs) || !cpumask_empty(data->cpumask));
 
        data->csd.func = func;
        data->csd.info = info;
        cpumask_and(data->cpumask, mask, cpu_online_mask);
        cpumask_clear_cpu(this_cpu, data->cpumask);
+
+       /*
+        * To ensure the interrupt handler gets an complete view
+        * we order the cpumask and refs writes and order the read
+        * of them in the interrupt handler.  In addition we may
+        * only clear our own cpu bit from the mask.
+        */
+       smp_wmb();
+
        atomic_set(&data->refs, cpumask_weight(data->cpumask));
 
        raw_spin_lock_irqsave(&call_function.lock, flags);
@@ -533,17 +572,20 @@ void ipi_call_unlock_irq(void)
 #endif /* USE_GENERIC_SMP_HELPERS */
 
 /*
- * Call a function on all processors
+ * Call a function on all processors.  May be used during early boot while
+ * early_boot_irqs_disabled is set.  Use local_irq_save/restore() instead
+ * of local_irq_disable/enable().
  */
 int on_each_cpu(void (*func) (void *info), void *info, int wait)
 {
+       unsigned long flags;
        int ret = 0;
 
        preempt_disable();
        ret = smp_call_function(func, info, wait);
-       local_irq_disable();
+       local_irq_save(flags);
        func(info);
-       local_irq_enable();
+       local_irq_restore(flags);
        preempt_enable();
        return ret;
 }
index 31b71a2..18da702 100644 (file)
@@ -1385,7 +1385,8 @@ static int check_prlimit_permission(struct task_struct *task)
        const struct cred *cred = current_cred(), *tcred;
 
        tcred = __task_cred(task);
-       if ((cred->uid != tcred->euid ||
+       if (current != task &&
+           (cred->uid != tcred->euid ||
             cred->uid != tcred->suid ||
             cred->uid != tcred->uid  ||
             cred->gid != tcred->egid ||
index bc86bb3..0f1bd83 100644 (file)
@@ -170,7 +170,8 @@ static int proc_taint(struct ctl_table *table, int write,
 #endif
 
 #ifdef CONFIG_MAGIC_SYSRQ
-static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */
+/* Note: sysrq code uses it's own private copy */
+static int __sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 
 static int sysrq_sysctl_handler(ctl_table *table, int write,
                                void __user *buffer, size_t *lenp,
index 48b2761..a3b5aff 100644 (file)
@@ -600,4 +600,14 @@ int tick_broadcast_oneshot_active(void)
        return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
 }
 
+/*
+ * Check whether the broadcast device supports oneshot.
+ */
+bool tick_broadcast_oneshot_available(void)
+{
+       struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
+       return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
+}
+
 #endif
index 051bc80..ed228ef 100644 (file)
@@ -51,7 +51,11 @@ int tick_is_oneshot_available(void)
 {
        struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
 
-       return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT);
+       if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+               return 0;
+       if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
+               return 1;
+       return tick_broadcast_oneshot_available();
 }
 
 /*
index 290eefb..f65d3a7 100644 (file)
@@ -36,6 +36,7 @@ extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
 extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
 extern int tick_broadcast_oneshot_active(void);
 extern void tick_check_oneshot_broadcast(int cpu);
+bool tick_broadcast_oneshot_available(void);
 # else /* BROADCAST */
 static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
@@ -46,6 +47,7 @@ static inline void tick_broadcast_switch_to_oneshot(void) { }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
 static inline int tick_broadcast_oneshot_active(void) { return 0; }
 static inline void tick_check_oneshot_broadcast(int cpu) { }
+static inline bool tick_broadcast_oneshot_available(void) { return true; }
 # endif /* !BROADCAST */
 
 #else /* !ONESHOT */
@@ -76,6 +78,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
        return 0;
 }
 static inline int tick_broadcast_oneshot_active(void) { return 0; }
+static inline bool tick_broadcast_oneshot_available(void) { return false; }
 #endif /* !TICK_ONESHOT */
 
 /*
index 3e216e0..c55ea24 100644 (file)
@@ -642,8 +642,7 @@ static void tick_nohz_switch_to_nohz(void)
        }
        local_irq_enable();
 
-       printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n",
-              smp_processor_id());
+       printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
 }
 
 /*
@@ -795,8 +794,10 @@ void tick_setup_sched_timer(void)
        }
 
 #ifdef CONFIG_NO_HZ
-       if (tick_nohz_enabled)
+       if (tick_nohz_enabled) {
                ts->nohz_mode = NOHZ_MODE_HIGHRES;
+               printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
+       }
 #endif
 }
 #endif /* HIGH_RES_TIMERS */
index 32a19f9..3258455 100644 (file)
@@ -41,7 +41,7 @@ static void print_name_offset(struct seq_file *m, void *sym)
        char symname[KSYM_NAME_LEN];
 
        if (lookup_symbol_name((unsigned long)sym, symname) < 0)
-               SEQ_printf(m, "<%p>", sym);
+               SEQ_printf(m, "<%pK>", sym);
        else
                SEQ_printf(m, "%s", symname);
 }
@@ -112,7 +112,7 @@ next_one:
 static void
 print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
 {
-       SEQ_printf(m, "  .base:       %p\n", base);
+       SEQ_printf(m, "  .base:       %pK\n", base);
        SEQ_printf(m, "  .index:      %d\n",
                        base->index);
        SEQ_printf(m, "  .resolution: %Lu nsecs\n",
index 43ca993..d645992 100644 (file)
@@ -959,7 +959,7 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
  *
  * Synchronization rules: Callers must prevent restarting of the timer,
  * otherwise this function is meaningless. It must not be called from
- * hardirq contexts. The caller must not hold locks which would prevent
+ * interrupt contexts. The caller must not hold locks which would prevent
  * completion of the timer's handler. The timer's handler must not call
  * add_timer_on(). Upon exit the timer is not queued and the handler is
  * not running on any CPU.
@@ -969,10 +969,12 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
 int del_timer_sync(struct timer_list *timer)
 {
 #ifdef CONFIG_LOCKDEP
-       local_bh_disable();
+       unsigned long flags;
+
+       local_irq_save(flags);
        lock_map_acquire(&timer->lockdep_map);
        lock_map_release(&timer->lockdep_map);
-       local_bh_enable();
+       local_irq_restore(flags);
 #endif
        /*
         * don't use it in hardirq context, because it
index 153562d..cbafed7 100644 (file)
@@ -138,6 +138,13 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...)
                     !blk_tracer_enabled))
                return;
 
+       /*
+        * If the BLK_TC_NOTIFY action mask isn't set, don't send any note
+        * message to the trace.
+        */
+       if (!(bt->act_mask & BLK_TC_NOTIFY))
+               return;
+
        local_irq_save(flags);
        buf = per_cpu_ptr(bt->msg_data, smp_processor_id());
        va_start(args, fmt);
@@ -1820,21 +1827,5 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
        rwbs[i] = '\0';
 }
 
-void blk_fill_rwbs_rq(char *rwbs, struct request *rq)
-{
-       int rw = rq->cmd_flags & 0x03;
-       int bytes;
-
-       if (rq->cmd_flags & REQ_DISCARD)
-               rw |= REQ_DISCARD;
-
-       if (rq->cmd_flags & REQ_SECURE)
-               rw |= REQ_SECURE;
-
-       bytes = blk_rq_bytes(rq);
-
-       blk_fill_rwbs(rwbs, rw, bytes);
-}
-
 #endif /* CONFIG_EVENT_TRACING */
 
index 35fde09..5f499e0 100644 (file)
@@ -1284,7 +1284,7 @@ trace_create_file_ops(struct module *mod)
 static void trace_module_add_events(struct module *mod)
 {
        struct ftrace_module_file_ops *file_ops = NULL;
-       struct ftrace_event_call *call, *start, *end;
+       struct ftrace_event_call **call, **start, **end;
 
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
@@ -1297,7 +1297,7 @@ static void trace_module_add_events(struct module *mod)
                return;
 
        for_each_event(call, start, end) {
-               __trace_add_event_call(call, mod,
+               __trace_add_event_call(*call, mod,
                                       &file_ops->id, &file_ops->enable,
                                       &file_ops->filter, &file_ops->format);
        }
@@ -1367,8 +1367,8 @@ static struct notifier_block trace_module_nb = {
        .priority = 0,
 };
 
-extern struct ftrace_event_call __start_ftrace_events[];
-extern struct ftrace_event_call __stop_ftrace_events[];
+extern struct ftrace_event_call *__start_ftrace_events[];
+extern struct ftrace_event_call *__stop_ftrace_events[];
 
 static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
 
@@ -1384,7 +1384,7 @@ __setup("trace_event=", setup_trace_event);
 
 static __init int event_trace_init(void)
 {
-       struct ftrace_event_call *call;
+       struct ftrace_event_call **call;
        struct dentry *d_tracer;
        struct dentry *entry;
        struct dentry *d_events;
@@ -1430,7 +1430,7 @@ static __init int event_trace_init(void)
                pr_warning("tracing: Failed to allocate common fields");
 
        for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
-               __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
+               __trace_add_event_call(*call, NULL, &ftrace_event_id_fops,
                                       &ftrace_enable_fops,
                                       &ftrace_event_filter_fops,
                                       &ftrace_event_format_fops);
index 4b74d71..bbeec31 100644 (file)
@@ -161,13 +161,13 @@ struct ftrace_event_class event_class_ftrace_##call = {                   \
        .fields                 = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
 };                                                                     \
                                                                        \
-struct ftrace_event_call __used                                                \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+struct ftrace_event_call __used event_##call = {                       \
        .name                   = #call,                                \
        .event.type             = etype,                                \
        .class                  = &event_class_ftrace_##call,           \
        .print_fmt              = print,                                \
 };                                                                     \
+struct ftrace_event_call __used                                                \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
 
 #include "trace_entries.h"
index 5cf8c60..92b6e1e 100644 (file)
@@ -453,14 +453,6 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1)
  * Stubs:
  */
 
-void early_boot_irqs_off(void)
-{
-}
-
-void early_boot_irqs_on(void)
-{
-}
-
 void trace_softirqs_on(unsigned long ip)
 {
 }
index b706529..5c9fe08 100644 (file)
@@ -55,20 +55,21 @@ struct ftrace_event_class event_class_syscall_exit = {
        .raw_init       = init_syscall_trace,
 };
 
-extern unsigned long __start_syscalls_metadata[];
-extern unsigned long __stop_syscalls_metadata[];
+extern struct syscall_metadata *__start_syscalls_metadata[];
+extern struct syscall_metadata *__stop_syscalls_metadata[];
 
 static struct syscall_metadata **syscalls_metadata;
 
-static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+static __init struct syscall_metadata *
+find_syscall_meta(unsigned long syscall)
 {
-       struct syscall_metadata *start;
-       struct syscall_metadata *stop;
+       struct syscall_metadata **start;
+       struct syscall_metadata **stop;
        char str[KSYM_SYMBOL_LEN];
 
 
-       start = (struct syscall_metadata *)__start_syscalls_metadata;
-       stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+       start = __start_syscalls_metadata;
+       stop = __stop_syscalls_metadata;
        kallsyms_lookup(syscall, NULL, NULL, NULL, str);
 
        for ( ; start < stop; start++) {
@@ -78,8 +79,8 @@ static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
                 * with "SyS" instead of "sys", leading to an unwanted
                 * mismatch.
                 */
-               if (start->name && !strcmp(start->name + 3, str + 3))
-                       return start;
+               if ((*start)->name && !strcmp((*start)->name + 3, str + 3))
+                       return *start;
        }
        return NULL;
 }
index e95ee7f..68187af 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/sched.h>
 #include <linux/jump_label.h>
 
-extern struct tracepoint __start___tracepoints[];
-extern struct tracepoint __stop___tracepoints[];
+extern struct tracepoint * const __start___tracepoints_ptrs[];
+extern struct tracepoint * const __stop___tracepoints_ptrs[];
 
 /* Set to 1 to enable tracepoint debug output */
 static const int tracepoint_debug;
@@ -298,10 +298,10 @@ static void disable_tracepoint(struct tracepoint *elem)
  *
  * Updates the probe callback corresponding to a range of tracepoints.
  */
-void
-tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+                                  struct tracepoint * const *end)
 {
-       struct tracepoint *iter;
+       struct tracepoint * const *iter;
        struct tracepoint_entry *mark_entry;
 
        if (!begin)
@@ -309,12 +309,12 @@ tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
 
        mutex_lock(&tracepoints_mutex);
        for (iter = begin; iter < end; iter++) {
-               mark_entry = get_tracepoint(iter->name);
+               mark_entry = get_tracepoint((*iter)->name);
                if (mark_entry) {
-                       set_tracepoint(&mark_entry, iter,
+                       set_tracepoint(&mark_entry, *iter,
                                        !!mark_entry->refcount);
                } else {
-                       disable_tracepoint(iter);
+                       disable_tracepoint(*iter);
                }
        }
        mutex_unlock(&tracepoints_mutex);
@@ -326,8 +326,8 @@ tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
 static void tracepoint_update_probes(void)
 {
        /* Core kernel tracepoints */
-       tracepoint_update_probe_range(__start___tracepoints,
-               __stop___tracepoints);
+       tracepoint_update_probe_range(__start___tracepoints_ptrs,
+               __stop___tracepoints_ptrs);
        /* tracepoints in modules. */
        module_update_tracepoints();
 }
@@ -514,8 +514,8 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
  * Will return the first tracepoint in the range if the input tracepoint is
  * NULL.
  */
-int tracepoint_get_iter_range(struct tracepoint **tracepoint,
-       struct tracepoint *begin, struct tracepoint *end)
+int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
+       struct tracepoint * const *begin, struct tracepoint * const *end)
 {
        if (!*tracepoint && begin != end) {
                *tracepoint = begin;
@@ -534,7 +534,8 @@ static void tracepoint_get_iter(struct tracepoint_iter *iter)
        /* Core kernel tracepoints */
        if (!iter->module) {
                found = tracepoint_get_iter_range(&iter->tracepoint,
-                               __start___tracepoints, __stop___tracepoints);
+                               __start___tracepoints_ptrs,
+                               __stop___tracepoints_ptrs);
                if (found)
                        goto end;
        }
@@ -585,8 +586,8 @@ int tracepoint_module_notify(struct notifier_block *self,
        switch (val) {
        case MODULE_STATE_COMING:
        case MODULE_STATE_GOING:
-               tracepoint_update_probe_range(mod->tracepoints,
-                       mod->tracepoints + mod->num_tracepoints);
+               tracepoint_update_probe_range(mod->tracepoints_ptrs,
+                       mod->tracepoints_ptrs + mod->num_tracepoints);
                break;
        }
        return 0;
index d7ebdf4..18bb157 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/irq_regs.h>
 #include <linux/perf_event.h>
 
-int watchdog_enabled;
+int watchdog_enabled = 1;
 int __read_mostly softlockup_thresh = 60;
 
 static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
@@ -43,9 +43,6 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int no_watchdog;
-
-
 /* boot commands */
 /*
  * Should we panic when a soft-lockup or hard-lockup occurs:
@@ -58,7 +55,7 @@ static int __init hardlockup_panic_setup(char *str)
        if (!strncmp(str, "panic", 5))
                hardlockup_panic = 1;
        else if (!strncmp(str, "0", 1))
-               no_watchdog = 1;
+               watchdog_enabled = 0;
        return 1;
 }
 __setup("nmi_watchdog=", hardlockup_panic_setup);
@@ -77,7 +74,7 @@ __setup("softlockup_panic=", softlockup_panic_setup);
 
 static int __init nowatchdog_setup(char *str)
 {
-       no_watchdog = 1;
+       watchdog_enabled = 0;
        return 1;
 }
 __setup("nowatchdog", nowatchdog_setup);
@@ -85,7 +82,7 @@ __setup("nowatchdog", nowatchdog_setup);
 /* deprecated */
 static int __init nosoftlockup_setup(char *str)
 {
-       no_watchdog = 1;
+       watchdog_enabled = 0;
        return 1;
 }
 __setup("nosoftlockup", nosoftlockup_setup);
@@ -366,8 +363,14 @@ static int watchdog_nmi_enable(int cpu)
                goto out_save;
        }
 
-       printk(KERN_ERR "NMI watchdog disabled for cpu%i: unable to create perf event: %ld\n",
-              cpu, PTR_ERR(event));
+
+       /* vary the KERN level based on the returned errno */
+       if (PTR_ERR(event) == -EOPNOTSUPP)
+               printk(KERN_INFO "NMI watchdog disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
+       else if (PTR_ERR(event) == -ENOENT)
+               printk(KERN_WARNING "NMI watchdog disabled (cpu%i): hardware events not enabled\n", cpu);
+       else
+               printk(KERN_ERR "NMI watchdog disabled (cpu%i): unable to create perf event: %ld\n", cpu, PTR_ERR(event));
        return PTR_ERR(event);
 
        /* success path */
@@ -432,9 +435,6 @@ static int watchdog_enable(int cpu)
                wake_up_process(p);
        }
 
-       /* if any cpu succeeds, watchdog is considered enabled for the system */
-       watchdog_enabled = 1;
-
        return 0;
 }
 
@@ -462,12 +462,16 @@ static void watchdog_disable(int cpu)
 static void watchdog_enable_all_cpus(void)
 {
        int cpu;
-       int result = 0;
+
+       watchdog_enabled = 0;
 
        for_each_online_cpu(cpu)
-               result += watchdog_enable(cpu);
+               if (!watchdog_enable(cpu))
+                       /* if any cpu succeeds, watchdog is considered
+                          enabled for the system */
+                       watchdog_enabled = 1;
 
-       if (result)
+       if (!watchdog_enabled)
                printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
 
 }
@@ -476,9 +480,6 @@ static void watchdog_disable_all_cpus(void)
 {
        int cpu;
 
-       if (no_watchdog)
-               return;
-
        for_each_online_cpu(cpu)
                watchdog_disable(cpu);
 
@@ -498,10 +499,12 @@ int proc_dowatchdog_enabled(struct ctl_table *table, int write,
 {
        proc_dointvec(table, write, buffer, length, ppos);
 
-       if (watchdog_enabled)
-               watchdog_enable_all_cpus();
-       else
-               watchdog_disable_all_cpus();
+       if (write) {
+               if (watchdog_enabled)
+                       watchdog_enable_all_cpus();
+               else
+                       watchdog_disable_all_cpus();
+       }
        return 0;
 }
 
@@ -530,7 +533,8 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               err = watchdog_enable(hotcpu);
+               if (watchdog_enabled)
+                       err = watchdog_enable(hotcpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
@@ -555,9 +559,6 @@ void __init lockup_detector_init(void)
        void *cpu = (void *)(long)smp_processor_id();
        int err;
 
-       if (no_watchdog)
-               return;
-
        err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
        WARN_ON(notifier_to_errno(err));
 
index 8ee6ec8..ee6578b 100644 (file)
@@ -79,7 +79,9 @@ enum {
        MAX_IDLE_WORKERS_RATIO  = 4,            /* 1/4 of busy can be idle */
        IDLE_WORKER_TIMEOUT     = 300 * HZ,     /* keep idle ones for 5 mins */
 
-       MAYDAY_INITIAL_TIMEOUT  = HZ / 100,     /* call for help after 10ms */
+       MAYDAY_INITIAL_TIMEOUT  = HZ / 100 >= 2 ? HZ / 100 : 2,
+                                               /* call for help after 10ms
+                                                  (min two ticks) */
        MAYDAY_INTERVAL         = HZ / 10,      /* and then every 100ms */
        CREATE_COOLDOWN         = HZ,           /* time to breath after fail */
        TRUSTEE_COOLDOWN        = HZ / 10,      /* for trustee draining */
@@ -768,7 +770,11 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
 
        worker->flags &= ~flags;
 
-       /* if transitioning out of NOT_RUNNING, increment nr_running */
+       /*
+        * If transitioning out of NOT_RUNNING, increment nr_running.  Note
+        * that the nested NOT_RUNNING is not a noop.  NOT_RUNNING is mask
+        * of multiple flags, not a single flag.
+        */
        if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
                if (!(worker->flags & WORKER_NOT_RUNNING))
                        atomic_inc(get_gcwq_nr_running(gcwq->cpu));
@@ -1840,7 +1846,7 @@ __acquires(&gcwq->lock)
        spin_unlock_irq(&gcwq->lock);
 
        work_clear_pending(work);
-       lock_map_acquire(&cwq->wq->lockdep_map);
+       lock_map_acquire_read(&cwq->wq->lockdep_map);
        lock_map_acquire(&lockdep_map);
        trace_workqueue_execute_start(work);
        f(work);
@@ -2043,6 +2049,15 @@ repeat:
                                move_linked_works(work, scheduled, &n);
 
                process_scheduled_works(rescuer);
+
+               /*
+                * Leave this gcwq.  If keep_working() is %true, notify a
+                * regular worker; otherwise, we end up with 0 concurrency
+                * and stalling the execution.
+                */
+               if (keep_working(gcwq))
+                       wake_up_worker(gcwq);
+
                spin_unlock_irq(&gcwq->lock);
        }
 
@@ -2384,8 +2399,18 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
        insert_wq_barrier(cwq, barr, work, worker);
        spin_unlock_irq(&gcwq->lock);
 
-       lock_map_acquire(&cwq->wq->lockdep_map);
+       /*
+        * If @max_active is 1 or rescuer is in use, flushing another work
+        * item on the same workqueue may lead to deadlock.  Make sure the
+        * flusher is not running on the same workqueue by verifying write
+        * access.
+        */
+       if (cwq->wq->saved_max_active == 1 || cwq->wq->flags & WQ_RESCUER)
+               lock_map_acquire(&cwq->wq->lockdep_map);
+       else
+               lock_map_acquire_read(&cwq->wq->lockdep_map);
        lock_map_release(&cwq->wq->lockdep_map);
+
        return true;
 already_gone:
        spin_unlock_irq(&gcwq->lock);
@@ -2942,7 +2967,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
         */
        spin_lock(&workqueue_lock);
 
-       if (workqueue_freezing && wq->flags & WQ_FREEZEABLE)
+       if (workqueue_freezing && wq->flags & WQ_FREEZABLE)
                for_each_cwq_cpu(cpu, wq)
                        get_cwq(cpu, wq)->max_active = 0;
 
@@ -3054,7 +3079,7 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 
                spin_lock_irq(&gcwq->lock);
 
-               if (!(wq->flags & WQ_FREEZEABLE) ||
+               if (!(wq->flags & WQ_FREEZABLE) ||
                    !(gcwq->flags & GCWQ_FREEZING))
                        get_cwq(gcwq->cpu, wq)->max_active = max_active;
 
@@ -3304,7 +3329,7 @@ static int __cpuinit trustee_thread(void *__gcwq)
         * want to get it over with ASAP - spam rescuers, wake up as
         * many idlers as necessary and create new ones till the
         * worklist is empty.  Note that if the gcwq is frozen, there
-        * may be frozen works in freezeable cwqs.  Don't declare
+        * may be frozen works in freezable cwqs.  Don't declare
         * completion while frozen.
         */
        while (gcwq->nr_workers != gcwq->nr_idle ||
@@ -3562,9 +3587,9 @@ EXPORT_SYMBOL_GPL(work_on_cpu);
 /**
  * freeze_workqueues_begin - begin freezing workqueues
  *
- * Start freezing workqueues.  After this function returns, all
- * freezeable workqueues will queue new works to their frozen_works
- * list instead of gcwq->worklist.
+ * Start freezing workqueues.  After this function returns, all freezable
+ * workqueues will queue new works to their frozen_works list instead of
+ * gcwq->worklist.
  *
  * CONTEXT:
  * Grabs and releases workqueue_lock and gcwq->lock's.
@@ -3590,7 +3615,7 @@ void freeze_workqueues_begin(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (cwq && wq->flags & WQ_FREEZEABLE)
+                       if (cwq && wq->flags & WQ_FREEZABLE)
                                cwq->max_active = 0;
                }
 
@@ -3601,7 +3626,7 @@ void freeze_workqueues_begin(void)
 }
 
 /**
- * freeze_workqueues_busy - are freezeable workqueues still busy?
+ * freeze_workqueues_busy - are freezable workqueues still busy?
  *
  * Check whether freezing is complete.  This function must be called
  * between freeze_workqueues_begin() and thaw_workqueues().
@@ -3610,8 +3635,8 @@ void freeze_workqueues_begin(void)
  * Grabs and releases workqueue_lock.
  *
  * RETURNS:
- * %true if some freezeable workqueues are still busy.  %false if
- * freezing is complete.
+ * %true if some freezable workqueues are still busy.  %false if freezing
+ * is complete.
  */
 bool freeze_workqueues_busy(void)
 {
@@ -3631,7 +3656,7 @@ bool freeze_workqueues_busy(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+                       if (!cwq || !(wq->flags & WQ_FREEZABLE))
                                continue;
 
                        BUG_ON(cwq->nr_active < 0);
@@ -3676,7 +3701,7 @@ void thaw_workqueues(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+                       if (!cwq || !(wq->flags & WQ_FREEZABLE))
                                continue;
 
                        /* restore max_active and repopulate worklist */
index 2d05adb..2b97418 100644 (file)
@@ -657,7 +657,7 @@ config DEBUG_HIGHMEM
          Disable for production systems.
 
 config DEBUG_BUGVERBOSE
-       bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
+       bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
        depends on BUG
        depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \
                   FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300
@@ -729,8 +729,8 @@ config DEBUG_WRITECOUNT
          If unsure, say N.
 
 config DEBUG_MEMORY_INIT
-       bool "Debug memory initialisation" if EMBEDDED
-       default !EMBEDDED
+       bool "Debug memory initialisation" if EXPERT
+       default !EXPERT
        help
          Enable this for additional checks during memory initialisation.
          The sanity checks verify aspects of the VM such as the memory model
@@ -805,7 +805,7 @@ config ARCH_WANT_FRAME_POINTERS
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
        depends on DEBUG_KERNEL && \
-               (CRIS || M68K || M68KNOMMU || FRV || UML || \
+               (CRIS || M68K || FRV || UML || \
                 AVR32 || SUPERH || BLACKFIN || MN10300) || \
                ARCH_WANT_FRAME_POINTERS
        default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS
index 344c710..b8029a5 100644 (file)
@@ -35,6 +35,31 @@ void __list_add(struct list_head *new,
 }
 EXPORT_SYMBOL(__list_add);
 
+void __list_del_entry(struct list_head *entry)
+{
+       struct list_head *prev, *next;
+
+       prev = entry->prev;
+       next = entry->next;
+
+       if (WARN(next == LIST_POISON1,
+               "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
+               entry, LIST_POISON1) ||
+           WARN(prev == LIST_POISON2,
+               "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
+               entry, LIST_POISON2) ||
+           WARN(prev->next != entry,
+               "list_del corruption. prev->next should be %p, "
+               "but was %p\n", entry, prev->next) ||
+           WARN(next->prev != entry,
+               "list_del corruption. next->prev should be %p, "
+               "but was %p\n", entry, next->prev))
+               return;
+
+       __list_del(prev, next);
+}
+EXPORT_SYMBOL(__list_del_entry);
+
 /**
  * list_del - deletes entry from list.
  * @entry: the element to delete from the list.
@@ -43,19 +68,7 @@ EXPORT_SYMBOL(__list_add);
  */
 void list_del(struct list_head *entry)
 {
-       WARN(entry->next == LIST_POISON1,
-               "list_del corruption, next is LIST_POISON1 (%p)\n",
-               LIST_POISON1);
-       WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2,
-               "list_del corruption, prev is LIST_POISON2 (%p)\n",
-               LIST_POISON2);
-       WARN(entry->prev->next != entry,
-               "list_del corruption. prev->next should be %p, "
-               "but was %p\n", entry, entry->prev->next);
-       WARN(entry->next->prev != entry,
-               "list_del corruption. next->prev should be %p, "
-               "but was %p\n", entry, entry->next->prev);
-       __list_del(entry->prev, entry->next);
+       __list_del_entry(entry);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
 }
index 5021cbc..ac09f22 100644 (file)
@@ -148,7 +148,7 @@ nla_policy_len(const struct nla_policy *p, int n)
 {
        int i, len = 0;
 
-       for (i = 0; i < n; i++) {
+       for (i = 0; i < n; i++, p++) {
                if (p->len)
                        len += nla_total_size(p->len);
                else if (nla_attr_minlen[p->type])
index 5086bb9..7ea2e03 100644 (file)
@@ -736,10 +736,11 @@ next:
                }
        }
        /*
-        * The iftag must have been set somewhere because otherwise
-        * we would return immediated at the beginning of the function
+        * We need not to tag the root tag if there is no tag which is set with
+        * settag within the range from *first_indexp to last_index.
         */
-       root_tag_set(root, settag);
+       if (tagged > 0)
+               root_tag_set(root, settag);
        *first_indexp = index;
 
        return tagged;
index 4693f79..a16be19 100644 (file)
@@ -315,6 +315,7 @@ void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data)
 
        rb_augment_path(node, func, data);
 }
+EXPORT_SYMBOL(rb_augment_insert);
 
 /*
  * before removing the node, find the deepest node on the rebalance path
@@ -340,6 +341,7 @@ struct rb_node *rb_augment_erase_begin(struct rb_node *node)
 
        return deepest;
 }
+EXPORT_SYMBOL(rb_augment_erase_begin);
 
 /*
  * after removal, update the tree to account for the removed entry
@@ -350,6 +352,7 @@ void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data)
        if (node)
                rb_augment_path(node, func, data);
 }
+EXPORT_SYMBOL(rb_augment_erase_end);
 
 /*
  * This function returns the first node (in sort order) of the tree.
index c47bbe1..93ca08b 100644 (file)
@@ -686,8 +686,10 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
        /*
         * Ensure that the address returned is DMA'ble
         */
-       if (!dma_capable(dev, dev_addr, size))
-               panic("map_single: bounce buffer is not DMA'ble");
+       if (!dma_capable(dev, dev_addr, size)) {
+               swiotlb_tbl_unmap_single(dev, map, size, dir);
+               dev_addr = swiotlb_virt_to_bus(dev, io_tlb_overflow_buffer);
+       }
 
        return dev_addr;
 }
index d608331..e0cc014 100644 (file)
@@ -13,7 +13,7 @@
  *
  * INTRODUCTION
  *
- *   The textsearch infrastructure provides text searching facitilies for
+ *   The textsearch infrastructure provides text searching facilities for
  *   both linear and non-linear data. Individual search algorithms are
  *   implemented in modules and chosen by the user.
  *
@@ -43,7 +43,7 @@
  *       to the algorithm to store persistent variables.
  *   (4) Core eventually resets the search offset and forwards the find()
  *       request to the algorithm.
- *   (5) Algorithm calls get_next_block() provided by the user continously
+ *   (5) Algorithm calls get_next_block() provided by the user continuously
  *       to fetch the data to be searched in block by block.
  *   (6) Algorithm invokes finish() after the last call to get_next_block
  *       to clean up any leftovers from get_next_block. (Optional)
  *   the pattern to look for and flags. As a flag, you can set TS_IGNORECASE
  *   to perform case insensitive matching. But it might slow down
  *   performance of algorithm, so you should use it at own your risk.
- *   The returned configuration may then be used for an arbitary
+ *   The returned configuration may then be used for an arbitrary
  *   amount of times and even in parallel as long as a separate struct
  *   ts_state variable is provided to every instance.
  *
  *   The actual search is performed by either calling textsearch_find_-
  *   continuous() for linear data or by providing an own get_next_block()
  *   implementation and calling textsearch_find(). Both functions return
- *   the position of the first occurrence of the patern or UINT_MAX if
- *   no match was found. Subsequent occurences can be found by calling
+ *   the position of the first occurrence of the pattern or UINT_MAX if
+ *   no match was found. Subsequent occurrences can be found by calling
  *   textsearch_next() regardless of the linearity of the data.
  *
  *   Once you're done using a configuration it must be given back via
index e3b6e18..60a6088 100644 (file)
@@ -7,37 +7,37 @@ config XZ_DEC
          CRC32 is supported. See Documentation/xz.txt for more information.
 
 config XZ_DEC_X86
-       bool "x86 BCJ filter decoder" if EMBEDDED
+       bool "x86 BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
 
 config XZ_DEC_POWERPC
-       bool "PowerPC BCJ filter decoder" if EMBEDDED
+       bool "PowerPC BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
 
 config XZ_DEC_IA64
-       bool "IA-64 BCJ filter decoder" if EMBEDDED
+       bool "IA-64 BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
 
 config XZ_DEC_ARM
-       bool "ARM BCJ filter decoder" if EMBEDDED
+       bool "ARM BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
 
 config XZ_DEC_ARMTHUMB
-       bool "ARM-Thumb BCJ filter decoder" if EMBEDDED
+       bool "ARM-Thumb BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
 
 config XZ_DEC_SPARC
-       bool "SPARC BCJ filter decoder" if EMBEDDED
+       bool "SPARC BCJ filter decoder" if EXPERT
        default y
        depends on XZ_DEC
        select XZ_DEC_BCJ
index 3ad483b..e9c0c61 100644 (file)
@@ -179,7 +179,7 @@ config SPLIT_PTLOCK_CPUS
 config COMPACTION
        bool "Allow for memory compaction"
        select MIGRATION
-       depends on EXPERIMENTAL && HUGETLB_PAGE && MMU
+       depends on MMU
        help
          Allows the compaction of memory for the allocation of huge pages.
 
index 6d592a0..8be430b 100644 (file)
@@ -406,6 +406,10 @@ static int compact_finished(struct zone *zone,
        if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
                return COMPACT_CONTINUE;
 
+       /*
+        * order == -1 is expected when compacting via
+        * /proc/sys/vm/compact_memory
+        */
        if (cc->order == -1)
                return COMPACT_CONTINUE;
 
@@ -454,6 +458,13 @@ unsigned long compaction_suitable(struct zone *zone, int order)
                return COMPACT_SKIPPED;
 
        /*
+        * order == -1 is expected when compacting via
+        * /proc/sys/vm/compact_memory
+        */
+       if (order == -1)
+               return COMPACT_CONTINUE;
+
+       /*
         * fragmentation index determines if allocation failures are due to
         * low memory or external fragmentation
         *
index 004c9c2..dbe99a5 100644 (file)
@@ -650,10 +650,10 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag)
 
 static inline struct page *alloc_hugepage_vma(int defrag,
                                              struct vm_area_struct *vma,
-                                             unsigned long haddr)
+                                             unsigned long haddr, int nd)
 {
        return alloc_pages_vma(alloc_hugepage_gfpmask(defrag),
-                              HPAGE_PMD_ORDER, vma, haddr);
+                              HPAGE_PMD_ORDER, vma, haddr, nd);
 }
 
 #ifndef CONFIG_NUMA
@@ -678,7 +678,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                if (unlikely(khugepaged_enter(vma)))
                        return VM_FAULT_OOM;
                page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                         vma, haddr);
+                                         vma, haddr, numa_node_id());
                if (unlikely(!page))
                        goto out;
                if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
@@ -799,8 +799,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
        }
 
        for (i = 0; i < HPAGE_PMD_NR; i++) {
-               pages[i] = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
-                                         vma, address);
+               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE,
+                                              vma, address, page_to_nid(page));
                if (unlikely(!pages[i] ||
                             mem_cgroup_newpage_charge(pages[i], mm,
                                                       GFP_KERNEL))) {
@@ -902,7 +902,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (transparent_hugepage_enabled(vma) &&
            !transparent_hugepage_debug_cow())
                new_page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                             vma, haddr);
+                                             vma, haddr, numa_node_id());
        else
                new_page = NULL;
 
@@ -1162,7 +1162,12 @@ static void __split_huge_page_refcount(struct page *page)
                /* after clearing PageTail the gup refcount can be released */
                smp_mb();
 
-               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
+               /*
+                * retain hwpoison flag of the poisoned tail page:
+                *   fix for the unsuitable process killed on Guest Machine(KVM)
+                *   by the memory-failure.
+                */
+               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
                page_tail->flags |= (page->flags &
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
@@ -1203,6 +1208,8 @@ static void __split_huge_page_refcount(struct page *page)
                BUG_ON(!PageDirty(page_tail));
                BUG_ON(!PageSwapBacked(page_tail));
 
+               mem_cgroup_split_huge_fixup(page, page_tail);
+
                lru_add_page_tail(zone, page, page_tail);
        }
 
@@ -1738,7 +1745,8 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
 static void collapse_huge_page(struct mm_struct *mm,
                               unsigned long address,
                               struct page **hpage,
-                              struct vm_area_struct *vma)
+                              struct vm_area_struct *vma,
+                              int node)
 {
        pgd_t *pgd;
        pud_t *pud;
@@ -1766,7 +1774,8 @@ static void collapse_huge_page(struct mm_struct *mm,
         * mmap_sem in read mode is good idea also to allow greater
         * scalability.
         */
-       new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address);
+       new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address,
+                                     node);
        if (unlikely(!new_page)) {
                up_read(&mm->mmap_sem);
                *hpage = ERR_PTR(-ENOMEM);
@@ -1804,6 +1813,8 @@ static void collapse_huge_page(struct mm_struct *mm,
        /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
        if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
                goto out;
+       if (is_vma_temporary_stack(vma))
+               goto out;
        VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
 
        pgd = pgd_offset(mm, address);
@@ -1837,15 +1848,14 @@ static void collapse_huge_page(struct mm_struct *mm,
        spin_lock(ptl);
        isolated = __collapse_huge_page_isolate(vma, address, pte);
        spin_unlock(ptl);
-       pte_unmap(pte);
 
        if (unlikely(!isolated)) {
+               pte_unmap(pte);
                spin_lock(&mm->page_table_lock);
                BUG_ON(!pmd_none(*pmd));
                set_pmd_at(mm, address, pmd, _pmd);
                spin_unlock(&mm->page_table_lock);
                anon_vma_unlock(vma->anon_vma);
-               mem_cgroup_uncharge_page(new_page);
                goto out;
        }
 
@@ -1856,6 +1866,7 @@ static void collapse_huge_page(struct mm_struct *mm,
        anon_vma_unlock(vma->anon_vma);
 
        __collapse_huge_page_copy(pte, new_page, vma, address, ptl);
+       pte_unmap(pte);
        __SetPageUptodate(new_page);
        pgtable = pmd_pgtable(_pmd);
        VM_BUG_ON(page_count(pgtable) != 1);
@@ -1890,6 +1901,7 @@ out_up_write:
        return;
 
 out:
+       mem_cgroup_uncharge_page(new_page);
 #ifdef CONFIG_NUMA
        put_page(new_page);
 #endif
@@ -1909,6 +1921,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
        struct page *page;
        unsigned long _address;
        spinlock_t *ptl;
+       int node = -1;
 
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 
@@ -1939,6 +1952,13 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
                page = vm_normal_page(vma, _address, pteval);
                if (unlikely(!page))
                        goto out_unmap;
+               /*
+                * Chose the node of the first page. This could
+                * be more sophisticated and look at more pages,
+                * but isn't for now.
+                */
+               if (node == -1)
+                       node = page_to_nid(page);
                VM_BUG_ON(PageCompound(page));
                if (!PageLRU(page) || PageLocked(page) || !PageAnon(page))
                        goto out_unmap;
@@ -1955,7 +1975,7 @@ out_unmap:
        pte_unmap_unlock(pte, ptl);
        if (ret)
                /* collapse_huge_page will return with the mmap_sem released */
-               collapse_huge_page(mm, address, hpage, vma);
+               collapse_huge_page(mm, address, hpage, vma, node);
 out:
        return ret;
 }
@@ -2024,32 +2044,27 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
                if ((!(vma->vm_flags & VM_HUGEPAGE) &&
                     !khugepaged_always()) ||
                    (vma->vm_flags & VM_NOHUGEPAGE)) {
+               skip:
                        progress++;
                        continue;
                }
-
                /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
-               if (!vma->anon_vma || vma->vm_ops || vma->vm_file) {
-                       khugepaged_scan.address = vma->vm_end;
-                       progress++;
-                       continue;
-               }
+               if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
+                       goto skip;
+               if (is_vma_temporary_stack(vma))
+                       goto skip;
+
                VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
 
                hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
                hend = vma->vm_end & HPAGE_PMD_MASK;
-               if (hstart >= hend) {
-                       progress++;
-                       continue;
-               }
+               if (hstart >= hend)
+                       goto skip;
+               if (khugepaged_scan.address > hend)
+                       goto skip;
                if (khugepaged_scan.address < hstart)
                        khugepaged_scan.address = hstart;
-               if (khugepaged_scan.address > hend) {
-                       khugepaged_scan.address = hend + HPAGE_PMD_SIZE;
-                       progress++;
-                       continue;
-               }
-               BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
+               VM_BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
 
                while (khugepaged_scan.address < hend) {
                        int ret;
@@ -2078,7 +2093,7 @@ breakouterloop:
 breakouterloop_mmap_sem:
 
        spin_lock(&khugepaged_mm_lock);
-       BUG_ON(khugepaged_scan.mm_slot != mm_slot);
+       VM_BUG_ON(khugepaged_scan.mm_slot != mm_slot);
        /*
         * Release the current mm_slot if this mm is about to die, or
         * if we scanned all vmas of this mm.
@@ -2233,9 +2248,9 @@ static int khugepaged(void *none)
 
        for (;;) {
                mutex_unlock(&khugepaged_mutex);
-               BUG_ON(khugepaged_thread != current);
+               VM_BUG_ON(khugepaged_thread != current);
                khugepaged_loop();
-               BUG_ON(khugepaged_thread != current);
+               VM_BUG_ON(khugepaged_thread != current);
 
                mutex_lock(&khugepaged_mutex);
                if (!khugepaged_enabled())
index 177a516..ff0d977 100644 (file)
@@ -75,13 +75,11 @@ static int __init kmemleak_test_init(void)
         * after the module is removed.
         */
        for (i = 0; i < 10; i++) {
-               elem = kmalloc(sizeof(*elem), GFP_KERNEL);
-               pr_info("kmemleak: kmalloc(sizeof(*elem)) = %p\n", elem);
+               elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+               pr_info("kmemleak: kzalloc(sizeof(*elem)) = %p\n", elem);
                if (!elem)
                        return -ENOMEM;
-               memset(elem, 0, sizeof(*elem));
                INIT_LIST_HEAD(&elem->list);
-
                list_add_tail(&elem->list, &test_list);
        }
 
index bd9bc21..84225f3 100644 (file)
 #define BYTES_PER_POINTER      sizeof(void *)
 
 /* GFP bitmask for kmemleak internal allocations */
-#define GFP_KMEMLEAK_MASK      (GFP_KERNEL | GFP_ATOMIC)
+#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \
+                                __GFP_NORETRY | __GFP_NOMEMALLOC | \
+                                __GFP_NOWARN)
 
 /* scanning area inside a memory block */
 struct kmemleak_scan_area {
@@ -511,9 +513,10 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
        struct kmemleak_object *object;
        struct prio_tree_node *node;
 
-       object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK);
+       object = kmem_cache_alloc(object_cache, gfp_kmemleak_mask(gfp));
        if (!object) {
-               kmemleak_stop("Cannot allocate a kmemleak_object structure\n");
+               pr_warning("Cannot allocate a kmemleak_object structure\n");
+               kmemleak_disable();
                return NULL;
        }
 
@@ -734,9 +737,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
                return;
        }
 
-       area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK);
+       area = kmem_cache_alloc(scan_area_cache, gfp_kmemleak_mask(gfp));
        if (!area) {
-               kmemleak_warn("Cannot allocate a scan area\n");
+               pr_warning("Cannot allocate a scan area\n");
                goto out;
        }
 
index 400dc62..4618fda 100644 (file)
@@ -137,8 +137,6 @@ static phys_addr_t __init_memblock memblock_find_base(phys_addr_t size,
 
        BUG_ON(0 == size);
 
-       size = memblock_align_up(size, align);
-
        /* Pump up max_addr */
        if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
                end = memblock.current_limit;
@@ -683,13 +681,13 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
 
 int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
 {
-       int idx = memblock_search(&memblock.reserved, base);
+       int idx = memblock_search(&memblock.memory, base);
 
        if (idx == -1)
                return 0;
-       return memblock.reserved.regions[idx].base <= base &&
-               (memblock.reserved.regions[idx].base +
-                memblock.reserved.regions[idx].size) >= (base + size);
+       return memblock.memory.regions[idx].base <= base &&
+               (memblock.memory.regions[idx].base +
+                memblock.memory.regions[idx].size) >= (base + size);
 }
 
 int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
index 8ab8410..da53a25 100644 (file)
@@ -600,23 +600,24 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
 }
 
 static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
-                                        struct page_cgroup *pc,
-                                        bool charge)
+                                        bool file, int nr_pages)
 {
-       int val = (charge) ? 1 : -1;
-
        preempt_disable();
 
-       if (PageCgroupCache(pc))
-               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_CACHE], val);
+       if (file)
+               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_CACHE], nr_pages);
        else
-               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_RSS], val);
+               __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_RSS], nr_pages);
 
-       if (charge)
+       /* pagein of a big page is an event. So, ignore page size */
+       if (nr_pages > 0)
                __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
-       else
+       else {
                __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
-       __this_cpu_inc(mem->stat->count[MEM_CGROUP_EVENTS]);
+               nr_pages = -nr_pages; /* for event */
+       }
+
+       __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
 
        preempt_enable();
 }
@@ -815,7 +816,8 @@ void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru)
         * removed from global LRU.
         */
        mz = page_cgroup_zoneinfo(pc);
-       MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+       /* huge page split is done under lru_lock. so, we have no races. */
+       MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
        if (mem_cgroup_is_root(pc->mem_cgroup))
                return;
        VM_BUG_ON(list_empty(&pc->lru));
@@ -836,13 +838,12 @@ void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
                return;
 
        pc = lookup_page_cgroup(page);
-       /*
-        * Used bit is set without atomic ops but after smp_wmb().
-        * For making pc->mem_cgroup visible, insert smp_rmb() here.
-        */
-       smp_rmb();
        /* unused or root page is not rotated. */
-       if (!PageCgroupUsed(pc) || mem_cgroup_is_root(pc->mem_cgroup))
+       if (!PageCgroupUsed(pc))
+               return;
+       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+       smp_rmb();
+       if (mem_cgroup_is_root(pc->mem_cgroup))
                return;
        mz = page_cgroup_zoneinfo(pc);
        list_move(&pc->lru, &mz->lists[lru]);
@@ -857,16 +858,13 @@ void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
                return;
        pc = lookup_page_cgroup(page);
        VM_BUG_ON(PageCgroupAcctLRU(pc));
-       /*
-        * Used bit is set without atomic ops but after smp_wmb().
-        * For making pc->mem_cgroup visible, insert smp_rmb() here.
-        */
-       smp_rmb();
        if (!PageCgroupUsed(pc))
                return;
-
+       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+       smp_rmb();
        mz = page_cgroup_zoneinfo(pc);
-       MEM_CGROUP_ZSTAT(mz, lru) += 1;
+       /* huge page split is done under lru_lock. so, we have no races. */
+       MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
        SetPageCgroupAcctLRU(pc);
        if (mem_cgroup_is_root(pc->mem_cgroup))
                return;
@@ -1030,14 +1028,10 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
                return NULL;
 
        pc = lookup_page_cgroup(page);
-       /*
-        * Used bit is set without atomic ops but after smp_wmb().
-        * For making pc->mem_cgroup visible, insert smp_rmb() here.
-        */
-       smp_rmb();
        if (!PageCgroupUsed(pc))
                return NULL;
-
+       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+       smp_rmb();
        mz = page_cgroup_zoneinfo(pc);
        if (!mz)
                return NULL;
@@ -1119,6 +1113,23 @@ static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
        return false;
 }
 
+/**
+ * mem_cgroup_check_margin - check if the memory cgroup allows charging
+ * @mem: memory cgroup to check
+ * @bytes: the number of bytes the caller intends to charge
+ *
+ * Returns a boolean value on whether @mem can be charged @bytes or
+ * whether this would exceed the limit.
+ */
+static bool mem_cgroup_check_margin(struct mem_cgroup *mem, unsigned long bytes)
+{
+       if (!res_counter_check_margin(&mem->res, bytes))
+               return false;
+       if (do_swap_account && !res_counter_check_margin(&mem->memsw, bytes))
+               return false;
+       return true;
+}
+
 static unsigned int get_swappiness(struct mem_cgroup *memcg)
 {
        struct cgroup *cgrp = memcg->css.cgroup;
@@ -1615,7 +1626,7 @@ void mem_cgroup_update_page_stat(struct page *page,
        if (unlikely(!mem || !PageCgroupUsed(pc)))
                goto out;
        /* pc->mem_cgroup is unstable ? */
-       if (unlikely(mem_cgroup_stealed(mem))) {
+       if (unlikely(mem_cgroup_stealed(mem)) || PageTransHuge(page)) {
                /* take a lock against to access pc->mem_cgroup */
                move_lock_page_cgroup(pc, &flags);
                need_unlock = true;
@@ -1840,27 +1851,39 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
                if (likely(!ret))
                        return CHARGE_OK;
 
+               res_counter_uncharge(&mem->res, csize);
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, memsw);
                flags |= MEM_CGROUP_RECLAIM_NOSWAP;
        } else
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, res);
-
-       if (csize > PAGE_SIZE) /* change csize and retry */
+       /*
+        * csize can be either a huge page (HPAGE_SIZE), a batch of
+        * regular pages (CHARGE_SIZE), or a single regular page
+        * (PAGE_SIZE).
+        *
+        * Never reclaim on behalf of optional batching, retry with a
+        * single page instead.
+        */
+       if (csize == CHARGE_SIZE)
                return CHARGE_RETRY;
 
        if (!(gfp_mask & __GFP_WAIT))
                return CHARGE_WOULDBLOCK;
 
        ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
-                                       gfp_mask, flags);
+                                             gfp_mask, flags);
+       if (mem_cgroup_check_margin(mem_over_limit, csize))
+               return CHARGE_RETRY;
        /*
-        * try_to_free_mem_cgroup_pages() might not give us a full
-        * picture of reclaim. Some pages are reclaimed and might be
-        * moved to swap cache or just unmapped from the cgroup.
-        * Check the limit again to see if the reclaim reduced the
-        * current usage of the cgroup before giving up
+        * Even though the limit is exceeded at this point, reclaim
+        * may have been able to free some pages.  Retry the charge
+        * before killing the task.
+        *
+        * Only for regular pages, though: huge pages are rather
+        * unlikely to succeed so close to the limit, and we fall back
+        * to regular pages anyway in case of failure.
         */
-       if (ret || mem_cgroup_check_under_limit(mem_over_limit))
+       if (csize == PAGE_SIZE && ret)
                return CHARGE_RETRY;
 
        /*
@@ -2084,14 +2107,27 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
        return mem;
 }
 
-/*
- * commit a charge got by __mem_cgroup_try_charge() and makes page_cgroup to be
- * USED state. If already USED, uncharge and return.
- */
-static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem,
-                                        struct page_cgroup *pc,
-                                        enum charge_type ctype)
+static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
+                                      struct page_cgroup *pc,
+                                      enum charge_type ctype,
+                                      int page_size)
 {
+       int nr_pages = page_size >> PAGE_SHIFT;
+
+       /* try_charge() can return NULL to *memcg, taking care of it. */
+       if (!mem)
+               return;
+
+       lock_page_cgroup(pc);
+       if (unlikely(PageCgroupUsed(pc))) {
+               unlock_page_cgroup(pc);
+               mem_cgroup_cancel_charge(mem, page_size);
+               return;
+       }
+       /*
+        * we don't need page_cgroup_lock about tail pages, becase they are not
+        * accessed by any other context at this point.
+        */
        pc->mem_cgroup = mem;
        /*
         * We access a page_cgroup asynchronously without lock_page_cgroup().
@@ -2115,43 +2151,57 @@ static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem,
                break;
        }
 
-       mem_cgroup_charge_statistics(mem, pc, true);
+       mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), nr_pages);
+       unlock_page_cgroup(pc);
+       /*
+        * "charge_statistics" updated event counter. Then, check it.
+        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
+        * if they exceeds softlimit.
+        */
+       memcg_check_events(mem, pc->page);
 }
 
-static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
-                                      struct page_cgroup *pc,
-                                      enum charge_type ctype,
-                                      int page_size)
-{
-       int i;
-       int count = page_size >> PAGE_SHIFT;
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
-       /* try_charge() can return NULL to *memcg, taking care of it. */
-       if (!mem)
-               return;
+#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\
+                       (1 << PCG_ACCT_LRU) | (1 << PCG_MIGRATION))
+/*
+ * Because tail pages are not marked as "used", set it. We're under
+ * zone->lru_lock, 'splitting on pmd' and compund_lock.
+ */
+void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
+{
+       struct page_cgroup *head_pc = lookup_page_cgroup(head);
+       struct page_cgroup *tail_pc = lookup_page_cgroup(tail);
+       unsigned long flags;
 
-       lock_page_cgroup(pc);
-       if (unlikely(PageCgroupUsed(pc))) {
-               unlock_page_cgroup(pc);
-               mem_cgroup_cancel_charge(mem, page_size);
+       if (mem_cgroup_disabled())
                return;
-       }
-
        /*
-        * we don't need page_cgroup_lock about tail pages, becase they are not
-        * accessed by any other context at this point.
+        * We have no races with charge/uncharge but will have races with
+        * page state accounting.
         */
-       for (i = 0; i < count; i++)
-               ____mem_cgroup_commit_charge(mem, pc + i, ctype);
+       move_lock_page_cgroup(head_pc, &flags);
 
-       unlock_page_cgroup(pc);
-       /*
-        * "charge_statistics" updated event counter. Then, check it.
-        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
-        * if they exceeds softlimit.
-        */
-       memcg_check_events(mem, pc->page);
+       tail_pc->mem_cgroup = head_pc->mem_cgroup;
+       smp_wmb(); /* see __commit_charge() */
+       if (PageCgroupAcctLRU(head_pc)) {
+               enum lru_list lru;
+               struct mem_cgroup_per_zone *mz;
+
+               /*
+                * LRU flags cannot be copied because we need to add tail
+                *.page to LRU by generic call and our hook will be called.
+                * We hold lru_lock, then, reduce counter directly.
+                */
+               lru = page_lru(head);
+               mz = page_cgroup_zoneinfo(head_pc);
+               MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+       }
+       tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
+       move_unlock_page_cgroup(head_pc, &flags);
 }
+#endif
 
 /**
  * __mem_cgroup_move_account - move account of the page
@@ -2171,8 +2221,11 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
  */
 
 static void __mem_cgroup_move_account(struct page_cgroup *pc,
-       struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
+       struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge,
+       int charge_size)
 {
+       int nr_pages = charge_size >> PAGE_SHIFT;
+
        VM_BUG_ON(from == to);
        VM_BUG_ON(PageLRU(pc->page));
        VM_BUG_ON(!page_is_cgroup_locked(pc));
@@ -2186,14 +2239,14 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
                __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
                preempt_enable();
        }
-       mem_cgroup_charge_statistics(from, pc, false);
+       mem_cgroup_charge_statistics(from, PageCgroupCache(pc), -nr_pages);
        if (uncharge)
                /* This is not "cancel", but cancel_charge does all we need. */
-               mem_cgroup_cancel_charge(from, PAGE_SIZE);
+               mem_cgroup_cancel_charge(from, charge_size);
 
        /* caller should have done css_get */
        pc->mem_cgroup = to;
-       mem_cgroup_charge_statistics(to, pc, true);
+       mem_cgroup_charge_statistics(to, PageCgroupCache(pc), nr_pages);
        /*
         * We charges against "to" which may not have any tasks. Then, "to"
         * can be under rmdir(). But in current implementation, caller of
@@ -2208,15 +2261,24 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
  * __mem_cgroup_move_account()
  */
 static int mem_cgroup_move_account(struct page_cgroup *pc,
-               struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
+               struct mem_cgroup *from, struct mem_cgroup *to,
+               bool uncharge, int charge_size)
 {
        int ret = -EINVAL;
        unsigned long flags;
+       /*
+        * The page is isolated from LRU. So, collapse function
+        * will not handle this page. But page splitting can happen.
+        * Do this check under compound_page_lock(). The caller should
+        * hold it.
+        */
+       if ((charge_size > PAGE_SIZE) && !PageTransHuge(pc->page))
+               return -EBUSY;
 
        lock_page_cgroup(pc);
        if (PageCgroupUsed(pc) && pc->mem_cgroup == from) {
                move_lock_page_cgroup(pc, &flags);
-               __mem_cgroup_move_account(pc, from, to, uncharge);
+               __mem_cgroup_move_account(pc, from, to, uncharge, charge_size);
                move_unlock_page_cgroup(pc, &flags);
                ret = 0;
        }
@@ -2241,6 +2303,8 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
        struct cgroup *cg = child->css.cgroup;
        struct cgroup *pcg = cg->parent;
        struct mem_cgroup *parent;
+       int page_size = PAGE_SIZE;
+       unsigned long flags;
        int ret;
 
        /* Is ROOT ? */
@@ -2253,15 +2317,24 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
        if (isolate_lru_page(page))
                goto put;
 
+       if (PageTransHuge(page))
+               page_size = HPAGE_SIZE;
+
        parent = mem_cgroup_from_cont(pcg);
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false,
-                                     PAGE_SIZE);
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask,
+                               &parent, false, page_size);
        if (ret || !parent)
                goto put_back;
 
-       ret = mem_cgroup_move_account(pc, child, parent, true);
+       if (page_size > PAGE_SIZE)
+               flags = compound_lock_irqsave(page);
+
+       ret = mem_cgroup_move_account(pc, child, parent, true, page_size);
        if (ret)
-               mem_cgroup_cancel_charge(parent, PAGE_SIZE);
+               mem_cgroup_cancel_charge(parent, page_size);
+
+       if (page_size > PAGE_SIZE)
+               compound_unlock_irqrestore(page, flags);
 put_back:
        putback_lru_page(page);
 put:
@@ -2280,13 +2353,19 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask, enum charge_type ctype)
 {
        struct mem_cgroup *mem = NULL;
+       int page_size = PAGE_SIZE;
        struct page_cgroup *pc;
+       bool oom = true;
        int ret;
-       int page_size = PAGE_SIZE;
 
        if (PageTransHuge(page)) {
                page_size <<= compound_order(page);
                VM_BUG_ON(!PageTransHuge(page));
+               /*
+                * Never OOM-kill a process for a huge page.  The
+                * fault handler will fall back to regular pages.
+                */
+               oom = false;
        }
 
        pc = lookup_page_cgroup(page);
@@ -2295,7 +2374,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                return 0;
        prefetchw(pc);
 
-       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true, page_size);
+       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, oom, page_size);
        if (ret || !mem)
                return ret;
 
@@ -2546,7 +2625,6 @@ direct_uncharge:
 static struct mem_cgroup *
 __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
 {
-       int i;
        int count;
        struct page_cgroup *pc;
        struct mem_cgroup *mem = NULL;
@@ -2596,8 +2674,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
                break;
        }
 
-       for (i = 0; i < count; i++)
-               mem_cgroup_charge_statistics(mem, pc + i, false);
+       mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -count);
 
        ClearPageCgroupUsed(pc);
        /*
@@ -4844,7 +4921,7 @@ retry:
                                goto put;
                        pc = lookup_page_cgroup(page);
                        if (!mem_cgroup_move_account(pc,
-                                               mc.from, mc.to, false)) {
+                                       mc.from, mc.to, false, PAGE_SIZE)) {
                                mc.precharge--;
                                /* we uncharge from mc.from later. */
                                mc.moved_charge++;
@@ -4983,9 +5060,9 @@ struct cgroup_subsys mem_cgroup_subsys = {
 static int __init enable_swap_account(char *s)
 {
        /* consider enabled if no parameter or 1 is given */
-       if (!s || !strcmp(s, "1"))
+       if (!(*s) || !strcmp(s, "=1"))
                really_do_swap_account = 1;
-       else if (!strcmp(s, "0"))
+       else if (!strcmp(s, "=0"))
                really_do_swap_account = 0;
        return 1;
 }
@@ -4993,7 +5070,8 @@ __setup("swapaccount", enable_swap_account);
 
 static int __init disable_swap_account(char *s)
 {
-       enable_swap_account("0");
+       printk_once("noswapaccount is deprecated and will be removed in 2.6.40. Use swapaccount=0 instead\n");
+       enable_swap_account("=0");
        return 1;
 }
 __setup("noswapaccount", disable_swap_account);
index 548fbd7..0207c2f 100644 (file)
@@ -233,8 +233,8 @@ void shake_page(struct page *p, int access)
        }
 
        /*
-        * Only all shrink_slab here (which would also
-        * shrink other caches) if access is not potentially fatal.
+        * Only call shrink_slab here (which would also shrink other caches) if
+        * access is not potentially fatal.
         */
        if (access) {
                int nr;
@@ -386,8 +386,6 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
        struct task_struct *tsk;
        struct anon_vma *av;
 
-       if (!PageHuge(page) && unlikely(split_huge_page(page)))
-               return;
        read_lock(&tasklist_lock);
        av = page_lock_anon_vma(page);
        if (av == NULL) /* Not actually mapped anymore */
@@ -856,6 +854,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        int ret;
        int kill = 1;
        struct page *hpage = compound_head(p);
+       struct page *ppage;
 
        if (PageReserved(p) || PageSlab(p))
                return SWAP_SUCCESS;
@@ -897,6 +896,44 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        }
 
        /*
+        * ppage: poisoned page
+        *   if p is regular page(4k page)
+        *        ppage == real poisoned page;
+        *   else p is hugetlb or THP, ppage == head page.
+        */
+       ppage = hpage;
+
+       if (PageTransHuge(hpage)) {
+               /*
+                * Verify that this isn't a hugetlbfs head page, the check for
+                * PageAnon is just for avoid tripping a split_huge_page
+                * internal debug check, as split_huge_page refuses to deal with
+                * anything that isn't an anon page. PageAnon can't go away fro
+                * under us because we hold a refcount on the hpage, without a
+                * refcount on the hpage. split_huge_page can't be safely called
+                * in the first place, having a refcount on the tail isn't
+                * enough * to be safe.
+                */
+               if (!PageHuge(hpage) && PageAnon(hpage)) {
+                       if (unlikely(split_huge_page(hpage))) {
+                               /*
+                                * FIXME: if splitting THP is failed, it is
+                                * better to stop the following operation rather
+                                * than causing panic by unmapping. System might
+                                * survive if the page is freed later.
+                                */
+                               printk(KERN_INFO
+                                       "MCE %#lx: failed to split THP\n", pfn);
+
+                               BUG_ON(!PageHWPoison(p));
+                               return SWAP_FAIL;
+                       }
+                       /* THP is split, so ppage should be the real poisoned page. */
+                       ppage = p;
+               }
+       }
+
+       /*
         * First collect all the processes that have the page
         * mapped in dirty form.  This has to be done before try_to_unmap,
         * because ttu takes the rmap data structures down.
@@ -905,12 +942,18 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * there's nothing that can be done.
         */
        if (kill)
-               collect_procs(hpage, &tokill);
+               collect_procs(ppage, &tokill);
+
+       if (hpage != ppage)
+               lock_page_nosync(ppage);
 
-       ret = try_to_unmap(hpage, ttu);
+       ret = try_to_unmap(ppage, ttu);
        if (ret != SWAP_SUCCESS)
                printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
-                               pfn, page_mapcount(hpage));
+                               pfn, page_mapcount(ppage));
+
+       if (hpage != ppage)
+               unlock_page(ppage);
 
        /*
         * Now that the dirty bit has been propagated to the
@@ -921,7 +964,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * use a more force-full uncatchable kill to prevent
         * any accesses to the poisoned memory.
         */
-       kill_procs_ao(&tokill, !!PageDirty(hpage), trapno,
+       kill_procs_ao(&tokill, !!PageDirty(ppage), trapno,
                      ret != SWAP_SUCCESS, p, pfn);
 
        return ret;
@@ -1022,19 +1065,22 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * The check (unnecessarily) ignores LRU pages being isolated and
         * walked by the page reclaim code, however that's not a big loss.
         */
-       if (!PageLRU(p) && !PageHuge(p))
-               shake_page(p, 0);
-       if (!PageLRU(p) && !PageHuge(p)) {
-               /*
-                * shake_page could have turned it free.
-                */
-               if (is_free_buddy_page(p)) {
-                       action_result(pfn, "free buddy, 2nd try", DELAYED);
-                       return 0;
+       if (!PageHuge(p) && !PageTransCompound(p)) {
+               if (!PageLRU(p))
+                       shake_page(p, 0);
+               if (!PageLRU(p)) {
+                       /*
+                        * shake_page could have turned it free.
+                        */
+                       if (is_free_buddy_page(p)) {
+                               action_result(pfn, "free buddy, 2nd try",
+                                               DELAYED);
+                               return 0;
+                       }
+                       action_result(pfn, "non LRU", IGNORED);
+                       put_page(p);
+                       return -EBUSY;
                }
-               action_result(pfn, "non LRU", IGNORED);
-               put_page(p);
-               return -EBUSY;
        }
 
        /*
@@ -1064,7 +1110,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * For error on the tail page, we should set PG_hwpoison
         * on the head page to show that the hugepage is hwpoisoned
         */
-       if (PageTail(p) && TestSetPageHWPoison(hpage)) {
+       if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) {
                action_result(pfn, "hugepage already hardware poisoned",
                                IGNORED);
                unlock_page(hpage);
@@ -1295,7 +1341,10 @@ static int soft_offline_huge_page(struct page *page, int flags)
        ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0,
                                true);
        if (ret) {
-               putback_lru_pages(&pagelist);
+               struct page *page1, *page2;
+               list_for_each_entry_safe(page1, page2, &pagelist, lru)
+                       put_page(page1);
+
                pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
                         pfn, ret, page->flags);
                if (ret > 0)
@@ -1419,6 +1468,7 @@ int soft_offline_page(struct page *page, int flags)
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
                                                                0, true);
                if (ret) {
+                       putback_lru_pages(&pagelist);
                        pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
                                pfn, ret, page->flags);
                        if (ret > 0)
index 31250fa..5823698 100644 (file)
@@ -2219,7 +2219,6 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                                         &ptl);
                        if (!pte_same(*page_table, orig_pte)) {
                                unlock_page(old_page);
-                               page_cache_release(old_page);
                                goto unlock;
                        }
                        page_cache_release(old_page);
@@ -2289,7 +2288,6 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                                         &ptl);
                        if (!pte_same(*page_table, orig_pte)) {
                                unlock_page(old_page);
-                               page_cache_release(old_page);
                                goto unlock;
                        }
 
@@ -2367,16 +2365,6 @@ gotten:
        }
        __SetPageUptodate(new_page);
 
-       /*
-        * Don't let another task, with possibly unlocked vma,
-        * keep the mlocked page.
-        */
-       if ((vma->vm_flags & VM_LOCKED) && old_page) {
-               lock_page(old_page);    /* for LRU manipulation */
-               clear_page_mlock(old_page);
-               unlock_page(old_page);
-       }
-
        if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))
                goto oom_free_new;
 
@@ -2444,10 +2432,20 @@ gotten:
 
        if (new_page)
                page_cache_release(new_page);
-       if (old_page)
-               page_cache_release(old_page);
 unlock:
        pte_unmap_unlock(page_table, ptl);
+       if (old_page) {
+               /*
+                * Don't let another task, with possibly unlocked vma,
+                * keep the mlocked page.
+                */
+               if ((ret & VM_FAULT_WRITE) && (vma->vm_flags & VM_LOCKED)) {
+                       lock_page(old_page);    /* LRU manipulation */
+                       munlock_vma_page(old_page);
+                       unlock_page(old_page);
+               }
+               page_cache_release(old_page);
+       }
        return ret;
 oom_free_new:
        page_cache_release(new_page);
@@ -2650,6 +2648,7 @@ void unmap_mapping_range(struct address_space *mapping,
                details.last_index = ULONG_MAX;
        details.i_mmap_lock = &mapping->i_mmap_lock;
 
+       mutex_lock(&mapping->unmap_mutex);
        spin_lock(&mapping->i_mmap_lock);
 
        /* Protect against endless unmapping loops */
@@ -2666,6 +2665,7 @@ void unmap_mapping_range(struct address_space *mapping,
        if (unlikely(!list_empty(&mapping->i_mmap_nonlinear)))
                unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details);
        spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->unmap_mutex);
 }
 EXPORT_SYMBOL(unmap_mapping_range);
 
@@ -3053,12 +3053,6 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                                goto out;
                        }
                        charged = 1;
-                       /*
-                        * Don't let another task, with possibly unlocked vma,
-                        * keep the mlocked page.
-                        */
-                       if (vma->vm_flags & VM_LOCKED)
-                               clear_page_mlock(vmf.page);
                        copy_user_highpage(page, vmf.page, address, vma);
                        __SetPageUptodate(page);
                } else {
index 368fc9d..b53ec99 100644 (file)
@@ -1524,10 +1524,9 @@ static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy)
 }
 
 /* Return a zonelist indicated by gfp for node representing a mempolicy */
-static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy)
+static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy,
+       int nd)
 {
-       int nd = numa_node_id();
-
        switch (policy->mode) {
        case MPOL_PREFERRED:
                if (!(policy->flags & MPOL_F_LOCAL))
@@ -1679,7 +1678,7 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
                zl = node_zonelist(interleave_nid(*mpol, vma, addr,
                                huge_page_shift(hstate_vma(vma))), gfp_flags);
        } else {
-               zl = policy_zonelist(gfp_flags, *mpol);
+               zl = policy_zonelist(gfp_flags, *mpol, numa_node_id());
                if ((*mpol)->mode == MPOL_BIND)
                        *nodemask = &(*mpol)->v.nodes;
        }
@@ -1820,7 +1819,7 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
  */
 struct page *
 alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
-               unsigned long addr)
+               unsigned long addr, int node)
 {
        struct mempolicy *pol = get_vma_policy(current, vma, addr);
        struct zonelist *zl;
@@ -1830,13 +1829,13 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
        if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
                unsigned nid;
 
-               nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
+               nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
                mpol_cond_put(pol);
                page = alloc_page_interleave(gfp, order, nid);
                put_mems_allowed();
                return page;
        }
-       zl = policy_zonelist(gfp, pol);
+       zl = policy_zonelist(gfp, pol, node);
        if (unlikely(mpol_needs_cond_ref(pol))) {
                /*
                 * slow path: ref counted shared policy
@@ -1892,7 +1891,8 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
                page = alloc_page_interleave(gfp, order, interleave_nodes(pol));
        else
                page = __alloc_pages_nodemask(gfp, order,
-                       policy_zonelist(gfp, pol), policy_nodemask(gfp, pol));
+                               policy_zonelist(gfp, pol, numa_node_id()),
+                               policy_nodemask(gfp, pol));
        put_mems_allowed();
        return page;
 }
index 46fe8cc..352de55 100644 (file)
@@ -772,6 +772,7 @@ uncharge:
 unlock:
        unlock_page(page);
 
+move_newpage:
        if (rc != -EAGAIN) {
                /*
                 * A page that has been migrated has all references
@@ -785,8 +786,6 @@ unlock:
                putback_lru_page(page);
        }
 
-move_newpage:
-
        /*
         * Move the new page to the LRU. If migration was not successful
         * then this will free the page.
@@ -888,7 +887,7 @@ out:
  * are movable anymore because to has become empty
  * or no retryable pages exist anymore.
  * Caller should call putback_lru_pages to return pages to the LRU
- * or free list.
+ * or free list only if ret != 0.
  *
  * Return: Number of pages not migrated or error code.
  */
@@ -981,10 +980,6 @@ int migrate_huge_pages(struct list_head *from,
        }
        rc = 0;
 out:
-
-       list_for_each_entry_safe(page, page2, from, lru)
-               put_page(page);
-
        if (rc)
                return rc;
 
@@ -1292,14 +1287,14 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
                return -EPERM;
 
        /* Find the mm_struct */
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
        task = pid ? find_task_by_vpid(pid) : current;
        if (!task) {
-               read_unlock(&tasklist_lock);
+               rcu_read_unlock();
                return -ESRCH;
        }
        mm = get_task_mm(task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        if (!mm)
                return -EINVAL;
index 13e81ee..c3924c7 100644 (file)
@@ -178,6 +178,13 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
                gup_flags |= FOLL_WRITE;
 
+       /*
+        * We want mlock to succeed for regions that have any permissions
+        * other than PROT_NONE.
+        */
+       if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
+               gup_flags |= FOLL_FORCE;
+
        if (vma->vm_flags & VM_LOCKED)
                gup_flags |= FOLL_MLOCK;
 
index 9925b63..1de98d4 100644 (file)
@@ -94,9 +94,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                 */
                mapping = vma->vm_file->f_mapping;
                spin_lock(&mapping->i_mmap_lock);
-               if (new_vma->vm_truncate_count &&
-                   new_vma->vm_truncate_count != vma->vm_truncate_count)
-                       new_vma->vm_truncate_count = 0;
+               new_vma->vm_truncate_count = 0;
        }
 
        /*
index 90c1439..cdef1d4 100644 (file)
@@ -1088,8 +1088,10 @@ static void drain_pages(unsigned int cpu)
                pset = per_cpu_ptr(zone->pageset, cpu);
 
                pcp = &pset->pcp;
-               free_pcppages_bulk(zone, pcp->count, pcp);
-               pcp->count = 0;
+               if (pcp->count) {
+                       free_pcppages_bulk(zone, pcp->count, pcp);
+                       pcp->count = 0;
+               }
                local_irq_restore(flags);
        }
 }
@@ -2034,6 +2036,14 @@ restart:
         */
        alloc_flags = gfp_to_alloc_flags(gfp_mask);
 
+       /*
+        * Find the true preferred zone if the allocation is unconstrained by
+        * cpusets.
+        */
+       if (!(alloc_flags & ALLOC_CPUSET) && !nodemask)
+               first_zones_zonelist(zonelist, high_zoneidx, NULL,
+                                       &preferred_zone);
+
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2192,7 +2202,9 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 
        get_mems_allowed();
        /* The preferred zone is used for statistics later */
-       first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
+       first_zones_zonelist(zonelist, high_zoneidx,
+                               nodemask ? : &cpuset_current_mems_allowed,
+                               &preferred_zone);
        if (!preferred_zone) {
                put_mems_allowed();
                return NULL;
@@ -5364,10 +5376,9 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count)
        for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
                unsigned long check = pfn + iter;
 
-               if (!pfn_valid_within(check)) {
-                       iter++;
+               if (!pfn_valid_within(check))
                        continue;
-               }
+
                page = pfn_to_page(check);
                if (!page_count(page)) {
                        if (PageBuddy(page))
index 0369f5b..eb663fb 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2010  Linus Torvalds
  */
 
+#include <linux/pagemap.h>
 #include <asm/tlb.h>
 #include <asm-generic/pgtable.h>
 
index 07a458d..0341c57 100644 (file)
@@ -1940,7 +1940,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 
        error = -EINVAL;
        if (S_ISBLK(inode->i_mode)) {
-               bdev = I_BDEV(inode);
+               bdev = bdgrab(I_BDEV(inode));
                error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL,
                                   sys_swapon);
                if (error < 0) {
index 3c2d5dd..d64296b 100644 (file)
@@ -225,6 +225,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
        next = start;
        while (next <= end &&
               pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+               mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
                        pgoff_t page_index = page->index;
@@ -247,6 +248,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        unlock_page(page);
                }
                pagevec_release(&pvec);
+               mem_cgroup_uncharge_end();
                cond_resched();
        }
 
@@ -549,13 +551,12 @@ EXPORT_SYMBOL(truncate_pagecache);
  * @inode: inode
  * @newsize: new file size
  *
- * truncate_setsize updastes i_size update and performs pagecache
- * truncation (if necessary) for a file size updates. It will be
- * typically be called from the filesystem's setattr function when
- * ATTR_SIZE is passed in.
+ * truncate_setsize updates i_size and performs pagecache truncation (if
+ * necessary) to @newsize. It will be typically be called from the filesystem's
+ * setattr function when ATTR_SIZE is passed in.
  *
- * Must be called with inode_mutex held and after all filesystem
- * specific block truncation has been performed.
+ * Must be called with inode_mutex held and before all filesystem specific
+ * block truncation has been performed.
  */
 void truncate_setsize(struct inode *inode, loff_t newsize)
 {
index 47a5096..6771ea7 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/memcontrol.h>
 #include <linux/delayacct.h>
 #include <linux/sysctl.h>
-#include <linux/compaction.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1842,16 +1841,28 @@ static inline bool should_continue_reclaim(struct zone *zone,
        if (!(sc->reclaim_mode & RECLAIM_MODE_COMPACTION))
                return false;
 
-       /*
-        * If we failed to reclaim and have scanned the full list, stop.
-        * NOTE: Checking just nr_reclaimed would exit reclaim/compaction far
-        *       faster but obviously would be less likely to succeed
-        *       allocation. If this is desirable, use GFP_REPEAT to decide
-        *       if both reclaimed and scanned should be checked or just
-        *       reclaimed
-        */
-       if (!nr_reclaimed && !nr_scanned)
-               return false;
+       /* Consider stopping depending on scan and reclaim activity */
+       if (sc->gfp_mask & __GFP_REPEAT) {
+               /*
+                * For __GFP_REPEAT allocations, stop reclaiming if the
+                * full LRU list has been scanned and we are still failing
+                * to reclaim pages. This full LRU scan is potentially
+                * expensive but a __GFP_REPEAT caller really wants to succeed
+                */
+               if (!nr_reclaimed && !nr_scanned)
+                       return false;
+       } else {
+               /*
+                * For non-__GFP_REPEAT allocations which can presumably
+                * fail without consequence, stop if we failed to reclaim
+                * any pages from the last SWAP_CLUSTER_MAX number of
+                * pages that were scanned. This will return to the
+                * caller faster at the risk reclaim/compaction and
+                * the resulting allocation attempt fails
+                */
+               if (!nr_reclaimed)
+                       return false;
+       }
 
        /*
         * If we have not reclaimed enough pages for compaction and the
@@ -1883,12 +1894,12 @@ static void shrink_zone(int priority, struct zone *zone,
        unsigned long nr[NR_LRU_LISTS];
        unsigned long nr_to_scan;
        enum lru_list l;
-       unsigned long nr_reclaimed;
+       unsigned long nr_reclaimed, nr_scanned;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
-       unsigned long nr_scanned = sc->nr_scanned;
 
 restart:
        nr_reclaimed = 0;
+       nr_scanned = sc->nr_scanned;
        get_scan_count(zone, sc, nr, priority);
 
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
@@ -2084,7 +2095,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                        struct zone *preferred_zone;
 
                        first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
-                                                       NULL, &preferred_zone);
+                                               &cpuset_current_mems_allowed,
+                                               &preferred_zone);
                        wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
                }
        }
index d4d9926..65106fb 100644 (file)
@@ -151,9 +151,9 @@ int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
        }                                                       \
        while (0)
 #else /* !CONFIG_BATMAN_ADV_DEBUG */
-static inline void bat_dbg(char type __attribute__((unused)),
-                          struct bat_priv *bat_priv __attribute__((unused)),
-                          char *fmt __attribute__((unused)), ...)
+static inline void bat_dbg(char type __always_unused,
+                          struct bat_priv *bat_priv __always_unused,
+                          char *fmt __always_unused, ...)
 {
 }
 #endif
index b49fdf7..2284e81 100644 (file)
@@ -63,7 +63,7 @@ struct batman_packet {
        uint8_t  num_hna;
        uint8_t  gw_flags;  /* flags related to gateway class */
        uint8_t  align;
-} __attribute__((packed));
+} __packed;
 
 #define BAT_PACKET_LEN sizeof(struct batman_packet)
 
@@ -76,7 +76,7 @@ struct icmp_packet {
        uint8_t  orig[6];
        uint16_t seqno;
        uint8_t  uid;
-} __attribute__((packed));
+} __packed;
 
 #define BAT_RR_LEN 16
 
@@ -93,14 +93,14 @@ struct icmp_packet_rr {
        uint8_t  uid;
        uint8_t  rr_cur;
        uint8_t  rr[BAT_RR_LEN][ETH_ALEN];
-} __attribute__((packed));
+} __packed;
 
 struct unicast_packet {
        uint8_t  packet_type;
        uint8_t  version;  /* batman version field */
        uint8_t  dest[6];
        uint8_t  ttl;
-} __attribute__((packed));
+} __packed;
 
 struct unicast_frag_packet {
        uint8_t  packet_type;
@@ -110,7 +110,7 @@ struct unicast_frag_packet {
        uint8_t  flags;
        uint8_t  orig[6];
        uint16_t seqno;
-} __attribute__((packed));
+} __packed;
 
 struct bcast_packet {
        uint8_t  packet_type;
@@ -118,7 +118,7 @@ struct bcast_packet {
        uint8_t  orig[6];
        uint8_t  ttl;
        uint32_t seqno;
-} __attribute__((packed));
+} __packed;
 
 struct vis_packet {
        uint8_t  packet_type;
@@ -131,6 +131,6 @@ struct vis_packet {
                                  * neighbors */
        uint8_t  target_orig[6]; /* who should receive this packet */
        uint8_t  sender_orig[6]; /* who sent or rebroadcasted this packet */
-} __attribute__((packed));
+} __packed;
 
 #endif /* _NET_BATMAN_ADV_PACKET_H_ */
index 97cb23d..bf3f6f5 100644 (file)
@@ -246,13 +246,13 @@ struct vis_info {
        /* this packet might be part of the vis send queue. */
        struct sk_buff *skb_packet;
        /* vis_info may follow here*/
-} __attribute__((packed));
+} __packed;
 
 struct vis_info_entry {
        uint8_t  src[ETH_ALEN];
        uint8_t  dest[ETH_ALEN];
        uint8_t  quality;       /* quality = 0 means HNA */
-} __attribute__((packed));
+} __packed;
 
 struct recvlist_node {
        struct list_head list;
index dc2e28b..d1a6113 100644 (file)
@@ -50,12 +50,12 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
                skb = tfp->skb;
        }
 
+       if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
+               goto err;
+
        skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
-       if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) {
-               /* free buffered skb, skb will be freed later */
-               kfree_skb(tfp->skb);
-               return NULL;
-       }
+       if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
+               goto err;
 
        /* move free entry to end */
        tfp->skb = NULL;
@@ -70,6 +70,11 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
        unicast_packet->packet_type = BAT_UNICAST;
 
        return skb;
+
+err:
+       /* free buffered skb, skb will be freed later */
+       kfree_skb(tfp->skb);
+       return NULL;
 }
 
 static void frag_create_entry(struct list_head *head, struct sk_buff *skb)
@@ -229,10 +234,12 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
        if (!bat_priv->primary_if)
                goto dropped;
 
-       unicast_packet = (struct unicast_packet *) skb->data;
+       frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
+       if (!frag_skb)
+               goto dropped;
 
+       unicast_packet = (struct unicast_packet *) skb->data;
        memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
-       frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
        skb_split(skb, frag_skb, data_len / 2);
 
        if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
index cd4c423..de1022c 100644 (file)
@@ -64,6 +64,7 @@ static void free_info(struct kref *ref)
 
        spin_unlock_bh(&bat_priv->vis_list_lock);
        kfree_skb(info->skb_packet);
+       kfree(info);
 }
 
 /* Compare two vis packets, used by the hashing algorithm */
@@ -268,10 +269,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
                                buff_pos += sprintf(buff + buff_pos, "%pM,",
                                                entry->addr);
 
-                               for (i = 0; i < packet->entries; i++)
+                               for (j = 0; j < packet->entries; j++)
                                        buff_pos += vis_data_read_entry(
                                                        buff + buff_pos,
-                                                       &entries[i],
+                                                       &entries[j],
                                                        entry->addr,
                                                        entry->primary);
 
@@ -444,7 +445,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
                              info);
        if (hash_added < 0) {
                /* did not work (for some reason) */
-               kref_put(&old_info->refcount, free_info);
+               kref_put(&info->refcount, free_info);
                info = NULL;
        }
 
@@ -815,7 +816,7 @@ static void send_vis_packets(struct work_struct *work)
                container_of(work, struct delayed_work, work);
        struct bat_priv *bat_priv =
                container_of(delayed_work, struct bat_priv, vis_work);
-       struct vis_info *info, *temp;
+       struct vis_info *info;
 
        spin_lock_bh(&bat_priv->vis_hash_lock);
        purge_vis_packets(bat_priv);
@@ -825,8 +826,9 @@ static void send_vis_packets(struct work_struct *work)
                send_list_add(bat_priv, bat_priv->my_vis_info);
        }
 
-       list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list,
-                                send_list) {
+       while (!list_empty(&bat_priv->vis_send_list)) {
+               info = list_first_entry(&bat_priv->vis_send_list,
+                                       typeof(*info), send_list);
 
                kref_get(&info->refcount);
                spin_unlock_bh(&bat_priv->vis_hash_lock);
index 6b90a41..99cd8d9 100644 (file)
@@ -379,14 +379,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
        hci_conn_hold(acl);
 
        if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
-               acl->sec_level = sec_level;
+               acl->sec_level = BT_SECURITY_LOW;
+               acl->pending_sec_level = sec_level;
                acl->auth_type = auth_type;
                hci_acl_connect(acl);
-       } else {
-               if (acl->sec_level < sec_level)
-                       acl->sec_level = sec_level;
-               if (acl->auth_type < auth_type)
-                       acl->auth_type = auth_type;
        }
 
        if (type == ACL_LINK)
@@ -442,11 +438,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
        BT_DBG("conn %p", conn);
 
+       if (conn->pending_sec_level > sec_level)
+               sec_level = conn->pending_sec_level;
+
        if (sec_level > conn->sec_level)
-               conn->sec_level = sec_level;
+               conn->pending_sec_level = sec_level;
        else if (conn->link_mode & HCI_LM_AUTH)
                return 1;
 
+       /* Make sure we preserve an existing MITM requirement*/
+       auth_type |= (conn->auth_type & 0x01);
+
        conn->auth_type = auth_type;
 
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
index 8b602d8..9c4541b 100644 (file)
@@ -1011,6 +1011,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        destroy_workqueue(hdev->workqueue);
 
+       hci_dev_lock_bh(hdev);
+       hci_blacklist_clear(hdev);
+       hci_dev_unlock_bh(hdev);
+
        __hci_dev_put(hdev);
 
        return 0;
index 3810017..a290854 100644 (file)
@@ -692,13 +692,13 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
        if (conn->state != BT_CONFIG || !conn->out)
                return 0;
 
-       if (conn->sec_level == BT_SECURITY_SDP)
+       if (conn->pending_sec_level == BT_SECURITY_SDP)
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
         * devices with sec_level HIGH */
        if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
-                                       conn->sec_level != BT_SECURITY_HIGH)
+                               conn->pending_sec_level != BT_SECURITY_HIGH)
                return 0;
 
        return 1;
@@ -1095,9 +1095,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
-               if (!ev->status)
+               if (!ev->status) {
                        conn->link_mode |= HCI_LM_AUTH;
-               else
+                       conn->sec_level = conn->pending_sec_level;
+               } else
                        conn->sec_level = BT_SECURITY_LOW;
 
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
index c791fcd..675614e 100644 (file)
@@ -305,33 +305,44 @@ static void l2cap_chan_del(struct sock *sk, int err)
        }
 }
 
-/* Service level security */
-static inline int l2cap_check_security(struct sock *sk)
+static inline u8 l2cap_get_auth_type(struct sock *sk)
 {
-       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-       __u8 auth_type;
+       if (sk->sk_type == SOCK_RAW) {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       return HCI_AT_DEDICATED_BONDING_MITM;
+               case BT_SECURITY_MEDIUM:
+                       return HCI_AT_DEDICATED_BONDING;
+               default:
+                       return HCI_AT_NO_BONDING;
+               }
+       } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 
-       if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
                if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
-                       auth_type = HCI_AT_NO_BONDING_MITM;
+                       return HCI_AT_NO_BONDING_MITM;
                else
-                       auth_type = HCI_AT_NO_BONDING;
-
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
-                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+                       return HCI_AT_NO_BONDING;
        } else {
                switch (l2cap_pi(sk)->sec_level) {
                case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
-                       break;
+                       return HCI_AT_GENERAL_BONDING_MITM;
                case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_GENERAL_BONDING;
-                       break;
+                       return HCI_AT_GENERAL_BONDING;
                default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
+                       return HCI_AT_NO_BONDING;
                }
        }
+}
+
+/* Service level security */
+static inline int l2cap_check_security(struct sock *sk)
+{
+       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+       __u8 auth_type;
+
+       auth_type = l2cap_get_auth_type(sk);
 
        return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
                                                                auth_type);
@@ -848,6 +859,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
                                result = L2CAP_CR_SEC_BLOCK;
                        else
                                result = L2CAP_CR_BAD_PSM;
+                       sk->sk_state = BT_DISCONN;
 
                        rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
                        rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -1068,39 +1080,7 @@ static int l2cap_do_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       if (sk->sk_type == SOCK_RAW) {
-               switch (l2cap_pi(sk)->sec_level) {
-               case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-                       break;
-               case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_DEDICATED_BONDING;
-                       break;
-               default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
-               }
-       } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
-                       auth_type = HCI_AT_NO_BONDING_MITM;
-               else
-                       auth_type = HCI_AT_NO_BONDING;
-
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
-                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
-       } else {
-               switch (l2cap_pi(sk)->sec_level) {
-               case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
-                       break;
-               case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_GENERAL_BONDING;
-                       break;
-               default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
-               }
-       }
+       auth_type = l2cap_get_auth_type(sk);
 
        hcon = hci_connect(hdev, ACL_LINK, dst,
                                        l2cap_pi(sk)->sec_level, auth_type);
@@ -1127,7 +1107,8 @@ static int l2cap_do_connect(struct sock *sk)
                if (sk->sk_type != SOCK_SEQPACKET &&
                                sk->sk_type != SOCK_STREAM) {
                        l2cap_sock_clear_timer(sk);
-                       sk->sk_state = BT_CONNECTED;
+                       if (l2cap_check_security(sk))
+                               sk->sk_state = BT_CONNECTED;
                } else
                        l2cap_do_start(sk);
        }
@@ -1893,8 +1874,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                if (pi->mode == L2CAP_MODE_STREAMING) {
                        l2cap_streaming_send(sk);
                } else {
-                       if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
-                                       pi->conn_state && L2CAP_CONN_WAIT_F) {
+                       if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+                                       (pi->conn_state & L2CAP_CONN_WAIT_F)) {
                                err = len;
                                break;
                        }
index ff8aaa7..6b83776 100644 (file)
@@ -1164,7 +1164,8 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
                         * initiator rfcomm_process_rx already calls
                         * rfcomm_session_put() */
                        if (s->sock->sk->sk_state != BT_CLOSED)
-                               rfcomm_session_put(s);
+                               if (list_empty(&s->dlcs))
+                                       rfcomm_session_put(s);
                        break;
                }
        }
index 2575c2d..d7b9af4 100644 (file)
@@ -727,7 +727,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
                        break;
                }
 
+               tty_unlock();
                schedule();
+               tty_lock();
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->wait, &wait);
index 2872393..88485cc 100644 (file)
@@ -328,12 +328,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
        fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
        if (fdb) {
                memcpy(fdb->addr.addr, addr, ETH_ALEN);
-               hlist_add_head_rcu(&fdb->hlist, head);
-
                fdb->dst = source;
                fdb->is_local = is_local;
                fdb->is_static = is_local;
                fdb->ageing_timer = jiffies;
+
+               hlist_add_head_rcu(&fdb->hlist, head);
        }
        return fdb;
 }
index 6f6d8e1..88e4aa9 100644 (file)
@@ -80,7 +80,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb);
                if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
-                       if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
+                       if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
                        br_multicast_forward(mdst, skb, skb2);
index f701a21..030a002 100644 (file)
        rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static inline int ipv6_is_local_multicast(const struct in6_addr *addr)
+static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
 {
-       if (ipv6_addr_is_multicast(addr) &&
-           IPV6_ADDR_MC_SCOPE(addr) <= IPV6_ADDR_SCOPE_LINKLOCAL)
+       if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr))
                return 1;
        return 0;
 }
@@ -232,8 +231,7 @@ static void br_multicast_group_expired(unsigned long data)
        if (!netif_running(br->dev) || timer_pending(&mp->timer))
                goto out;
 
-       if (!hlist_unhashed(&mp->mglist))
-               hlist_del_init(&mp->mglist);
+       mp->mglist = false;
 
        if (mp->ports)
                goto out;
@@ -276,7 +274,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
                del_timer(&p->query_timer);
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
 
-               if (!mp->ports && hlist_unhashed(&mp->mglist) &&
+               if (!mp->ports && !mp->mglist &&
                    netif_running(br->dev))
                        mod_timer(&mp->timer, jiffies);
 
@@ -436,7 +434,6 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        eth = eth_hdr(skb);
 
        memcpy(eth->h_source, br->dev->dev_addr, 6);
-       ipv6_eth_mc_map(group, eth->h_dest);
        eth->h_proto = htons(ETH_P_IPV6);
        skb_put(skb, sizeof(*eth));
 
@@ -448,8 +445,10 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        ip6h->payload_len = htons(8 + sizeof(*mldq));
        ip6h->nexthdr = IPPROTO_HOPOPTS;
        ip6h->hop_limit = 1;
-       ipv6_addr_set(&ip6h->saddr, 0, 0, 0, 0);
+       ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
+                          &ip6h->saddr);
        ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
+       ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
 
        hopopt = (u8 *)(ip6h + 1);
        hopopt[0] = IPPROTO_ICMPV6;             /* next hdr */
@@ -528,7 +527,7 @@ static void br_multicast_group_query_expired(unsigned long data)
        struct net_bridge *br = mp->br;
 
        spin_lock(&br->multicast_lock);
-       if (!netif_running(br->dev) || hlist_unhashed(&mp->mglist) ||
+       if (!netif_running(br->dev) || !mp->mglist ||
            mp->queries_sent >= br->multicast_last_member_count)
                goto out;
 
@@ -719,7 +718,7 @@ static int br_multicast_add_group(struct net_bridge *br,
                goto err;
 
        if (!port) {
-               hlist_add_head(&mp->mglist, &br->mglist);
+               mp->mglist = true;
                mod_timer(&mp->timer, now + br->multicast_membership_interval);
                goto out;
        }
@@ -781,11 +780,11 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
 {
        struct br_ip br_group;
 
-       if (ipv6_is_local_multicast(group))
+       if (!ipv6_is_transient_multicast(group))
                return 0;
 
        ipv6_addr_copy(&br_group.u.ip6, group);
-       br_group.proto = htons(ETH_P_IP);
+       br_group.proto = htons(ETH_P_IPV6);
 
        return br_multicast_add_group(br, port, &br_group);
 }
@@ -1014,18 +1013,19 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 
                nsrcs = skb_header_pointer(skb,
                                           len + offsetof(struct mld2_grec,
-                                                         grec_mca),
+                                                         grec_nsrcs),
                                           sizeof(_nsrcs), &_nsrcs);
                if (!nsrcs)
                        return -EINVAL;
 
                if (!pskb_may_pull(skb,
                                   len + sizeof(*grec) +
-                                  sizeof(struct in6_addr) * (*nsrcs)))
+                                  sizeof(struct in6_addr) * ntohs(*nsrcs)))
                        return -EINVAL;
 
                grec = (struct mld2_grec *)(skb->data + len);
-               len += sizeof(*grec) + sizeof(struct in6_addr) * (*nsrcs);
+               len += sizeof(*grec) +
+                      sizeof(struct in6_addr) * ntohs(*nsrcs);
 
                /* We treat these as MLDv1 reports for now. */
                switch (grec->grec_type) {
@@ -1165,7 +1165,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
 
        max_delay *= br->multicast_last_member_count;
 
-       if (!hlist_unhashed(&mp->mglist) &&
+       if (mp->mglist &&
            (timer_pending(&mp->timer) ?
             time_after(mp->timer.expires, now + max_delay) :
             try_to_del_timer_sync(&mp->timer) >= 0))
@@ -1177,7 +1177,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                if (timer_pending(&p->timer) ?
                    time_after(p->timer.expires, now + max_delay) :
                    try_to_del_timer_sync(&p->timer) >= 0)
-                       mod_timer(&mp->timer, now + max_delay);
+                       mod_timer(&p->timer, now + max_delay);
        }
 
 out:
@@ -1236,7 +1236,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                goto out;
 
        max_delay *= br->multicast_last_member_count;
-       if (!hlist_unhashed(&mp->mglist) &&
+       if (mp->mglist &&
            (timer_pending(&mp->timer) ?
             time_after(mp->timer.expires, now + max_delay) :
             try_to_del_timer_sync(&mp->timer) >= 0))
@@ -1248,7 +1248,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                if (timer_pending(&p->timer) ?
                    time_after(p->timer.expires, now + max_delay) :
                    try_to_del_timer_sync(&p->timer) >= 0)
-                       mod_timer(&mp->timer, now + max_delay);
+                       mod_timer(&p->timer, now + max_delay);
        }
 
 out:
@@ -1283,7 +1283,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
                     br->multicast_last_member_interval;
 
        if (!port) {
-               if (!hlist_unhashed(&mp->mglist) &&
+               if (mp->mglist &&
                    (timer_pending(&mp->timer) ?
                     time_after(mp->timer.expires, time) :
                     try_to_del_timer_sync(&mp->timer) >= 0)) {
@@ -1341,7 +1341,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
 {
        struct br_ip br_group;
 
-       if (ipv6_is_local_multicast(group))
+       if (!ipv6_is_transient_multicast(group))
                return;
 
        ipv6_addr_copy(&br_group.u.ip6, group);
index 84aac77..4e1b620 100644 (file)
@@ -84,13 +84,13 @@ struct net_bridge_port_group {
 struct net_bridge_mdb_entry
 {
        struct hlist_node               hlist[2];
-       struct hlist_node               mglist;
        struct net_bridge               *br;
        struct net_bridge_port_group __rcu *ports;
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct timer_list               query_timer;
        struct br_ip                    addr;
+       bool                            mglist;
        u32                             queries_sent;
 };
 
@@ -238,7 +238,6 @@ struct net_bridge
        spinlock_t                      multicast_lock;
        struct net_bridge_mdb_htable __rcu *mdb;
        struct hlist_head               router_list;
-       struct hlist_head               mglist;
 
        struct timer_list               multicast_router_timer;
        struct timer_list               multicast_querier_timer;
index 21ede14..c665de7 100644 (file)
@@ -191,6 +191,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
        struct cflayer *servl = NULL;
        struct cfcnfg_phyinfo *phyinfo = NULL;
        u8 phyid = 0;
+
        caif_assert(adap_layer != NULL);
        channel_id = adap_layer->id;
        if (adap_layer->dn == NULL || channel_id == 0) {
@@ -199,16 +200,16 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
                goto end;
        }
        servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
-       if (servl == NULL)
-               goto end;
-       layer_set_up(servl, NULL);
-       ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
        if (servl == NULL) {
                pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
                       channel_id);
                ret = -EINVAL;
                goto end;
        }
+       layer_set_up(servl, NULL);
+       ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+       if (ret)
+               goto end;
        caif_assert(channel_id == servl->id);
        if (adap_layer->dn != NULL) {
                phyid = cfsrvl_getphyid(adap_layer->dn);
index fa9dab3..6008d6d 100644 (file)
@@ -394,9 +394,7 @@ static void ipcaif_net_setup(struct net_device *dev)
        priv->conn_req.sockaddr.u.dgm.connection_id = -1;
        priv->flowenabled = false;
 
-       ASSERT_RTNL();
        init_waitqueue_head(&priv->netmgmt_wq);
-       list_add(&priv->list_field, &chnl_net_list);
 }
 
 
@@ -453,6 +451,8 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
        ret = register_netdevice(dev);
        if (ret)
                pr_warn("device rtml registration failed\n");
+       else
+               list_add(&caifdev->list_field, &chnl_net_list);
        return ret;
 }
 
index 9d5e8ac..092dc88 100644 (file)
@@ -1256,6 +1256,9 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
                struct sockaddr_can *addr =
                        (struct sockaddr_can *)msg->msg_name;
 
+               if (msg->msg_namelen < sizeof(*addr))
+                       return -EINVAL;
+
                if (addr->can_family != AF_CAN)
                        return -EINVAL;
 
index e88f610..883e9d7 100644 (file)
@@ -649,6 +649,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
                struct sockaddr_can *addr =
                        (struct sockaddr_can *)msg->msg_name;
 
+               if (msg->msg_namelen < sizeof(*addr))
+                       return -EINVAL;
+
                if (addr->can_family != AF_CAN)
                        return -EINVAL;
 
index dff633d..05f3578 100644 (file)
@@ -252,8 +252,12 @@ static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
 {
        struct kvec iov = {buf, len};
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+       int r;
 
-       return kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+       r = kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+       if (r == -EAGAIN)
+               r = 0;
+       return r;
 }
 
 /*
@@ -264,13 +268,17 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
                     size_t kvlen, size_t len, int more)
 {
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+       int r;
 
        if (more)
                msg.msg_flags |= MSG_MORE;
        else
                msg.msg_flags |= MSG_EOR;  /* superfluous, but what the hell */
 
-       return kernel_sendmsg(sock, &msg, iov, kvlen, len);
+       r = kernel_sendmsg(sock, &msg, iov, kvlen, len);
+       if (r == -EAGAIN)
+               r = 0;
+       return r;
 }
 
 
@@ -328,7 +336,6 @@ static void reset_connection(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
-       con->out_keepalive_pending = false;
        con->in_seq = 0;
        con->in_seq_acked = 0;
 }
@@ -847,6 +854,8 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                    (msg->pages || msg->pagelist || msg->bio || in_trail))
                        kunmap(page);
 
+               if (ret == -EAGAIN)
+                       ret = 0;
                if (ret <= 0)
                        goto out;
 
@@ -1238,8 +1247,6 @@ static int process_connect(struct ceph_connection *con)
                     con->auth_retry);
                if (con->auth_retry == 2) {
                        con->error_msg = "connect authorization failure";
-                       reset_connection(con);
-                       set_bit(CLOSED, &con->state);
                        return -1;
                }
                con->auth_retry = 1;
@@ -1705,14 +1712,6 @@ more:
 
        /* open the socket first? */
        if (con->sock == NULL) {
-               /*
-                * if we were STANDBY and are reconnecting _this_
-                * connection, bump connect_seq now.  Always bump
-                * global_seq.
-                */
-               if (test_and_clear_bit(STANDBY, &con->state))
-                       con->connect_seq++;
-
                prepare_write_banner(msgr, con);
                prepare_write_connect(msgr, con, 1);
                prepare_read_banner(con);
@@ -1737,16 +1736,12 @@ more_kvec:
        if (con->out_skip) {
                ret = write_partial_skip(con);
                if (ret <= 0)
-                       goto done;
-               if (ret < 0) {
-                       dout("try_write write_partial_skip err %d\n", ret);
-                       goto done;
-               }
+                       goto out;
        }
        if (con->out_kvec_left) {
                ret = write_partial_kvec(con);
                if (ret <= 0)
-                       goto done;
+                       goto out;
        }
 
        /* msg pages? */
@@ -1761,11 +1756,11 @@ more_kvec:
                if (ret == 1)
                        goto more_kvec;  /* we need to send the footer, too! */
                if (ret == 0)
-                       goto done;
+                       goto out;
                if (ret < 0) {
                        dout("try_write write_partial_msg_pages err %d\n",
                             ret);
-                       goto done;
+                       goto out;
                }
        }
 
@@ -1789,10 +1784,9 @@ do_next:
        /* Nothing to do! */
        clear_bit(WRITE_PENDING, &con->state);
        dout("try_write nothing else to write.\n");
-done:
        ret = 0;
 out:
-       dout("try_write done on %p\n", con);
+       dout("try_write done on %p ret %d\n", con, ret);
        return ret;
 }
 
@@ -1821,19 +1815,17 @@ more:
                        dout("try_read connecting\n");
                        ret = read_partial_banner(con);
                        if (ret <= 0)
-                               goto done;
-                       if (process_banner(con) < 0) {
-                               ret = -1;
                                goto out;
-                       }
+                       ret = process_banner(con);
+                       if (ret < 0)
+                               goto out;
                }
                ret = read_partial_connect(con);
                if (ret <= 0)
-                       goto done;
-               if (process_connect(con) < 0) {
-                       ret = -1;
                        goto out;
-               }
+               ret = process_connect(con);
+               if (ret < 0)
+                       goto out;
                goto more;
        }
 
@@ -1848,7 +1840,7 @@ more:
                dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
                ret = ceph_tcp_recvmsg(con->sock, buf, skip);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                con->in_base_pos += ret;
                if (con->in_base_pos)
                        goto more;
@@ -1859,7 +1851,7 @@ more:
                 */
                ret = ceph_tcp_recvmsg(con->sock, &con->in_tag, 1);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                dout("try_read got tag %d\n", (int)con->in_tag);
                switch (con->in_tag) {
                case CEPH_MSGR_TAG_MSG:
@@ -1870,7 +1862,7 @@ more:
                        break;
                case CEPH_MSGR_TAG_CLOSE:
                        set_bit(CLOSED, &con->state);   /* fixme */
-                       goto done;
+                       goto out;
                default:
                        goto bad_tag;
                }
@@ -1882,13 +1874,12 @@ more:
                        case -EBADMSG:
                                con->error_msg = "bad crc";
                                ret = -EIO;
-                               goto out;
+                               break;
                        case -EIO:
                                con->error_msg = "io error";
-                               goto out;
-                       default:
-                               goto done;
+                               break;
                        }
+                       goto out;
                }
                if (con->in_tag == CEPH_MSGR_TAG_READY)
                        goto more;
@@ -1898,15 +1889,13 @@ more:
        if (con->in_tag == CEPH_MSGR_TAG_ACK) {
                ret = read_partial_ack(con);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                process_ack(con);
                goto more;
        }
 
-done:
-       ret = 0;
 out:
-       dout("try_read done on %p\n", con);
+       dout("try_read done on %p ret %d\n", con, ret);
        return ret;
 
 bad_tag:
@@ -1951,7 +1940,24 @@ static void con_work(struct work_struct *work)
                                                   work.work);
 
        mutex_lock(&con->mutex);
+       if (test_and_clear_bit(BACKOFF, &con->state)) {
+               dout("con_work %p backing off\n", con);
+               if (queue_delayed_work(ceph_msgr_wq, &con->work,
+                                      round_jiffies_relative(con->delay))) {
+                       dout("con_work %p backoff %lu\n", con, con->delay);
+                       mutex_unlock(&con->mutex);
+                       return;
+               } else {
+                       con->ops->put(con);
+                       dout("con_work %p FAILED to back off %lu\n", con,
+                            con->delay);
+               }
+       }
 
+       if (test_bit(STANDBY, &con->state)) {
+               dout("con_work %p STANDBY\n", con);
+               goto done;
+       }
        if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
                dout("con_work CLOSED\n");
                con_close_socket(con);
@@ -2008,10 +2014,12 @@ static void ceph_fault(struct ceph_connection *con)
        /* Requeue anything that hasn't been acked */
        list_splice_init(&con->out_sent, &con->out_queue);
 
-       /* If there are no messages in the queue, place the connection
-        * in a STANDBY state (i.e., don't try to reconnect just yet). */
-       if (list_empty(&con->out_queue) && !con->out_keepalive_pending) {
-               dout("fault setting STANDBY\n");
+       /* If there are no messages queued or keepalive pending, place
+        * the connection in a STANDBY state */
+       if (list_empty(&con->out_queue) &&
+           !test_bit(KEEPALIVE_PENDING, &con->state)) {
+               dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con);
+               clear_bit(WRITE_PENDING, &con->state);
                set_bit(STANDBY, &con->state);
        } else {
                /* retry after a delay. */
@@ -2019,11 +2027,24 @@ static void ceph_fault(struct ceph_connection *con)
                        con->delay = BASE_DELAY_INTERVAL;
                else if (con->delay < MAX_DELAY_INTERVAL)
                        con->delay *= 2;
-               dout("fault queueing %p delay %lu\n", con, con->delay);
                con->ops->get(con);
                if (queue_delayed_work(ceph_msgr_wq, &con->work,
-                                      round_jiffies_relative(con->delay)) == 0)
+                                      round_jiffies_relative(con->delay))) {
+                       dout("fault queued %p delay %lu\n", con, con->delay);
+               } else {
                        con->ops->put(con);
+                       dout("fault failed to queue %p delay %lu, backoff\n",
+                            con, con->delay);
+                       /*
+                        * In many cases we see a socket state change
+                        * while con_work is running and end up
+                        * queuing (non-delayed) work, such that we
+                        * can't backoff with a delay.  Set a flag so
+                        * that when con_work restarts we schedule the
+                        * delay then.
+                        */
+                       set_bit(BACKOFF, &con->state);
+               }
        }
 
 out_unlock:
@@ -2094,6 +2115,19 @@ void ceph_messenger_destroy(struct ceph_messenger *msgr)
 }
 EXPORT_SYMBOL(ceph_messenger_destroy);
 
+static void clear_standby(struct ceph_connection *con)
+{
+       /* come back from STANDBY? */
+       if (test_and_clear_bit(STANDBY, &con->state)) {
+               mutex_lock(&con->mutex);
+               dout("clear_standby %p and ++connect_seq\n", con);
+               con->connect_seq++;
+               WARN_ON(test_bit(WRITE_PENDING, &con->state));
+               WARN_ON(test_bit(KEEPALIVE_PENDING, &con->state));
+               mutex_unlock(&con->mutex);
+       }
+}
+
 /*
  * Queue up an outgoing message on the given connection.
  */
@@ -2126,6 +2160,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
 
        /* if there wasn't anything waiting to send before, queue
         * new work */
+       clear_standby(con);
        if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
 }
@@ -2191,6 +2226,8 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
  */
 void ceph_con_keepalive(struct ceph_connection *con)
 {
+       dout("con_keepalive %p\n", con);
+       clear_standby(con);
        if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
            test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
index 1a040e6..cd9c21d 100644 (file)
@@ -16,22 +16,30 @@ struct page **ceph_get_direct_page_vector(const char __user *data,
                                          int num_pages, bool write_page)
 {
        struct page **pages;
-       int rc;
+       int got = 0;
+       int rc = 0;
 
        pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
        if (!pages)
                return ERR_PTR(-ENOMEM);
 
        down_read(&current->mm->mmap_sem);
-       rc = get_user_pages(current, current->mm, (unsigned long)data,
-                           num_pages, write_page, 0, pages, NULL);
+       while (got < num_pages) {
+               rc = get_user_pages(current, current->mm,
+                   (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
+                   num_pages - got, write_page, 0, pages + got, NULL);
+               if (rc < 0)
+                       break;
+               BUG_ON(rc == 0);
+               got += rc;
+       }
        up_read(&current->mm->mmap_sem);
-       if (rc < num_pages)
+       if (rc < 0)
                goto fail;
        return pages;
 
 fail:
-       ceph_put_page_vector(pages, rc > 0 ? rc : 0, false);
+       ceph_put_page_vector(pages, got, false);
        return ERR_PTR(rc);
 }
 EXPORT_SYMBOL(ceph_get_direct_page_vector);
index 54277df..8ae6631 100644 (file)
@@ -749,7 +749,8 @@ EXPORT_SYMBOL(dev_get_by_index);
  *     @ha: hardware address
  *
  *     Search for an interface by MAC address. Returns NULL if the device
- *     is not found or a pointer to the device. The caller must hold RCU
+ *     is not found or a pointer to the device.
+ *     The caller must hold RCU or RTNL.
  *     The returned device has not had its ref count increased
  *     and the caller must therefore be careful about locking
  *
@@ -1279,10 +1280,13 @@ static int __dev_close_many(struct list_head *head)
 
 static int __dev_close(struct net_device *dev)
 {
+       int retval;
        LIST_HEAD(single);
 
        list_add(&dev->unreg_list, &single);
-       return __dev_close_many(&single);
+       retval = __dev_close_many(&single);
+       list_del(&single);
+       return retval;
 }
 
 int dev_close_many(struct list_head *head)
@@ -1324,7 +1328,7 @@ int dev_close(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        dev_close_many(&single);
-
+       list_del(&single);
        return 0;
 }
 EXPORT_SYMBOL(dev_close);
@@ -2001,7 +2005,7 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
 
 static int harmonize_features(struct sk_buff *skb, __be16 protocol, int features)
 {
-       if (!can_checksum_protocol(protocol, features)) {
+       if (!can_checksum_protocol(features, protocol)) {
                features &= ~NETIF_F_ALL_CSUM;
                features &= ~NETIF_F_SG;
        } else if (illegal_highdma(skb->dev, skb)) {
@@ -2023,13 +2027,13 @@ int netif_skb_features(struct sk_buff *skb)
                return harmonize_features(skb, protocol, features);
        }
 
-       features &= skb->dev->vlan_features;
+       features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX);
 
        if (protocol != htons(ETH_P_8021Q)) {
                return harmonize_features(skb, protocol, features);
        } else {
                features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
-                               NETIF_F_GEN_CSUM;
+                               NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX;
                return harmonize_features(skb, protocol, features);
        }
 }
@@ -2562,7 +2566,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
 
        map = rcu_dereference(rxqueue->rps_map);
        if (map) {
-               if (map->len == 1) {
+               if (map->len == 1 &&
+                   !rcu_dereference_raw(rxqueue->rps_flow_table)) {
                        tcpu = map->cpus[0];
                        if (cpu_online(tcpu))
                                cpu = tcpu;
@@ -3423,6 +3428,8 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
        __skb_pull(skb, skb_headlen(skb));
        skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
        skb->vlan_tci = 0;
+       skb->dev = napi->dev;
+       skb->skb_iif = 0;
 
        napi->skb = skb;
 }
@@ -5059,6 +5066,7 @@ static void rollback_registered(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        rollback_registered_many(&single);
+       list_del(&single);
 }
 
 unsigned long netdev_fix_features(unsigned long features, const char *name)
@@ -5656,30 +5664,35 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 
        dev_net_set(dev, &init_net);
 
+       dev->gso_max_size = GSO_MAX_SIZE;
+
+       INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
+       dev->ethtool_ntuple_list.count = 0;
+       INIT_LIST_HEAD(&dev->napi_list);
+       INIT_LIST_HEAD(&dev->unreg_list);
+       INIT_LIST_HEAD(&dev->link_watch_list);
+       dev->priv_flags = IFF_XMIT_DST_RELEASE;
+       setup(dev);
+
        dev->num_tx_queues = txqs;
        dev->real_num_tx_queues = txqs;
        if (netif_alloc_netdev_queues(dev))
-               goto free_pcpu;
+               goto free_all;
 
 #ifdef CONFIG_RPS
        dev->num_rx_queues = rxqs;
        dev->real_num_rx_queues = rxqs;
        if (netif_alloc_rx_queues(dev))
-               goto free_pcpu;
+               goto free_all;
 #endif
 
-       dev->gso_max_size = GSO_MAX_SIZE;
-
-       INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
-       dev->ethtool_ntuple_list.count = 0;
-       INIT_LIST_HEAD(&dev->napi_list);
-       INIT_LIST_HEAD(&dev->unreg_list);
-       INIT_LIST_HEAD(&dev->link_watch_list);
-       dev->priv_flags = IFF_XMIT_DST_RELEASE;
-       setup(dev);
        strcpy(dev->name, name);
        return dev;
 
+free_all:
+       free_netdev(dev);
+       return NULL;
+
 free_pcpu:
        free_percpu(dev->pcpu_refcnt);
        kfree(dev->_tx);
@@ -6207,6 +6220,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
                }
        }
        unregister_netdevice_many(&dev_kill_list);
+       list_del(&dev_kill_list);
        rtnl_unlock();
 }
 
index 508f9c1..133fd22 100644 (file)
@@ -144,7 +144,7 @@ void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
 
        list_for_each_entry(ha, &from_list->list, list) {
                type = addr_type ? addr_type : ha->type;
-               __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
+               __hw_addr_del(to_list, ha->addr, addr_len, type);
        }
 }
 EXPORT_SYMBOL(__hw_addr_del_multiple);
index 1774178..ff23029 100644 (file)
@@ -817,7 +817,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
        if (regs.len > reglen)
                regs.len = reglen;
 
-       regbuf = vmalloc(reglen);
+       regbuf = vzalloc(reglen);
        if (!regbuf)
                return -ENOMEM;
 
index a5f7535..2d65c6b 100644 (file)
@@ -1121,8 +1121,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
                                return -EOPNOTSUPP;
 
                        if (af_ops->validate_link_af) {
-                               err = af_ops->validate_link_af(dev,
-                                                       tb[IFLA_AF_SPEC]);
+                               err = af_ops->validate_link_af(dev, af);
                                if (err < 0)
                                        return err;
                        }
@@ -1672,6 +1671,9 @@ replay:
                        snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
 
                dest_net = rtnl_link_get_net(net, tb);
+               if (IS_ERR(dest_net))
+                       return PTR_ERR(dest_net);
+
                dev = rtnl_create_link(net, dest_net, ifname, ops, tb);
 
                if (IS_ERR(dev))
@@ -1820,7 +1822,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
                return -EPERM;
 
-       if (kind == 2 && (nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+       if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
                struct sock *rtnl;
                rtnl_dumpit_func dumpit;
 
index d31bb36..d883dcc 100644 (file)
@@ -210,6 +210,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        shinfo = skb_shinfo(skb);
        memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
 
        if (fclone) {
                struct sk_buff *child = skb + 1;
@@ -2744,8 +2745,12 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 
 merge:
        if (offset > headlen) {
-               skbinfo->frags[0].page_offset += offset - headlen;
-               skbinfo->frags[0].size -= offset - headlen;
+               unsigned int eat = offset - headlen;
+
+               skbinfo->frags[0].page_offset += eat;
+               skbinfo->frags[0].size -= eat;
+               skb->data_len -= eat;
+               skb->len -= eat;
                offset = headlen;
        }
 
index d900ab9..c44348a 100644 (file)
@@ -583,7 +583,7 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
        u8 up, idtype;
        int ret = -EINVAL;
 
-       if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
+       if (!tb[DCB_ATTR_APP])
                goto out;
 
        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
@@ -604,7 +604,16 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
                goto out;
 
        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
-       up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
+
+       if (netdev->dcbnl_ops->getapp) {
+               up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
+       } else {
+               struct dcb_app app = {
+                                       .selector = idtype,
+                                       .protocol = id,
+                                    };
+               up = dcb_getapp(netdev, &app);
+       }
 
        /* send this back */
        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -617,6 +626,9 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
        dcb->cmd = DCB_CMD_GAPP;
 
        app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
+       if (!app_nest)
+               goto out_cancel;
+
        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
        if (ret)
                goto out_cancel;
@@ -1181,7 +1193,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
                        goto err;
        }
 
-       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
+       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
                struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
                err = ops->ieee_setpfc(netdev, pfc);
                if (err)
@@ -1604,6 +1616,10 @@ EXPORT_SYMBOL(dcb_getapp);
 u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
 {
        struct dcb_app_type *itr;
+       struct dcb_app_type event;
+
+       memcpy(&event.name, dev->name, sizeof(event.name));
+       memcpy(&event.app, new, sizeof(event.app));
 
        spin_lock(&dcb_lock);
        /* Search for existing match and replace */
@@ -1635,7 +1651,7 @@ u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
        }
 out:
        spin_unlock(&dcb_lock);
-       call_dcbevent_notifiers(DCB_APP_EVENT, new);
+       call_dcbevent_notifiers(DCB_APP_EVENT, &event);
        return 0;
 }
 EXPORT_SYMBOL(dcb_setapp);
index 8cde009..4222e7a 100644 (file)
@@ -614,6 +614,9 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                /* Caller (dccp_v4_do_rcv) will send Reset */
                dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
                return 1;
+       } else if (sk->sk_state == DCCP_CLOSED) {
+               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
+               return 1;
        }
 
        if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
@@ -668,10 +671,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
        }
 
        switch (sk->sk_state) {
-       case DCCP_CLOSED:
-               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
-               return 1;
-
        case DCCP_REQUESTING:
                queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
                if (queued >= 0)
index 739435a..cfa7a5e 100644 (file)
@@ -67,8 +67,9 @@ dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
        size_t result_len = 0;
        const char *data = _data, *end, *opt;
 
-       kenter("%%%d,%s,'%s',%zu",
-              key->serial, key->description, data, datalen);
+       kenter("%%%d,%s,'%*.*s',%zu",
+              key->serial, key->description,
+              (int)datalen, (int)datalen, data, datalen);
 
        if (datalen <= 1 || !data || data[datalen - 1] != '\0')
                return -EINVAL;
@@ -217,6 +218,19 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
                seq_printf(m, ": %u", key->datalen);
 }
 
+/*
+ * read the DNS data
+ * - the key's semaphore is read-locked
+ */
+static long dns_resolver_read(const struct key *key,
+                             char __user *buffer, size_t buflen)
+{
+       if (key->type_data.x[0])
+               return key->type_data.x[0];
+
+       return user_read(key, buffer, buflen);
+}
+
 struct key_type key_type_dns_resolver = {
        .name           = "dns_resolver",
        .instantiate    = dns_resolver_instantiate,
@@ -224,7 +238,7 @@ struct key_type key_type_dns_resolver = {
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = dns_resolver_describe,
-       .read           = user_read,
+       .read           = dns_resolver_read,
 };
 
 static int __init init_dns_resolver(void)
index 0c877a7..3fb14b7 100644 (file)
@@ -428,7 +428,7 @@ static void __exit dsa_cleanup_module(void)
 }
 module_exit(dsa_cleanup_module);
 
-MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>")
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
 MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:dsa");
index 15dcc1a..0c28263 100644 (file)
@@ -265,13 +265,13 @@ static void ec_tx_done(struct sk_buff *skb, int result)
 static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                          struct msghdr *msg, size_t len)
 {
-       struct sock *sk = sock->sk;
        struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
        struct net_device *dev;
        struct ec_addr addr;
        int err;
        unsigned char port, cb;
 #if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
+       struct sock *sk = sock->sk;
        struct sk_buff *skb;
        struct ec_cb *eb;
 #endif
@@ -488,10 +488,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
 error_free_buf:
        vfree(userbuf);
+error:
 #else
        err = -EPROTOTYPE;
 #endif
-       error:
        mutex_unlock(&econet_mutex);
 
        return err;
index f2b6110..45b89d7 100644 (file)
@@ -880,6 +880,19 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 }
 EXPORT_SYMBOL(inet_ioctl);
 
+#ifdef CONFIG_COMPAT
+int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+       int err = -ENOIOCTLCMD;
+
+       if (sk->sk_prot->compat_ioctl)
+               err = sk->sk_prot->compat_ioctl(sk, cmd, arg);
+
+       return err;
+}
+#endif
+
 const struct proto_ops inet_stream_ops = {
        .family            = PF_INET,
        .owner             = THIS_MODULE,
@@ -903,6 +916,7 @@ const struct proto_ops inet_stream_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 EXPORT_SYMBOL(inet_stream_ops);
@@ -929,6 +943,7 @@ const struct proto_ops inet_dgram_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 EXPORT_SYMBOL(inet_dgram_ops);
@@ -959,6 +974,7 @@ static const struct proto_ops inet_sockraw_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 
index 04c8b69..7927589 100644 (file)
@@ -1017,14 +1017,13 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
                IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
                return 0;
        }
-       if (__in_dev_get_rcu(dev)) {
-               IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
+       if (__in_dev_get_rtnl(dev)) {
+               IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
                return 0;
        }
        return -ENXIO;
 }
 
-/* must be called with rcu_read_lock() */
 static int arp_req_set_public(struct net *net, struct arpreq *r,
                struct net_device *dev)
 {
@@ -1233,10 +1232,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        if (!(r.arp_flags & ATF_NETMASK))
                ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
                                                           htonl(0xFFFFFFFFUL);
-       rcu_read_lock();
+       rtnl_lock();
        if (r.arp_dev[0]) {
                err = -ENODEV;
-               dev = dev_get_by_name_rcu(net, r.arp_dev);
+               dev = __dev_get_by_name(net, r.arp_dev);
                if (dev == NULL)
                        goto out;
 
@@ -1263,7 +1262,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                break;
        }
 out:
-       rcu_read_unlock();
+       rtnl_unlock();
        if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
                err = -EFAULT;
        return err;
index 748cb5b..df4616f 100644 (file)
@@ -1030,6 +1030,21 @@ static inline bool inetdev_valid_mtu(unsigned mtu)
        return mtu >= 68;
 }
 
+static void inetdev_send_gratuitous_arp(struct net_device *dev,
+                                       struct in_device *in_dev)
+
+{
+       struct in_ifaddr *ifa = in_dev->ifa_list;
+
+       if (!ifa)
+               return;
+
+       arp_send(ARPOP_REQUEST, ETH_P_ARP,
+                ifa->ifa_address, dev,
+                ifa->ifa_address, NULL,
+                dev->dev_addr, NULL);
+}
+
 /* Called only under RTNL semaphore */
 
 static int inetdev_event(struct notifier_block *this, unsigned long event,
@@ -1082,18 +1097,13 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
                }
                ip_mc_up(in_dev);
                /* fall through */
-       case NETDEV_NOTIFY_PEERS:
        case NETDEV_CHANGEADDR:
+               if (!IN_DEV_ARP_NOTIFY(in_dev))
+                       break;
+               /* fall through */
+       case NETDEV_NOTIFY_PEERS:
                /* Send gratuitous ARP to notify of link change */
-               if (IN_DEV_ARP_NOTIFY(in_dev)) {
-                       struct in_ifaddr *ifa = in_dev->ifa_list;
-
-                       if (ifa)
-                               arp_send(ARPOP_REQUEST, ETH_P_ARP,
-                                        ifa->ifa_address, dev,
-                                        ifa->ifa_address, NULL,
-                                        dev->dev_addr, NULL);
-               }
+               inetdev_send_gratuitous_arp(dev, in_dev);
                break;
        case NETDEV_DOWN:
                ip_mc_down(in_dev);
index 2746c1f..2ada171 100644 (file)
@@ -858,7 +858,7 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
            nlmsg_len(nlh) < hdrlen)
                return -EINVAL;
 
-       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
                if (nlmsg_attrlen(nlh, hdrlen)) {
                        struct nlattr *attr;
 
index c5af909..3c8dfa1 100644 (file)
@@ -505,7 +505,9 @@ restart:
                        }
 
                        rcu_read_unlock();
+                       local_bh_disable();
                        inet_twsk_deschedule(tw, twdr);
+                       local_bh_enable();
                        inet_twsk_put(tw);
                        goto restart_rcu;
                }
index d9bc857..a96e656 100644 (file)
@@ -475,7 +475,7 @@ static int cleanup_once(unsigned long ttl)
 struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
 {
        struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
-       struct inet_peer_base *base = family_to_base(AF_INET);
+       struct inet_peer_base *base = family_to_base(daddr->family);
        struct inet_peer *p;
 
        /* Look up for the address quickly, lockless.
index eb68a0e..6613edf 100644 (file)
@@ -775,6 +775,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                        .fl4_dst = dst,
                        .fl4_src = tiph->saddr,
                        .fl4_tos = RT_TOS(tos),
+                       .proto = IPPROTO_GRE,
                        .fl_gre_key = tunnel->parms.o_key
                };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
index 3f3a9af..8b65a12 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/notifier.h>
 #include <linux/if_arp.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/compat.h>
 #include <net/ipip.h>
 #include <net/checksum.h>
 #include <net/netlink.h>
@@ -1434,6 +1435,81 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_sioc_sg_req {
+       struct in_addr src;
+       struct in_addr grp;
+       compat_ulong_t pktcnt;
+       compat_ulong_t bytecnt;
+       compat_ulong_t wrong_if;
+};
+
+struct compat_sioc_vif_req {
+       vifi_t  vifi;           /* Which iface */
+       compat_ulong_t icount;
+       compat_ulong_t ocount;
+       compat_ulong_t ibytes;
+       compat_ulong_t obytes;
+};
+
+int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
+{
+       struct compat_sioc_sg_req sr;
+       struct compat_sioc_vif_req vr;
+       struct vif_device *vif;
+       struct mfc_cache *c;
+       struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
+
+       switch (cmd) {
+       case SIOCGETVIFCNT:
+               if (copy_from_user(&vr, arg, sizeof(vr)))
+                       return -EFAULT;
+               if (vr.vifi >= mrt->maxvif)
+                       return -EINVAL;
+               read_lock(&mrt_lock);
+               vif = &mrt->vif_table[vr.vifi];
+               if (VIF_EXISTS(mrt, vr.vifi)) {
+                       vr.icount = vif->pkt_in;
+                       vr.ocount = vif->pkt_out;
+                       vr.ibytes = vif->bytes_in;
+                       vr.obytes = vif->bytes_out;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &vr, sizeof(vr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       case SIOCGETSGCNT:
+               if (copy_from_user(&sr, arg, sizeof(sr)))
+                       return -EFAULT;
+
+               rcu_read_lock();
+               c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
+               if (c) {
+                       sr.pktcnt = c->mfc_un.res.pkt;
+                       sr.bytecnt = c->mfc_un.res.bytes;
+                       sr.wrong_if = c->mfc_un.res.wrong_if;
+                       rcu_read_unlock();
+
+                       if (copy_to_user(arg, &sr, sizeof(sr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               rcu_read_unlock();
+               return -EADDRNOTAVAIL;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
+
 
 static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
index b8ddcc4..a5e52a9 100644 (file)
@@ -60,12 +60,12 @@ static int checkentry(const struct xt_tgchk_param *par)
 
        if (mangle->flags & ~ARPT_MANGLE_MASK ||
            !(mangle->flags & ARPT_MANGLE_MASK))
-               return false;
+               return -EINVAL;
 
        if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
           mangle->target != XT_CONTINUE)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target arpt_mangle_reg __read_mostly = {
index a3d5ab7..6390ba2 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/seq_file.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/compat.h>
 
 static struct raw_hashinfo raw_v4_hashinfo = {
        .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
@@ -838,6 +839,23 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       case SIOCINQ:
+               return -ENOIOCTLCMD;
+       default:
+#ifdef CONFIG_IP_MROUTE
+               return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg));
+#else
+               return -ENOIOCTLCMD;
+#endif
+       }
+}
+#endif
+
 struct proto raw_prot = {
        .name              = "RAW",
        .owner             = THIS_MODULE,
@@ -860,6 +878,7 @@ struct proto raw_prot = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_raw_setsockopt,
        .compat_getsockopt = compat_raw_getsockopt,
+       .compat_ioctl      = compat_raw_ioctl,
 #endif
 };
 
index 351dc4e..6ed6603 100644 (file)
@@ -2707,6 +2707,11 @@ static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 coo
        return NULL;
 }
 
+static unsigned int ipv4_blackhole_default_mtu(const struct dst_entry *dst)
+{
+       return 0;
+}
+
 static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
@@ -2716,6 +2721,8 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
        .protocol               =       cpu_to_be16(ETH_P_IP),
        .destroy                =       ipv4_dst_destroy,
        .check                  =       ipv4_blackhole_dst_check,
+       .default_mtu            =       ipv4_blackhole_default_mtu,
+       .default_advmss         =       ipv4_default_advmss,
        .update_pmtu            =       ipv4_rt_blackhole_update_pmtu,
 };
 
index 2549b29..65f6c04 100644 (file)
@@ -1222,7 +1222,7 @@ static int tcp_check_dsack(struct sock *sk, struct sk_buff *ack_skb,
        }
 
        /* D-SACK for already forgotten data... Do dumb counting. */
-       if (dup_sack &&
+       if (dup_sack && tp->undo_marker && tp->undo_retrans &&
            !after(end_seq_0, prior_snd_una) &&
            after(end_seq_0, tp->undo_marker))
                tp->undo_retrans--;
@@ -1299,7 +1299,8 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
 
        /* Account D-SACK for retransmitted packet. */
        if (dup_sack && (sacked & TCPCB_RETRANS)) {
-               if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
+               if (tp->undo_marker && tp->undo_retrans &&
+                   after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
                        tp->undo_retrans--;
                if (sacked & TCPCB_SACKED_ACKED)
                        state->reord = min(fack_count, state->reord);
@@ -4399,7 +4400,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
                                tp->ucopy.len -= chunk;
                                tp->copied_seq += chunk;
-                               eaten = (chunk == skb->len && !th->fin);
+                               eaten = (chunk == skb->len);
                                tcp_rcv_space_adjust(sk);
                        }
                        local_bh_disable();
index 856f684..02f583b 100644 (file)
@@ -1994,7 +1994,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
                                }
                                req = req->dl_next;
                        }
-                       st->offset = 0;
                        if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
                                break;
 get_req:
index 406f320..dfa5beb 100644 (file)
@@ -2162,7 +2162,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                if (!tp->retrans_stamp)
                        tp->retrans_stamp = TCP_SKB_CB(skb)->when;
 
-               tp->undo_retrans++;
+               tp->undo_retrans += tcp_skb_pcount(skb);
 
                /* snd_nxt is stored to detect loss of retransmitted segment,
                 * see tcp_input.c tcp_sacktag_write_queue().
index 5b189c9..fd6782e 100644 (file)
@@ -420,9 +420,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
            dev->type == ARPHRD_TUNNEL6 ||
            dev->type == ARPHRD_SIT ||
            dev->type == ARPHRD_NONE) {
-               printk(KERN_INFO
-                      "%s: Disabled Privacy Extensions\n",
-                      dev->name);
                ndev->cnf.use_tempaddr = -1;
        } else {
                in6_dev_hold(ndev);
@@ -2664,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        struct net *net = dev_net(dev);
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa;
-       LIST_HEAD(keep_list);
-       int state;
+       int state, i;
 
        ASSERT_RTNL();
 
-       /* Flush routes if device is being removed or it is not loopback */
-       if (how || !(dev->flags & IFF_LOOPBACK))
-               rt6_ifdown(net, dev);
+       rt6_ifdown(net, dev);
+       neigh_ifdown(&nd_tbl, dev);
 
        idev = __in6_dev_get(dev);
        if (idev == NULL)
@@ -2692,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        }
 
+       /* Step 2: clear hash table */
+       for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+               struct hlist_head *h = &inet6_addr_lst[i];
+               struct hlist_node *n;
+
+               spin_lock_bh(&addrconf_hash_lock);
+       restart:
+               hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
+                       if (ifa->idev == idev) {
+                               hlist_del_init_rcu(&ifa->addr_lst);
+                               addrconf_del_timer(ifa);
+                               goto restart;
+                       }
+               }
+               spin_unlock_bh(&addrconf_hash_lock);
+       }
+
        write_lock_bh(&idev->lock);
 
        /* Step 2: clear flags for stateless addrconf */
@@ -2725,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                                       struct inet6_ifaddr, if_list);
                addrconf_del_timer(ifa);
 
-               /* If just doing link down, and address is permanent
-                  and not link-local, then retain it. */
-               if (!how &&
-                   (ifa->flags&IFA_F_PERMANENT) &&
-                   !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
-                       list_move_tail(&ifa->if_list, &keep_list);
-
-                       /* If not doing DAD on this address, just keep it. */
-                       if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
-                           idev->cnf.accept_dad <= 0 ||
-                           (ifa->flags & IFA_F_NODAD))
-                               continue;
+               list_del(&ifa->if_list);
 
-                       /* If it was tentative already, no need to notify */
-                       if (ifa->flags & IFA_F_TENTATIVE)
-                               continue;
+               write_unlock_bh(&idev->lock);
 
-                       /* Flag it for later restoration when link comes up */
-                       ifa->flags |= IFA_F_TENTATIVE;
-                       ifa->state = INET6_IFADDR_STATE_DAD;
-               } else {
-                       list_del(&ifa->if_list);
-
-                       /* clear hash table */
-                       spin_lock_bh(&addrconf_hash_lock);
-                       hlist_del_init_rcu(&ifa->addr_lst);
-                       spin_unlock_bh(&addrconf_hash_lock);
-
-                       write_unlock_bh(&idev->lock);
-                       spin_lock_bh(&ifa->state_lock);
-                       state = ifa->state;
-                       ifa->state = INET6_IFADDR_STATE_DEAD;
-                       spin_unlock_bh(&ifa->state_lock);
-
-                       if (state != INET6_IFADDR_STATE_DEAD) {
-                               __ipv6_ifa_notify(RTM_DELADDR, ifa);
-                               atomic_notifier_call_chain(&inet6addr_chain,
-                                                          NETDEV_DOWN, ifa);
-                       }
+               spin_lock_bh(&ifa->state_lock);
+               state = ifa->state;
+               ifa->state = INET6_IFADDR_STATE_DEAD;
+               spin_unlock_bh(&ifa->state_lock);
 
-                       in6_ifa_put(ifa);
-                       write_lock_bh(&idev->lock);
+               if (state != INET6_IFADDR_STATE_DEAD) {
+                       __ipv6_ifa_notify(RTM_DELADDR, ifa);
+                       atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
                }
-       }
+               in6_ifa_put(ifa);
 
-       list_splice(&keep_list, &idev->addr_list);
+               write_lock_bh(&idev->lock);
+       }
 
        write_unlock_bh(&idev->lock);
 
@@ -4159,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                addrconf_leave_solict(ifp->idev, &ifp->addr);
                dst_hold(&ifp->rt->dst);
 
-               if (ifp->state == INET6_IFADDR_STATE_DEAD &&
-                   ip6_del_rt(ifp->rt))
+               if (ip6_del_rt(ifp->rt))
                        dst_free(&ifp->rt->dst);
                break;
        }
index 9fab274..0e1d53b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -1804,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_sioc_sg_req6 {
+       struct sockaddr_in6 src;
+       struct sockaddr_in6 grp;
+       compat_ulong_t pktcnt;
+       compat_ulong_t bytecnt;
+       compat_ulong_t wrong_if;
+};
+
+struct compat_sioc_mif_req6 {
+       mifi_t  mifi;
+       compat_ulong_t icount;
+       compat_ulong_t ocount;
+       compat_ulong_t ibytes;
+       compat_ulong_t obytes;
+};
+
+int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
+{
+       struct compat_sioc_sg_req6 sr;
+       struct compat_sioc_mif_req6 vr;
+       struct mif_device *vif;
+       struct mfc6_cache *c;
+       struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
+
+       switch (cmd) {
+       case SIOCGETMIFCNT_IN6:
+               if (copy_from_user(&vr, arg, sizeof(vr)))
+                       return -EFAULT;
+               if (vr.mifi >= mrt->maxvif)
+                       return -EINVAL;
+               read_lock(&mrt_lock);
+               vif = &mrt->vif6_table[vr.mifi];
+               if (MIF_EXISTS(mrt, vr.mifi)) {
+                       vr.icount = vif->pkt_in;
+                       vr.ocount = vif->pkt_out;
+                       vr.ibytes = vif->bytes_in;
+                       vr.obytes = vif->bytes_out;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &vr, sizeof(vr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       case SIOCGETSGCNT_IN6:
+               if (copy_from_user(&sr, arg, sizeof(sr)))
+                       return -EFAULT;
+
+               read_lock(&mrt_lock);
+               c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
+               if (c) {
+                       sr.pktcnt = c->mfc_un.res.pkt;
+                       sr.bytecnt = c->mfc_un.res.bytes;
+                       sr.wrong_if = c->mfc_un.res.wrong_if;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &sr, sizeof(sr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
 
 static inline int ip6mr_forward2_finish(struct sk_buff *skb)
 {
index 09c8889..de33803 100644 (file)
@@ -410,7 +410,7 @@ fallback:
                if (p != NULL) {
                        sb_add(m, "%02x", *p++);
                        for (i = 1; i < len; i++)
-                               sb_add(m, ":%02x", p[i]);
+                               sb_add(m, ":%02x", *p++);
                }
                sb_add(m, " ");
 
index 86c3952..c5b0915 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/skbuff.h>
+#include <linux/compat.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -1157,6 +1158,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       case SIOCINQ:
+               return -ENOIOCTLCMD;
+       default:
+#ifdef CONFIG_IPV6_MROUTE
+               return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
+#else
+               return -ENOIOCTLCMD;
+#endif
+       }
+}
+#endif
+
 static void rawv6_close(struct sock *sk, long timeout)
 {
        if (inet_sk(sk)->inet_num == IPPROTO_RAW)
@@ -1215,6 +1233,7 @@ struct proto rawv6_prot = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_rawv6_setsockopt,
        .compat_getsockopt = compat_rawv6_getsockopt,
+       .compat_ioctl      = compat_rawv6_ioctl,
 #endif
 };
 
index 373bd04..904312e 100644 (file)
@@ -72,8 +72,6 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-#define CLONE_OFFLINK_ROUTE 0
-
 static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
 static struct dst_entry        *ip6_dst_check(struct dst_entry *dst, u32 cookie);
 static unsigned int     ip6_default_advmss(const struct dst_entry *dst);
@@ -115,6 +113,11 @@ static struct dst_ops ip6_dst_ops_template = {
        .local_out              =       __ip6_local_out,
 };
 
+static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst)
+{
+       return 0;
+}
+
 static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
@@ -124,6 +127,8 @@ static struct dst_ops ip6_dst_blackhole_ops = {
        .protocol               =       cpu_to_be16(ETH_P_IPV6),
        .destroy                =       ip6_dst_destroy,
        .check                  =       ip6_dst_check,
+       .default_mtu            =       ip6_blackhole_default_mtu,
+       .default_advmss         =       ip6_default_advmss,
        .update_pmtu            =       ip6_rt_blackhole_update_pmtu,
 };
 
@@ -196,7 +201,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
                in6_dev_put(idev);
        }
        if (peer) {
-               BUG_ON(!(rt->rt6i_flags & RTF_CACHE));
                rt->rt6i_peer = NULL;
                inet_putpeer(peer);
        }
@@ -206,9 +210,6 @@ void rt6_bind_peer(struct rt6_info *rt, int create)
 {
        struct inet_peer *peer;
 
-       if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE)))
-               return;
-
        peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
        if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
                inet_putpeer(peer);
@@ -738,13 +739,8 @@ restart:
 
        if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
                nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
-       else {
-#if CLONE_OFFLINK_ROUTE
+       else
                nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
-#else
-               goto out2;
-#endif
-       }
 
        dst_release(&rt->dst);
        rt = nrt ? : net->ipv6.ip6_null_entry;
@@ -2561,14 +2557,16 @@ static
 int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
                              void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       struct net *net = current->nsproxy->net_ns;
-       int delay = net->ipv6.sysctl.flush_delay;
-       if (write) {
-               proc_dointvec(ctl, write, buffer, lenp, ppos);
-               fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
-               return 0;
-       } else
+       struct net *net;
+       int delay;
+       if (!write)
                return -EINVAL;
+
+       net = (struct net *)ctl->extra1;
+       delay = net->ipv6.sysctl.flush_delay;
+       proc_dointvec(ctl, write, buffer, lenp, ppos);
+       fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
+       return 0;
 }
 
 ctl_table ipv6_route_table_template[] = {
@@ -2655,6 +2653,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
 
        if (table) {
                table[0].data = &net->ipv6.sysctl.flush_delay;
+               table[0].extra1 = net;
                table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
                table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
                table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
index fa1d8f4..7cb65ef 100644 (file)
@@ -15,6 +15,8 @@
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
 
+static struct ctl_table empty[1];
+
 static ctl_table ipv6_table_template[] = {
        {
                .procname       = "route",
@@ -35,6 +37,12 @@ static ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "neigh",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = empty,
+       },
        { }
 };
 
@@ -152,7 +160,6 @@ static struct ctl_table_header *ip6_base;
 
 int ipv6_static_sysctl_register(void)
 {
-       static struct ctl_table empty[1];
        ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty);
        if (ip6_base == NULL)
                return -ENOMEM;
index 7e74023..da87428 100644 (file)
@@ -98,6 +98,10 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        if (!xdst->u.rt6.rt6i_idev)
                return -ENODEV;
 
+       xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
+       if (rt->rt6i_peer)
+               atomic_inc(&rt->rt6i_peer->refcnt);
+
        /* Sheit... I remember I did this right. Apparently,
         * it was magically lost, so this code needs audit */
        xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
@@ -216,6 +220,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
 
        if (likely(xdst->u.rt6.rt6i_idev))
                in6_dev_put(xdst->u.rt6.rt6i_idev);
+       if (likely(xdst->u.rt6.rt6i_peer))
+               inet_putpeer(xdst->u.rt6.rt6i_peer);
        xfrm_dst_destroy(xdst);
 }
 
index 9109262..c766056 100644 (file)
@@ -20,7 +20,7 @@ config MAC80211_HAS_RC
        def_bool n
 
 config MAC80211_RC_PID
-       bool "PID controller based rate control algorithm" if EMBEDDED
+       bool "PID controller based rate control algorithm" if EXPERT
        select MAC80211_HAS_RC
        ---help---
          This option enables a TX rate control algorithm for
@@ -28,14 +28,14 @@ config MAC80211_RC_PID
          rate.
 
 config MAC80211_RC_MINSTREL
-       bool "Minstrel" if EMBEDDED
+       bool "Minstrel" if EXPERT
        select MAC80211_HAS_RC
        default y
        ---help---
          This option enables the 'minstrel' TX rate control algorithm
 
 config MAC80211_RC_MINSTREL_HT
-       bool "Minstrel 802.11n support" if EMBEDDED
+       bool "Minstrel 802.11n support" if EXPERT
        depends on MAC80211_RC_MINSTREL
        default y
        ---help---
index f138b19..227ca82 100644 (file)
@@ -185,8 +185,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len)
 {
-       struct ieee80211_hw *hw = &local->hw;
-       struct ieee80211_conf *conf = &hw->conf;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
        u8 dialog_token;
@@ -231,13 +229,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                goto end_no_lock;
        }
        /* determine default buffer size */
-       if (buf_size == 0) {
-               struct ieee80211_supported_band *sband;
-
-               sband = local->hw.wiphy->bands[conf->channel->band];
-               buf_size = IEEE80211_MIN_AMPDU_BUF;
-               buf_size = buf_size << sband->ht_cap.ampdu_factor;
-       }
+       if (buf_size == 0)
+               buf_size = IEEE80211_MAX_AMPDU_BUF;
 
 
        /* examine state machine */
index 4bc8a92..9cd73b1 100644 (file)
@@ -1822,6 +1822,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                *cookie ^= 2;
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
                local->hw_roc_skb = skb;
+               local->hw_roc_skb_for_status = skb;
                mutex_unlock(&local->mtx);
 
                return 0;
@@ -1875,6 +1876,7 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
                if (ret == 0) {
                        kfree_skb(local->hw_roc_skb);
                        local->hw_roc_skb = NULL;
+                       local->hw_roc_skb_for_status = NULL;
                }
 
                mutex_unlock(&local->mtx);
index c47d7c0..533fd32 100644 (file)
@@ -953,7 +953,7 @@ struct ieee80211_local {
 
        struct ieee80211_channel *hw_roc_channel;
        struct net_device *hw_roc_dev;
-       struct sk_buff *hw_roc_skb;
+       struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
        struct work_struct hw_roc_start, hw_roc_done;
        enum nl80211_channel_type hw_roc_channel_type;
        unsigned int hw_roc_duration;
index 8acba45..7a10a8d 100644 (file)
@@ -1229,6 +1229,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
        }
        mutex_unlock(&local->iflist_mtx);
        unregister_netdevice_many(&unreg_list);
+       list_del(&unreg_list);
 }
 
 static u32 ieee80211_idle_off(struct ieee80211_local *local,
index 485d36b..a46ff06 100644 (file)
@@ -39,6 +39,8 @@ module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
 MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
                 "Disable 40MHz support in the 2.4GHz band");
 
+static struct lock_class_key ieee80211_rx_skb_queue_class;
+
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
        u64 mc;
@@ -569,7 +571,15 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        spin_lock_init(&local->filter_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
-       skb_queue_head_init(&local->rx_skb_queue);
+       /*
+        * The rx_skb_queue is only accessed from tasklets,
+        * but other SKB queues are used from within IRQ
+        * context. Therefore, this one needs a different
+        * locking class so our direct, non-irq-safe use of
+        * the queue's lock doesn't throw lockdep warnings.
+        */
+       skb_queue_head_init_class(&local->rx_skb_queue,
+                                 &ieee80211_rx_skb_queue_class);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
index 45fbb9e..c9ceb4d 100644 (file)
@@ -1033,6 +1033,12 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
        if (is_multicast_ether_addr(hdr->addr1))
                return;
 
+       /*
+        * In case we receive frames after disassociation.
+        */
+       if (!sdata->u.mgd.associated)
+               return;
+
        ieee80211_sta_reset_conn_monitor(sdata);
 }
 
index 38a7972..071ac95 100644 (file)
@@ -323,6 +323,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
                struct ieee80211_work *wk;
+               u64 cookie = (unsigned long)skb;
 
                rcu_read_lock();
                list_for_each_entry_rcu(wk, &local->work_list, list) {
@@ -334,8 +335,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        break;
                }
                rcu_read_unlock();
+               if (local->hw_roc_skb_for_status == skb) {
+                       cookie = local->hw_roc_cookie ^ 2;
+                       local->hw_roc_skb_for_status = NULL;
+               }
                cfg80211_mgmt_tx_status(
-                       skb->dev, (unsigned long) skb, skb->data, skb->len,
+                       skb->dev, cookie, skb->data, skb->len,
                        !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
        }
 
index 5950e3a..b0beaa5 100644 (file)
@@ -1547,7 +1547,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
                skb_orphan(skb);
        }
 
-       if (skb_header_cloned(skb))
+       if (skb_cloned(skb))
                I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
        else if (head_need || tail_need)
                I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -2230,6 +2230,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 
        sdata = vif_to_sdata(vif);
 
+       if (!ieee80211_sdata_running(sdata))
+               goto out;
+
        if (tim_offset)
                *tim_offset = 0;
        if (tim_length)
index cf68700..d036597 100644 (file)
@@ -1210,7 +1210,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC;
+                       mutex_lock(&sdata->u.mgd.mtx);
                        ieee80211_bss_info_change_notify(sdata, changed);
+                       mutex_unlock(&sdata->u.mgd.mtx);
                        break;
                case NL80211_IFTYPE_ADHOC:
                        changed |= BSS_CHANGED_IBSS;
index 32fcbe2..4aa614b 100644 (file)
@@ -133,6 +133,7 @@ unsigned int nf_iterate(struct list_head *head,
 
                /* Optimization: we don't need to hold module
                   reference here, since function can't sleep. --RR */
+repeat:
                verdict = elem->hook(hook, skb, indev, outdev, okfn);
                if (verdict != NF_ACCEPT) {
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -145,7 +146,7 @@ unsigned int nf_iterate(struct list_head *head,
 #endif
                        if (verdict != NF_REPEAT)
                                return verdict;
-                       *i = (*i)->prev;
+                       goto repeat;
                }
        }
        return NF_ACCEPT;
index 22f7ad5..ba98e13 100644 (file)
@@ -808,9 +808,9 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        dest->u_threshold = udest->u_threshold;
        dest->l_threshold = udest->l_threshold;
 
-       spin_lock(&dest->dst_lock);
+       spin_lock_bh(&dest->dst_lock);
        ip_vs_dst_reset(dest);
-       spin_unlock(&dest->dst_lock);
+       spin_unlock_bh(&dest->dst_lock);
 
        if (add)
                ip_vs_new_estimator(&dest->stats);
index e615119..84f4fcc 100644 (file)
@@ -942,8 +942,15 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
        if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
                nf_conntrack_event_cache(IPCT_REPLY, ct);
 out:
-       if (tmpl)
-               nf_ct_put(tmpl);
+       if (tmpl) {
+               /* Special case: we have to repeat this hook, assign the
+                * template again to this packet. We assume that this packet
+                * has no conntrack assigned. This is used by nf_ct_tcp. */
+               if (ret == NF_REPEAT)
+                       skb->nfct = (struct nf_conntrack *)tmpl;
+               else
+                       nf_ct_put(tmpl);
+       }
 
        return ret;
 }
index 5702de3..63a1b91 100644 (file)
@@ -63,6 +63,9 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
                 * this does not harm and it happens very rarely. */
                unsigned long missed = e->missed;
 
+               if (!((events | missed) & e->ctmask))
+                       goto out_unlock;
+
                ret = notify->fcn(events | missed, &item);
                if (unlikely(ret < 0 || missed)) {
                        spin_lock_bh(&ct->lock);
index 2b7eef3..eead9db 100644 (file)
@@ -667,6 +667,7 @@ restart:
                        if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                                cb->nlh->nlmsg_seq,
                                                IPCTNL_MSG_CT_NEW, ct) < 0) {
+                               nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
                                goto out;
                        }
@@ -924,7 +925,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
        u16 zone;
        int err;
 
-       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
+       if (nlh->nlmsg_flags & NLM_F_DUMP)
                return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
                                          ctnetlink_done);
 
@@ -1787,7 +1788,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
        u16 zone;
        int err;
 
-       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
                return netlink_dump_start(ctnl, skb, nlh,
                                          ctnetlink_exp_dump_table,
                                          ctnetlink_exp_done);
index b07393e..9181699 100644 (file)
@@ -85,6 +85,8 @@ EXPORT_SYMBOL(nf_log_unregister);
 
 int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
 {
+       if (pf >= ARRAY_SIZE(nf_loggers))
+               return -EINVAL;
        mutex_lock(&nf_log_mutex);
        if (__find_logger(pf, logger->name) == NULL) {
                mutex_unlock(&nf_log_mutex);
@@ -98,6 +100,8 @@ EXPORT_SYMBOL(nf_log_bind_pf);
 
 void nf_log_unbind_pf(u_int8_t pf)
 {
+       if (pf >= ARRAY_SIZE(nf_loggers))
+               return;
        mutex_lock(&nf_log_mutex);
        rcu_assign_pointer(nf_loggers[pf], NULL);
        mutex_unlock(&nf_log_mutex);
index 4d87bef..474d621 100644 (file)
@@ -28,26 +28,23 @@ nf_tproxy_destructor(struct sk_buff *skb)
        skb->destructor = NULL;
 
        if (sk)
-               nf_tproxy_put_sock(sk);
+               sock_put(sk);
 }
 
 /* consumes sk */
-int
+void
 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
 {
-       bool transparent = (sk->sk_state == TCP_TIME_WAIT) ?
-                               inet_twsk(sk)->tw_transparent :
-                               inet_sk(sk)->transparent;
-
-       if (transparent) {
-               skb_orphan(skb);
-               skb->sk = sk;
-               skb->destructor = nf_tproxy_destructor;
-               return 1;
-       } else
-               nf_tproxy_put_sock(sk);
-
-       return 0;
+       /* assigning tw sockets complicates things; most
+        * skb->sk->X checks would have to test sk->sk_state first */
+       if (sk->sk_state == TCP_TIME_WAIT) {
+               inet_twsk_put(inet_twsk(sk));
+               return;
+       }
+
+       skb_orphan(skb);
+       skb->sk = sk;
+       skb->destructor = nf_tproxy_destructor;
 }
 EXPORT_SYMBOL_GPL(nf_tproxy_assign_sock);
 
index 640678f..dcfd57e 100644 (file)
 #include <net/netfilter/nf_tproxy_core.h>
 #include <linux/netfilter/xt_TPROXY.h>
 
+static bool tproxy_sk_is_transparent(struct sock *sk)
+{
+       if (sk->sk_state != TCP_TIME_WAIT) {
+               if (inet_sk(sk)->transparent)
+                       return true;
+               sock_put(sk);
+       } else {
+               if (inet_twsk(sk)->tw_transparent)
+                       return true;
+               inet_twsk_put(inet_twsk(sk));
+       }
+       return false;
+}
+
 static inline __be32
 tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
 {
@@ -141,7 +155,7 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
                                           skb->dev, NFT_LOOKUP_LISTENER);
 
        /* NOTE: assign_sock consumes our sk reference */
-       if (sk && nf_tproxy_assign_sock(skb, sk)) {
+       if (sk && tproxy_sk_is_transparent(sk)) {
                /* This should be in a separate target, but we don't do multiple
                   targets on the same rule yet */
                skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
@@ -149,6 +163,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
                pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
                         iph->protocol, &iph->daddr, ntohs(hp->dest),
                         &laddr, ntohs(lport), skb->mark);
+
+               nf_tproxy_assign_sock(skb, sk);
                return NF_ACCEPT;
        }
 
@@ -306,7 +322,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
                                           par->in, NFT_LOOKUP_LISTENER);
 
        /* NOTE: assign_sock consumes our sk reference */
-       if (sk && nf_tproxy_assign_sock(skb, sk)) {
+       if (sk && tproxy_sk_is_transparent(sk)) {
                /* This should be in a separate target, but we don't do multiple
                   targets on the same rule yet */
                skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
@@ -314,6 +330,8 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
                pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
                         tproto, &iph->saddr, ntohs(hp->source),
                         laddr, ntohs(lport), skb->mark);
+
+               nf_tproxy_assign_sock(skb, sk);
                return NF_ACCEPT;
        }
 
index 88f7c35..73c33a4 100644 (file)
@@ -53,15 +53,13 @@ iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
 }
 
 static inline int
-iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b)
+iprange_ipv6_lt(const struct in6_addr *a, const struct in6_addr *b)
 {
        unsigned int i;
-       int r;
 
        for (i = 0; i < 4; ++i) {
-               r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]);
-               if (r != 0)
-                       return r;
+               if (a->s6_addr32[i] != b->s6_addr32[i])
+                       return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]);
        }
 
        return 0;
@@ -75,15 +73,15 @@ iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
        bool m;
 
        if (info->flags & IPRANGE_SRC) {
-               m  = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0;
-               m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0;
+               m  = iprange_ipv6_lt(&iph->saddr, &info->src_min.in6);
+               m |= iprange_ipv6_lt(&info->src_max.in6, &iph->saddr);
                m ^= !!(info->flags & IPRANGE_SRC_INV);
                if (m)
                        return false;
        }
        if (info->flags & IPRANGE_DST) {
-               m  = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0;
-               m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0;
+               m  = iprange_ipv6_lt(&iph->daddr, &info->dst_min.in6);
+               m |= iprange_ipv6_lt(&info->dst_max.in6, &iph->daddr);
                m ^= !!(info->flags & IPRANGE_DST_INV);
                if (m)
                        return false;
index 00d6ae8..9cc4635 100644 (file)
 #include <net/netfilter/nf_conntrack.h>
 #endif
 
+static void
+xt_socket_put_sk(struct sock *sk)
+{
+       if (sk->sk_state == TCP_TIME_WAIT)
+               inet_twsk_put(inet_twsk(sk));
+       else
+               sock_put(sk);
+}
+
 static int
 extract_icmp4_fields(const struct sk_buff *skb,
                    u8 *protocol,
@@ -164,7 +173,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
                                       (sk->sk_state == TCP_TIME_WAIT &&
                                        inet_twsk(sk)->tw_transparent));
 
-               nf_tproxy_put_sock(sk);
+               xt_socket_put_sk(sk);
 
                if (wildcard || !transparent)
                        sk = NULL;
@@ -298,7 +307,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
                                       (sk->sk_state == TCP_TIME_WAIT &&
                                        inet_twsk(sk)->tw_transparent));
 
-               nf_tproxy_put_sock(sk);
+               xt_socket_put_sk(sk);
 
                if (wildcard || !transparent)
                        sk = NULL;
index 478181d..1f92459 100644 (file)
@@ -1407,7 +1407,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        int noblock = flags&MSG_DONTWAIT;
        size_t copied;
        struct sk_buff *skb, *data_skb;
-       int err;
+       int err, ret;
 
        if (flags&MSG_OOB)
                return -EOPNOTSUPP;
@@ -1470,8 +1470,13 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
 
        skb_free_datagram(sk, skb);
 
-       if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
-               netlink_dump(sk);
+       if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
+               ret = netlink_dump(sk);
+               if (ret) {
+                       sk->sk_err = ret;
+                       sk->sk_error_report(sk);
+               }
+       }
 
        scm_recv(sock, msg, siocb->scm, flags);
 out:
@@ -1736,6 +1741,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        struct netlink_callback *cb;
        struct sock *sk;
        struct netlink_sock *nlk;
+       int ret;
 
        cb = kzalloc(sizeof(*cb), GFP_KERNEL);
        if (cb == NULL)
@@ -1764,9 +1770,13 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        nlk->cb = cb;
        mutex_unlock(nlk->cb_mutex);
 
-       netlink_dump(sk);
+       ret = netlink_dump(sk);
+
        sock_put(sk);
 
+       if (ret)
+               return ret;
+
        /* We successfully started a dump, by returning -EINTR we
         * signal not to send ACK even if it was requested.
         */
index f83cb37..1781d99 100644 (file)
@@ -519,7 +519,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
            security_netlink_recv(skb, CAP_NET_ADMIN))
                return -EPERM;
 
-       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
                if (ops->dumpit == NULL)
                        return -EOPNOTSUPP;
 
index eaf7658..7fce6df 100644 (file)
@@ -18,7 +18,7 @@ config RFKILL_LEDS
        default y
 
 config RFKILL_INPUT
-       bool "RF switch input support" if EMBEDDED
+       bool "RF switch input support" if EXPERT
        depends on RFKILL
        depends on INPUT = y || RFKILL = INPUT
-       default y if !EMBEDDED
+       default y if !EXPERT
index 8931500..1a2b063 100644 (file)
@@ -423,6 +423,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
                        goto protocol_error;
                }
 
+       case RXRPC_PACKET_TYPE_ACKALL:
        case RXRPC_PACKET_TYPE_ACK:
                /* ACK processing is done in process context */
                read_lock_bh(&call->state_lock);
index 5ee16f0..d763793 100644 (file)
@@ -89,11 +89,11 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
                return ret;
 
        plen -= sizeof(*token);
-       token = kmalloc(sizeof(*token), GFP_KERNEL);
+       token = kzalloc(sizeof(*token), GFP_KERNEL);
        if (!token)
                return -ENOMEM;
 
-       token->kad = kmalloc(plen, GFP_KERNEL);
+       token->kad = kzalloc(plen, GFP_KERNEL);
        if (!token->kad) {
                kfree(token);
                return -ENOMEM;
@@ -731,10 +731,10 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
                goto error;
 
        ret = -ENOMEM;
-       token = kmalloc(sizeof(*token), GFP_KERNEL);
+       token = kzalloc(sizeof(*token), GFP_KERNEL);
        if (!token)
                goto error;
-       token->kad = kmalloc(plen, GFP_KERNEL);
+       token->kad = kzalloc(plen, GFP_KERNEL);
        if (!token->kad)
                goto error_free;
 
index c80d1c2..5f63ec5 100644 (file)
@@ -390,7 +390,6 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        ret = qdisc_enqueue(skb, cl->q);
        if (ret == NET_XMIT_SUCCESS) {
                sch->q.qlen++;
-               qdisc_bstats_update(sch, skb);
                cbq_mark_toplevel(q, cl);
                if (!cl->next_alive)
                        cbq_activate_class(cl);
@@ -649,7 +648,6 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
                ret = qdisc_enqueue(skb, cl->q);
                if (ret == NET_XMIT_SUCCESS) {
                        sch->q.qlen++;
-                       qdisc_bstats_update(sch, skb);
                        if (!cl->next_alive)
                                cbq_activate_class(cl);
                        return 0;
@@ -971,6 +969,7 @@ cbq_dequeue(struct Qdisc *sch)
 
                skb = cbq_dequeue_1(sch);
                if (skb) {
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        sch->flags &= ~TCQ_F_THROTTLED;
                        return skb;
index de55e64..6b7fe4a 100644 (file)
@@ -376,7 +376,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        }
 
        bstats_update(&cl->bstats, skb);
-       qdisc_bstats_update(sch, skb);
 
        sch->q.qlen++;
        return err;
@@ -403,6 +402,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
                        skb = qdisc_dequeue_peeked(cl->qdisc);
                        if (cl->qdisc->q.qlen == 0)
                                list_del(&cl->alist);
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
index 60f4bdd..0f7bf3f 100644 (file)
@@ -260,7 +260,6 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
        }
 
-       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -283,6 +282,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
        if (skb == NULL)
                return NULL;
 
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
 
        index = skb->tc_index & (p->indices - 1);
index aa4d633..d468b47 100644 (file)
@@ -46,17 +46,14 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
-       struct sk_buff *skb_head;
        struct fifo_sched_data *q = qdisc_priv(sch);
 
        if (likely(skb_queue_len(&sch->q) < q->limit))
                return qdisc_enqueue_tail(skb, sch);
 
        /* queue full, remove one skb to fulfill the limit */
-       skb_head = qdisc_dequeue_head(sch);
+       __qdisc_queue_drop_head(sch, &sch->q);
        sch->qstats.drops++;
-       kfree_skb(skb_head);
-
        qdisc_enqueue_tail(skb, sch);
 
        return NET_XMIT_CN;
index 34dc598..1bc6980 100644 (file)
@@ -839,6 +839,7 @@ void dev_deactivate(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        dev_deactivate_many(&single);
+       list_del(&single);
 }
 
 static void dev_init_scheduler_queue(struct net_device *dev,
index 2e45791..14a799d 100644 (file)
@@ -1600,7 +1600,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                set_active(cl, qdisc_pkt_len(skb));
 
        bstats_update(&cl->bstats, skb);
-       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -1666,6 +1665,7 @@ hfsc_dequeue(struct Qdisc *sch)
        }
 
        sch->flags &= ~TCQ_F_THROTTLED;
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
 
        return skb;
index 984c1b0..fc12fe6 100644 (file)
@@ -574,7 +574,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        }
 
        sch->q.qlen++;
-       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
@@ -842,7 +841,7 @@ next:
 
 static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 {
-       struct sk_buff *skb = NULL;
+       struct sk_buff *skb;
        struct htb_sched *q = qdisc_priv(sch);
        int level;
        psched_time_t next_event;
@@ -851,6 +850,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
        /* try to dequeue direct packets as high prio (!) to minimize cpu work */
        skb = __skb_dequeue(&q->direct_queue);
        if (skb != NULL) {
+ok:
+               qdisc_bstats_update(sch, skb);
                sch->flags &= ~TCQ_F_THROTTLED;
                sch->q.qlen--;
                return skb;
@@ -884,11 +885,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
                        int prio = ffz(m);
                        m |= 1 << prio;
                        skb = htb_dequeue_tree(q, prio, level);
-                       if (likely(skb != NULL)) {
-                               sch->q.qlen--;
-                               sch->flags &= ~TCQ_F_THROTTLED;
-                               goto fin;
-                       }
+                       if (likely(skb != NULL))
+                               goto ok;
                }
        }
        sch->qstats.overlimits++;
index 21f13da..436a2e7 100644 (file)
@@ -83,7 +83,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
@@ -112,6 +111,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
                        qdisc = q->queues[q->curband];
                        skb = qdisc->dequeue(qdisc);
                        if (skb) {
+                               qdisc_bstats_update(sch, skb);
                                sch->q.qlen--;
                                return skb;
                        }
index 1c4bce8..6a3006b 100644 (file)
@@ -240,7 +240,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        if (likely(ret == NET_XMIT_SUCCESS)) {
                sch->q.qlen++;
-               qdisc_bstats_update(sch, skb);
        } else if (net_xmit_drop_count(ret)) {
                sch->qstats.drops++;
        }
@@ -289,6 +288,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                                skb->tstamp.tv64 = 0;
 #endif
                        pr_debug("netem_dequeue: return skb=%p\n", skb);
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
@@ -476,7 +476,6 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
                __skb_queue_after(list, skb, nskb);
 
                sch->qstats.backlog += qdisc_pkt_len(nskb);
-               qdisc_bstats_update(sch, nskb);
 
                return NET_XMIT_SUCCESS;
        }
index 966158d..fbd710d 100644 (file)
@@ -84,7 +84,6 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
@@ -116,6 +115,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc* sch)
                struct Qdisc *qdisc = q->queues[prio];
                struct sk_buff *skb = qdisc->dequeue(qdisc);
                if (skb) {
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
index a6009c5..9f98dbd 100644 (file)
@@ -94,7 +94,6 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        ret = qdisc_enqueue(skb, child);
        if (likely(ret == NET_XMIT_SUCCESS)) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
        } else if (net_xmit_drop_count(ret)) {
                q->stats.pdrop++;
@@ -114,11 +113,13 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
        struct Qdisc *child = q->qdisc;
 
        skb = child->dequeue(child);
-       if (skb)
+       if (skb) {
+               qdisc_bstats_update(sch, skb);
                sch->q.qlen--;
-       else if (!red_is_idling(&q->parms))
-               red_start_of_idle_period(&q->parms);
-
+       } else {
+               if (!red_is_idling(&q->parms))
+                       red_start_of_idle_period(&q->parms);
+       }
        return skb;
 }
 
index 239ec53..edea8ce 100644 (file)
@@ -402,10 +402,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                q->tail = slot;
                slot->allot = q->scaled_quantum;
        }
-       if (++sch->q.qlen <= q->limit) {
-               qdisc_bstats_update(sch, skb);
+       if (++sch->q.qlen <= q->limit)
                return NET_XMIT_SUCCESS;
-       }
 
        sfq_drop(sch);
        return NET_XMIT_CN;
@@ -445,6 +443,7 @@ next_slot:
        }
        skb = slot_dequeue_head(slot);
        sfq_dec(q, a);
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
        sch->qstats.backlog -= qdisc_pkt_len(skb);
 
index 77565e7..e931658 100644 (file)
@@ -134,7 +134,6 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
        }
 
        sch->q.qlen++;
-       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
@@ -187,6 +186,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
                        q->ptokens = ptoks;
                        sch->q.qlen--;
                        sch->flags &= ~TCQ_F_THROTTLED;
+                       qdisc_bstats_update(sch, skb);
                        return skb;
                }
 
index 84ce48e..d84e732 100644 (file)
@@ -87,7 +87,6 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        if (q->q.qlen < dev->tx_queue_len) {
                __skb_queue_tail(&q->q, skb);
-               qdisc_bstats_update(sch, skb);
                return NET_XMIT_SUCCESS;
        }
 
@@ -111,6 +110,8 @@ teql_dequeue(struct Qdisc* sch)
                        dat->m->slaves = sch;
                        netif_wake_queue(m);
                }
+       } else {
+               qdisc_bstats_update(sch, skb);
        }
        sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
        return skb;
index 2cc46f0..b23428f 100644 (file)
@@ -2029,11 +2029,11 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
                        *errp = sctp_make_op_error_fixed(asoc, chunk);
 
                if (*errp) {
-                       sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
-                                       WORD_ROUND(ntohs(param.p->length)));
-                       sctp_addto_chunk_fixed(*errp,
-                                       WORD_ROUND(ntohs(param.p->length)),
-                                       param.v);
+                       if (!sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
+                                       WORD_ROUND(ntohs(param.p->length))))
+                               sctp_addto_chunk_fixed(*errp,
+                                               WORD_ROUND(ntohs(param.p->length)),
+                                               param.v);
                } else {
                        /* If there is no memory for generating the ERROR
                         * report as specified, an ABORT will be triggered
index a09b0dd..8e02550 100644 (file)
@@ -3428,7 +3428,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
                break;
 
-       case SCTP_DELAYED_ACK:
+       case SCTP_DELAYED_SACK:
                retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
                break;
        case SCTP_PARTIAL_DELIVERY_POINT:
@@ -5333,7 +5333,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
                                                          optlen);
                break;
-       case SCTP_DELAYED_ACK:
+       case SCTP_DELAYED_SACK:
                retval = sctp_getsockopt_delayed_ack(sk, len, optval,
                                                          optlen);
                break;
index 7bd3bbb..d802e94 100644 (file)
@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
  */
 static void svc_bc_sock_free(struct svc_xprt *xprt)
 {
-       if (xprt) {
-               kfree(xprt->xpt_bc_sid);
+       if (xprt)
                kfree(container_of(xprt, struct svc_sock, sk_xprt));
-       }
 }
 #endif /* CONFIG_NFS_V4_1 */
index d0ee290..1f1ef70 100644 (file)
@@ -95,7 +95,7 @@ config CFG80211_DEBUGFS
          If unsure, say N.
 
 config CFG80211_INTERNAL_REGDB
-       bool "use statically compiled regulatory rules database" if EMBEDDED
+       bool "use statically compiled regulatory rules database" if EXPERT
        default n
        depends on CFG80211
        ---help---
index 3e5dbd4..d112f03 100644 (file)
@@ -802,11 +802,11 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
                        return freq;
                if (freq == 0)
                        return -EINVAL;
-               wdev_lock(wdev);
                mutex_lock(&rdev->devlist_mtx);
+               wdev_lock(wdev);
                err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
-               mutex_unlock(&rdev->devlist_mtx);
                wdev_unlock(wdev);
+               mutex_unlock(&rdev->devlist_mtx);
                return err;
        default:
                return -EOPNOTSUPP;
index 55187c8..4062075 100644 (file)
 #include <net/sock.h>
 #include <net/x25.h>
 
-/*
- * Parse a set of facilities into the facilities structures. Unrecognised
- *     facilities are written to the debug log file.
+/**
+ * x25_parse_facilities - Parse facilities from skb into the facilities structs
+ *
+ * @skb: sk_buff to parse
+ * @facilities: Regular facilites, updated as facilities are found
+ * @dte_facs: ITU DTE facilities, updated as DTE facilities are found
+ * @vc_fac_mask: mask is updated with all facilities found
+ *
+ * Return codes:
+ *  -1 - Parsing error, caller should drop call and clean up
+ *   0 - Parse OK, this skb has no facilities
+ *  >0 - Parse OK, returns the length of the facilities header
+ *
  */
 int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
@@ -62,7 +72,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                switch (*p & X25_FAC_CLASS_MASK) {
                case X25_FAC_CLASS_A:
                        if (len < 2)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_REVERSE:
                                if((p[1] & 0x81) == 0x81) {
@@ -107,7 +117,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_B:
                        if (len < 3)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_PACKET_SIZE:
                                facilities->pacsize_in  = p[1];
@@ -130,7 +140,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_C:
                        if (len < 4)
-                               return 0;
+                               return -1;
                        printk(KERN_DEBUG "X.25: unknown facility %02X, "
                               "values %02X, %02X, %02X\n",
                               p[0], p[1], p[2], p[3]);
@@ -139,18 +149,18 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_D:
                        if (len < p[1] + 2)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
                                if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
-                                       return 0;
+                                       return -1;
                                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 || p[1] <= 1)
-                                       return 0;
+                                       return -1;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
index f729f02..15de65f 100644 (file)
@@ -91,10 +91,10 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 {
        struct x25_address source_addr, dest_addr;
        int len;
+       struct x25_sock *x25 = x25_sk(sk);
 
        switch (frametype) {
                case X25_CALL_ACCEPTED: {
-                       struct x25_sock *x25 = x25_sk(sk);
 
                        x25_stop_timer(sk);
                        x25->condition = 0x00;
@@ -113,14 +113,16 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &dest_addr);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else if (len < 0)
+                               goto out_clear;
 
                        len = x25_parse_facilities(skb, &x25->facilities,
                                                &x25->dte_facilities,
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
-                       else
-                               return -1;
+                       else if (len < 0)
+                               goto out_clear;
                        /*
                         *      Copy any Call User Data.
                         */
@@ -144,6 +146,12 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
        }
 
        return 0;
+
+out_clear:
+       x25_write_internal(sk, X25_CLEAR_REQUEST);
+       x25->state = X25_STATE_2;
+       x25_start_t23timer(sk);
+       return 0;
 }
 
 /*
index 4cbc942..2130692 100644 (file)
@@ -396,9 +396,12 @@ void __exit x25_link_free(void)
        write_lock_bh(&x25_neigh_list_lock);
 
        list_for_each_safe(entry, tmp, &x25_neigh_list) {
+               struct net_device *dev;
+
                nb = list_entry(entry, struct x25_neigh, node);
+               dev = nb->dev;
                __x25_remove_neigh(nb);
-               dev_put(nb->dev);
+               dev_put(dev);
        }
        write_unlock_bh(&x25_neigh_list_lock);
 }
index 8b3ef40..6459588 100644 (file)
@@ -1340,10 +1340,13 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
        default:
                BUG();
        }
-       xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS);
+       xdst = dst_alloc(dst_ops);
        xfrm_policy_put_afinfo(afinfo);
 
-       xdst->flo.ops = &xfrm_bundle_fc_ops;
+       if (likely(xdst))
+               xdst->flo.ops = &xfrm_bundle_fc_ops;
+       else
+               xdst = ERR_PTR(-ENOBUFS);
 
        return xdst;
 }
index d5e1e0b..6129196 100644 (file)
@@ -2189,7 +2189,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
        if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
             type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
-           (nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+           (nlh->nlmsg_flags & NLM_F_DUMP)) {
                if (link->dump == NULL)
                        return -EINVAL;
 
index c9a16ab..6c94c6c 100644 (file)
@@ -315,6 +315,7 @@ static void parse_dep_file(void *map, size_t len)
        char *end = m + len;
        char *p;
        char s[PATH_MAX];
+       int first;
 
        p = strchr(m, ':');
        if (!p) {
@@ -327,6 +328,7 @@ static void parse_dep_file(void *map, size_t len)
 
        clear_config();
 
+       first = 1;
        while (m < end) {
                while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
                        m++;
@@ -340,9 +342,17 @@ static void parse_dep_file(void *map, size_t len)
                if (strrcmp(s, "include/generated/autoconf.h") &&
                    strrcmp(s, "arch/um/include/uml-config.h") &&
                    strrcmp(s, ".ver")) {
-                       printf("  %s \\\n", s);
+                       /*
+                        * Do not output the first dependency (the
+                        * source file), so that kbuild is not confused
+                        * if a .c file is rewritten into .S or vice
+                        * versa.
+                        */
+                       if (!first)
+                               printf("  %s \\\n", s);
                        do_config_file(s);
                }
+               first = 0;
                m = p + 1;
        }
        printf("\n%s: $(deps_%s)\n\n", target, target);
index b0b2357..f6cbc3d 100644 (file)
@@ -238,12 +238,12 @@ EOF
 fi
 
 # Build header package
-find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$
-find arch/x86/include include scripts -type f >> /tmp/files$$
+(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$)
+(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$)
 (cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$)
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
-tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -)
+(cd $srctree; tar -c -f - -T /tmp/files$$) | (cd $destdir; tar -xf -)
 (cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -)
 rm -f /tmp/files$$ /tmp/objfiles$$
 arch=$(dpkg --print-architecture)
index 6c94105..1bf090a 100644 (file)
@@ -13,8 +13,8 @@ obj-y := \
        request_key_auth.o \
        user_defined.o
 
-obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o
+obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
index 792c0a6..07a5f35 100644 (file)
@@ -1,4 +1,4 @@
-/* compat.c: 32-bit compatibility syscall for 64-bit systems
+/* 32-bit compatibility syscall for 64-bit systems
  *
  * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <linux/compat.h>
 #include "internal.h"
 
-/*****************************************************************************/
 /*
- * the key control system call, 32-bit compatibility version for 64-bit archs
- * - this should only be called if the 64-bit arch uses weird pointers in
- *   32-bit mode or doesn't guarantee that the top 32-bits of the argument
- *   registers on taking a 32-bit syscall are zero
- * - if you can, you should call sys_keyctl directly
+ * The key control system call, 32-bit compatibility version for 64-bit archs
+ *
+ * This should only be called if the 64-bit arch uses weird pointers in 32-bit
+ * mode or doesn't guarantee that the top 32-bits of the argument registers on
+ * taking a 32-bit syscall are zero.  If you can, you should call sys_keyctl()
+ * directly.
  */
 asmlinkage long compat_sys_keyctl(u32 option,
                                  u32 arg2, u32 arg3, u32 arg4, u32 arg5)
@@ -88,5 +88,4 @@ asmlinkage long compat_sys_keyctl(u32 option,
        default:
                return -EOPNOTSUPP;
        }
-
-} /* end compat_sys_keyctl() */
+}
diff --git a/security/keys/encrypted.c b/security/keys/encrypted.c
new file mode 100644 (file)
index 0000000..9e7e4ce
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * See Documentation/keys-trusted-encrypted.txt
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <keys/user-type.h>
+#include <keys/trusted-type.h>
+#include <keys/encrypted-type.h>
+#include <linux/key-type.h>
+#include <linux/random.h>
+#include <linux/rcupdate.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <crypto/aes.h>
+
+#include "encrypted.h"
+
+static const char KEY_TRUSTED_PREFIX[] = "trusted:";
+static const char KEY_USER_PREFIX[] = "user:";
+static const char hash_alg[] = "sha256";
+static const char hmac_alg[] = "hmac(sha256)";
+static const char blkcipher_alg[] = "cbc(aes)";
+static unsigned int ivsize;
+static int blksize;
+
+#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
+#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
+#define HASH_SIZE SHA256_DIGEST_SIZE
+#define MAX_DATA_SIZE 4096
+#define MIN_DATA_SIZE  20
+
+struct sdesc {
+       struct shash_desc shash;
+       char ctx[];
+};
+
+static struct crypto_shash *hashalg;
+static struct crypto_shash *hmacalg;
+
+enum {
+       Opt_err = -1, Opt_new, Opt_load, Opt_update
+};
+
+static const match_table_t key_tokens = {
+       {Opt_new, "new"},
+       {Opt_load, "load"},
+       {Opt_update, "update"},
+       {Opt_err, NULL}
+};
+
+static int aes_get_sizes(void)
+{
+       struct crypto_blkcipher *tfm;
+
+       tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
+                      PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+       ivsize = crypto_blkcipher_ivsize(tfm);
+       blksize = crypto_blkcipher_blocksize(tfm);
+       crypto_free_blkcipher(tfm);
+       return 0;
+}
+
+/*
+ * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
+ *
+ * key-type:= "trusted:" | "encrypted:"
+ * desc:= master-key description
+ *
+ * Verify that 'key-type' is valid and that 'desc' exists. On key update,
+ * only the master key description is permitted to change, not the key-type.
+ * The key-type remains constant.
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int valid_master_desc(const char *new_desc, const char *orig_desc)
+{
+       if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
+               if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
+                       goto out;
+               if (orig_desc)
+                       if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
+                               goto out;
+       } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
+               if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
+                       goto out;
+               if (orig_desc)
+                       if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
+                               goto out;
+       } else
+               goto out;
+       return 0;
+out:
+       return -EINVAL;
+}
+
+/*
+ * datablob_parse - parse the keyctl data
+ *
+ * datablob format:
+ * new <master-key name> <decrypted data length>
+ * load <master-key name> <decrypted data length> <encrypted iv + data>
+ * update <new-master-key name>
+ *
+ * Tokenizes a copy of the keyctl data, returning a pointer to each token,
+ * which is null terminated.
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int datablob_parse(char *datablob, char **master_desc,
+                         char **decrypted_datalen, char **hex_encoded_iv)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int ret = -EINVAL;
+       int key_cmd;
+       char *p;
+
+       p = strsep(&datablob, " \t");
+       if (!p)
+               return ret;
+       key_cmd = match_token(p, key_tokens, args);
+
+       *master_desc = strsep(&datablob, " \t");
+       if (!*master_desc)
+               goto out;
+
+       if (valid_master_desc(*master_desc, NULL) < 0)
+               goto out;
+
+       if (decrypted_datalen) {
+               *decrypted_datalen = strsep(&datablob, " \t");
+               if (!*decrypted_datalen)
+                       goto out;
+       }
+
+       switch (key_cmd) {
+       case Opt_new:
+               if (!decrypted_datalen)
+                       break;
+               ret = 0;
+               break;
+       case Opt_load:
+               if (!decrypted_datalen)
+                       break;
+               *hex_encoded_iv = strsep(&datablob, " \t");
+               if (!*hex_encoded_iv)
+                       break;
+               ret = 0;
+               break;
+       case Opt_update:
+               if (decrypted_datalen)
+                       break;
+               ret = 0;
+               break;
+       case Opt_err:
+               break;
+       }
+out:
+       return ret;
+}
+
+/*
+ * datablob_format - format as an ascii string, before copying to userspace
+ */
+static char *datablob_format(struct encrypted_key_payload *epayload,
+                            size_t asciiblob_len)
+{
+       char *ascii_buf, *bufp;
+       u8 *iv = epayload->iv;
+       int len;
+       int i;
+
+       ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL);
+       if (!ascii_buf)
+               goto out;
+
+       ascii_buf[asciiblob_len] = '\0';
+
+       /* copy datablob master_desc and datalen strings */
+       len = sprintf(ascii_buf, "%s %s ", epayload->master_desc,
+                     epayload->datalen);
+
+       /* convert the hex encoded iv, encrypted-data and HMAC to ascii */
+       bufp = &ascii_buf[len];
+       for (i = 0; i < (asciiblob_len - len) / 2; i++)
+               bufp = pack_hex_byte(bufp, iv[i]);
+out:
+       return ascii_buf;
+}
+
+/*
+ * request_trusted_key - request the trusted key
+ *
+ * Trusted keys are sealed to PCRs and other metadata. Although userspace
+ * manages both trusted/encrypted key-types, like the encrypted key type
+ * data, trusted key type data is not visible decrypted from userspace.
+ */
+static struct key *request_trusted_key(const char *trusted_desc,
+                                      u8 **master_key, size_t *master_keylen)
+{
+       struct trusted_key_payload *tpayload;
+       struct key *tkey;
+
+       tkey = request_key(&key_type_trusted, trusted_desc, NULL);
+       if (IS_ERR(tkey))
+               goto error;
+
+       down_read(&tkey->sem);
+       tpayload = rcu_dereference(tkey->payload.data);
+       *master_key = tpayload->key;
+       *master_keylen = tpayload->key_len;
+error:
+       return tkey;
+}
+
+/*
+ * request_user_key - request the user key
+ *
+ * Use a user provided key to encrypt/decrypt an encrypted-key.
+ */
+static struct key *request_user_key(const char *master_desc, u8 **master_key,
+                                   size_t *master_keylen)
+{
+       struct user_key_payload *upayload;
+       struct key *ukey;
+
+       ukey = request_key(&key_type_user, master_desc, NULL);
+       if (IS_ERR(ukey))
+               goto error;
+
+       down_read(&ukey->sem);
+       upayload = rcu_dereference(ukey->payload.data);
+       *master_key = upayload->data;
+       *master_keylen = upayload->datalen;
+error:
+       return ukey;
+}
+
+static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
+{
+       struct sdesc *sdesc;
+       int size;
+
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+       sdesc = kmalloc(size, GFP_KERNEL);
+       if (!sdesc)
+               return ERR_PTR(-ENOMEM);
+       sdesc->shash.tfm = alg;
+       sdesc->shash.flags = 0x0;
+       return sdesc;
+}
+
+static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
+                    const u8 *buf, unsigned int buflen)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = alloc_sdesc(hmacalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_setkey(hmacalg, key, keylen);
+       if (!ret)
+               ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = alloc_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("encrypted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+enum derived_key_type { ENC_KEY, AUTH_KEY };
+
+/* Derive authentication/encryption key from trusted key */
+static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
+                          const u8 *master_key, size_t master_keylen)
+{
+       u8 *derived_buf;
+       unsigned int derived_buf_len;
+       int ret;
+
+       derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
+       if (derived_buf_len < HASH_SIZE)
+               derived_buf_len = HASH_SIZE;
+
+       derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
+       if (!derived_buf) {
+               pr_err("encrypted_key: out of memory\n");
+               return -ENOMEM;
+       }
+       if (key_type)
+               strcpy(derived_buf, "AUTH_KEY");
+       else
+               strcpy(derived_buf, "ENC_KEY");
+
+       memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
+              master_keylen);
+       ret = calc_hash(derived_key, derived_buf, derived_buf_len);
+       kfree(derived_buf);
+       return ret;
+}
+
+static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
+                              unsigned int key_len, const u8 *iv,
+                              unsigned int ivsize)
+{
+       int ret;
+
+       desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(desc->tfm)) {
+               pr_err("encrypted_key: failed to load %s transform (%ld)\n",
+                      blkcipher_alg, PTR_ERR(desc->tfm));
+               return PTR_ERR(desc->tfm);
+       }
+       desc->flags = 0;
+
+       ret = crypto_blkcipher_setkey(desc->tfm, key, key_len);
+       if (ret < 0) {
+               pr_err("encrypted_key: failed to setkey (%d)\n", ret);
+               crypto_free_blkcipher(desc->tfm);
+               return ret;
+       }
+       crypto_blkcipher_set_iv(desc->tfm, iv, ivsize);
+       return 0;
+}
+
+static struct key *request_master_key(struct encrypted_key_payload *epayload,
+                                     u8 **master_key, size_t *master_keylen)
+{
+       struct key *mkey = NULL;
+
+       if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
+                    KEY_TRUSTED_PREFIX_LEN)) {
+               mkey = request_trusted_key(epayload->master_desc +
+                                          KEY_TRUSTED_PREFIX_LEN,
+                                          master_key, master_keylen);
+       } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
+                           KEY_USER_PREFIX_LEN)) {
+               mkey = request_user_key(epayload->master_desc +
+                                       KEY_USER_PREFIX_LEN,
+                                       master_key, master_keylen);
+       } else
+               goto out;
+
+       if (IS_ERR(mkey))
+               pr_info("encrypted_key: key %s not found",
+                       epayload->master_desc);
+       if (mkey)
+               dump_master_key(*master_key, *master_keylen);
+out:
+       return mkey;
+}
+
+/* Before returning data to userspace, encrypt decrypted data. */
+static int derived_key_encrypt(struct encrypted_key_payload *epayload,
+                              const u8 *derived_key,
+                              unsigned int derived_keylen)
+{
+       struct scatterlist sg_in[2];
+       struct scatterlist sg_out[1];
+       struct blkcipher_desc desc;
+       unsigned int encrypted_datalen;
+       unsigned int padlen;
+       char pad[16];
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       padlen = encrypted_datalen - epayload->decrypted_datalen;
+
+       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
+                                 epayload->iv, ivsize);
+       if (ret < 0)
+               goto out;
+       dump_decrypted_data(epayload);
+
+       memset(pad, 0, sizeof pad);
+       sg_init_table(sg_in, 2);
+       sg_set_buf(&sg_in[0], epayload->decrypted_data,
+                  epayload->decrypted_datalen);
+       sg_set_buf(&sg_in[1], pad, padlen);
+
+       sg_init_table(sg_out, 1);
+       sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
+
+       ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen);
+       crypto_free_blkcipher(desc.tfm);
+       if (ret < 0)
+               pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
+       else
+               dump_encrypted_data(epayload, encrypted_datalen);
+out:
+       return ret;
+}
+
+static int datablob_hmac_append(struct encrypted_key_payload *epayload,
+                               const u8 *master_key, size_t master_keylen)
+{
+       u8 derived_key[HASH_SIZE];
+       u8 *digest;
+       int ret;
+
+       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       digest = epayload->master_desc + epayload->datablob_len;
+       ret = calc_hmac(digest, derived_key, sizeof derived_key,
+                       epayload->master_desc, epayload->datablob_len);
+       if (!ret)
+               dump_hmac(NULL, digest, HASH_SIZE);
+out:
+       return ret;
+}
+
+/* verify HMAC before decrypting encrypted key */
+static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
+                               const u8 *master_key, size_t master_keylen)
+{
+       u8 derived_key[HASH_SIZE];
+       u8 digest[HASH_SIZE];
+       int ret;
+
+       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = calc_hmac(digest, derived_key, sizeof derived_key,
+                       epayload->master_desc, epayload->datablob_len);
+       if (ret < 0)
+               goto out;
+       ret = memcmp(digest, epayload->master_desc + epayload->datablob_len,
+                    sizeof digest);
+       if (ret) {
+               ret = -EINVAL;
+               dump_hmac("datablob",
+                         epayload->master_desc + epayload->datablob_len,
+                         HASH_SIZE);
+               dump_hmac("calc", digest, HASH_SIZE);
+       }
+out:
+       return ret;
+}
+
+static int derived_key_decrypt(struct encrypted_key_payload *epayload,
+                              const u8 *derived_key,
+                              unsigned int derived_keylen)
+{
+       struct scatterlist sg_in[1];
+       struct scatterlist sg_out[2];
+       struct blkcipher_desc desc;
+       unsigned int encrypted_datalen;
+       char pad[16];
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
+                                 epayload->iv, ivsize);
+       if (ret < 0)
+               goto out;
+       dump_encrypted_data(epayload, encrypted_datalen);
+
+       memset(pad, 0, sizeof pad);
+       sg_init_table(sg_in, 1);
+       sg_init_table(sg_out, 2);
+       sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
+       sg_set_buf(&sg_out[0], epayload->decrypted_data,
+                  epayload->decrypted_datalen);
+       sg_set_buf(&sg_out[1], pad, sizeof pad);
+
+       ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen);
+       crypto_free_blkcipher(desc.tfm);
+       if (ret < 0)
+               goto out;
+       dump_decrypted_data(epayload);
+out:
+       return ret;
+}
+
+/* Allocate memory for decrypted key and datablob. */
+static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
+                                                        const char *master_desc,
+                                                        const char *datalen)
+{
+       struct encrypted_key_payload *epayload = NULL;
+       unsigned short datablob_len;
+       unsigned short decrypted_datalen;
+       unsigned int encrypted_datalen;
+       long dlen;
+       int ret;
+
+       ret = strict_strtol(datalen, 10, &dlen);
+       if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
+               return ERR_PTR(-EINVAL);
+
+       decrypted_datalen = dlen;
+       encrypted_datalen = roundup(decrypted_datalen, blksize);
+
+       datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1
+           + ivsize + 1 + encrypted_datalen;
+
+       ret = key_payload_reserve(key, decrypted_datalen + datablob_len
+                                 + HASH_SIZE + 1);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       epayload = kzalloc(sizeof(*epayload) + decrypted_datalen +
+                          datablob_len + HASH_SIZE + 1, GFP_KERNEL);
+       if (!epayload)
+               return ERR_PTR(-ENOMEM);
+
+       epayload->decrypted_datalen = decrypted_datalen;
+       epayload->datablob_len = datablob_len;
+       return epayload;
+}
+
+static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
+                                const char *hex_encoded_iv)
+{
+       struct key *mkey;
+       u8 derived_key[HASH_SIZE];
+       u8 *master_key;
+       u8 *hmac;
+       const char *hex_encoded_data;
+       unsigned int encrypted_datalen;
+       size_t master_keylen;
+       size_t asciilen;
+       int ret;
+
+       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
+       asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
+       if (strlen(hex_encoded_iv) != asciilen)
+               return -EINVAL;
+
+       hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
+       hex2bin(epayload->iv, hex_encoded_iv, ivsize);
+       hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
+
+       hmac = epayload->master_desc + epayload->datablob_len;
+       hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
+
+       mkey = request_master_key(epayload, &master_key, &master_keylen);
+       if (IS_ERR(mkey))
+               return PTR_ERR(mkey);
+
+       ret = datablob_hmac_verify(epayload, master_key, master_keylen);
+       if (ret < 0) {
+               pr_err("encrypted_key: bad hmac (%d)\n", ret);
+               goto out;
+       }
+
+       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
+       if (ret < 0)
+               pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
+out:
+       up_read(&mkey->sem);
+       key_put(mkey);
+       return ret;
+}
+
+static void __ekey_init(struct encrypted_key_payload *epayload,
+                       const char *master_desc, const char *datalen)
+{
+       epayload->master_desc = epayload->decrypted_data
+           + epayload->decrypted_datalen;
+       epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
+       epayload->iv = epayload->datalen + strlen(datalen) + 1;
+       epayload->encrypted_data = epayload->iv + ivsize + 1;
+
+       memcpy(epayload->master_desc, master_desc, strlen(master_desc));
+       memcpy(epayload->datalen, datalen, strlen(datalen));
+}
+
+/*
+ * encrypted_init - initialize an encrypted key
+ *
+ * For a new key, use a random number for both the iv and data
+ * itself.  For an old key, decrypt the hex encoded data.
+ */
+static int encrypted_init(struct encrypted_key_payload *epayload,
+                         const char *master_desc, const char *datalen,
+                         const char *hex_encoded_iv)
+{
+       int ret = 0;
+
+       __ekey_init(epayload, master_desc, datalen);
+       if (!hex_encoded_iv) {
+               get_random_bytes(epayload->iv, ivsize);
+
+               get_random_bytes(epayload->decrypted_data,
+                                epayload->decrypted_datalen);
+       } else
+               ret = encrypted_key_decrypt(epayload, hex_encoded_iv);
+       return ret;
+}
+
+/*
+ * encrypted_instantiate - instantiate an encrypted key
+ *
+ * Decrypt an existing encrypted datablob or create a new encrypted key
+ * based on a kernel random number.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int encrypted_instantiate(struct key *key, const void *data,
+                                size_t datalen)
+{
+       struct encrypted_key_payload *epayload = NULL;
+       char *datablob = NULL;
+       char *master_desc = NULL;
+       char *decrypted_datalen = NULL;
+       char *hex_encoded_iv = NULL;
+       int ret;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       datablob[datalen] = 0;
+       memcpy(datablob, data, datalen);
+       ret = datablob_parse(datablob, &master_desc, &decrypted_datalen,
+                            &hex_encoded_iv);
+       if (ret < 0)
+               goto out;
+
+       epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen);
+       if (IS_ERR(epayload)) {
+               ret = PTR_ERR(epayload);
+               goto out;
+       }
+       ret = encrypted_init(epayload, master_desc, decrypted_datalen,
+                            hex_encoded_iv);
+       if (ret < 0) {
+               kfree(epayload);
+               goto out;
+       }
+
+       rcu_assign_pointer(key->payload.data, epayload);
+out:
+       kfree(datablob);
+       return ret;
+}
+
+static void encrypted_rcu_free(struct rcu_head *rcu)
+{
+       struct encrypted_key_payload *epayload;
+
+       epayload = container_of(rcu, struct encrypted_key_payload, rcu);
+       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
+       kfree(epayload);
+}
+
+/*
+ * encrypted_update - update the master key description
+ *
+ * Change the master key description for an existing encrypted key.
+ * The next read will return an encrypted datablob using the new
+ * master key description.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int encrypted_update(struct key *key, const void *data, size_t datalen)
+{
+       struct encrypted_key_payload *epayload = key->payload.data;
+       struct encrypted_key_payload *new_epayload;
+       char *buf;
+       char *new_master_desc = NULL;
+       int ret = 0;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       buf = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[datalen] = 0;
+       memcpy(buf, data, datalen);
+       ret = datablob_parse(buf, &new_master_desc, NULL, NULL);
+       if (ret < 0)
+               goto out;
+
+       ret = valid_master_desc(new_master_desc, epayload->master_desc);
+       if (ret < 0)
+               goto out;
+
+       new_epayload = encrypted_key_alloc(key, new_master_desc,
+                                          epayload->datalen);
+       if (IS_ERR(new_epayload)) {
+               ret = PTR_ERR(new_epayload);
+               goto out;
+       }
+
+       __ekey_init(new_epayload, new_master_desc, epayload->datalen);
+
+       memcpy(new_epayload->iv, epayload->iv, ivsize);
+       memcpy(new_epayload->decrypted_data, epayload->decrypted_data,
+              epayload->decrypted_datalen);
+
+       rcu_assign_pointer(key->payload.data, new_epayload);
+       call_rcu(&epayload->rcu, encrypted_rcu_free);
+out:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * encrypted_read - format and copy the encrypted data to userspace
+ *
+ * The resulting datablob format is:
+ * <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
+ *
+ * On success, return to userspace the encrypted key datablob size.
+ */
+static long encrypted_read(const struct key *key, char __user *buffer,
+                          size_t buflen)
+{
+       struct encrypted_key_payload *epayload;
+       struct key *mkey;
+       u8 *master_key;
+       size_t master_keylen;
+       char derived_key[HASH_SIZE];
+       char *ascii_buf;
+       size_t asciiblob_len;
+       int ret;
+
+       epayload = rcu_dereference_protected(key->payload.data,
+                                 rwsem_is_locked(&((struct key *)key)->sem));
+
+       /* returns the hex encoded iv, encrypted-data, and hmac as ascii */
+       asciiblob_len = epayload->datablob_len + ivsize + 1
+           + roundup(epayload->decrypted_datalen, blksize)
+           + (HASH_SIZE * 2);
+
+       if (!buffer || buflen < asciiblob_len)
+               return asciiblob_len;
+
+       mkey = request_master_key(epayload, &master_key, &master_keylen);
+       if (IS_ERR(mkey))
+               return PTR_ERR(mkey);
+
+       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key);
+       if (ret < 0)
+               goto out;
+
+       ret = datablob_hmac_append(epayload, master_key, master_keylen);
+       if (ret < 0)
+               goto out;
+
+       ascii_buf = datablob_format(epayload, asciiblob_len);
+       if (!ascii_buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       up_read(&mkey->sem);
+       key_put(mkey);
+
+       if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
+               ret = -EFAULT;
+       kfree(ascii_buf);
+
+       return asciiblob_len;
+out:
+       up_read(&mkey->sem);
+       key_put(mkey);
+       return ret;
+}
+
+/*
+ * encrypted_destroy - before freeing the key, clear the decrypted data
+ *
+ * Before freeing the key, clear the memory containing the decrypted
+ * key data.
+ */
+static void encrypted_destroy(struct key *key)
+{
+       struct encrypted_key_payload *epayload = key->payload.data;
+
+       if (!epayload)
+               return;
+
+       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
+       kfree(key->payload.data);
+}
+
+struct key_type key_type_encrypted = {
+       .name = "encrypted",
+       .instantiate = encrypted_instantiate,
+       .update = encrypted_update,
+       .match = user_match,
+       .destroy = encrypted_destroy,
+       .describe = user_describe,
+       .read = encrypted_read,
+};
+EXPORT_SYMBOL_GPL(key_type_encrypted);
+
+static void encrypted_shash_release(void)
+{
+       if (hashalg)
+               crypto_free_shash(hashalg);
+       if (hmacalg)
+               crypto_free_shash(hmacalg);
+}
+
+static int __init encrypted_shash_alloc(void)
+{
+       int ret;
+
+       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hmacalg)) {
+               pr_info("encrypted_key: could not allocate crypto %s\n",
+                       hmac_alg);
+               return PTR_ERR(hmacalg);
+       }
+
+       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hashalg)) {
+               pr_info("encrypted_key: could not allocate crypto %s\n",
+                       hash_alg);
+               ret = PTR_ERR(hashalg);
+               goto hashalg_fail;
+       }
+
+       return 0;
+
+hashalg_fail:
+       crypto_free_shash(hmacalg);
+       return ret;
+}
+
+static int __init init_encrypted(void)
+{
+       int ret;
+
+       ret = encrypted_shash_alloc();
+       if (ret < 0)
+               return ret;
+       ret = register_key_type(&key_type_encrypted);
+       if (ret < 0)
+               goto out;
+       return aes_get_sizes();
+out:
+       encrypted_shash_release();
+       return ret;
+
+}
+
+static void __exit cleanup_encrypted(void)
+{
+       encrypted_shash_release();
+       unregister_key_type(&key_type_encrypted);
+}
+
+late_initcall(init_encrypted);
+module_exit(cleanup_encrypted);
+
+MODULE_LICENSE("GPL");
diff --git a/security/keys/encrypted.h b/security/keys/encrypted.h
new file mode 100644 (file)
index 0000000..cef5e2f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __ENCRYPTED_KEY_H
+#define __ENCRYPTED_KEY_H
+
+#define ENCRYPTED_DEBUG 0
+
+#if ENCRYPTED_DEBUG
+static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
+{
+       print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1,
+                      master_key, master_keylen, 0);
+}
+
+static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
+{
+       print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1,
+                      epayload->decrypted_data,
+                      epayload->decrypted_datalen, 0);
+}
+
+static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
+                                      unsigned int encrypted_datalen)
+{
+       print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1,
+                      epayload->encrypted_data, encrypted_datalen, 0);
+}
+
+static inline void dump_hmac(const char *str, const u8 *digest,
+                            unsigned int hmac_size)
+{
+       if (str)
+               pr_info("encrypted_key: %s", str);
+       print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest,
+                      hmac_size, 0);
+}
+#else
+static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
+{
+}
+
+static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
+{
+}
+
+static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
+                                      unsigned int encrypted_datalen)
+{
+}
+
+static inline void dump_hmac(const char *str, const u8 *digest,
+                            unsigned int hmac_size)
+{
+}
+#endif
+#endif
diff --git a/security/keys/encrypted_defined.c b/security/keys/encrypted_defined.c
deleted file mode 100644 (file)
index 32d27c8..0000000
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- * Copyright (C) 2010 IBM Corporation
- *
- * Author:
- * Mimi Zohar <zohar@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * See Documentation/keys-trusted-encrypted.txt
- */
-
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/parser.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <keys/user-type.h>
-#include <keys/trusted-type.h>
-#include <keys/encrypted-type.h>
-#include <linux/key-type.h>
-#include <linux/random.h>
-#include <linux/rcupdate.h>
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
-#include <crypto/hash.h>
-#include <crypto/sha.h>
-#include <crypto/aes.h>
-
-#include "encrypted_defined.h"
-
-static const char KEY_TRUSTED_PREFIX[] = "trusted:";
-static const char KEY_USER_PREFIX[] = "user:";
-static const char hash_alg[] = "sha256";
-static const char hmac_alg[] = "hmac(sha256)";
-static const char blkcipher_alg[] = "cbc(aes)";
-static unsigned int ivsize;
-static int blksize;
-
-#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
-#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
-#define HASH_SIZE SHA256_DIGEST_SIZE
-#define MAX_DATA_SIZE 4096
-#define MIN_DATA_SIZE  20
-
-struct sdesc {
-       struct shash_desc shash;
-       char ctx[];
-};
-
-static struct crypto_shash *hashalg;
-static struct crypto_shash *hmacalg;
-
-enum {
-       Opt_err = -1, Opt_new, Opt_load, Opt_update
-};
-
-static const match_table_t key_tokens = {
-       {Opt_new, "new"},
-       {Opt_load, "load"},
-       {Opt_update, "update"},
-       {Opt_err, NULL}
-};
-
-static int aes_get_sizes(void)
-{
-       struct crypto_blkcipher *tfm;
-
-       tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm)) {
-               pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
-                      PTR_ERR(tfm));
-               return PTR_ERR(tfm);
-       }
-       ivsize = crypto_blkcipher_ivsize(tfm);
-       blksize = crypto_blkcipher_blocksize(tfm);
-       crypto_free_blkcipher(tfm);
-       return 0;
-}
-
-/*
- * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
- *
- * key-type:= "trusted:" | "encrypted:"
- * desc:= master-key description
- *
- * Verify that 'key-type' is valid and that 'desc' exists. On key update,
- * only the master key description is permitted to change, not the key-type.
- * The key-type remains constant.
- *
- * On success returns 0, otherwise -EINVAL.
- */
-static int valid_master_desc(const char *new_desc, const char *orig_desc)
-{
-       if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
-               if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
-                       goto out;
-               if (orig_desc)
-                       if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
-                               goto out;
-       } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
-               if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
-                       goto out;
-               if (orig_desc)
-                       if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
-                               goto out;
-       } else
-               goto out;
-       return 0;
-out:
-       return -EINVAL;
-}
-
-/*
- * datablob_parse - parse the keyctl data
- *
- * datablob format:
- * new <master-key name> <decrypted data length>
- * load <master-key name> <decrypted data length> <encrypted iv + data>
- * update <new-master-key name>
- *
- * Tokenizes a copy of the keyctl data, returning a pointer to each token,
- * which is null terminated.
- *
- * On success returns 0, otherwise -EINVAL.
- */
-static int datablob_parse(char *datablob, char **master_desc,
-                         char **decrypted_datalen, char **hex_encoded_iv)
-{
-       substring_t args[MAX_OPT_ARGS];
-       int ret = -EINVAL;
-       int key_cmd;
-       char *p;
-
-       p = strsep(&datablob, " \t");
-       if (!p)
-               return ret;
-       key_cmd = match_token(p, key_tokens, args);
-
-       *master_desc = strsep(&datablob, " \t");
-       if (!*master_desc)
-               goto out;
-
-       if (valid_master_desc(*master_desc, NULL) < 0)
-               goto out;
-
-       if (decrypted_datalen) {
-               *decrypted_datalen = strsep(&datablob, " \t");
-               if (!*decrypted_datalen)
-                       goto out;
-       }
-
-       switch (key_cmd) {
-       case Opt_new:
-               if (!decrypted_datalen)
-                       break;
-               ret = 0;
-               break;
-       case Opt_load:
-               if (!decrypted_datalen)
-                       break;
-               *hex_encoded_iv = strsep(&datablob, " \t");
-               if (!*hex_encoded_iv)
-                       break;
-               ret = 0;
-               break;
-       case Opt_update:
-               if (decrypted_datalen)
-                       break;
-               ret = 0;
-               break;
-       case Opt_err:
-               break;
-       }
-out:
-       return ret;
-}
-
-/*
- * datablob_format - format as an ascii string, before copying to userspace
- */
-static char *datablob_format(struct encrypted_key_payload *epayload,
-                            size_t asciiblob_len)
-{
-       char *ascii_buf, *bufp;
-       u8 *iv = epayload->iv;
-       int len;
-       int i;
-
-       ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL);
-       if (!ascii_buf)
-               goto out;
-
-       ascii_buf[asciiblob_len] = '\0';
-
-       /* copy datablob master_desc and datalen strings */
-       len = sprintf(ascii_buf, "%s %s ", epayload->master_desc,
-                     epayload->datalen);
-
-       /* convert the hex encoded iv, encrypted-data and HMAC to ascii */
-       bufp = &ascii_buf[len];
-       for (i = 0; i < (asciiblob_len - len) / 2; i++)
-               bufp = pack_hex_byte(bufp, iv[i]);
-out:
-       return ascii_buf;
-}
-
-/*
- * request_trusted_key - request the trusted key
- *
- * Trusted keys are sealed to PCRs and other metadata. Although userspace
- * manages both trusted/encrypted key-types, like the encrypted key type
- * data, trusted key type data is not visible decrypted from userspace.
- */
-static struct key *request_trusted_key(const char *trusted_desc,
-                                      u8 **master_key, size_t *master_keylen)
-{
-       struct trusted_key_payload *tpayload;
-       struct key *tkey;
-
-       tkey = request_key(&key_type_trusted, trusted_desc, NULL);
-       if (IS_ERR(tkey))
-               goto error;
-
-       down_read(&tkey->sem);
-       tpayload = rcu_dereference(tkey->payload.data);
-       *master_key = tpayload->key;
-       *master_keylen = tpayload->key_len;
-error:
-       return tkey;
-}
-
-/*
- * request_user_key - request the user key
- *
- * Use a user provided key to encrypt/decrypt an encrypted-key.
- */
-static struct key *request_user_key(const char *master_desc, u8 **master_key,
-                                   size_t *master_keylen)
-{
-       struct user_key_payload *upayload;
-       struct key *ukey;
-
-       ukey = request_key(&key_type_user, master_desc, NULL);
-       if (IS_ERR(ukey))
-               goto error;
-
-       down_read(&ukey->sem);
-       upayload = rcu_dereference(ukey->payload.data);
-       *master_key = upayload->data;
-       *master_keylen = upayload->datalen;
-error:
-       return ukey;
-}
-
-static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
-{
-       struct sdesc *sdesc;
-       int size;
-
-       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
-       sdesc = kmalloc(size, GFP_KERNEL);
-       if (!sdesc)
-               return ERR_PTR(-ENOMEM);
-       sdesc->shash.tfm = alg;
-       sdesc->shash.flags = 0x0;
-       return sdesc;
-}
-
-static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
-                    const u8 *buf, unsigned int buflen)
-{
-       struct sdesc *sdesc;
-       int ret;
-
-       sdesc = alloc_sdesc(hmacalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       ret = crypto_shash_setkey(hmacalg, key, keylen);
-       if (!ret)
-               ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
-       kfree(sdesc);
-       return ret;
-}
-
-static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
-{
-       struct sdesc *sdesc;
-       int ret;
-
-       sdesc = alloc_sdesc(hashalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("encrypted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
-       kfree(sdesc);
-       return ret;
-}
-
-enum derived_key_type { ENC_KEY, AUTH_KEY };
-
-/* Derive authentication/encryption key from trusted key */
-static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
-                          const u8 *master_key, size_t master_keylen)
-{
-       u8 *derived_buf;
-       unsigned int derived_buf_len;
-       int ret;
-
-       derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
-       if (derived_buf_len < HASH_SIZE)
-               derived_buf_len = HASH_SIZE;
-
-       derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
-       if (!derived_buf) {
-               pr_err("encrypted_key: out of memory\n");
-               return -ENOMEM;
-       }
-       if (key_type)
-               strcpy(derived_buf, "AUTH_KEY");
-       else
-               strcpy(derived_buf, "ENC_KEY");
-
-       memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
-              master_keylen);
-       ret = calc_hash(derived_key, derived_buf, derived_buf_len);
-       kfree(derived_buf);
-       return ret;
-}
-
-static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
-                              unsigned int key_len, const u8 *iv,
-                              unsigned int ivsize)
-{
-       int ret;
-
-       desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(desc->tfm)) {
-               pr_err("encrypted_key: failed to load %s transform (%ld)\n",
-                      blkcipher_alg, PTR_ERR(desc->tfm));
-               return PTR_ERR(desc->tfm);
-       }
-       desc->flags = 0;
-
-       ret = crypto_blkcipher_setkey(desc->tfm, key, key_len);
-       if (ret < 0) {
-               pr_err("encrypted_key: failed to setkey (%d)\n", ret);
-               crypto_free_blkcipher(desc->tfm);
-               return ret;
-       }
-       crypto_blkcipher_set_iv(desc->tfm, iv, ivsize);
-       return 0;
-}
-
-static struct key *request_master_key(struct encrypted_key_payload *epayload,
-                                     u8 **master_key, size_t *master_keylen)
-{
-       struct key *mkey = NULL;
-
-       if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
-                    KEY_TRUSTED_PREFIX_LEN)) {
-               mkey = request_trusted_key(epayload->master_desc +
-                                          KEY_TRUSTED_PREFIX_LEN,
-                                          master_key, master_keylen);
-       } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
-                           KEY_USER_PREFIX_LEN)) {
-               mkey = request_user_key(epayload->master_desc +
-                                       KEY_USER_PREFIX_LEN,
-                                       master_key, master_keylen);
-       } else
-               goto out;
-
-       if (IS_ERR(mkey))
-               pr_info("encrypted_key: key %s not found",
-                       epayload->master_desc);
-       if (mkey)
-               dump_master_key(*master_key, *master_keylen);
-out:
-       return mkey;
-}
-
-/* Before returning data to userspace, encrypt decrypted data. */
-static int derived_key_encrypt(struct encrypted_key_payload *epayload,
-                              const u8 *derived_key,
-                              unsigned int derived_keylen)
-{
-       struct scatterlist sg_in[2];
-       struct scatterlist sg_out[1];
-       struct blkcipher_desc desc;
-       unsigned int encrypted_datalen;
-       unsigned int padlen;
-       char pad[16];
-       int ret;
-
-       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
-       padlen = encrypted_datalen - epayload->decrypted_datalen;
-
-       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
-                                 epayload->iv, ivsize);
-       if (ret < 0)
-               goto out;
-       dump_decrypted_data(epayload);
-
-       memset(pad, 0, sizeof pad);
-       sg_init_table(sg_in, 2);
-       sg_set_buf(&sg_in[0], epayload->decrypted_data,
-                  epayload->decrypted_datalen);
-       sg_set_buf(&sg_in[1], pad, padlen);
-
-       sg_init_table(sg_out, 1);
-       sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
-
-       ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen);
-       crypto_free_blkcipher(desc.tfm);
-       if (ret < 0)
-               pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
-       else
-               dump_encrypted_data(epayload, encrypted_datalen);
-out:
-       return ret;
-}
-
-static int datablob_hmac_append(struct encrypted_key_payload *epayload,
-                               const u8 *master_key, size_t master_keylen)
-{
-       u8 derived_key[HASH_SIZE];
-       u8 *digest;
-       int ret;
-
-       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
-       if (ret < 0)
-               goto out;
-
-       digest = epayload->master_desc + epayload->datablob_len;
-       ret = calc_hmac(digest, derived_key, sizeof derived_key,
-                       epayload->master_desc, epayload->datablob_len);
-       if (!ret)
-               dump_hmac(NULL, digest, HASH_SIZE);
-out:
-       return ret;
-}
-
-/* verify HMAC before decrypting encrypted key */
-static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
-                               const u8 *master_key, size_t master_keylen)
-{
-       u8 derived_key[HASH_SIZE];
-       u8 digest[HASH_SIZE];
-       int ret;
-
-       ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
-       if (ret < 0)
-               goto out;
-
-       ret = calc_hmac(digest, derived_key, sizeof derived_key,
-                       epayload->master_desc, epayload->datablob_len);
-       if (ret < 0)
-               goto out;
-       ret = memcmp(digest, epayload->master_desc + epayload->datablob_len,
-                    sizeof digest);
-       if (ret) {
-               ret = -EINVAL;
-               dump_hmac("datablob",
-                         epayload->master_desc + epayload->datablob_len,
-                         HASH_SIZE);
-               dump_hmac("calc", digest, HASH_SIZE);
-       }
-out:
-       return ret;
-}
-
-static int derived_key_decrypt(struct encrypted_key_payload *epayload,
-                              const u8 *derived_key,
-                              unsigned int derived_keylen)
-{
-       struct scatterlist sg_in[1];
-       struct scatterlist sg_out[2];
-       struct blkcipher_desc desc;
-       unsigned int encrypted_datalen;
-       char pad[16];
-       int ret;
-
-       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
-       ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
-                                 epayload->iv, ivsize);
-       if (ret < 0)
-               goto out;
-       dump_encrypted_data(epayload, encrypted_datalen);
-
-       memset(pad, 0, sizeof pad);
-       sg_init_table(sg_in, 1);
-       sg_init_table(sg_out, 2);
-       sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
-       sg_set_buf(&sg_out[0], epayload->decrypted_data,
-                  epayload->decrypted_datalen);
-       sg_set_buf(&sg_out[1], pad, sizeof pad);
-
-       ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen);
-       crypto_free_blkcipher(desc.tfm);
-       if (ret < 0)
-               goto out;
-       dump_decrypted_data(epayload);
-out:
-       return ret;
-}
-
-/* Allocate memory for decrypted key and datablob. */
-static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
-                                                        const char *master_desc,
-                                                        const char *datalen)
-{
-       struct encrypted_key_payload *epayload = NULL;
-       unsigned short datablob_len;
-       unsigned short decrypted_datalen;
-       unsigned int encrypted_datalen;
-       long dlen;
-       int ret;
-
-       ret = strict_strtol(datalen, 10, &dlen);
-       if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
-               return ERR_PTR(-EINVAL);
-
-       decrypted_datalen = dlen;
-       encrypted_datalen = roundup(decrypted_datalen, blksize);
-
-       datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1
-           + ivsize + 1 + encrypted_datalen;
-
-       ret = key_payload_reserve(key, decrypted_datalen + datablob_len
-                                 + HASH_SIZE + 1);
-       if (ret < 0)
-               return ERR_PTR(ret);
-
-       epayload = kzalloc(sizeof(*epayload) + decrypted_datalen +
-                          datablob_len + HASH_SIZE + 1, GFP_KERNEL);
-       if (!epayload)
-               return ERR_PTR(-ENOMEM);
-
-       epayload->decrypted_datalen = decrypted_datalen;
-       epayload->datablob_len = datablob_len;
-       return epayload;
-}
-
-static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
-                                const char *hex_encoded_iv)
-{
-       struct key *mkey;
-       u8 derived_key[HASH_SIZE];
-       u8 *master_key;
-       u8 *hmac;
-       const char *hex_encoded_data;
-       unsigned int encrypted_datalen;
-       size_t master_keylen;
-       size_t asciilen;
-       int ret;
-
-       encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
-       asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
-       if (strlen(hex_encoded_iv) != asciilen)
-               return -EINVAL;
-
-       hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
-       hex2bin(epayload->iv, hex_encoded_iv, ivsize);
-       hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
-
-       hmac = epayload->master_desc + epayload->datablob_len;
-       hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
-
-       mkey = request_master_key(epayload, &master_key, &master_keylen);
-       if (IS_ERR(mkey))
-               return PTR_ERR(mkey);
-
-       ret = datablob_hmac_verify(epayload, master_key, master_keylen);
-       if (ret < 0) {
-               pr_err("encrypted_key: bad hmac (%d)\n", ret);
-               goto out;
-       }
-
-       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
-       if (ret < 0)
-               goto out;
-
-       ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
-       if (ret < 0)
-               pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
-out:
-       up_read(&mkey->sem);
-       key_put(mkey);
-       return ret;
-}
-
-static void __ekey_init(struct encrypted_key_payload *epayload,
-                       const char *master_desc, const char *datalen)
-{
-       epayload->master_desc = epayload->decrypted_data
-           + epayload->decrypted_datalen;
-       epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
-       epayload->iv = epayload->datalen + strlen(datalen) + 1;
-       epayload->encrypted_data = epayload->iv + ivsize + 1;
-
-       memcpy(epayload->master_desc, master_desc, strlen(master_desc));
-       memcpy(epayload->datalen, datalen, strlen(datalen));
-}
-
-/*
- * encrypted_init - initialize an encrypted key
- *
- * For a new key, use a random number for both the iv and data
- * itself.  For an old key, decrypt the hex encoded data.
- */
-static int encrypted_init(struct encrypted_key_payload *epayload,
-                         const char *master_desc, const char *datalen,
-                         const char *hex_encoded_iv)
-{
-       int ret = 0;
-
-       __ekey_init(epayload, master_desc, datalen);
-       if (!hex_encoded_iv) {
-               get_random_bytes(epayload->iv, ivsize);
-
-               get_random_bytes(epayload->decrypted_data,
-                                epayload->decrypted_datalen);
-       } else
-               ret = encrypted_key_decrypt(epayload, hex_encoded_iv);
-       return ret;
-}
-
-/*
- * encrypted_instantiate - instantiate an encrypted key
- *
- * Decrypt an existing encrypted datablob or create a new encrypted key
- * based on a kernel random number.
- *
- * On success, return 0. Otherwise return errno.
- */
-static int encrypted_instantiate(struct key *key, const void *data,
-                                size_t datalen)
-{
-       struct encrypted_key_payload *epayload = NULL;
-       char *datablob = NULL;
-       char *master_desc = NULL;
-       char *decrypted_datalen = NULL;
-       char *hex_encoded_iv = NULL;
-       int ret;
-
-       if (datalen <= 0 || datalen > 32767 || !data)
-               return -EINVAL;
-
-       datablob = kmalloc(datalen + 1, GFP_KERNEL);
-       if (!datablob)
-               return -ENOMEM;
-       datablob[datalen] = 0;
-       memcpy(datablob, data, datalen);
-       ret = datablob_parse(datablob, &master_desc, &decrypted_datalen,
-                            &hex_encoded_iv);
-       if (ret < 0)
-               goto out;
-
-       epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen);
-       if (IS_ERR(epayload)) {
-               ret = PTR_ERR(epayload);
-               goto out;
-       }
-       ret = encrypted_init(epayload, master_desc, decrypted_datalen,
-                            hex_encoded_iv);
-       if (ret < 0) {
-               kfree(epayload);
-               goto out;
-       }
-
-       rcu_assign_pointer(key->payload.data, epayload);
-out:
-       kfree(datablob);
-       return ret;
-}
-
-static void encrypted_rcu_free(struct rcu_head *rcu)
-{
-       struct encrypted_key_payload *epayload;
-
-       epayload = container_of(rcu, struct encrypted_key_payload, rcu);
-       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
-       kfree(epayload);
-}
-
-/*
- * encrypted_update - update the master key description
- *
- * Change the master key description for an existing encrypted key.
- * The next read will return an encrypted datablob using the new
- * master key description.
- *
- * On success, return 0. Otherwise return errno.
- */
-static int encrypted_update(struct key *key, const void *data, size_t datalen)
-{
-       struct encrypted_key_payload *epayload = key->payload.data;
-       struct encrypted_key_payload *new_epayload;
-       char *buf;
-       char *new_master_desc = NULL;
-       int ret = 0;
-
-       if (datalen <= 0 || datalen > 32767 || !data)
-               return -EINVAL;
-
-       buf = kmalloc(datalen + 1, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf[datalen] = 0;
-       memcpy(buf, data, datalen);
-       ret = datablob_parse(buf, &new_master_desc, NULL, NULL);
-       if (ret < 0)
-               goto out;
-
-       ret = valid_master_desc(new_master_desc, epayload->master_desc);
-       if (ret < 0)
-               goto out;
-
-       new_epayload = encrypted_key_alloc(key, new_master_desc,
-                                          epayload->datalen);
-       if (IS_ERR(new_epayload)) {
-               ret = PTR_ERR(new_epayload);
-               goto out;
-       }
-
-       __ekey_init(new_epayload, new_master_desc, epayload->datalen);
-
-       memcpy(new_epayload->iv, epayload->iv, ivsize);
-       memcpy(new_epayload->decrypted_data, epayload->decrypted_data,
-              epayload->decrypted_datalen);
-
-       rcu_assign_pointer(key->payload.data, new_epayload);
-       call_rcu(&epayload->rcu, encrypted_rcu_free);
-out:
-       kfree(buf);
-       return ret;
-}
-
-/*
- * encrypted_read - format and copy the encrypted data to userspace
- *
- * The resulting datablob format is:
- * <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
- *
- * On success, return to userspace the encrypted key datablob size.
- */
-static long encrypted_read(const struct key *key, char __user *buffer,
-                          size_t buflen)
-{
-       struct encrypted_key_payload *epayload;
-       struct key *mkey;
-       u8 *master_key;
-       size_t master_keylen;
-       char derived_key[HASH_SIZE];
-       char *ascii_buf;
-       size_t asciiblob_len;
-       int ret;
-
-       epayload = rcu_dereference_protected(key->payload.data,
-                                 rwsem_is_locked(&((struct key *)key)->sem));
-
-       /* returns the hex encoded iv, encrypted-data, and hmac as ascii */
-       asciiblob_len = epayload->datablob_len + ivsize + 1
-           + roundup(epayload->decrypted_datalen, blksize)
-           + (HASH_SIZE * 2);
-
-       if (!buffer || buflen < asciiblob_len)
-               return asciiblob_len;
-
-       mkey = request_master_key(epayload, &master_key, &master_keylen);
-       if (IS_ERR(mkey))
-               return PTR_ERR(mkey);
-
-       ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
-       if (ret < 0)
-               goto out;
-
-       ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key);
-       if (ret < 0)
-               goto out;
-
-       ret = datablob_hmac_append(epayload, master_key, master_keylen);
-       if (ret < 0)
-               goto out;
-
-       ascii_buf = datablob_format(epayload, asciiblob_len);
-       if (!ascii_buf) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       up_read(&mkey->sem);
-       key_put(mkey);
-
-       if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
-               ret = -EFAULT;
-       kfree(ascii_buf);
-
-       return asciiblob_len;
-out:
-       up_read(&mkey->sem);
-       key_put(mkey);
-       return ret;
-}
-
-/*
- * encrypted_destroy - before freeing the key, clear the decrypted data
- *
- * Before freeing the key, clear the memory containing the decrypted
- * key data.
- */
-static void encrypted_destroy(struct key *key)
-{
-       struct encrypted_key_payload *epayload = key->payload.data;
-
-       if (!epayload)
-               return;
-
-       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
-       kfree(key->payload.data);
-}
-
-struct key_type key_type_encrypted = {
-       .name = "encrypted",
-       .instantiate = encrypted_instantiate,
-       .update = encrypted_update,
-       .match = user_match,
-       .destroy = encrypted_destroy,
-       .describe = user_describe,
-       .read = encrypted_read,
-};
-EXPORT_SYMBOL_GPL(key_type_encrypted);
-
-static void encrypted_shash_release(void)
-{
-       if (hashalg)
-               crypto_free_shash(hashalg);
-       if (hmacalg)
-               crypto_free_shash(hmacalg);
-}
-
-static int __init encrypted_shash_alloc(void)
-{
-       int ret;
-
-       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hmacalg)) {
-               pr_info("encrypted_key: could not allocate crypto %s\n",
-                       hmac_alg);
-               return PTR_ERR(hmacalg);
-       }
-
-       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hashalg)) {
-               pr_info("encrypted_key: could not allocate crypto %s\n",
-                       hash_alg);
-               ret = PTR_ERR(hashalg);
-               goto hashalg_fail;
-       }
-
-       return 0;
-
-hashalg_fail:
-       crypto_free_shash(hmacalg);
-       return ret;
-}
-
-static int __init init_encrypted(void)
-{
-       int ret;
-
-       ret = encrypted_shash_alloc();
-       if (ret < 0)
-               return ret;
-       ret = register_key_type(&key_type_encrypted);
-       if (ret < 0)
-               goto out;
-       return aes_get_sizes();
-out:
-       encrypted_shash_release();
-       return ret;
-
-}
-
-static void __exit cleanup_encrypted(void)
-{
-       encrypted_shash_release();
-       unregister_key_type(&key_type_encrypted);
-}
-
-late_initcall(init_encrypted);
-module_exit(cleanup_encrypted);
-
-MODULE_LICENSE("GPL");
diff --git a/security/keys/encrypted_defined.h b/security/keys/encrypted_defined.h
deleted file mode 100644 (file)
index cef5e2f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef __ENCRYPTED_KEY_H
-#define __ENCRYPTED_KEY_H
-
-#define ENCRYPTED_DEBUG 0
-
-#if ENCRYPTED_DEBUG
-static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
-{
-       print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1,
-                      master_key, master_keylen, 0);
-}
-
-static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
-{
-       print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1,
-                      epayload->decrypted_data,
-                      epayload->decrypted_datalen, 0);
-}
-
-static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
-                                      unsigned int encrypted_datalen)
-{
-       print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1,
-                      epayload->encrypted_data, encrypted_datalen, 0);
-}
-
-static inline void dump_hmac(const char *str, const u8 *digest,
-                            unsigned int hmac_size)
-{
-       if (str)
-               pr_info("encrypted_key: %s", str);
-       print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest,
-                      hmac_size, 0);
-}
-#else
-static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
-{
-}
-
-static inline void dump_decrypted_data(struct encrypted_key_payload *epayload)
-{
-}
-
-static inline void dump_encrypted_data(struct encrypted_key_payload *epayload,
-                                      unsigned int encrypted_datalen)
-{
-}
-
-static inline void dump_hmac(const char *str, const u8 *digest,
-                            unsigned int hmac_size)
-{
-}
-#endif
-#endif
index a46e825..89df6b5 100644 (file)
@@ -32,8 +32,8 @@ static time_t key_gc_next_run = LONG_MAX;
 static time_t key_gc_new_timer;
 
 /*
- * Schedule a garbage collection run
- * - precision isn't particularly important
+ * Schedule a garbage collection run.
+ * - time precision isn't particularly important
  */
 void key_schedule_gc(time_t gc_at)
 {
@@ -61,8 +61,9 @@ static void key_gc_timer_func(unsigned long data)
 }
 
 /*
- * Garbage collect pointers from a keyring
- * - return true if we altered the keyring
+ * Garbage collect pointers from a keyring.
+ *
+ * Return true if we altered the keyring.
  */
 static bool key_gc_keyring(struct key *keyring, time_t limit)
        __releases(key_serial_lock)
@@ -107,9 +108,8 @@ do_gc:
 }
 
 /*
- * Garbage collector for keys
- * - this involves scanning the keyrings for dead, expired and revoked keys
- *   that have overstayed their welcome
+ * Garbage collector for keys.  This involves scanning the keyrings for dead,
+ * expired and revoked keys that have overstayed their welcome
  */
 static void key_garbage_collector(struct work_struct *work)
 {
index 56a133d..a52aa7c 100644 (file)
@@ -1,4 +1,4 @@
-/* internal.h: authentication token and access key management internal defs
+/* Authentication token and access key management internal defs
  *
  * Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -35,10 +35,12 @@ extern struct key_type key_type_user;
 
 /*****************************************************************************/
 /*
- * keep track of keys for a user
- * - this needs to be separate to user_struct to avoid a refcount-loop
- *   (user_struct pins some keyrings which pin this struct)
- * - this also keeps track of keys under request from userspace for this UID
+ * Keep track of keys for a user.
+ *
+ * This needs to be separate to user_struct to avoid a refcount-loop
+ * (user_struct pins some keyrings which pin this struct).
+ *
+ * We also keep track of keys under request from userspace for this UID here.
  */
 struct key_user {
        struct rb_node          node;
@@ -62,7 +64,7 @@ extern struct key_user *key_user_lookup(uid_t uid,
 extern void key_user_put(struct key_user *user);
 
 /*
- * key quota limits
+ * Key quota limits.
  * - root has its own separate limits to everyone else
  */
 extern unsigned key_quota_root_maxkeys;
@@ -85,13 +87,13 @@ extern void key_type_put(struct key_type *ktype);
 extern int __key_link_begin(struct key *keyring,
                            const struct key_type *type,
                            const char *description,
-                           struct keyring_list **_prealloc);
+                           unsigned long *_prealloc);
 extern int __key_link_check_live_key(struct key *keyring, struct key *key);
 extern void __key_link(struct key *keyring, struct key *key,
-                      struct keyring_list **_prealloc);
+                      unsigned long *_prealloc);
 extern void __key_link_end(struct key *keyring,
                           struct key_type *type,
-                          struct keyring_list *prealloc);
+                          unsigned long prealloc);
 
 extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
                                      const struct key_type *type,
@@ -146,13 +148,13 @@ extern unsigned key_gc_delay;
 extern void keyring_gc(struct key *keyring, time_t limit);
 extern void key_schedule_gc(time_t expiry_at);
 
-/*
- * check to see whether permission is granted to use a key in the desired way
- */
 extern int key_task_permission(const key_ref_t key_ref,
                               const struct cred *cred,
                               key_perm_t perm);
 
+/*
+ * Check to see whether permission is granted to use a key in the desired way.
+ */
 static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
 {
        return key_task_permission(key_ref, current_cred(), perm);
@@ -168,7 +170,7 @@ static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
 #define        KEY_ALL         0x3f    /* all the above permissions */
 
 /*
- * request_key authorisation
+ * Authorisation record for request_key().
  */
 struct request_key_auth {
        struct key              *target_key;
@@ -188,7 +190,7 @@ extern struct key *request_key_auth_new(struct key *target,
 extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
 
 /*
- * keyctl functions
+ * keyctl() functions
  */
 extern long keyctl_get_keyring_ID(key_serial_t, int);
 extern long keyctl_join_session_keyring(const char __user *);
@@ -214,7 +216,7 @@ extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
 extern long keyctl_session_to_parent(void);
 
 /*
- * debugging key validation
+ * Debugging key validation
  */
 #ifdef KEY_DEBUGGING
 extern void __key_check(const struct key *);
index c1eac80..1c2d43d 100644 (file)
@@ -39,10 +39,10 @@ static DECLARE_RWSEM(key_types_sem);
 static void key_cleanup(struct work_struct *work);
 static DECLARE_WORK(key_cleanup_task, key_cleanup);
 
-/* we serialise key instantiation and link */
+/* We serialise key instantiation and link */
 DEFINE_MUTEX(key_construction_mutex);
 
-/* any key who's type gets unegistered will be re-typed to this */
+/* Any key who's type gets unegistered will be re-typed to this */
 static struct key_type key_type_dead = {
        .name           = "dead",
 };
@@ -56,10 +56,9 @@ void __key_check(const struct key *key)
 }
 #endif
 
-/*****************************************************************************/
 /*
- * get the key quota record for a user, allocating a new record if one doesn't
- * already exist
+ * Get the key quota record for a user, allocating a new record if one doesn't
+ * already exist.
  */
 struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
 {
@@ -67,7 +66,7 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
        struct rb_node *parent = NULL;
        struct rb_node **p;
 
- try_again:
+try_again:
        p = &key_user_tree.rb_node;
        spin_lock(&key_user_lock);
 
@@ -124,18 +123,16 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
        goto out;
 
        /* okay - we found a user record for this UID */
- found:
+found:
        atomic_inc(&user->usage);
        spin_unlock(&key_user_lock);
        kfree(candidate);
- out:
+out:
        return user;
+}
 
-} /* end key_user_lookup() */
-
-/*****************************************************************************/
 /*
- * dispose of a user structure
+ * Dispose of a user structure
  */
 void key_user_put(struct key_user *user)
 {
@@ -146,14 +143,11 @@ void key_user_put(struct key_user *user)
 
                kfree(user);
        }
+}
 
-} /* end key_user_put() */
-
-/*****************************************************************************/
 /*
- * assign a key the next unique serial number
- * - these are assigned randomly to avoid security issues through covert
- *   channel problems
+ * Allocate a serial number for a key.  These are assigned randomly to avoid
+ * security issues through covert channel problems.
  */
 static inline void key_alloc_serial(struct key *key)
 {
@@ -211,18 +205,36 @@ serial_exists:
                if (key->serial < xkey->serial)
                        goto attempt_insertion;
        }
+}
 
-} /* end key_alloc_serial() */
-
-/*****************************************************************************/
-/*
- * allocate a key of the specified type
- * - update the user's quota to reflect the existence of the key
- * - called from a key-type operation with key_types_sem read-locked by
- *   key_create_or_update()
- *   - this prevents unregistration of the key type
- * - upon return the key is as yet uninstantiated; the caller needs to either
- *   instantiate the key or discard it before returning
+/**
+ * key_alloc - Allocate a key of the specified type.
+ * @type: The type of key to allocate.
+ * @desc: The key description to allow the key to be searched out.
+ * @uid: The owner of the new key.
+ * @gid: The group ID for the new key's group permissions.
+ * @cred: The credentials specifying UID namespace.
+ * @perm: The permissions mask of the new key.
+ * @flags: Flags specifying quota properties.
+ *
+ * Allocate a key of the specified type with the attributes given.  The key is
+ * returned in an uninstantiated state and the caller needs to instantiate the
+ * key before returning.
+ *
+ * The user's key count quota is updated to reflect the creation of the key and
+ * the user's key data quota has the default for the key type reserved.  The
+ * instantiation function should amend this as necessary.  If insufficient
+ * quota is available, -EDQUOT will be returned.
+ *
+ * The LSM security modules can prevent a key being created, in which case
+ * -EACCES will be returned.
+ *
+ * Returns a pointer to the new key if successful and an error code otherwise.
+ *
+ * Note that the caller needs to ensure the key type isn't uninstantiated.
+ * Internally this can be done by locking key_types_sem.  Externally, this can
+ * be done by either never unregistering the key type, or making sure
+ * key_alloc() calls don't race with module unloading.
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
                      uid_t uid, gid_t gid, const struct cred *cred,
@@ -344,14 +356,19 @@ no_quota:
        key_user_put(user);
        key = ERR_PTR(-EDQUOT);
        goto error;
-
-} /* end key_alloc() */
-
+}
 EXPORT_SYMBOL(key_alloc);
 
-/*****************************************************************************/
-/*
- * reserve an amount of quota for the key's payload
+/**
+ * key_payload_reserve - Adjust data quota reservation for the key's payload
+ * @key: The key to make the reservation for.
+ * @datalen: The amount of data payload the caller now wants.
+ *
+ * Adjust the amount of the owning user's key data quota that a key reserves.
+ * If the amount is increased, then -EDQUOT may be returned if there isn't
+ * enough free quota available.
+ *
+ * If successful, 0 is returned.
  */
 int key_payload_reserve(struct key *key, size_t datalen)
 {
@@ -384,22 +401,21 @@ int key_payload_reserve(struct key *key, size_t datalen)
                key->datalen = datalen;
 
        return ret;
-
-} /* end key_payload_reserve() */
-
+}
 EXPORT_SYMBOL(key_payload_reserve);
 
-/*****************************************************************************/
 /*
- * instantiate a key and link it into the target keyring atomically
- * - called with the target keyring's semaphore writelocked
+ * Instantiate a key and link it into the target keyring atomically.  Must be
+ * called with the target keyring's semaphore writelocked.  The target key's
+ * semaphore need not be locked as instantiation is serialised by
+ * key_construction_mutex.
  */
 static int __key_instantiate_and_link(struct key *key,
                                      const void *data,
                                      size_t datalen,
                                      struct key *keyring,
                                      struct key *authkey,
-                                     struct keyring_list **_prealloc)
+                                     unsigned long *_prealloc)
 {
        int ret, awaken;
 
@@ -441,12 +457,23 @@ static int __key_instantiate_and_link(struct key *key,
                wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
        return ret;
+}
 
-} /* end __key_instantiate_and_link() */
-
-/*****************************************************************************/
-/*
- * instantiate a key and link it into the target keyring atomically
+/**
+ * key_instantiate_and_link - Instantiate a key and link it into the keyring.
+ * @key: The key to instantiate.
+ * @data: The data to use to instantiate the keyring.
+ * @datalen: The length of @data.
+ * @keyring: Keyring to create a link in on success (or NULL).
+ * @authkey: The authorisation token permitting instantiation.
+ *
+ * Instantiate a key that's in the uninstantiated state using the provided data
+ * and, if successful, link it in to the destination keyring if one is
+ * supplied.
+ *
+ * If successful, 0 is returned, the authorisation token is revoked and anyone
+ * waiting for the key is woken up.  If the key was already instantiated,
+ * -EBUSY will be returned.
  */
 int key_instantiate_and_link(struct key *key,
                             const void *data,
@@ -454,7 +481,7 @@ int key_instantiate_and_link(struct key *key,
                             struct key *keyring,
                             struct key *authkey)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        int ret;
 
        if (keyring) {
@@ -471,21 +498,35 @@ int key_instantiate_and_link(struct key *key,
                __key_link_end(keyring, key->type, prealloc);
 
        return ret;
-
-} /* end key_instantiate_and_link() */
+}
 
 EXPORT_SYMBOL(key_instantiate_and_link);
 
-/*****************************************************************************/
-/*
- * negatively instantiate a key and link it into the target keyring atomically
+/**
+ * key_negate_and_link - Negatively instantiate a key and link it into the keyring.
+ * @key: The key to instantiate.
+ * @timeout: The timeout on the negative key.
+ * @keyring: Keyring to create a link in on success (or NULL).
+ * @authkey: The authorisation token permitting instantiation.
+ *
+ * Negatively instantiate a key that's in the uninstantiated state and, if
+ * successful, set its timeout and link it in to the destination keyring if one
+ * is supplied.  The key and any links to the key will be automatically garbage
+ * collected after the timeout expires.
+ *
+ * Negative keys are used to rate limit repeated request_key() calls by causing
+ * them to return -ENOKEY until the negative key expires.
+ *
+ * If successful, 0 is returned, the authorisation token is revoked and anyone
+ * waiting for the key is woken up.  If the key was already instantiated,
+ * -EBUSY will be returned.
  */
 int key_negate_and_link(struct key *key,
                        unsigned timeout,
                        struct key *keyring,
                        struct key *authkey)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        struct timespec now;
        int ret, awaken, link_ret = 0;
 
@@ -535,22 +576,23 @@ int key_negate_and_link(struct key *key,
                wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
        return ret == 0 ? link_ret : ret;
-
-} /* end key_negate_and_link() */
+}
 
 EXPORT_SYMBOL(key_negate_and_link);
 
-/*****************************************************************************/
 /*
- * do cleaning up in process context so that we don't have to disable
- * interrupts all over the place
+ * Garbage collect keys in process context so that we don't have to disable
+ * interrupts all over the place.
+ *
+ * key_put() schedules this rather than trying to do the cleanup itself, which
+ * means key_put() doesn't have to sleep.
  */
 static void key_cleanup(struct work_struct *work)
 {
        struct rb_node *_n;
        struct key *key;
 
- go_again:
+go_again:
        /* look for a dead key in the tree */
        spin_lock(&key_serial_lock);
 
@@ -564,7 +606,7 @@ static void key_cleanup(struct work_struct *work)
        spin_unlock(&key_serial_lock);
        return;
 
- found_dead_key:
+found_dead_key:
        /* we found a dead key - once we've removed it from the tree, we can
         * drop the lock */
        rb_erase(&key->serial_node, &key_serial_tree);
@@ -601,14 +643,15 @@ static void key_cleanup(struct work_struct *work)
 
        /* there may, of course, be more than one key to destroy */
        goto go_again;
+}
 
-} /* end key_cleanup() */
-
-/*****************************************************************************/
-/*
- * dispose of a reference to a key
- * - when all the references are gone, we schedule the cleanup task to come and
- *   pull it out of the tree in definite process context
+/**
+ * key_put - Discard a reference to a key.
+ * @key: The key to discard a reference from.
+ *
+ * Discard a reference to a key, and when all the references are gone, we
+ * schedule the cleanup task to come and pull it out of the tree in process
+ * context at some later time.
  */
 void key_put(struct key *key)
 {
@@ -618,14 +661,11 @@ void key_put(struct key *key)
                if (atomic_dec_and_test(&key->usage))
                        schedule_work(&key_cleanup_task);
        }
-
-} /* end key_put() */
-
+}
 EXPORT_SYMBOL(key_put);
 
-/*****************************************************************************/
 /*
- * find a key by its serial number
+ * Find a key by its serial number.
  */
 struct key *key_lookup(key_serial_t id)
 {
@@ -647,11 +687,11 @@ struct key *key_lookup(key_serial_t id)
                        goto found;
        }
 
- not_found:
+not_found:
        key = ERR_PTR(-ENOKEY);
        goto error;
 
- found:
+found:
        /* pretend it doesn't exist if it is awaiting deletion */
        if (atomic_read(&key->usage) == 0)
                goto not_found;
@@ -661,16 +701,16 @@ struct key *key_lookup(key_serial_t id)
         */
        atomic_inc(&key->usage);
 
- error:
+error:
        spin_unlock(&key_serial_lock);
        return key;
+}
 
-} /* end key_lookup() */
-
-/*****************************************************************************/
 /*
- * find and lock the specified key type against removal
- * - we return with the sem readlocked
+ * Find and lock the specified key type against removal.
+ *
+ * We return with the sem read-locked if successful.  If the type wasn't
+ * available -ENOKEY is returned instead.
  */
 struct key_type *key_type_lookup(const char *type)
 {
@@ -688,26 +728,23 @@ struct key_type *key_type_lookup(const char *type)
        up_read(&key_types_sem);
        ktype = ERR_PTR(-ENOKEY);
 
- found_kernel_type:
+found_kernel_type:
        return ktype;
+}
 
-} /* end key_type_lookup() */
-
-/*****************************************************************************/
 /*
- * unlock a key type
+ * Unlock a key type locked by key_type_lookup().
  */
 void key_type_put(struct key_type *ktype)
 {
        up_read(&key_types_sem);
+}
 
-} /* end key_type_put() */
-
-/*****************************************************************************/
 /*
- * attempt to update an existing key
- * - the key has an incremented refcount
- * - we need to put the key if we get an error
+ * Attempt to update an existing key.
+ *
+ * The key is given to us with an incremented refcount that we need to discard
+ * if we get an error.
  */
 static inline key_ref_t __key_update(key_ref_t key_ref,
                                     const void *payload, size_t plen)
@@ -742,13 +779,32 @@ error:
        key_put(key);
        key_ref = ERR_PTR(ret);
        goto out;
+}
 
-} /* end __key_update() */
-
-/*****************************************************************************/
-/*
- * search the specified keyring for a key of the same description; if one is
- * found, update it, otherwise add a new one
+/**
+ * key_create_or_update - Update or create and instantiate a key.
+ * @keyring_ref: A pointer to the destination keyring with possession flag.
+ * @type: The type of key.
+ * @description: The searchable description for the key.
+ * @payload: The data to use to instantiate or update the key.
+ * @plen: The length of @payload.
+ * @perm: The permissions mask for a new key.
+ * @flags: The quota flags for a new key.
+ *
+ * Search the destination keyring for a key of the same description and if one
+ * is found, update it, otherwise create and instantiate a new one and create a
+ * link to it from that keyring.
+ *
+ * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
+ * concocted.
+ *
+ * Returns a pointer to the new key if successful, -ENODEV if the key type
+ * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
+ * caller isn't permitted to modify the keyring or the LSM did not permit
+ * creation of the key.
+ *
+ * On success, the possession flag from the keyring ref will be tacked on to
+ * the key ref before it is returned.
  */
 key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               const char *type,
@@ -758,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               key_perm_t perm,
                               unsigned long flags)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        const struct cred *cred = current_cred();
        struct key_type *ktype;
        struct key *keyring, *key = NULL;
@@ -855,14 +911,21 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
        key_ref = __key_update(key_ref, payload, plen);
        goto error;
-
-} /* end key_create_or_update() */
-
+}
 EXPORT_SYMBOL(key_create_or_update);
 
-/*****************************************************************************/
-/*
- * update a key
+/**
+ * key_update - Update a key's contents.
+ * @key_ref: The pointer (plus possession flag) to the key.
+ * @payload: The data to be used to update the key.
+ * @plen: The length of @payload.
+ *
+ * Attempt to update the contents of a key with the given payload data.  The
+ * caller must be granted Write permission on the key.  Negative keys can be
+ * instantiated by this method.
+ *
+ * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key
+ * type does not support updating.  The key type may return other errors.
  */
 int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 {
@@ -891,14 +954,17 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 
  error:
        return ret;
-
-} /* end key_update() */
-
+}
 EXPORT_SYMBOL(key_update);
 
-/*****************************************************************************/
-/*
- * revoke a key
+/**
+ * key_revoke - Revoke a key.
+ * @key: The key to be revoked.
+ *
+ * Mark a key as being revoked and ask the type to free up its resources.  The
+ * revocation timeout is set and the key and all its links will be
+ * automatically garbage collected after key_gc_delay amount of time if they
+ * are not manually dealt with first.
  */
 void key_revoke(struct key *key)
 {
@@ -926,14 +992,16 @@ void key_revoke(struct key *key)
        }
 
        up_write(&key->sem);
-
-} /* end key_revoke() */
-
+}
 EXPORT_SYMBOL(key_revoke);
 
-/*****************************************************************************/
-/*
- * register a type of key
+/**
+ * register_key_type - Register a type of key.
+ * @ktype: The new key type.
+ *
+ * Register a new key type.
+ *
+ * Returns 0 on success or -EEXIST if a type of this name already exists.
  */
 int register_key_type(struct key_type *ktype)
 {
@@ -953,17 +1021,19 @@ int register_key_type(struct key_type *ktype)
        list_add(&ktype->link, &key_types_list);
        ret = 0;
 
- out:
+out:
        up_write(&key_types_sem);
        return ret;
-
-} /* end register_key_type() */
-
+}
 EXPORT_SYMBOL(register_key_type);
 
-/*****************************************************************************/
-/*
- * unregister a type of key
+/**
+ * unregister_key_type - Unregister a type of key.
+ * @ktype: The key type.
+ *
+ * Unregister a key type and mark all the extant keys of this type as dead.
+ * Those keys of this type are then destroyed to get rid of their payloads and
+ * they and their links will be garbage collected as soon as possible.
  */
 void unregister_key_type(struct key_type *ktype)
 {
@@ -1010,14 +1080,11 @@ void unregister_key_type(struct key_type *ktype)
        up_write(&key_types_sem);
 
        key_schedule_gc(0);
-
-} /* end unregister_key_type() */
-
+}
 EXPORT_SYMBOL(unregister_key_type);
 
-/*****************************************************************************/
 /*
- * initialise the key management stuff
+ * Initialise the key management state.
  */
 void __init key_init(void)
 {
@@ -1037,5 +1104,4 @@ void __init key_init(void)
 
        rb_insert_color(&root_key_user.node,
                        &key_user_tree);
-
-} /* end key_init() */
+}
index 60924f6..31a0fd8 100644 (file)
@@ -1,4 +1,4 @@
-/* keyctl.c: userspace keyctl operations
+/* Userspace key control operations
  *
  * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -31,28 +31,24 @@ static int key_get_type_from_user(char *type,
        int ret;
 
        ret = strncpy_from_user(type, _type, len);
-
        if (ret < 0)
                return ret;
-
        if (ret == 0 || ret >= len)
                return -EINVAL;
-
        if (type[0] == '.')
                return -EPERM;
-
        type[len - 1] = '\0';
-
        return 0;
 }
 
-/*****************************************************************************/
 /*
- * extract the description of a new key from userspace and either add it as a
- * new key to the specified keyring or update a matching key in that keyring
- * - the keyring must be writable
- * - returns the new key's serial number
- * - implements add_key()
+ * Extract the description of a new key from userspace and either add it as a
+ * new key to the specified keyring or update a matching key in that keyring.
+ *
+ * The keyring must be writable so that we can attach the key to it.
+ *
+ * If successful, the new key's serial number is returned, otherwise an error
+ * code is returned.
  */
 SYSCALL_DEFINE5(add_key, const char __user *, _type,
                const char __user *, _description,
@@ -132,19 +128,20 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        kfree(description);
  error:
        return ret;
+}
 
-} /* end sys_add_key() */
-
-/*****************************************************************************/
 /*
- * search the process keyrings for a matching key
- * - nested keyrings may also be searched if they have Search permission
- * - if a key is found, it will be attached to the destination keyring if
- *   there's one specified
- * - /sbin/request-key will be invoked if _callout_info is non-NULL
- *   - the _callout_info string will be passed to /sbin/request-key
- *   - if the _callout_info string is empty, it will be rendered as "-"
- * - implements request_key()
+ * Search the process keyrings and keyring trees linked from those for a
+ * matching key.  Keyrings must have appropriate Search permission to be
+ * searched.
+ *
+ * If a key is found, it will be attached to the destination keyring if there's
+ * one specified and the serial number of the key will be returned.
+ *
+ * If no key is found, /sbin/request-key will be invoked if _callout_info is
+ * non-NULL in an attempt to create a key.  The _callout_info string will be
+ * passed to /sbin/request-key to aid with completing the request.  If the
+ * _callout_info string is "" then it will be changed to "-".
  */
 SYSCALL_DEFINE4(request_key, const char __user *, _type,
                const char __user *, _description,
@@ -222,14 +219,14 @@ error2:
        kfree(description);
 error:
        return ret;
+}
 
-} /* end sys_request_key() */
-
-/*****************************************************************************/
 /*
- * get the ID of the specified process keyring
- * - the keyring must have search permission to be found
- * - implements keyctl(KEYCTL_GET_KEYRING_ID)
+ * Get the ID of the specified process keyring.
+ *
+ * The requested keyring must have search permission to be found.
+ *
+ * If successful, the ID of the requested keyring will be returned.
  */
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
@@ -248,13 +245,17 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
        key_ref_put(key_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_get_keyring_ID() */
-
-/*****************************************************************************/
 /*
- * join the session keyring
- * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING)
+ * Join a (named) session keyring.
+ *
+ * Create and join an anonymous session keyring or join a named session
+ * keyring, creating it if necessary.  A named session keyring must have Search
+ * permission for it to be joined.  Session keyrings without this permit will
+ * be skipped over.
+ *
+ * If successful, the ID of the joined session keyring will be returned.
  */
 long keyctl_join_session_keyring(const char __user *_name)
 {
@@ -277,14 +278,17 @@ long keyctl_join_session_keyring(const char __user *_name)
 
 error:
        return ret;
+}
 
-} /* end keyctl_join_session_keyring() */
-
-/*****************************************************************************/
 /*
- * update a key's data payload
- * - the key must be writable
- * - implements keyctl(KEYCTL_UPDATE)
+ * Update a key's data payload from the given data.
+ *
+ * The key must grant the caller Write permission and the key type must support
+ * updating for this to work.  A negative key can be positively instantiated
+ * with this call.
+ *
+ * If successful, 0 will be returned.  If the key type does not support
+ * updating, then -EOPNOTSUPP will be returned.
  */
 long keyctl_update_key(key_serial_t id,
                       const void __user *_payload,
@@ -326,14 +330,17 @@ error2:
        kfree(payload);
 error:
        return ret;
+}
 
-} /* end keyctl_update_key() */
-
-/*****************************************************************************/
 /*
- * revoke a key
- * - the key must be writable
- * - implements keyctl(KEYCTL_REVOKE)
+ * Revoke a key.
+ *
+ * The key must be grant the caller Write or Setattr permission for this to
+ * work.  The key type should give up its quota claim when revoked.  The key
+ * and any links to the key will be automatically garbage collected after a
+ * certain amount of time (/proc/sys/kernel/keys/gc_delay).
+ *
+ * If successful, 0 is returned.
  */
 long keyctl_revoke_key(key_serial_t id)
 {
@@ -358,14 +365,14 @@ long keyctl_revoke_key(key_serial_t id)
        key_ref_put(key_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_revoke_key() */
-
-/*****************************************************************************/
 /*
- * clear the specified process keyring
- * - the keyring must be writable
- * - implements keyctl(KEYCTL_CLEAR)
+ * Clear the specified keyring, creating an empty process keyring if one of the
+ * special keyring IDs is used.
+ *
+ * The keyring must grant the caller Write permission for this to work.  If
+ * successful, 0 will be returned.
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
@@ -383,15 +390,18 @@ long keyctl_keyring_clear(key_serial_t ringid)
        key_ref_put(keyring_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_keyring_clear() */
-
-/*****************************************************************************/
 /*
- * link a key into a keyring
- * - the keyring must be writable
- * - the key must be linkable
- * - implements keyctl(KEYCTL_LINK)
+ * Create a link from a keyring to a key if there's no matching key in the
+ * keyring, otherwise replace the link to the matching key with a link to the
+ * new key.
+ *
+ * The key must grant the caller Link permission and the the keyring must grant
+ * the caller Write permission.  Furthermore, if an additional link is created,
+ * the keyring's quota will be extended.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
 {
@@ -417,15 +427,16 @@ error2:
        key_ref_put(keyring_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_keyring_link() */
-
-/*****************************************************************************/
 /*
- * unlink the first attachment of a key from a keyring
- * - the keyring must be writable
- * - we don't need any permissions on the key
- * - implements keyctl(KEYCTL_UNLINK)
+ * Unlink a key from a keyring.
+ *
+ * The keyring must grant the caller Write permission for this to work; the key
+ * itself need not grant the caller anything.  If the last link to a key is
+ * removed then that key will be scheduled for destruction.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
@@ -451,19 +462,20 @@ error2:
        key_ref_put(keyring_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_keyring_unlink() */
-
-/*****************************************************************************/
 /*
- * describe a user key
- * - the key must have view permission
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of description available,
- *   irrespective of how much we may have copied
- * - the description is formatted thus:
+ * Return a description of a key to userspace.
+ *
+ * The key must grant the caller View permission for this to work.
+ *
+ * If there's a buffer, we place up to buflen bytes of data into it formatted
+ * in the following way:
+ *
  *     type;uid;gid;perm;description<NUL>
- * - implements keyctl(KEYCTL_DESCRIBE)
+ *
+ * If successful, we return the amount of description available, irrespective
+ * of how much we may have copied into the buffer.
  */
 long keyctl_describe_key(key_serial_t keyid,
                         char __user *buffer,
@@ -531,18 +543,17 @@ error2:
        key_ref_put(key_ref);
 error:
        return ret;
+}
 
-} /* end keyctl_describe_key() */
-
-/*****************************************************************************/
 /*
- * search the specified keyring for a matching key
- * - the start keyring must be searchable
- * - nested keyrings may also be searched if they are searchable
- * - only keys with search permission may be found
- * - if a key is found, it will be attached to the destination keyring if
- *   there's one specified
- * - implements keyctl(KEYCTL_SEARCH)
+ * Search the specified keyring and any keyrings it links to for a matching
+ * key.  Only keyrings that grant the caller Search permission will be searched
+ * (this includes the starting keyring).  Only keys with Search permission can
+ * be found.
+ *
+ * If successful, the found key will be linked to the destination keyring if
+ * supplied and the key has Link permission, and the found key ID will be
+ * returned.
  */
 long keyctl_keyring_search(key_serial_t ringid,
                           const char __user *_type,
@@ -626,18 +637,17 @@ error2:
        kfree(description);
 error:
        return ret;
+}
 
-} /* end keyctl_keyring_search() */
-
-/*****************************************************************************/
 /*
- * read a user key's payload
- * - the keyring must be readable or the key must be searchable from the
- *   process's keyrings
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of data in the key,
- *   irrespective of how much we may have copied
- * - implements keyctl(KEYCTL_READ)
+ * Read a key's payload.
+ *
+ * The key must either grant the caller Read permission, or it must grant the
+ * caller Search permission when searched for from the process keyrings.
+ *
+ * If successful, we place up to buflen bytes of data into the buffer, if one
+ * is provided, and return the amount of data that is available in the key,
+ * irrespective of how much we copied into the buffer.
  */
 long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 {
@@ -688,15 +698,22 @@ error2:
        key_put(key);
 error:
        return ret;
+}
 
-} /* end keyctl_read_key() */
-
-/*****************************************************************************/
 /*
- * change the ownership of a key
- * - the keyring owned by the changer
- * - if the uid or gid is -1, then that parameter is not changed
- * - implements keyctl(KEYCTL_CHOWN)
+ * Change the ownership of a key
+ *
+ * The key must grant the caller Setattr permission for this to work, though
+ * the key need not be fully instantiated yet.  For the UID to be changed, or
+ * for the GID to be changed to a group the caller is not a member of, the
+ * caller must have sysadmin capability.  If either uid or gid is -1 then that
+ * attribute is not changed.
+ *
+ * If the UID is to be changed, the new user must have sufficient quota to
+ * accept the key.  The quota deduction will be removed from the old user to
+ * the new user should the attribute be changed.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
@@ -796,14 +813,14 @@ quota_overrun:
        zapowner = newowner;
        ret = -EDQUOT;
        goto error_put;
+}
 
-} /* end keyctl_chown_key() */
-
-/*****************************************************************************/
 /*
- * change the permission mask on a key
- * - the keyring owned by the changer
- * - implements keyctl(KEYCTL_SETPERM)
+ * Change the permission mask on a key.
+ *
+ * The key must grant the caller Setattr permission for this to work, though
+ * the key need not be fully instantiated yet.  If the caller does not have
+ * sysadmin capability, it may only change the permission on keys that it owns.
  */
 long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 {
@@ -838,11 +855,11 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
        key_put(key);
 error:
        return ret;
-
-} /* end keyctl_setperm_key() */
+}
 
 /*
- * get the destination keyring for instantiation
+ * Get the destination keyring for instantiation and check that the caller has
+ * Write permission on it.
  */
 static long get_instantiation_keyring(key_serial_t ringid,
                                      struct request_key_auth *rka,
@@ -879,7 +896,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
 }
 
 /*
- * change the request_key authorisation key on the current process
+ * Change the request_key authorisation key on the current process.
  */
 static int keyctl_change_reqkey_auth(struct key *key)
 {
@@ -895,10 +912,14 @@ static int keyctl_change_reqkey_auth(struct key *key)
        return commit_creds(new);
 }
 
-/*****************************************************************************/
 /*
- * instantiate the key with the specified payload, and, if one is given, link
- * the key into the keyring
+ * Instantiate a key with the specified payload and link the key into the
+ * destination keyring if one is given.
+ *
+ * The caller must have the appropriate instantiation permit set for this to
+ * work (see keyctl_assume_authority).  No other permissions are required.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_instantiate_key(key_serial_t id,
                            const void __user *_payload,
@@ -973,13 +994,22 @@ error2:
                vfree(payload);
 error:
        return ret;
+}
 
-} /* end keyctl_instantiate_key() */
-
-/*****************************************************************************/
 /*
- * negatively instantiate the key with the given timeout (in seconds), and, if
- * one is given, link the key into the keyring
+ * Negatively instantiate the key with the given timeout (in seconds) and link
+ * the key into the destination keyring if one is given.
+ *
+ * The caller must have the appropriate instantiation permit set for this to
+ * work (see keyctl_assume_authority).  No other permissions are required.
+ *
+ * The key and any links to the key will be automatically garbage collected
+ * after the timeout expires.
+ *
+ * Negative keys are used to rate limit repeated request_key() calls by causing
+ * them to return -ENOKEY until the negative key expires.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
@@ -1020,13 +1050,14 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 
 error:
        return ret;
+}
 
-} /* end keyctl_negate_key() */
-
-/*****************************************************************************/
 /*
- * set the default keyring in which request_key() will cache keys
- * - return the old setting
+ * Read or set the default keyring in which request_key() will cache keys and
+ * return the old setting.
+ *
+ * If a process keyring is specified then this will be created if it doesn't
+ * yet exist.  The old setting will be returned if successful.
  */
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
@@ -1079,12 +1110,19 @@ set:
 error:
        abort_creds(new);
        return ret;
+}
 
-} /* end keyctl_set_reqkey_keyring() */
-
-/*****************************************************************************/
 /*
- * set or clear the timeout for a key
+ * Set or clear the timeout on a key.
+ *
+ * Either the key must grant the caller Setattr permission or else the caller
+ * must hold an instantiation authorisation token for the key.
+ *
+ * The timeout is either 0 to clear the timeout, or a number of seconds from
+ * the current time.  The key and any links to the key will be automatically
+ * garbage collected after the timeout expires.
+ *
+ * If successful, 0 is returned.
  */
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
@@ -1136,12 +1174,24 @@ okay:
        ret = 0;
 error:
        return ret;
+}
 
-} /* end keyctl_set_timeout() */
-
-/*****************************************************************************/
 /*
- * assume the authority to instantiate the specified key
+ * Assume (or clear) the authority to instantiate the specified key.
+ *
+ * This sets the authoritative token currently in force for key instantiation.
+ * This must be done for a key to be instantiated.  It has the effect of making
+ * available all the keys from the caller of the request_key() that created a
+ * key to request_key() calls made by the caller of this function.
+ *
+ * The caller must have the instantiation key in their process keyrings with a
+ * Search permission grant available to the caller.
+ *
+ * If the ID given is 0, then the setting will be cleared and 0 returned.
+ *
+ * If the ID given has a matching an authorisation key, then that key will be
+ * set and its ID will be returned.  The authorisation key can be read to get
+ * the callout information passed to request_key().
  */
 long keyctl_assume_authority(key_serial_t id)
 {
@@ -1178,16 +1228,17 @@ long keyctl_assume_authority(key_serial_t id)
        ret = authkey->serial;
 error:
        return ret;
-
-} /* end keyctl_assume_authority() */
+}
 
 /*
- * get the security label of a key
- * - the key must grant us view permission
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of information available,
- *   irrespective of how much we may have copied (including the terminal NUL)
- * - implements keyctl(KEYCTL_GET_SECURITY)
+ * Get a key's the LSM security label.
+ *
+ * The key must grant the caller View permission for this to work.
+ *
+ * If there's a buffer, then up to buflen bytes of data will be placed into it.
+ *
+ * If successful, the amount of information available will be returned,
+ * irrespective of how much was copied (including the terminal NUL).
  */
 long keyctl_get_security(key_serial_t keyid,
                         char __user *buffer,
@@ -1242,10 +1293,16 @@ long keyctl_get_security(key_serial_t keyid,
 }
 
 /*
- * attempt to install the calling process's session keyring on the process's
- * parent process
- * - the keyring must exist and must grant us LINK permission
- * - implements keyctl(KEYCTL_SESSION_TO_PARENT)
+ * Attempt to install the calling process's session keyring on the process's
+ * parent process.
+ *
+ * The keyring must exist and must grant the caller LINK permission, and the
+ * parent process must be single-threaded and must have the same effective
+ * ownership as this process and mustn't be SUID/SGID.
+ *
+ * The keyring will be emplaced on the parent when it next resumes userspace.
+ *
+ * If successful, 0 will be returned.
  */
 long keyctl_session_to_parent(void)
 {
@@ -1348,9 +1405,8 @@ error_keyring:
 #endif /* !TIF_NOTIFY_RESUME */
 }
 
-/*****************************************************************************/
 /*
- * the key control system call
+ * The key control system call
  */
 SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
                unsigned long, arg4, unsigned long, arg5)
@@ -1439,5 +1495,4 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
        default:
                return -EOPNOTSUPP;
        }
-
-} /* end sys_keyctl() */
+}
index d37f713..5620f08 100644 (file)
                (keyring)->payload.subscriptions,                       \
                rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
 
+#define KEY_LINK_FIXQUOTA 1UL
+
 /*
- * when plumbing the depths of the key tree, this sets a hard limit set on how
- * deep we're willing to go
+ * When plumbing the depths of the key tree, this sets a hard limit
+ * set on how deep we're willing to go.
  */
 #define KEYRING_SEARCH_MAX_DEPTH 6
 
 /*
- * we keep all named keyrings in a hash to speed looking them up
+ * We keep all named keyrings in a hash to speed looking them up.
  */
 #define KEYRING_NAME_HASH_SIZE (1 << 5)
 
@@ -50,7 +52,9 @@ static inline unsigned keyring_hash(const char *desc)
 }
 
 /*
- * the keyring type definition
+ * The keyring key type definition.  Keyrings are simply keys of this type and
+ * can be treated as ordinary keys in addition to having their own special
+ * operations.
  */
 static int keyring_instantiate(struct key *keyring,
                               const void *data, size_t datalen);
@@ -71,19 +75,17 @@ struct key_type key_type_keyring = {
        .describe       = keyring_describe,
        .read           = keyring_read,
 };
-
 EXPORT_SYMBOL(key_type_keyring);
 
 /*
- * semaphore to serialise link/link calls to prevent two link calls in parallel
- * introducing a cycle
+ * Semaphore to serialise link/link calls to prevent two link calls in parallel
+ * introducing a cycle.
  */
 static DECLARE_RWSEM(keyring_serialise_link_sem);
 
-/*****************************************************************************/
 /*
- * publish the name of a keyring so that it can be found by name (if it has
- * one)
+ * Publish the name of a keyring so that it can be found by name (if it has
+ * one).
  */
 static void keyring_publish_name(struct key *keyring)
 {
@@ -102,13 +104,12 @@ static void keyring_publish_name(struct key *keyring)
 
                write_unlock(&keyring_name_lock);
        }
+}
 
-} /* end keyring_publish_name() */
-
-/*****************************************************************************/
 /*
- * initialise a keyring
- * - we object if we were given any data
+ * Initialise a keyring.
+ *
+ * Returns 0 on success, -EINVAL if given any data.
  */
 static int keyring_instantiate(struct key *keyring,
                               const void *data, size_t datalen)
@@ -123,23 +124,20 @@ static int keyring_instantiate(struct key *keyring,
        }
 
        return ret;
+}
 
-} /* end keyring_instantiate() */
-
-/*****************************************************************************/
 /*
- * match keyrings on their name
+ * Match keyrings on their name
  */
 static int keyring_match(const struct key *keyring, const void *description)
 {
        return keyring->description &&
                strcmp(keyring->description, description) == 0;
+}
 
-} /* end keyring_match() */
-
-/*****************************************************************************/
 /*
- * dispose of the data dangling from the corpse of a keyring
+ * Clean up a keyring when it is destroyed.  Unpublish its name if it had one
+ * and dispose of its data.
  */
 static void keyring_destroy(struct key *keyring)
 {
@@ -164,12 +162,10 @@ static void keyring_destroy(struct key *keyring)
                        key_put(klist->keys[loop]);
                kfree(klist);
        }
+}
 
-} /* end keyring_destroy() */
-
-/*****************************************************************************/
 /*
- * describe the keyring
+ * Describe a keyring for /proc.
  */
 static void keyring_describe(const struct key *keyring, struct seq_file *m)
 {
@@ -187,13 +183,12 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
        else
                seq_puts(m, ": empty");
        rcu_read_unlock();
+}
 
-} /* end keyring_describe() */
-
-/*****************************************************************************/
 /*
- * read a list of key IDs from the keyring's contents
- * - the keyring's semaphore is read-locked
+ * Read a list of key IDs from the keyring's contents in binary form
+ *
+ * The keyring's semaphore is read-locked by the caller.
  */
 static long keyring_read(const struct key *keyring,
                         char __user *buffer, size_t buflen)
@@ -241,12 +236,10 @@ static long keyring_read(const struct key *keyring,
 
 error:
        return ret;
+}
 
-} /* end keyring_read() */
-
-/*****************************************************************************/
 /*
- * allocate a keyring and link into the destination keyring
+ * Allocate a keyring and link into the destination keyring.
  */
 struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
                          const struct cred *cred, unsigned long flags,
@@ -269,20 +262,42 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
        }
 
        return keyring;
+}
 
-} /* end keyring_alloc() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we use the supplied match function to see if the description (or other
- *   feature of interest) matches
- * - we rely on RCU to prevent the keyring lists from disappearing on us
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
- * - we propagate the possession attribute from the keyring ref to the key ref
+/**
+ * keyring_search_aux - Search a keyring tree for a key matching some criteria
+ * @keyring_ref: A pointer to the keyring with possession indicator.
+ * @cred: The credentials to use for permissions checks.
+ * @type: The type of key to search for.
+ * @description: Parameter for @match.
+ * @match: Function to rule on whether or not a key is the one required.
+ *
+ * Search the supplied keyring tree for a key that matches the criteria given.
+ * The root keyring and any linked keyrings must grant Search permission to the
+ * caller to be searchable and keys can only be found if they too grant Search
+ * to the caller. The possession flag on the root keyring pointer controls use
+ * of the possessor bits in permissions checking of the entire tree.  In
+ * addition, the LSM gets to forbid keyring searches and key matches.
+ *
+ * The search is performed as a breadth-then-depth search up to the prescribed
+ * limit (KEYRING_SEARCH_MAX_DEPTH).
+ *
+ * Keys are matched to the type provided and are then filtered by the match
+ * function, which is given the description to use in any way it sees fit.  The
+ * match function may use any attributes of a key that it wishes to to
+ * determine the match.  Normally the match function from the key type would be
+ * used.
+ *
+ * RCU is used to prevent the keyring key lists from disappearing without the
+ * need to take lots of locks.
+ *
+ * Returns a pointer to the found key and increments the key usage count if
+ * successful; -EAGAIN if no matching keys were found, or if expired or revoked
+ * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the
+ * specified keyring wasn't a keyring.
+ *
+ * In the case of a successful return, the possession attribute from
+ * @keyring_ref is propagated to the returned key reference.
  */
 key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                             const struct cred *cred,
@@ -444,17 +459,16 @@ error_2:
        rcu_read_unlock();
 error:
        return key_ref;
+}
 
-} /* end keyring_search_aux() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we readlock the keyrings as we search down the tree
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
+/**
+ * keyring_search - Search the supplied keyring tree for a matching key
+ * @keyring: The root of the keyring tree to be searched.
+ * @type: The type of keyring we want to find.
+ * @description: The name of the keyring we want to find.
+ *
+ * As keyring_search_aux() above, but using the current task's credentials and
+ * type's default matching function.
  */
 key_ref_t keyring_search(key_ref_t keyring,
                         struct key_type *type,
@@ -465,16 +479,23 @@ key_ref_t keyring_search(key_ref_t keyring,
 
        return keyring_search_aux(keyring, current->cred,
                                  type, description, type->match);
-
-} /* end keyring_search() */
-
+}
 EXPORT_SYMBOL(keyring_search);
 
-/*****************************************************************************/
 /*
- * search the given keyring only (no recursion)
- * - keyring must be locked by caller
- * - caller must guarantee that the keyring is a keyring
+ * Search the given keyring only (no recursion).
+ *
+ * The caller must guarantee that the keyring is a keyring and that the
+ * permission is granted to search the keyring as no check is made here.
+ *
+ * RCU is used to make it unnecessary to lock the keyring key list here.
+ *
+ * Returns a pointer to the found key with usage count incremented if
+ * successful and returns -ENOKEY if not found.  Revoked keys and keys not
+ * providing the requested permission are skipped over.
+ *
+ * If successful, the possession indicator is propagated from the keyring ref
+ * to the returned key reference.
  */
 key_ref_t __keyring_search_one(key_ref_t keyring_ref,
                               const struct key_type *ktype,
@@ -514,14 +535,18 @@ found:
        atomic_inc(&key->usage);
        rcu_read_unlock();
        return make_key_ref(key, possessed);
+}
 
-} /* end __keyring_search_one() */
-
-/*****************************************************************************/
 /*
- * find a keyring with the specified name
- * - all named keyrings are searched
- * - normally only finds keyrings with search permission for the current process
+ * Find a keyring with the specified name.
+ *
+ * All named keyrings in the current user namespace are searched, provided they
+ * grant Search permission directly to the caller (unless this check is
+ * skipped).  Keyrings whose usage points have reached zero or who have been
+ * revoked are skipped.
+ *
+ * Returns a pointer to the keyring with the keyring's refcount having being
+ * incremented on success.  -ENOKEY is returned if a key could not be found.
  */
 struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
 {
@@ -569,15 +594,14 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
 out:
        read_unlock(&keyring_name_lock);
        return keyring;
+}
 
-} /* end find_keyring_by_name() */
-
-/*****************************************************************************/
 /*
- * see if a cycle will will be created by inserting acyclic tree B in acyclic
- * tree A at the topmost level (ie: as a direct child of A)
- * - since we are adding B to A at the top level, checking for cycles should
- *   just be a matter of seeing if node A is somewhere in tree B
+ * See if a cycle will will be created by inserting acyclic tree B in acyclic
+ * tree A at the topmost level (ie: as a direct child of A).
+ *
+ * Since we are adding B to A at the top level, checking for cycles should just
+ * be a matter of seeing if node A is somewhere in tree B.
  */
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
@@ -657,11 +681,10 @@ too_deep:
 cycle_detected:
        ret = -EDEADLK;
        goto error;
-
-} /* end keyring_detect_cycle() */
+}
 
 /*
- * dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * Dispose of a keyring list after the RCU grace period, freeing the unlinked
  * key
  */
 static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
@@ -675,14 +698,14 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
 }
 
 /*
- * preallocate memory so that a key can be linked into to a keyring
+ * Preallocate memory so that a key can be linked into to a keyring.
  */
 int __key_link_begin(struct key *keyring, const struct key_type *type,
-                    const char *description,
-                    struct keyring_list **_prealloc)
+                    const char *description, unsigned long *_prealloc)
        __acquires(&keyring->sem)
 {
        struct keyring_list *klist, *nklist;
+       unsigned long prealloc;
        unsigned max;
        size_t size;
        int loop, ret;
@@ -725,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
 
                                /* note replacement slot */
                                klist->delkey = nklist->delkey = loop;
+                               prealloc = (unsigned long)nklist;
                                goto done;
                        }
                }
@@ -739,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
        if (klist && klist->nkeys < klist->maxkeys) {
                /* there's sufficient slack space to append directly */
                nklist = NULL;
+               prealloc = KEY_LINK_FIXQUOTA;
        } else {
                /* grow the key list */
                max = 4;
@@ -773,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
                nklist->keys[nklist->delkey] = NULL;
        }
 
+       prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
 done:
-       *_prealloc = nklist;
+       *_prealloc = prealloc;
        kleave(" = 0");
        return 0;
 
@@ -792,10 +818,10 @@ error_krsem:
 }
 
 /*
- * check already instantiated keys aren't going to be a problem
- * - the caller must have called __key_link_begin()
- * - don't need to call this for keys that were created since __key_link_begin()
- *   was called
+ * Check already instantiated keys aren't going to be a problem.
+ *
+ * The caller must have called __key_link_begin(). Don't need to call this for
+ * keys that were created since __key_link_begin() was called.
  */
 int __key_link_check_live_key(struct key *keyring, struct key *key)
 {
@@ -807,17 +833,20 @@ int __key_link_check_live_key(struct key *keyring, struct key *key)
 }
 
 /*
- * link a key into to a keyring
- * - must be called with __key_link_begin() having being called
- * - discard already extant link to matching key if there is one
+ * Link a key into to a keyring.
+ *
+ * Must be called with __key_link_begin() having being called.  Discards any
+ * already extant link to matching key if there is one, so that each keyring
+ * holds at most one link to any given key of a particular type+description
+ * combination.
  */
 void __key_link(struct key *keyring, struct key *key,
-               struct keyring_list **_prealloc)
+               unsigned long *_prealloc)
 {
        struct keyring_list *klist, *nklist;
 
-       nklist = *_prealloc;
-       *_prealloc = NULL;
+       nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
+       *_prealloc = 0;
 
        kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
 
@@ -852,34 +881,54 @@ void __key_link(struct key *keyring, struct key *key,
 }
 
 /*
- * finish linking a key into to a keyring
- * - must be called with __key_link_begin() having being called
+ * Finish linking a key into to a keyring.
+ *
+ * Must be called with __key_link_begin() having being called.
  */
 void __key_link_end(struct key *keyring, struct key_type *type,
-                   struct keyring_list *prealloc)
+                   unsigned long prealloc)
        __releases(&keyring->sem)
 {
        BUG_ON(type == NULL);
        BUG_ON(type->name == NULL);
-       kenter("%d,%s,%p", keyring->serial, type->name, prealloc);
+       kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
 
        if (type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
        if (prealloc) {
-               kfree(prealloc);
-               key_payload_reserve(keyring,
-                                   keyring->datalen - KEYQUOTA_LINK_BYTES);
+               if (prealloc & KEY_LINK_FIXQUOTA)
+                       key_payload_reserve(keyring,
+                                           keyring->datalen -
+                                           KEYQUOTA_LINK_BYTES);
+               kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA));
        }
        up_write(&keyring->sem);
 }
 
-/*
- * link a key to a keyring
+/**
+ * key_link - Link a key to a keyring
+ * @keyring: The keyring to make the link in.
+ * @key: The key to link to.
+ *
+ * Make a link in a keyring to a key, such that the keyring holds a reference
+ * on that key and the key can potentially be found by searching that keyring.
+ *
+ * This function will write-lock the keyring's semaphore and will consume some
+ * of the user's key data quota to hold the link.
+ *
+ * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring,
+ * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is
+ * full, -EDQUOT if there is insufficient key data quota remaining to add
+ * another link or -ENOMEM if there's insufficient memory.
+ *
+ * It is assumed that the caller has checked that it is permitted for a link to
+ * be made (the keyring should have Write permission and the key Link
+ * permission).
  */
 int key_link(struct key *keyring, struct key *key)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        int ret;
 
        key_check(keyring);
@@ -895,12 +944,24 @@ int key_link(struct key *keyring, struct key *key)
 
        return ret;
 }
-
 EXPORT_SYMBOL(key_link);
 
-/*****************************************************************************/
-/*
- * unlink the first link to a key from a keyring
+/**
+ * key_unlink - Unlink the first link to a key from a keyring.
+ * @keyring: The keyring to remove the link from.
+ * @key: The key the link is to.
+ *
+ * Remove a link from a keyring to a key.
+ *
+ * This function will write-lock the keyring's semaphore.
+ *
+ * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if
+ * the key isn't linked to by the keyring or -ENOMEM if there's insufficient
+ * memory.
+ *
+ * It is assumed that the caller has checked that it is permitted for a link to
+ * be removed (the keyring should have Write permission; no permissions are
+ * required on the key).
  */
 int key_unlink(struct key *keyring, struct key *key)
 {
@@ -968,15 +1029,12 @@ nomem:
        ret = -ENOMEM;
        up_write(&keyring->sem);
        goto error;
-
-} /* end key_unlink() */
-
+}
 EXPORT_SYMBOL(key_unlink);
 
-/*****************************************************************************/
 /*
- * dispose of a keyring list after the RCU grace period, releasing the keys it
- * links to
+ * Dispose of a keyring list after the RCU grace period, releasing the keys it
+ * links to.
  */
 static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
 {
@@ -989,13 +1047,15 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
                key_put(klist->keys[loop]);
 
        kfree(klist);
+}
 
-} /* end keyring_clear_rcu_disposal() */
-
-/*****************************************************************************/
-/*
- * clear the specified process keyring
- * - implements keyctl(KEYCTL_CLEAR)
+/**
+ * keyring_clear - Clear a keyring
+ * @keyring: The keyring to clear.
+ *
+ * Clear the contents of the specified keyring.
+ *
+ * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring.
  */
 int keyring_clear(struct key *keyring)
 {
@@ -1027,15 +1087,13 @@ int keyring_clear(struct key *keyring)
        }
 
        return ret;
-
-} /* end keyring_clear() */
-
+}
 EXPORT_SYMBOL(keyring_clear);
 
-/*****************************************************************************/
 /*
- * dispose of the links from a revoked keyring
- * - called with the key sem write-locked
+ * Dispose of the links from a revoked keyring.
+ *
+ * This is called with the key sem write-locked.
  */
 static void keyring_revoke(struct key *keyring)
 {
@@ -1050,11 +1108,10 @@ static void keyring_revoke(struct key *keyring)
                rcu_assign_pointer(keyring->payload.subscriptions, NULL);
                call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
        }
-
-} /* end keyring_revoke() */
+}
 
 /*
- * Determine whether a key is dead
+ * Determine whether a key is dead.
  */
 static bool key_is_dead(struct key *key, time_t limit)
 {
@@ -1063,7 +1120,12 @@ static bool key_is_dead(struct key *key, time_t limit)
 }
 
 /*
- * Collect garbage from the contents of a keyring
+ * Collect garbage from the contents of a keyring, replacing the old list with
+ * a new one with the pointers all shuffled down.
+ *
+ * Dead keys are classed as oned that are flagged as being dead or are revoked,
+ * expired or negative keys that were revoked or expired before the specified
+ * limit.
  */
 void keyring_gc(struct key *keyring, time_t limit)
 {
index 2864550..c35b522 100644 (file)
@@ -1,4 +1,4 @@
-/* permission.c: key permission determination
+/* Key permission checking
  *
  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <linux/security.h>
 #include "internal.h"
 
-/*****************************************************************************/
 /**
  * key_task_permission - Check a key can be used
- * @key_ref: The key to check
- * @cred: The credentials to use
- * @perm: The permissions to check for
+ * @key_ref: The key to check.
+ * @cred: The credentials to use.
+ * @perm: The permissions to check for.
  *
  * Check to see whether permission is granted to use a key in the desired way,
  * but permit the security modules to override.
  *
- * The caller must hold either a ref on cred or must hold the RCU readlock or a
- * spinlock.
+ * The caller must hold either a ref on cred or must hold the RCU readlock.
+ *
+ * Returns 0 if successful, -EACCES if access is denied based on the
+ * permissions bits or the LSM check.
  */
 int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
                        key_perm_t perm)
@@ -79,14 +80,16 @@ use_these_perms:
 
        /* let LSM be the final arbiter */
        return security_key_permission(key_ref, cred, perm);
-
-} /* end key_task_permission() */
-
+}
 EXPORT_SYMBOL(key_task_permission);
 
-/*****************************************************************************/
-/*
- * validate a key
+/**
+ * key_validate - Validate a key.
+ * @key: The key to be validated.
+ *
+ * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if
+ * the key's type has been removed or if the key has been revoked or
+ * -EKEYEXPIRED if the key has expired.
  */
 int key_validate(struct key *key)
 {
@@ -111,7 +114,5 @@ int key_validate(struct key *key)
 
 error:
        return ret;
-
-} /* end key_validate() */
-
+}
 EXPORT_SYMBOL(key_validate);
index 7037396..525cf8a 100644 (file)
@@ -1,4 +1,4 @@
-/* proc.c: proc files for key database enumeration
+/* procfs files for key database enumeration
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -60,9 +60,8 @@ static const struct file_operations proc_key_users_fops = {
        .release        = seq_release,
 };
 
-/*****************************************************************************/
 /*
- * declare the /proc files
+ * Declare the /proc files.
  */
 static int __init key_proc_init(void)
 {
@@ -79,14 +78,13 @@ static int __init key_proc_init(void)
                panic("Cannot create /proc/key-users\n");
 
        return 0;
-
-} /* end key_proc_init() */
+}
 
 __initcall(key_proc_init);
 
-/*****************************************************************************/
 /*
- * implement "/proc/keys" to provides a list of the keys on the system
+ * Implement "/proc/keys" to provide a list of the keys on the system that
+ * grant View permission to the caller.
  */
 #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 
@@ -293,9 +291,9 @@ static struct rb_node *key_user_first(struct rb_root *r)
        return __key_user_next(n);
 }
 
-/*****************************************************************************/
 /*
- * implement "/proc/key-users" to provides a list of the key users
+ * Implement "/proc/key-users" to provides a list of the key users and their
+ * quotas.
  */
 static int proc_key_users_open(struct inode *inode, struct file *file)
 {
@@ -351,5 +349,4 @@ static int proc_key_users_show(struct seq_file *m, void *v)
                   maxbytes);
 
        return 0;
-
 }
index 504bdd2..930634e 100644 (file)
@@ -1,4 +1,4 @@
-/* Management of a process's keyrings
+/* Manage a process's keyrings
  *
  * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <asm/uaccess.h>
 #include "internal.h"
 
-/* session keyring create vs join semaphore */
+/* Session keyring create vs join semaphore */
 static DEFINE_MUTEX(key_session_mutex);
 
-/* user keyring creation semaphore */
+/* User keyring creation semaphore */
 static DEFINE_MUTEX(key_user_keyring_mutex);
 
-/* the root user's tracking struct */
+/* The root user's tracking struct */
 struct key_user root_key_user = {
        .usage          = ATOMIC_INIT(3),
        .cons_lock      = __MUTEX_INITIALIZER(root_key_user.cons_lock),
@@ -38,9 +38,8 @@ struct key_user root_key_user = {
        .user_ns        = &init_user_ns,
 };
 
-/*****************************************************************************/
 /*
- * install user and user session keyrings for a particular UID
+ * Install the user and user session keyrings for the current process's UID.
  */
 int install_user_keyrings(void)
 {
@@ -122,7 +121,8 @@ error:
 }
 
 /*
- * install a fresh thread keyring directly to new credentials
+ * Install a fresh thread keyring directly to new credentials.  This keyring is
+ * allowed to overrun the quota.
  */
 int install_thread_keyring_to_cred(struct cred *new)
 {
@@ -138,7 +138,7 @@ int install_thread_keyring_to_cred(struct cred *new)
 }
 
 /*
- * install a fresh thread keyring, discarding the old one
+ * Install a fresh thread keyring, discarding the old one.
  */
 static int install_thread_keyring(void)
 {
@@ -161,9 +161,10 @@ static int install_thread_keyring(void)
 }
 
 /*
- * install a process keyring directly to a credentials struct
- * - returns -EEXIST if there was already a process keyring, 0 if one installed,
- *   and other -ve on any other error
+ * Install a process keyring directly to a credentials struct.
+ *
+ * Returns -EEXIST if there was already a process keyring, 0 if one installed,
+ * and other value on any other error
  */
 int install_process_keyring_to_cred(struct cred *new)
 {
@@ -192,8 +193,11 @@ int install_process_keyring_to_cred(struct cred *new)
 }
 
 /*
- * make sure a process keyring is installed
- * - we
+ * Make sure a process keyring is installed for the current process.  The
+ * existing process keyring is not replaced.
+ *
+ * Returns 0 if there is a process keyring by the end of this function, some
+ * error otherwise.
  */
 static int install_process_keyring(void)
 {
@@ -214,7 +218,7 @@ static int install_process_keyring(void)
 }
 
 /*
- * install a session keyring directly to a credentials struct
+ * Install a session keyring directly to a credentials struct.
  */
 int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 {
@@ -254,8 +258,8 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 }
 
 /*
- * install a session keyring, discarding the old one
- * - if a keyring is not supplied, an empty one is invented
+ * Install a session keyring, discarding the old one.  If a keyring is not
+ * supplied, an empty one is invented.
  */
 static int install_session_keyring(struct key *keyring)
 {
@@ -275,9 +279,8 @@ static int install_session_keyring(struct key *keyring)
        return commit_creds(new);
 }
 
-/*****************************************************************************/
 /*
- * the filesystem user ID changed
+ * Handle the fsuid changing.
  */
 void key_fsuid_changed(struct task_struct *tsk)
 {
@@ -288,12 +291,10 @@ void key_fsuid_changed(struct task_struct *tsk)
                tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
                up_write(&tsk->cred->thread_keyring->sem);
        }
+}
 
-} /* end key_fsuid_changed() */
-
-/*****************************************************************************/
 /*
- * the filesystem group ID changed
+ * Handle the fsgid changing.
  */
 void key_fsgid_changed(struct task_struct *tsk)
 {
@@ -304,16 +305,28 @@ void key_fsgid_changed(struct task_struct *tsk)
                tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
                up_write(&tsk->cred->thread_keyring->sem);
        }
+}
 
-} /* end key_fsgid_changed() */
-
-/*****************************************************************************/
 /*
- * search only my process keyrings for the first matching key
- * - we use the supplied match function to see if the description (or other
- *   feature of interest) matches
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
+ * Search the process keyrings attached to the supplied cred for the first
+ * matching key.
+ *
+ * The search criteria are the type and the match function.  The description is
+ * given to the match function as a parameter, but doesn't otherwise influence
+ * the search.  Typically the match function will compare the description
+ * parameter to the key's description.
+ *
+ * This can only search keyrings that grant Search permission to the supplied
+ * credentials.  Keyrings linked to searched keyrings will also be searched if
+ * they grant Search permission too.  Keys can only be found if they grant
+ * Search permission to the credentials.
+ *
+ * Returns a pointer to the key with the key usage count incremented if
+ * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
+ * matched negative keys.
+ *
+ * In the case of a successful return, the possession attribute is set on the
+ * returned key reference.
  */
 key_ref_t search_my_process_keyrings(struct key_type *type,
                                     const void *description,
@@ -428,13 +441,13 @@ found:
        return key_ref;
 }
 
-/*****************************************************************************/
 /*
- * search the process keyrings for the first matching key
- * - we use the supplied match function to see if the description (or other
- *   feature of interest) matches
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
+ * Search the process keyrings attached to the supplied cred for the first
+ * matching key in the manner of search_my_process_keyrings(), but also search
+ * the keys attached to the assumed authorisation key using its credentials if
+ * one is available.
+ *
+ * Return same as search_my_process_keyrings().
  */
 key_ref_t search_process_keyrings(struct key_type *type,
                                  const void *description,
@@ -489,24 +502,33 @@ key_ref_t search_process_keyrings(struct key_type *type,
 
 found:
        return key_ref;
+}
 
-} /* end search_process_keyrings() */
-
-/*****************************************************************************/
 /*
- * see if the key we're looking at is the target key
+ * See if the key we're looking at is the target key.
  */
 int lookup_user_key_possessed(const struct key *key, const void *target)
 {
        return key == target;
+}
 
-} /* end lookup_user_key_possessed() */
-
-/*****************************************************************************/
 /*
- * lookup a key given a key ID from userspace with a given permissions mask
- * - don't create special keyrings unless so requested
- * - partially constructed keys aren't found unless requested
+ * Look up a key ID given us by userspace with a given permissions mask to get
+ * the key it refers to.
+ *
+ * Flags can be passed to request that special keyrings be created if referred
+ * to directly, to permit partially constructed keys to be found and to skip
+ * validity and permission checks on the found key.
+ *
+ * Returns a pointer to the key with an incremented usage count if successful;
+ * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
+ * to a key or the best found key was a negative key; -EKEYREVOKED or
+ * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
+ * found key doesn't grant the requested permit or the LSM denied access to it;
+ * or -ENOMEM if a special keyring couldn't be created.
+ *
+ * In the case of a successful return, the possession attribute is set on the
+ * returned key reference.
  */
 key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
@@ -711,15 +733,18 @@ invalid_key:
 reget_creds:
        put_cred(cred);
        goto try_again;
+}
 
-} /* end lookup_user_key() */
-
-/*****************************************************************************/
 /*
- * join the named keyring as the session keyring if possible, or attempt to
- * create a new one of that name if not
- * - if the name is NULL, an empty anonymous keyring is installed instead
- * - named session keyring joining is done with a semaphore held
+ * Join the named keyring as the session keyring if possible else attempt to
+ * create a new one of that name and join that.
+ *
+ * If the name is NULL, an empty anonymous keyring will be installed as the
+ * session keyring.
+ *
+ * Named session keyrings are joined with a semaphore held to prevent the
+ * keyrings from going away whilst the attempt is made to going them and also
+ * to prevent a race in creating compatible session keyrings.
  */
 long join_session_keyring(const char *name)
 {
@@ -791,8 +816,8 @@ error:
 }
 
 /*
- * Replace a process's session keyring when that process resumes userspace on
- * behalf of one of its children
+ * Replace a process's session keyring on behalf of one of its children when
+ * the target  process is about to resume userspace execution.
  */
 void key_replace_session_keyring(void)
 {
index 0ea52d2..a3dc0d4 100644 (file)
@@ -39,8 +39,14 @@ static int key_wait_bit_intr(void *flags)
        return signal_pending(current) ? -ERESTARTSYS : 0;
 }
 
-/*
- * call to complete the construction of a key
+/**
+ * complete_request_key - Complete the construction of a key.
+ * @cons: The key construction record.
+ * @error: The success or failute of the construction.
+ *
+ * Complete the attempt to construct a key.  The key will be negated
+ * if an error is indicated.  The authorisation key will be revoked
+ * unconditionally.
  */
 void complete_request_key(struct key_construction *cons, int error)
 {
@@ -58,23 +64,33 @@ void complete_request_key(struct key_construction *cons, int error)
 }
 EXPORT_SYMBOL(complete_request_key);
 
+/*
+ * Initialise a usermode helper that is going to have a specific session
+ * keyring.
+ *
+ * This is called in context of freshly forked kthread before kernel_execve(),
+ * so we can simply install the desired session_keyring at this point.
+ */
 static int umh_keys_init(struct subprocess_info *info)
 {
        struct cred *cred = (struct cred*)current_cred();
        struct key *keyring = info->data;
-       /*
-        * This is called in context of freshly forked kthread before
-        * kernel_execve(), we can just change our ->session_keyring.
-        */
+
        return install_session_keyring_to_cred(cred, keyring);
 }
 
+/*
+ * Clean up a usermode helper with session keyring.
+ */
 static void umh_keys_cleanup(struct subprocess_info *info)
 {
        struct key *keyring = info->data;
        key_put(keyring);
 }
 
+/*
+ * Call a usermode helper with a specific session keyring.
+ */
 static int call_usermodehelper_keys(char *path, char **argv, char **envp,
                         struct key *session_keyring, enum umh_wait wait)
 {
@@ -91,7 +107,7 @@ static int call_usermodehelper_keys(char *path, char **argv, char **envp,
 }
 
 /*
- * request userspace finish the construction of a key
+ * Request userspace finish the construction of a key
  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
  */
 static int call_sbin_request_key(struct key_construction *cons,
@@ -198,8 +214,9 @@ error_alloc:
 }
 
 /*
- * call out to userspace for key construction
- * - we ignore program failure and go on key status instead
+ * Call out to userspace for key construction.
+ *
+ * Program failure is ignored in favour of key status.
  */
 static int construct_key(struct key *key, const void *callout_info,
                         size_t callout_len, void *aux,
@@ -246,9 +263,10 @@ static int construct_key(struct key *key, const void *callout_info,
 }
 
 /*
- * get the appropriate destination keyring for the request
- * - we return whatever keyring we select with an extra reference upon it which
- *   the caller must release
+ * Get the appropriate destination keyring for the request.
+ *
+ * The keyring selected is returned with an extra reference upon it which the
+ * caller must release.
  */
 static void construct_get_dest_keyring(struct key **_dest_keyring)
 {
@@ -321,9 +339,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 }
 
 /*
- * allocate a new key in under-construction state and attempt to link it in to
- * the requested place
- * - may return a key that's already under construction instead
+ * Allocate a new key in under-construction state and attempt to link it in to
+ * the requested keyring.
+ *
+ * May return a key that's already under construction instead if there was a
+ * race between two thread calling request_key().
  */
 static int construct_alloc_key(struct key_type *type,
                               const char *description,
@@ -332,8 +352,8 @@ static int construct_alloc_key(struct key_type *type,
                               struct key_user *user,
                               struct key **_key)
 {
-       struct keyring_list *prealloc;
        const struct cred *cred = current_cred();
+       unsigned long prealloc;
        struct key *key;
        key_ref_t key_ref;
        int ret;
@@ -414,7 +434,7 @@ alloc_failed:
 }
 
 /*
- * commence key construction
+ * Commence key construction.
  */
 static struct key *construct_key_and_link(struct key_type *type,
                                          const char *description,
@@ -465,12 +485,32 @@ construction_failed:
        return ERR_PTR(ret);
 }
 
-/*
- * request a key
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - cache the key in an appropriate keyring
+/**
+ * request_key_and_link - Request a key and cache it in a keyring.
+ * @type: The type of key we want.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ * @dest_keyring: Where to cache the key.
+ * @flags: Flags to key_alloc().
+ *
+ * A key matching the specified criteria is searched for in the process's
+ * keyrings and returned with its usage count incremented if found.  Otherwise,
+ * if callout_info is not NULL, a key will be allocated and some service
+ * (probably in userspace) will be asked to instantiate it.
+ *
+ * If successfully found or created, the key will be linked to the destination
+ * keyring if one is provided.
+ *
+ * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED
+ * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was
+ * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT
+ * if insufficient key quota was available to create a new key; or -ENOMEM if
+ * insufficient memory was available.
+ *
+ * If the returned key was created, then it may still be under construction,
+ * and wait_for_key_construction() should be used to wait for that to complete.
  */
 struct key *request_key_and_link(struct key_type *type,
                                 const char *description,
@@ -524,8 +564,16 @@ error:
        return key;
 }
 
-/*
- * wait for construction of a key to complete
+/**
+ * wait_for_key_construction - Wait for construction of a key to complete
+ * @key: The key being waited for.
+ * @intr: Whether to wait interruptibly.
+ *
+ * Wait for a key to finish being constructed.
+ *
+ * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY
+ * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was
+ * revoked or expired.
  */
 int wait_for_key_construction(struct key *key, bool intr)
 {
@@ -542,12 +590,19 @@ int wait_for_key_construction(struct key *key, bool intr)
 }
 EXPORT_SYMBOL(wait_for_key_construction);
 
-/*
- * request a key
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - waits uninterruptible for creation to complete
+/**
+ * request_key - Request a key and wait for construction
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found, new keys are always allocated in the user's quota,
+ * the callout_info must be a NUL-terminated string and no auxiliary data can
+ * be passed.
+ *
+ * Furthermore, it then works as wait_for_key_construction() to wait for the
+ * completion of keys undergoing construction with a non-interruptible wait.
  */
 struct key *request_key(struct key_type *type,
                        const char *description,
@@ -572,12 +627,19 @@ struct key *request_key(struct key_type *type,
 }
 EXPORT_SYMBOL(request_key);
 
-/*
- * request a key with auxiliary data for the upcaller
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - waits uninterruptible for creation to complete
+/**
+ * request_key_with_auxdata - Request a key with auxiliary data for the upcaller
+ * @type: The type of key we want.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found and new keys are always allocated in the user's quota.
+ *
+ * Furthermore, it then works as wait_for_key_construction() to wait for the
+ * completion of keys undergoing construction with a non-interruptible wait.
  */
 struct key *request_key_with_auxdata(struct key_type *type,
                                     const char *description,
@@ -602,10 +664,18 @@ struct key *request_key_with_auxdata(struct key_type *type,
 EXPORT_SYMBOL(request_key_with_auxdata);
 
 /*
- * request a key (allow async construction)
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
+ * request_key_async - Request a key (allow async construction)
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found, new keys are always allocated in the user's quota and
+ * no auxiliary data can be passed.
+ *
+ * The caller should call wait_for_key_construction() to wait for the
+ * completion of the returned key if it is still undergoing construction.
  */
 struct key *request_key_async(struct key_type *type,
                              const char *description,
@@ -620,9 +690,17 @@ EXPORT_SYMBOL(request_key_async);
 
 /*
  * request a key with auxiliary data for the upcaller (allow async construction)
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found and new keys are always allocated in the user's quota.
+ *
+ * The caller should call wait_for_key_construction() to wait for the
+ * completion of the returned key if it is still undergoing construction.
  */
 struct key *request_key_async_with_auxdata(struct key_type *type,
                                           const char *description,
index 8674715..6816403 100644 (file)
@@ -1,4 +1,4 @@
-/* request_key_auth.c: request key authorisation controlling key def
+/* Request key authorisation token key definition.
  *
  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -26,7 +26,7 @@ static void request_key_auth_destroy(struct key *);
 static long request_key_auth_read(const struct key *, char __user *, size_t);
 
 /*
- * the request-key authorisation key type definition
+ * The request-key authorisation key type definition.
  */
 struct key_type key_type_request_key_auth = {
        .name           = ".request_key_auth",
@@ -38,9 +38,8 @@ struct key_type key_type_request_key_auth = {
        .read           = request_key_auth_read,
 };
 
-/*****************************************************************************/
 /*
- * instantiate a request-key authorisation key
+ * Instantiate a request-key authorisation key.
  */
 static int request_key_auth_instantiate(struct key *key,
                                        const void *data,
@@ -48,12 +47,10 @@ static int request_key_auth_instantiate(struct key *key,
 {
        key->payload.data = (struct request_key_auth *) data;
        return 0;
+}
 
-} /* end request_key_auth_instantiate() */
-
-/*****************************************************************************/
 /*
- * reading a request-key authorisation key retrieves the callout information
+ * Describe an authorisation token.
  */
 static void request_key_auth_describe(const struct key *key,
                                      struct seq_file *m)
@@ -63,12 +60,10 @@ static void request_key_auth_describe(const struct key *key,
        seq_puts(m, "key:");
        seq_puts(m, key->description);
        seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+}
 
-} /* end request_key_auth_describe() */
-
-/*****************************************************************************/
 /*
- * read the callout_info data
+ * Read the callout_info data (retrieves the callout information).
  * - the key's semaphore is read-locked
  */
 static long request_key_auth_read(const struct key *key,
@@ -91,13 +86,12 @@ static long request_key_auth_read(const struct key *key,
        }
 
        return ret;
+}
 
-} /* end request_key_auth_read() */
-
-/*****************************************************************************/
 /*
- * handle revocation of an authorisation token key
- * - called with the key sem write-locked
+ * Handle revocation of an authorisation token key.
+ *
+ * Called with the key sem write-locked.
  */
 static void request_key_auth_revoke(struct key *key)
 {
@@ -109,12 +103,10 @@ static void request_key_auth_revoke(struct key *key)
                put_cred(rka->cred);
                rka->cred = NULL;
        }
+}
 
-} /* end request_key_auth_revoke() */
-
-/*****************************************************************************/
 /*
- * destroy an instantiation authorisation token key
+ * Destroy an instantiation authorisation token key.
  */
 static void request_key_auth_destroy(struct key *key)
 {
@@ -131,13 +123,11 @@ static void request_key_auth_destroy(struct key *key)
        key_put(rka->dest_keyring);
        kfree(rka->callout_info);
        kfree(rka);
+}
 
-} /* end request_key_auth_destroy() */
-
-/*****************************************************************************/
 /*
- * create an authorisation token for /sbin/request-key or whoever to gain
- * access to the caller's security data
+ * Create an authorisation token for /sbin/request-key or whoever to gain
+ * access to the caller's security data.
  */
 struct key *request_key_auth_new(struct key *target, const void *callout_info,
                                 size_t callout_len, struct key *dest_keyring)
@@ -228,12 +218,10 @@ error_alloc:
        kfree(rka);
        kleave("= %d", ret);
        return ERR_PTR(ret);
+}
 
-} /* end request_key_auth_new() */
-
-/*****************************************************************************/
 /*
- * see if an authorisation key is associated with a particular key
+ * See if an authorisation key is associated with a particular key.
  */
 static int key_get_instantiation_authkey_match(const struct key *key,
                                               const void *_id)
@@ -242,16 +230,11 @@ static int key_get_instantiation_authkey_match(const struct key *key,
        key_serial_t id = (key_serial_t)(unsigned long) _id;
 
        return rka->target_key->serial == id;
+}
 
-} /* end key_get_instantiation_authkey_match() */
-
-/*****************************************************************************/
 /*
- * get the authorisation key for instantiation of a specific key if attached to
- * the current process's keyrings
- * - this key is inserted into a keyring and that is set as /sbin/request-key's
- *   session keyring
- * - a target_id of zero specifies any valid token
+ * Search the current process's keyrings for the authorisation key for
+ * instantiation of a key.
  */
 struct key *key_get_instantiation_authkey(key_serial_t target_id)
 {
@@ -278,5 +261,4 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
 
 error:
        return authkey;
-
-} /* end key_get_instantiation_authkey() */
+}
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
new file mode 100644 (file)
index 0000000..83fc92e
--- /dev/null
@@ -0,0 +1,1181 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Author:
+ * David Safford <safford@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * See Documentation/keys-trusted-encrypted.txt
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <keys/user-type.h>
+#include <keys/trusted-type.h>
+#include <linux/key-type.h>
+#include <linux/rcupdate.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <linux/capability.h>
+#include <linux/tpm.h>
+#include <linux/tpm_command.h>
+
+#include "trusted.h"
+
+static const char hmac_alg[] = "hmac(sha1)";
+static const char hash_alg[] = "sha1";
+
+struct sdesc {
+       struct shash_desc shash;
+       char ctx[];
+};
+
+static struct crypto_shash *hashalg;
+static struct crypto_shash *hmacalg;
+
+static struct sdesc *init_sdesc(struct crypto_shash *alg)
+{
+       struct sdesc *sdesc;
+       int size;
+
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+       sdesc = kmalloc(size, GFP_KERNEL);
+       if (!sdesc)
+               return ERR_PTR(-ENOMEM);
+       sdesc->shash.tfm = alg;
+       sdesc->shash.flags = 0x0;
+       return sdesc;
+}
+
+static int TSS_sha1(const unsigned char *data, unsigned int datalen,
+                   unsigned char *digest)
+{
+       struct sdesc *sdesc;
+       int ret;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
+       kfree(sdesc);
+       return ret;
+}
+
+static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
+                      unsigned int keylen, ...)
+{
+       struct sdesc *sdesc;
+       va_list argp;
+       unsigned int dlen;
+       unsigned char *data;
+       int ret;
+
+       sdesc = init_sdesc(hmacalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hmac_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       ret = crypto_shash_setkey(hmacalg, key, keylen);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+
+       va_start(argp, keylen);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               data = va_arg(argp, unsigned char *);
+               if (data == NULL) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = crypto_shash_update(&sdesc->shash, data, dlen);
+               if (ret < 0)
+                       break;
+       }
+       va_end(argp);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, digest);
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * calculate authorization info fields to send to TPM
+ */
+static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
+                       unsigned int keylen, unsigned char *h1,
+                       unsigned char *h2, unsigned char h3, ...)
+{
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned char *data;
+       unsigned char c;
+       int ret;
+       va_list argp;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+
+       c = h3;
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       va_start(argp, h3);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               data = va_arg(argp, unsigned char *);
+               if (!data) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = crypto_shash_update(&sdesc->shash, data, dlen);
+               if (ret < 0)
+                       break;
+       }
+       va_end(argp);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (!ret)
+               ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
+                                 paramdigest, TPM_NONCE_SIZE, h1,
+                                 TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * verify the AUTH1_COMMAND (Seal) result from TPM
+ */
+static int TSS_checkhmac1(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key,
+                         unsigned int keylen, ...)
+{
+       uint32_t bufsize;
+       uint16_t tag;
+       uint32_t ordinal;
+       uint32_t result;
+       unsigned char *enonce;
+       unsigned char *continueflag;
+       unsigned char *authdata;
+       unsigned char testhmac[SHA1_DIGEST_SIZE];
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned int dpos;
+       va_list argp;
+       int ret;
+
+       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
+       tag = LOAD16(buffer, 0);
+       ordinal = command;
+       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
+       if (tag == TPM_TAG_RSP_COMMAND)
+               return 0;
+       if (tag != TPM_TAG_RSP_AUTH1_COMMAND)
+               return -EINVAL;
+       authdata = buffer + bufsize - SHA1_DIGEST_SIZE;
+       continueflag = authdata - 1;
+       enonce = continueflag - TPM_NONCE_SIZE;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
+                                 sizeof result);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
+                                 sizeof ordinal);
+       if (ret < 0)
+               goto out;
+       va_start(argp, keylen);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               dpos = va_arg(argp, unsigned int);
+               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
+               if (ret < 0)
+                       break;
+       }
+       va_end(argp);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (ret < 0)
+               goto out;
+
+       ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
+                         TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
+                         1, continueflag, 0, 0);
+       if (ret < 0)
+               goto out;
+
+       if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
+               ret = -EINVAL;
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * verify the AUTH2_COMMAND (unseal) result from TPM
+ */
+static int TSS_checkhmac2(unsigned char *buffer,
+                         const uint32_t command,
+                         const unsigned char *ononce,
+                         const unsigned char *key1,
+                         unsigned int keylen1,
+                         const unsigned char *key2,
+                         unsigned int keylen2, ...)
+{
+       uint32_t bufsize;
+       uint16_t tag;
+       uint32_t ordinal;
+       uint32_t result;
+       unsigned char *enonce1;
+       unsigned char *continueflag1;
+       unsigned char *authdata1;
+       unsigned char *enonce2;
+       unsigned char *continueflag2;
+       unsigned char *authdata2;
+       unsigned char testhmac1[SHA1_DIGEST_SIZE];
+       unsigned char testhmac2[SHA1_DIGEST_SIZE];
+       unsigned char paramdigest[SHA1_DIGEST_SIZE];
+       struct sdesc *sdesc;
+       unsigned int dlen;
+       unsigned int dpos;
+       va_list argp;
+       int ret;
+
+       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
+       tag = LOAD16(buffer, 0);
+       ordinal = command;
+       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
+
+       if (tag == TPM_TAG_RSP_COMMAND)
+               return 0;
+       if (tag != TPM_TAG_RSP_AUTH2_COMMAND)
+               return -EINVAL;
+       authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1
+                       + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE);
+       authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE);
+       continueflag1 = authdata1 - 1;
+       continueflag2 = authdata2 - 1;
+       enonce1 = continueflag1 - TPM_NONCE_SIZE;
+       enonce2 = continueflag2 - TPM_NONCE_SIZE;
+
+       sdesc = init_sdesc(hashalg);
+       if (IS_ERR(sdesc)) {
+               pr_info("trusted_key: can't alloc %s\n", hash_alg);
+               return PTR_ERR(sdesc);
+       }
+       ret = crypto_shash_init(&sdesc->shash);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
+                                 sizeof result);
+       if (ret < 0)
+               goto out;
+       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
+                                 sizeof ordinal);
+       if (ret < 0)
+               goto out;
+
+       va_start(argp, keylen2);
+       for (;;) {
+               dlen = va_arg(argp, unsigned int);
+               if (dlen == 0)
+                       break;
+               dpos = va_arg(argp, unsigned int);
+               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
+               if (ret < 0)
+                       break;
+       }
+       va_end(argp);
+       if (!ret)
+               ret = crypto_shash_final(&sdesc->shash, paramdigest);
+       if (ret < 0)
+               goto out;
+
+       ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
+                         paramdigest, TPM_NONCE_SIZE, enonce1,
+                         TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
+                         paramdigest, TPM_NONCE_SIZE, enonce2,
+                         TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
+               ret = -EINVAL;
+out:
+       kfree(sdesc);
+       return ret;
+}
+
+/*
+ * For key specific tpm requests, we will generate and send our
+ * own TPM command packets using the drivers send function.
+ */
+static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
+                           size_t buflen)
+{
+       int rc;
+
+       dump_tpm_buf(cmd);
+       rc = tpm_send(chip_num, cmd, buflen);
+       dump_tpm_buf(cmd);
+       if (rc > 0)
+               /* Can't return positive return codes values to keyctl */
+               rc = -EPERM;
+       return rc;
+}
+
+/*
+ * get a random value from TPM
+ */
+static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
+{
+       int ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_GETRANDOM_SIZE);
+       store32(tb, TPM_ORD_GETRANDOM);
+       store32(tb, len);
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
+       if (!ret)
+               memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
+       return ret;
+}
+
+static int my_get_random(unsigned char *buf, int len)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kmalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+       ret = tpm_get_random(tb, buf, len);
+
+       kfree(tb);
+       return ret;
+}
+
+/*
+ * Lock a trusted key, by extending a selected PCR.
+ *
+ * Prevents a trusted key that is sealed to PCRs from being accessed.
+ * This uses the tpm driver's extend function.
+ */
+static int pcrlock(const int pcrnum)
+{
+       unsigned char hash[SHA1_DIGEST_SIZE];
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       ret = my_get_random(hash, SHA1_DIGEST_SIZE);
+       if (ret < 0)
+               return ret;
+       return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
+}
+
+/*
+ * Create an object specific authorisation protocol (OSAP) session
+ */
+static int osap(struct tpm_buf *tb, struct osapsess *s,
+               const unsigned char *key, uint16_t type, uint32_t handle)
+{
+       unsigned char enonce[TPM_NONCE_SIZE];
+       unsigned char ononce[TPM_NONCE_SIZE];
+       int ret;
+
+       ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
+       if (ret < 0)
+               return ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_OSAP_SIZE);
+       store32(tb, TPM_ORD_OSAP);
+       store16(tb, type);
+       store32(tb, handle);
+       storebytes(tb, ononce, TPM_NONCE_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               return ret;
+
+       s->handle = LOAD32(tb->data, TPM_DATA_OFFSET);
+       memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]),
+              TPM_NONCE_SIZE);
+       memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
+                                 TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
+       return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
+                          enonce, TPM_NONCE_SIZE, ononce, 0, 0);
+}
+
+/*
+ * Create an object independent authorisation protocol (oiap) session
+ */
+static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
+{
+       int ret;
+
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_COMMAND);
+       store32(tb, TPM_OIAP_SIZE);
+       store32(tb, TPM_ORD_OIAP);
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               return ret;
+
+       *handle = LOAD32(tb->data, TPM_DATA_OFFSET);
+       memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
+              TPM_NONCE_SIZE);
+       return 0;
+}
+
+struct tpm_digests {
+       unsigned char encauth[SHA1_DIGEST_SIZE];
+       unsigned char pubauth[SHA1_DIGEST_SIZE];
+       unsigned char xorwork[SHA1_DIGEST_SIZE * 2];
+       unsigned char xorhash[SHA1_DIGEST_SIZE];
+       unsigned char nonceodd[TPM_NONCE_SIZE];
+};
+
+/*
+ * Have the TPM seal(encrypt) the trusted key, possibly based on
+ * Platform Configuration Registers (PCRs). AUTH1 for sealing key.
+ */
+static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
+                   uint32_t keyhandle, const unsigned char *keyauth,
+                   const unsigned char *data, uint32_t datalen,
+                   unsigned char *blob, uint32_t *bloblen,
+                   const unsigned char *blobauth,
+                   const unsigned char *pcrinfo, uint32_t pcrinfosize)
+{
+       struct osapsess sess;
+       struct tpm_digests *td;
+       unsigned char cont;
+       uint32_t ordinal;
+       uint32_t pcrsize;
+       uint32_t datsize;
+       int sealinfosize;
+       int encdatasize;
+       int storedsize;
+       int ret;
+       int i;
+
+       /* alloc some work space for all the hashes */
+       td = kmalloc(sizeof *td, GFP_KERNEL);
+       if (!td)
+               return -ENOMEM;
+
+       /* get session for sealing key */
+       ret = osap(tb, &sess, keyauth, keytype, keyhandle);
+       if (ret < 0)
+               goto out;
+       dump_sess(&sess);
+
+       /* calculate encrypted authorization value */
+       memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE);
+       memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
+       ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
+       if (ret < 0)
+               goto out;
+
+       ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
+       if (ret < 0)
+               goto out;
+       ordinal = htonl(TPM_ORD_SEAL);
+       datsize = htonl(datalen);
+       pcrsize = htonl(pcrinfosize);
+       cont = 0;
+
+       /* encrypt data authorization key */
+       for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
+               td->encauth[i] = td->xorhash[i] ^ blobauth[i];
+
+       /* calculate authorization HMAC value */
+       if (pcrinfosize == 0) {
+               /* no pcr info specified */
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  sizeof(uint32_t), &datsize, datalen, data, 0,
+                                  0);
+       } else {
+               /* pcr info specified */
+               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
+                                  sess.enonce, td->nonceodd, cont,
+                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
+                                  td->encauth, sizeof(uint32_t), &pcrsize,
+                                  pcrinfosize, pcrinfo, sizeof(uint32_t),
+                                  &datsize, datalen, data, 0, 0);
+       }
+       if (ret < 0)
+               goto out;
+
+       /* build and send the TPM request packet */
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_AUTH1_COMMAND);
+       store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen);
+       store32(tb, TPM_ORD_SEAL);
+       store32(tb, keyhandle);
+       storebytes(tb, td->encauth, SHA1_DIGEST_SIZE);
+       store32(tb, pcrinfosize);
+       storebytes(tb, pcrinfo, pcrinfosize);
+       store32(tb, datalen);
+       storebytes(tb, data, datalen);
+       store32(tb, sess.handle);
+       storebytes(tb, td->nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0)
+               goto out;
+
+       /* calculate the size of the returned Blob */
+       sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
+       encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) +
+                            sizeof(uint32_t) + sealinfosize);
+       storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize +
+           sizeof(uint32_t) + encdatasize;
+
+       /* check the HMAC in the response */
+       ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret,
+                            SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0,
+                            0);
+
+       /* copy the returned blob to caller */
+       if (!ret) {
+               memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
+               *bloblen = storedsize;
+       }
+out:
+       kfree(td);
+       return ret;
+}
+
+/*
+ * use the AUTH2_COMMAND form of unseal, to authorize both key and blob
+ */
+static int tpm_unseal(struct tpm_buf *tb,
+                     uint32_t keyhandle, const unsigned char *keyauth,
+                     const unsigned char *blob, int bloblen,
+                     const unsigned char *blobauth,
+                     unsigned char *data, unsigned int *datalen)
+{
+       unsigned char nonceodd[TPM_NONCE_SIZE];
+       unsigned char enonce1[TPM_NONCE_SIZE];
+       unsigned char enonce2[TPM_NONCE_SIZE];
+       unsigned char authdata1[SHA1_DIGEST_SIZE];
+       unsigned char authdata2[SHA1_DIGEST_SIZE];
+       uint32_t authhandle1 = 0;
+       uint32_t authhandle2 = 0;
+       unsigned char cont = 0;
+       uint32_t ordinal;
+       uint32_t keyhndl;
+       int ret;
+
+       /* sessions for unsealing key and data */
+       ret = oiap(tb, &authhandle1, enonce1);
+       if (ret < 0) {
+               pr_info("trusted_key: oiap failed (%d)\n", ret);
+               return ret;
+       }
+       ret = oiap(tb, &authhandle2, enonce2);
+       if (ret < 0) {
+               pr_info("trusted_key: oiap failed (%d)\n", ret);
+               return ret;
+       }
+
+       ordinal = htonl(TPM_ORD_UNSEAL);
+       keyhndl = htonl(SRKHANDLE);
+       ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
+       if (ret < 0) {
+               pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
+               return ret;
+       }
+       ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
+                          enonce1, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
+       ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
+                          enonce2, nonceodd, cont, sizeof(uint32_t),
+                          &ordinal, bloblen, blob, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       /* build and send TPM request packet */
+       INIT_BUF(tb);
+       store16(tb, TPM_TAG_RQU_AUTH2_COMMAND);
+       store32(tb, TPM_UNSEAL_SIZE + bloblen);
+       store32(tb, TPM_ORD_UNSEAL);
+       store32(tb, keyhandle);
+       storebytes(tb, blob, bloblen);
+       store32(tb, authhandle1);
+       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, authdata1, SHA1_DIGEST_SIZE);
+       store32(tb, authhandle2);
+       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
+       store8(tb, cont);
+       storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
+
+       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       if (ret < 0) {
+               pr_info("trusted_key: authhmac failed (%d)\n", ret);
+               return ret;
+       }
+
+       *datalen = LOAD32(tb->data, TPM_DATA_OFFSET);
+       ret = TSS_checkhmac2(tb->data, ordinal, nonceodd,
+                            keyauth, SHA1_DIGEST_SIZE,
+                            blobauth, SHA1_DIGEST_SIZE,
+                            sizeof(uint32_t), TPM_DATA_OFFSET,
+                            *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
+                            0);
+       if (ret < 0) {
+               pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
+               return ret;
+       }
+       memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
+       return 0;
+}
+
+/*
+ * Have the TPM seal(encrypt) the symmetric key
+ */
+static int key_seal(struct trusted_key_payload *p,
+                   struct trusted_key_options *o)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kzalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+
+       /* include migratable flag at end of sealed key */
+       p->key[p->key_len] = p->migratable;
+
+       ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
+                      p->key, p->key_len + 1, p->blob, &p->blob_len,
+                      o->blobauth, o->pcrinfo, o->pcrinfo_len);
+       if (ret < 0)
+               pr_info("trusted_key: srkseal failed (%d)\n", ret);
+
+       kfree(tb);
+       return ret;
+}
+
+/*
+ * Have the TPM unseal(decrypt) the symmetric key
+ */
+static int key_unseal(struct trusted_key_payload *p,
+                     struct trusted_key_options *o)
+{
+       struct tpm_buf *tb;
+       int ret;
+
+       tb = kzalloc(sizeof *tb, GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+
+       ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+                        o->blobauth, p->key, &p->key_len);
+       if (ret < 0)
+               pr_info("trusted_key: srkunseal failed (%d)\n", ret);
+       else
+               /* pull migratable flag out of sealed key */
+               p->migratable = p->key[--p->key_len];
+
+       kfree(tb);
+       return ret;
+}
+
+enum {
+       Opt_err = -1,
+       Opt_new, Opt_load, Opt_update,
+       Opt_keyhandle, Opt_keyauth, Opt_blobauth,
+       Opt_pcrinfo, Opt_pcrlock, Opt_migratable
+};
+
+static const match_table_t key_tokens = {
+       {Opt_new, "new"},
+       {Opt_load, "load"},
+       {Opt_update, "update"},
+       {Opt_keyhandle, "keyhandle=%s"},
+       {Opt_keyauth, "keyauth=%s"},
+       {Opt_blobauth, "blobauth=%s"},
+       {Opt_pcrinfo, "pcrinfo=%s"},
+       {Opt_pcrlock, "pcrlock=%s"},
+       {Opt_migratable, "migratable=%s"},
+       {Opt_err, NULL}
+};
+
+/* can have zero or more token= options */
+static int getoptions(char *c, struct trusted_key_payload *pay,
+                     struct trusted_key_options *opt)
+{
+       substring_t args[MAX_OPT_ARGS];
+       char *p = c;
+       int token;
+       int res;
+       unsigned long handle;
+       unsigned long lock;
+
+       while ((p = strsep(&c, " \t"))) {
+               if (*p == '\0' || *p == ' ' || *p == '\t')
+                       continue;
+               token = match_token(p, key_tokens, args);
+
+               switch (token) {
+               case Opt_pcrinfo:
+                       opt->pcrinfo_len = strlen(args[0].from) / 2;
+                       if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len);
+                       break;
+               case Opt_keyhandle:
+                       res = strict_strtoul(args[0].from, 16, &handle);
+                       if (res < 0)
+                               return -EINVAL;
+                       opt->keytype = SEAL_keytype;
+                       opt->keyhandle = handle;
+                       break;
+               case Opt_keyauth:
+                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE);
+                       break;
+               case Opt_blobauth:
+                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
+                               return -EINVAL;
+                       hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE);
+                       break;
+               case Opt_migratable:
+                       if (*args[0].from == '0')
+                               pay->migratable = 0;
+                       else
+                               return -EINVAL;
+                       break;
+               case Opt_pcrlock:
+                       res = strict_strtoul(args[0].from, 10, &lock);
+                       if (res < 0)
+                               return -EINVAL;
+                       opt->pcrlock = lock;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+/*
+ * datablob_parse - parse the keyctl data and fill in the
+ *                 payload and options structures
+ *
+ * On success returns 0, otherwise -EINVAL.
+ */
+static int datablob_parse(char *datablob, struct trusted_key_payload *p,
+                         struct trusted_key_options *o)
+{
+       substring_t args[MAX_OPT_ARGS];
+       long keylen;
+       int ret = -EINVAL;
+       int key_cmd;
+       char *c;
+
+       /* main command */
+       c = strsep(&datablob, " \t");
+       if (!c)
+               return -EINVAL;
+       key_cmd = match_token(c, key_tokens, args);
+       switch (key_cmd) {
+       case Opt_new:
+               /* first argument is key size */
+               c = strsep(&datablob, " \t");
+               if (!c)
+                       return -EINVAL;
+               ret = strict_strtol(c, 10, &keylen);
+               if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE)
+                       return -EINVAL;
+               p->key_len = keylen;
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_new;
+               break;
+       case Opt_load:
+               /* first argument is sealed blob */
+               c = strsep(&datablob, " \t");
+               if (!c)
+                       return -EINVAL;
+               p->blob_len = strlen(c) / 2;
+               if (p->blob_len > MAX_BLOB_SIZE)
+                       return -EINVAL;
+               hex2bin(p->blob, c, p->blob_len);
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_load;
+               break;
+       case Opt_update:
+               /* all arguments are options */
+               ret = getoptions(datablob, p, o);
+               if (ret < 0)
+                       return ret;
+               ret = Opt_update;
+               break;
+       case Opt_err:
+               return -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static struct trusted_key_options *trusted_options_alloc(void)
+{
+       struct trusted_key_options *options;
+
+       options = kzalloc(sizeof *options, GFP_KERNEL);
+       if (options) {
+               /* set any non-zero defaults */
+               options->keytype = SRK_keytype;
+               options->keyhandle = SRKHANDLE;
+       }
+       return options;
+}
+
+static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
+{
+       struct trusted_key_payload *p = NULL;
+       int ret;
+
+       ret = key_payload_reserve(key, sizeof *p);
+       if (ret < 0)
+               return p;
+       p = kzalloc(sizeof *p, GFP_KERNEL);
+       if (p)
+               p->migratable = 1; /* migratable by default */
+       return p;
+}
+
+/*
+ * trusted_instantiate - create a new trusted key
+ *
+ * Unseal an existing trusted blob or, for a new key, get a
+ * random key, then seal and create a trusted key-type key,
+ * adding it to the specified keyring.
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+static int trusted_instantiate(struct key *key, const void *data,
+                              size_t datalen)
+{
+       struct trusted_key_payload *payload = NULL;
+       struct trusted_key_options *options = NULL;
+       char *datablob;
+       int ret = 0;
+       int key_cmd;
+
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       memcpy(datablob, data, datalen);
+       datablob[datalen] = '\0';
+
+       options = trusted_options_alloc();
+       if (!options) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       payload = trusted_payload_alloc(key);
+       if (!payload) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key_cmd = datablob_parse(datablob, payload, options);
+       if (key_cmd < 0) {
+               ret = key_cmd;
+               goto out;
+       }
+
+       dump_payload(payload);
+       dump_options(options);
+
+       switch (key_cmd) {
+       case Opt_load:
+               ret = key_unseal(payload, options);
+               dump_payload(payload);
+               dump_options(options);
+               if (ret < 0)
+                       pr_info("trusted_key: key_unseal failed (%d)\n", ret);
+               break;
+       case Opt_new:
+               ret = my_get_random(payload->key, payload->key_len);
+               if (ret < 0) {
+                       pr_info("trusted_key: key_create failed (%d)\n", ret);
+                       goto out;
+               }
+               ret = key_seal(payload, options);
+               if (ret < 0)
+                       pr_info("trusted_key: key_seal failed (%d)\n", ret);
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!ret && options->pcrlock)
+               ret = pcrlock(options->pcrlock);
+out:
+       kfree(datablob);
+       kfree(options);
+       if (!ret)
+               rcu_assign_pointer(key->payload.data, payload);
+       else
+               kfree(payload);
+       return ret;
+}
+
+static void trusted_rcu_free(struct rcu_head *rcu)
+{
+       struct trusted_key_payload *p;
+
+       p = container_of(rcu, struct trusted_key_payload, rcu);
+       memset(p->key, 0, p->key_len);
+       kfree(p);
+}
+
+/*
+ * trusted_update - reseal an existing key with new PCR values
+ */
+static int trusted_update(struct key *key, const void *data, size_t datalen)
+{
+       struct trusted_key_payload *p = key->payload.data;
+       struct trusted_key_payload *new_p;
+       struct trusted_key_options *new_o;
+       char *datablob;
+       int ret = 0;
+
+       if (!p->migratable)
+               return -EPERM;
+       if (datalen <= 0 || datalen > 32767 || !data)
+               return -EINVAL;
+
+       datablob = kmalloc(datalen + 1, GFP_KERNEL);
+       if (!datablob)
+               return -ENOMEM;
+       new_o = trusted_options_alloc();
+       if (!new_o) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       new_p = trusted_payload_alloc(key);
+       if (!new_p) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(datablob, data, datalen);
+       datablob[datalen] = '\0';
+       ret = datablob_parse(datablob, new_p, new_o);
+       if (ret != Opt_update) {
+               ret = -EINVAL;
+               kfree(new_p);
+               goto out;
+       }
+       /* copy old key values, and reseal with new pcrs */
+       new_p->migratable = p->migratable;
+       new_p->key_len = p->key_len;
+       memcpy(new_p->key, p->key, p->key_len);
+       dump_payload(p);
+       dump_payload(new_p);
+
+       ret = key_seal(new_p, new_o);
+       if (ret < 0) {
+               pr_info("trusted_key: key_seal failed (%d)\n", ret);
+               kfree(new_p);
+               goto out;
+       }
+       if (new_o->pcrlock) {
+               ret = pcrlock(new_o->pcrlock);
+               if (ret < 0) {
+                       pr_info("trusted_key: pcrlock failed (%d)\n", ret);
+                       kfree(new_p);
+                       goto out;
+               }
+       }
+       rcu_assign_pointer(key->payload.data, new_p);
+       call_rcu(&p->rcu, trusted_rcu_free);
+out:
+       kfree(datablob);
+       kfree(new_o);
+       return ret;
+}
+
+/*
+ * trusted_read - copy the sealed blob data to userspace in hex.
+ * On success, return to userspace the trusted key datablob size.
+ */
+static long trusted_read(const struct key *key, char __user *buffer,
+                        size_t buflen)
+{
+       struct trusted_key_payload *p;
+       char *ascii_buf;
+       char *bufp;
+       int i;
+
+       p = rcu_dereference_protected(key->payload.data,
+                       rwsem_is_locked(&((struct key *)key)->sem));
+       if (!p)
+               return -EINVAL;
+       if (!buffer || buflen <= 0)
+               return 2 * p->blob_len;
+       ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
+       if (!ascii_buf)
+               return -ENOMEM;
+
+       bufp = ascii_buf;
+       for (i = 0; i < p->blob_len; i++)
+               bufp = pack_hex_byte(bufp, p->blob[i]);
+       if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
+               kfree(ascii_buf);
+               return -EFAULT;
+       }
+       kfree(ascii_buf);
+       return 2 * p->blob_len;
+}
+
+/*
+ * trusted_destroy - before freeing the key, clear the decrypted data
+ */
+static void trusted_destroy(struct key *key)
+{
+       struct trusted_key_payload *p = key->payload.data;
+
+       if (!p)
+               return;
+       memset(p->key, 0, p->key_len);
+       kfree(key->payload.data);
+}
+
+struct key_type key_type_trusted = {
+       .name = "trusted",
+       .instantiate = trusted_instantiate,
+       .update = trusted_update,
+       .match = user_match,
+       .destroy = trusted_destroy,
+       .describe = user_describe,
+       .read = trusted_read,
+};
+
+EXPORT_SYMBOL_GPL(key_type_trusted);
+
+static void trusted_shash_release(void)
+{
+       if (hashalg)
+               crypto_free_shash(hashalg);
+       if (hmacalg)
+               crypto_free_shash(hmacalg);
+}
+
+static int __init trusted_shash_alloc(void)
+{
+       int ret;
+
+       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hmacalg)) {
+               pr_info("trusted_key: could not allocate crypto %s\n",
+                       hmac_alg);
+               return PTR_ERR(hmacalg);
+       }
+
+       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hashalg)) {
+               pr_info("trusted_key: could not allocate crypto %s\n",
+                       hash_alg);
+               ret = PTR_ERR(hashalg);
+               goto hashalg_fail;
+       }
+
+       return 0;
+
+hashalg_fail:
+       crypto_free_shash(hmacalg);
+       return ret;
+}
+
+static int __init init_trusted(void)
+{
+       int ret;
+
+       ret = trusted_shash_alloc();
+       if (ret < 0)
+               return ret;
+       ret = register_key_type(&key_type_trusted);
+       if (ret < 0)
+               trusted_shash_release();
+       return ret;
+}
+
+static void __exit cleanup_trusted(void)
+{
+       trusted_shash_release();
+       unregister_key_type(&key_type_trusted);
+}
+
+late_initcall(init_trusted);
+module_exit(cleanup_trusted);
+
+MODULE_LICENSE("GPL");
diff --git a/security/keys/trusted.h b/security/keys/trusted.h
new file mode 100644 (file)
index 0000000..3249fbd
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __TRUSTED_KEY_H
+#define __TRUSTED_KEY_H
+
+/* implementation specific TPM constants */
+#define MAX_PCRINFO_SIZE               64
+#define MAX_BUF_SIZE                   512
+#define TPM_GETRANDOM_SIZE             14
+#define TPM_OSAP_SIZE                  36
+#define TPM_OIAP_SIZE                  10
+#define TPM_SEAL_SIZE                  87
+#define TPM_UNSEAL_SIZE                        104
+#define TPM_SIZE_OFFSET                        2
+#define TPM_RETURN_OFFSET              6
+#define TPM_DATA_OFFSET                        10
+
+#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset]))
+#define LOAD32N(buffer, offset)        (*(uint32_t *)&buffer[offset])
+#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset]))
+
+struct tpm_buf {
+       int len;
+       unsigned char data[MAX_BUF_SIZE];
+};
+
+#define INIT_BUF(tb) (tb->len = 0)
+
+struct osapsess {
+       uint32_t handle;
+       unsigned char secret[SHA1_DIGEST_SIZE];
+       unsigned char enonce[TPM_NONCE_SIZE];
+};
+
+/* discrete values, but have to store in uint16_t for TPM use */
+enum {
+       SEAL_keytype = 1,
+       SRK_keytype = 4
+};
+
+struct trusted_key_options {
+       uint16_t keytype;
+       uint32_t keyhandle;
+       unsigned char keyauth[SHA1_DIGEST_SIZE];
+       unsigned char blobauth[SHA1_DIGEST_SIZE];
+       uint32_t pcrinfo_len;
+       unsigned char pcrinfo[MAX_PCRINFO_SIZE];
+       int pcrlock;
+};
+
+#define TPM_DEBUG 0
+
+#if TPM_DEBUG
+static inline void dump_options(struct trusted_key_options *o)
+{
+       pr_info("trusted_key: sealing key type %d\n", o->keytype);
+       pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
+       pr_info("trusted_key: pcrlock %d\n", o->pcrlock);
+       pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len);
+       print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
+                      16, 1, o->pcrinfo, o->pcrinfo_len, 0);
+}
+
+static inline void dump_payload(struct trusted_key_payload *p)
+{
+       pr_info("trusted_key: key_len %d\n", p->key_len);
+       print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE,
+                      16, 1, p->key, p->key_len, 0);
+       pr_info("trusted_key: bloblen %d\n", p->blob_len);
+       print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE,
+                      16, 1, p->blob, p->blob_len, 0);
+       pr_info("trusted_key: migratable %d\n", p->migratable);
+}
+
+static inline void dump_sess(struct osapsess *s)
+{
+       print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
+                      16, 1, &s->handle, 4, 0);
+       pr_info("trusted-key: secret:\n");
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+                      16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
+       pr_info("trusted-key: enonce:\n");
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+                      16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
+}
+
+static inline void dump_tpm_buf(unsigned char *buf)
+{
+       int len;
+
+       pr_info("\ntrusted-key: tpm buffer\n");
+       len = LOAD32(buf, TPM_SIZE_OFFSET);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
+}
+#else
+static inline void dump_options(struct trusted_key_options *o)
+{
+}
+
+static inline void dump_payload(struct trusted_key_payload *p)
+{
+}
+
+static inline void dump_sess(struct osapsess *s)
+{
+}
+
+static inline void dump_tpm_buf(unsigned char *buf)
+{
+}
+#endif
+
+static inline void store8(struct tpm_buf *buf, const unsigned char value)
+{
+       buf->data[buf->len++] = value;
+}
+
+static inline void store16(struct tpm_buf *buf, const uint16_t value)
+{
+       *(uint16_t *) & buf->data[buf->len] = htons(value);
+       buf->len += sizeof value;
+}
+
+static inline void store32(struct tpm_buf *buf, const uint32_t value)
+{
+       *(uint32_t *) & buf->data[buf->len] = htonl(value);
+       buf->len += sizeof value;
+}
+
+static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
+                             const int len)
+{
+       memcpy(buf->data + buf->len, in, len);
+       buf->len += len;
+}
+#endif
diff --git a/security/keys/trusted_defined.c b/security/keys/trusted_defined.c
deleted file mode 100644 (file)
index 975e9f2..0000000
+++ /dev/null
@@ -1,1175 +0,0 @@
-/*
- * Copyright (C) 2010 IBM Corporation
- *
- * Author:
- * David Safford <safford@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * See Documentation/keys-trusted-encrypted.txt
- */
-
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/parser.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <keys/user-type.h>
-#include <keys/trusted-type.h>
-#include <linux/key-type.h>
-#include <linux/rcupdate.h>
-#include <linux/crypto.h>
-#include <crypto/hash.h>
-#include <crypto/sha.h>
-#include <linux/capability.h>
-#include <linux/tpm.h>
-#include <linux/tpm_command.h>
-
-#include "trusted_defined.h"
-
-static const char hmac_alg[] = "hmac(sha1)";
-static const char hash_alg[] = "sha1";
-
-struct sdesc {
-       struct shash_desc shash;
-       char ctx[];
-};
-
-static struct crypto_shash *hashalg;
-static struct crypto_shash *hmacalg;
-
-static struct sdesc *init_sdesc(struct crypto_shash *alg)
-{
-       struct sdesc *sdesc;
-       int size;
-
-       size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
-       sdesc = kmalloc(size, GFP_KERNEL);
-       if (!sdesc)
-               return ERR_PTR(-ENOMEM);
-       sdesc->shash.tfm = alg;
-       sdesc->shash.flags = 0x0;
-       return sdesc;
-}
-
-static int TSS_sha1(const unsigned char *data, unsigned int datalen,
-                   unsigned char *digest)
-{
-       struct sdesc *sdesc;
-       int ret;
-
-       sdesc = init_sdesc(hashalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
-       kfree(sdesc);
-       return ret;
-}
-
-static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
-                      unsigned int keylen, ...)
-{
-       struct sdesc *sdesc;
-       va_list argp;
-       unsigned int dlen;
-       unsigned char *data;
-       int ret;
-
-       sdesc = init_sdesc(hmacalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hmac_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       ret = crypto_shash_setkey(hmacalg, key, keylen);
-       if (ret < 0)
-               goto out;
-       ret = crypto_shash_init(&sdesc->shash);
-       if (ret < 0)
-               goto out;
-
-       va_start(argp, keylen);
-       for (;;) {
-               dlen = va_arg(argp, unsigned int);
-               if (dlen == 0)
-                       break;
-               data = va_arg(argp, unsigned char *);
-               if (data == NULL)
-                       return -EINVAL;
-               ret = crypto_shash_update(&sdesc->shash, data, dlen);
-               if (ret < 0)
-                       goto out;
-       }
-       va_end(argp);
-       if (!ret)
-               ret = crypto_shash_final(&sdesc->shash, digest);
-out:
-       kfree(sdesc);
-       return ret;
-}
-
-/*
- * calculate authorization info fields to send to TPM
- */
-static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
-                       unsigned int keylen, unsigned char *h1,
-                       unsigned char *h2, unsigned char h3, ...)
-{
-       unsigned char paramdigest[SHA1_DIGEST_SIZE];
-       struct sdesc *sdesc;
-       unsigned int dlen;
-       unsigned char *data;
-       unsigned char c;
-       int ret;
-       va_list argp;
-
-       sdesc = init_sdesc(hashalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-
-       c = h3;
-       ret = crypto_shash_init(&sdesc->shash);
-       if (ret < 0)
-               goto out;
-       va_start(argp, h3);
-       for (;;) {
-               dlen = va_arg(argp, unsigned int);
-               if (dlen == 0)
-                       break;
-               data = va_arg(argp, unsigned char *);
-               ret = crypto_shash_update(&sdesc->shash, data, dlen);
-               if (ret < 0) {
-                       va_end(argp);
-                       goto out;
-               }
-       }
-       va_end(argp);
-       ret = crypto_shash_final(&sdesc->shash, paramdigest);
-       if (!ret)
-               ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
-                                 paramdigest, TPM_NONCE_SIZE, h1,
-                                 TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
-out:
-       kfree(sdesc);
-       return ret;
-}
-
-/*
- * verify the AUTH1_COMMAND (Seal) result from TPM
- */
-static int TSS_checkhmac1(unsigned char *buffer,
-                         const uint32_t command,
-                         const unsigned char *ononce,
-                         const unsigned char *key,
-                         unsigned int keylen, ...)
-{
-       uint32_t bufsize;
-       uint16_t tag;
-       uint32_t ordinal;
-       uint32_t result;
-       unsigned char *enonce;
-       unsigned char *continueflag;
-       unsigned char *authdata;
-       unsigned char testhmac[SHA1_DIGEST_SIZE];
-       unsigned char paramdigest[SHA1_DIGEST_SIZE];
-       struct sdesc *sdesc;
-       unsigned int dlen;
-       unsigned int dpos;
-       va_list argp;
-       int ret;
-
-       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
-       tag = LOAD16(buffer, 0);
-       ordinal = command;
-       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
-       if (tag == TPM_TAG_RSP_COMMAND)
-               return 0;
-       if (tag != TPM_TAG_RSP_AUTH1_COMMAND)
-               return -EINVAL;
-       authdata = buffer + bufsize - SHA1_DIGEST_SIZE;
-       continueflag = authdata - 1;
-       enonce = continueflag - TPM_NONCE_SIZE;
-
-       sdesc = init_sdesc(hashalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-       ret = crypto_shash_init(&sdesc->shash);
-       if (ret < 0)
-               goto out;
-       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
-                                 sizeof result);
-       if (ret < 0)
-               goto out;
-       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
-                                 sizeof ordinal);
-       if (ret < 0)
-               goto out;
-       va_start(argp, keylen);
-       for (;;) {
-               dlen = va_arg(argp, unsigned int);
-               if (dlen == 0)
-                       break;
-               dpos = va_arg(argp, unsigned int);
-               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
-               if (ret < 0) {
-                       va_end(argp);
-                       goto out;
-               }
-       }
-       va_end(argp);
-       ret = crypto_shash_final(&sdesc->shash, paramdigest);
-       if (ret < 0)
-               goto out;
-
-       ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest,
-                         TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce,
-                         1, continueflag, 0, 0);
-       if (ret < 0)
-               goto out;
-
-       if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
-               ret = -EINVAL;
-out:
-       kfree(sdesc);
-       return ret;
-}
-
-/*
- * verify the AUTH2_COMMAND (unseal) result from TPM
- */
-static int TSS_checkhmac2(unsigned char *buffer,
-                         const uint32_t command,
-                         const unsigned char *ononce,
-                         const unsigned char *key1,
-                         unsigned int keylen1,
-                         const unsigned char *key2,
-                         unsigned int keylen2, ...)
-{
-       uint32_t bufsize;
-       uint16_t tag;
-       uint32_t ordinal;
-       uint32_t result;
-       unsigned char *enonce1;
-       unsigned char *continueflag1;
-       unsigned char *authdata1;
-       unsigned char *enonce2;
-       unsigned char *continueflag2;
-       unsigned char *authdata2;
-       unsigned char testhmac1[SHA1_DIGEST_SIZE];
-       unsigned char testhmac2[SHA1_DIGEST_SIZE];
-       unsigned char paramdigest[SHA1_DIGEST_SIZE];
-       struct sdesc *sdesc;
-       unsigned int dlen;
-       unsigned int dpos;
-       va_list argp;
-       int ret;
-
-       bufsize = LOAD32(buffer, TPM_SIZE_OFFSET);
-       tag = LOAD16(buffer, 0);
-       ordinal = command;
-       result = LOAD32N(buffer, TPM_RETURN_OFFSET);
-
-       if (tag == TPM_TAG_RSP_COMMAND)
-               return 0;
-       if (tag != TPM_TAG_RSP_AUTH2_COMMAND)
-               return -EINVAL;
-       authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1
-                       + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE);
-       authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE);
-       continueflag1 = authdata1 - 1;
-       continueflag2 = authdata2 - 1;
-       enonce1 = continueflag1 - TPM_NONCE_SIZE;
-       enonce2 = continueflag2 - TPM_NONCE_SIZE;
-
-       sdesc = init_sdesc(hashalg);
-       if (IS_ERR(sdesc)) {
-               pr_info("trusted_key: can't alloc %s\n", hash_alg);
-               return PTR_ERR(sdesc);
-       }
-       ret = crypto_shash_init(&sdesc->shash);
-       if (ret < 0)
-               goto out;
-       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result,
-                                 sizeof result);
-       if (ret < 0)
-               goto out;
-       ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal,
-                                 sizeof ordinal);
-       if (ret < 0)
-               goto out;
-
-       va_start(argp, keylen2);
-       for (;;) {
-               dlen = va_arg(argp, unsigned int);
-               if (dlen == 0)
-                       break;
-               dpos = va_arg(argp, unsigned int);
-               ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
-               if (ret < 0) {
-                       va_end(argp);
-                       goto out;
-               }
-       }
-       va_end(argp);
-       ret = crypto_shash_final(&sdesc->shash, paramdigest);
-       if (ret < 0)
-               goto out;
-
-       ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE,
-                         paramdigest, TPM_NONCE_SIZE, enonce1,
-                         TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0);
-       if (ret < 0)
-               goto out;
-       if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) {
-               ret = -EINVAL;
-               goto out;
-       }
-       ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE,
-                         paramdigest, TPM_NONCE_SIZE, enonce2,
-                         TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0);
-       if (ret < 0)
-               goto out;
-       if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
-               ret = -EINVAL;
-out:
-       kfree(sdesc);
-       return ret;
-}
-
-/*
- * For key specific tpm requests, we will generate and send our
- * own TPM command packets using the drivers send function.
- */
-static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
-                           size_t buflen)
-{
-       int rc;
-
-       dump_tpm_buf(cmd);
-       rc = tpm_send(chip_num, cmd, buflen);
-       dump_tpm_buf(cmd);
-       if (rc > 0)
-               /* Can't return positive return codes values to keyctl */
-               rc = -EPERM;
-       return rc;
-}
-
-/*
- * get a random value from TPM
- */
-static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
-{
-       int ret;
-
-       INIT_BUF(tb);
-       store16(tb, TPM_TAG_RQU_COMMAND);
-       store32(tb, TPM_GETRANDOM_SIZE);
-       store32(tb, TPM_ORD_GETRANDOM);
-       store32(tb, len);
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
-       if (!ret)
-               memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
-       return ret;
-}
-
-static int my_get_random(unsigned char *buf, int len)
-{
-       struct tpm_buf *tb;
-       int ret;
-
-       tb = kmalloc(sizeof *tb, GFP_KERNEL);
-       if (!tb)
-               return -ENOMEM;
-       ret = tpm_get_random(tb, buf, len);
-
-       kfree(tb);
-       return ret;
-}
-
-/*
- * Lock a trusted key, by extending a selected PCR.
- *
- * Prevents a trusted key that is sealed to PCRs from being accessed.
- * This uses the tpm driver's extend function.
- */
-static int pcrlock(const int pcrnum)
-{
-       unsigned char hash[SHA1_DIGEST_SIZE];
-       int ret;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       ret = my_get_random(hash, SHA1_DIGEST_SIZE);
-       if (ret < 0)
-               return ret;
-       return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
-}
-
-/*
- * Create an object specific authorisation protocol (OSAP) session
- */
-static int osap(struct tpm_buf *tb, struct osapsess *s,
-               const unsigned char *key, uint16_t type, uint32_t handle)
-{
-       unsigned char enonce[TPM_NONCE_SIZE];
-       unsigned char ononce[TPM_NONCE_SIZE];
-       int ret;
-
-       ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
-       if (ret < 0)
-               return ret;
-
-       INIT_BUF(tb);
-       store16(tb, TPM_TAG_RQU_COMMAND);
-       store32(tb, TPM_OSAP_SIZE);
-       store32(tb, TPM_ORD_OSAP);
-       store16(tb, type);
-       store32(tb, handle);
-       storebytes(tb, ononce, TPM_NONCE_SIZE);
-
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
-       if (ret < 0)
-               return ret;
-
-       s->handle = LOAD32(tb->data, TPM_DATA_OFFSET);
-       memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]),
-              TPM_NONCE_SIZE);
-       memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) +
-                                 TPM_NONCE_SIZE]), TPM_NONCE_SIZE);
-       return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE,
-                          enonce, TPM_NONCE_SIZE, ononce, 0, 0);
-}
-
-/*
- * Create an object independent authorisation protocol (oiap) session
- */
-static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
-{
-       int ret;
-
-       INIT_BUF(tb);
-       store16(tb, TPM_TAG_RQU_COMMAND);
-       store32(tb, TPM_OIAP_SIZE);
-       store32(tb, TPM_ORD_OIAP);
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
-       if (ret < 0)
-               return ret;
-
-       *handle = LOAD32(tb->data, TPM_DATA_OFFSET);
-       memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)],
-              TPM_NONCE_SIZE);
-       return 0;
-}
-
-struct tpm_digests {
-       unsigned char encauth[SHA1_DIGEST_SIZE];
-       unsigned char pubauth[SHA1_DIGEST_SIZE];
-       unsigned char xorwork[SHA1_DIGEST_SIZE * 2];
-       unsigned char xorhash[SHA1_DIGEST_SIZE];
-       unsigned char nonceodd[TPM_NONCE_SIZE];
-};
-
-/*
- * Have the TPM seal(encrypt) the trusted key, possibly based on
- * Platform Configuration Registers (PCRs). AUTH1 for sealing key.
- */
-static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
-                   uint32_t keyhandle, const unsigned char *keyauth,
-                   const unsigned char *data, uint32_t datalen,
-                   unsigned char *blob, uint32_t *bloblen,
-                   const unsigned char *blobauth,
-                   const unsigned char *pcrinfo, uint32_t pcrinfosize)
-{
-       struct osapsess sess;
-       struct tpm_digests *td;
-       unsigned char cont;
-       uint32_t ordinal;
-       uint32_t pcrsize;
-       uint32_t datsize;
-       int sealinfosize;
-       int encdatasize;
-       int storedsize;
-       int ret;
-       int i;
-
-       /* alloc some work space for all the hashes */
-       td = kmalloc(sizeof *td, GFP_KERNEL);
-       if (!td)
-               return -ENOMEM;
-
-       /* get session for sealing key */
-       ret = osap(tb, &sess, keyauth, keytype, keyhandle);
-       if (ret < 0)
-               return ret;
-       dump_sess(&sess);
-
-       /* calculate encrypted authorization value */
-       memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE);
-       memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
-       ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
-       if (ret < 0)
-               return ret;
-
-       ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
-       if (ret < 0)
-               return ret;
-       ordinal = htonl(TPM_ORD_SEAL);
-       datsize = htonl(datalen);
-       pcrsize = htonl(pcrinfosize);
-       cont = 0;
-
-       /* encrypt data authorization key */
-       for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
-               td->encauth[i] = td->xorhash[i] ^ blobauth[i];
-
-       /* calculate authorization HMAC value */
-       if (pcrinfosize == 0) {
-               /* no pcr info specified */
-               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
-                                  sess.enonce, td->nonceodd, cont,
-                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
-                                  td->encauth, sizeof(uint32_t), &pcrsize,
-                                  sizeof(uint32_t), &datsize, datalen, data, 0,
-                                  0);
-       } else {
-               /* pcr info specified */
-               ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE,
-                                  sess.enonce, td->nonceodd, cont,
-                                  sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE,
-                                  td->encauth, sizeof(uint32_t), &pcrsize,
-                                  pcrinfosize, pcrinfo, sizeof(uint32_t),
-                                  &datsize, datalen, data, 0, 0);
-       }
-       if (ret < 0)
-               return ret;
-
-       /* build and send the TPM request packet */
-       INIT_BUF(tb);
-       store16(tb, TPM_TAG_RQU_AUTH1_COMMAND);
-       store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen);
-       store32(tb, TPM_ORD_SEAL);
-       store32(tb, keyhandle);
-       storebytes(tb, td->encauth, SHA1_DIGEST_SIZE);
-       store32(tb, pcrinfosize);
-       storebytes(tb, pcrinfo, pcrinfosize);
-       store32(tb, datalen);
-       storebytes(tb, data, datalen);
-       store32(tb, sess.handle);
-       storebytes(tb, td->nonceodd, TPM_NONCE_SIZE);
-       store8(tb, cont);
-       storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
-
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
-       if (ret < 0)
-               return ret;
-
-       /* calculate the size of the returned Blob */
-       sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
-       encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) +
-                            sizeof(uint32_t) + sealinfosize);
-       storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize +
-           sizeof(uint32_t) + encdatasize;
-
-       /* check the HMAC in the response */
-       ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret,
-                            SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0,
-                            0);
-
-       /* copy the returned blob to caller */
-       if (!ret) {
-               memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
-               *bloblen = storedsize;
-       }
-       return ret;
-}
-
-/*
- * use the AUTH2_COMMAND form of unseal, to authorize both key and blob
- */
-static int tpm_unseal(struct tpm_buf *tb,
-                     uint32_t keyhandle, const unsigned char *keyauth,
-                     const unsigned char *blob, int bloblen,
-                     const unsigned char *blobauth,
-                     unsigned char *data, unsigned int *datalen)
-{
-       unsigned char nonceodd[TPM_NONCE_SIZE];
-       unsigned char enonce1[TPM_NONCE_SIZE];
-       unsigned char enonce2[TPM_NONCE_SIZE];
-       unsigned char authdata1[SHA1_DIGEST_SIZE];
-       unsigned char authdata2[SHA1_DIGEST_SIZE];
-       uint32_t authhandle1 = 0;
-       uint32_t authhandle2 = 0;
-       unsigned char cont = 0;
-       uint32_t ordinal;
-       uint32_t keyhndl;
-       int ret;
-
-       /* sessions for unsealing key and data */
-       ret = oiap(tb, &authhandle1, enonce1);
-       if (ret < 0) {
-               pr_info("trusted_key: oiap failed (%d)\n", ret);
-               return ret;
-       }
-       ret = oiap(tb, &authhandle2, enonce2);
-       if (ret < 0) {
-               pr_info("trusted_key: oiap failed (%d)\n", ret);
-               return ret;
-       }
-
-       ordinal = htonl(TPM_ORD_UNSEAL);
-       keyhndl = htonl(SRKHANDLE);
-       ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
-       if (ret < 0) {
-               pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
-               return ret;
-       }
-       ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE,
-                          enonce1, nonceodd, cont, sizeof(uint32_t),
-                          &ordinal, bloblen, blob, 0, 0);
-       if (ret < 0)
-               return ret;
-       ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE,
-                          enonce2, nonceodd, cont, sizeof(uint32_t),
-                          &ordinal, bloblen, blob, 0, 0);
-       if (ret < 0)
-               return ret;
-
-       /* build and send TPM request packet */
-       INIT_BUF(tb);
-       store16(tb, TPM_TAG_RQU_AUTH2_COMMAND);
-       store32(tb, TPM_UNSEAL_SIZE + bloblen);
-       store32(tb, TPM_ORD_UNSEAL);
-       store32(tb, keyhandle);
-       storebytes(tb, blob, bloblen);
-       store32(tb, authhandle1);
-       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
-       store8(tb, cont);
-       storebytes(tb, authdata1, SHA1_DIGEST_SIZE);
-       store32(tb, authhandle2);
-       storebytes(tb, nonceodd, TPM_NONCE_SIZE);
-       store8(tb, cont);
-       storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
-
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
-       if (ret < 0) {
-               pr_info("trusted_key: authhmac failed (%d)\n", ret);
-               return ret;
-       }
-
-       *datalen = LOAD32(tb->data, TPM_DATA_OFFSET);
-       ret = TSS_checkhmac2(tb->data, ordinal, nonceodd,
-                            keyauth, SHA1_DIGEST_SIZE,
-                            blobauth, SHA1_DIGEST_SIZE,
-                            sizeof(uint32_t), TPM_DATA_OFFSET,
-                            *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0,
-                            0);
-       if (ret < 0) {
-               pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret);
-               return ret;
-       }
-       memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen);
-       return 0;
-}
-
-/*
- * Have the TPM seal(encrypt) the symmetric key
- */
-static int key_seal(struct trusted_key_payload *p,
-                   struct trusted_key_options *o)
-{
-       struct tpm_buf *tb;
-       int ret;
-
-       tb = kzalloc(sizeof *tb, GFP_KERNEL);
-       if (!tb)
-               return -ENOMEM;
-
-       /* include migratable flag at end of sealed key */
-       p->key[p->key_len] = p->migratable;
-
-       ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
-                      p->key, p->key_len + 1, p->blob, &p->blob_len,
-                      o->blobauth, o->pcrinfo, o->pcrinfo_len);
-       if (ret < 0)
-               pr_info("trusted_key: srkseal failed (%d)\n", ret);
-
-       kfree(tb);
-       return ret;
-}
-
-/*
- * Have the TPM unseal(decrypt) the symmetric key
- */
-static int key_unseal(struct trusted_key_payload *p,
-                     struct trusted_key_options *o)
-{
-       struct tpm_buf *tb;
-       int ret;
-
-       tb = kzalloc(sizeof *tb, GFP_KERNEL);
-       if (!tb)
-               return -ENOMEM;
-
-       ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
-                        o->blobauth, p->key, &p->key_len);
-       if (ret < 0)
-               pr_info("trusted_key: srkunseal failed (%d)\n", ret);
-       else
-               /* pull migratable flag out of sealed key */
-               p->migratable = p->key[--p->key_len];
-
-       kfree(tb);
-       return ret;
-}
-
-enum {
-       Opt_err = -1,
-       Opt_new, Opt_load, Opt_update,
-       Opt_keyhandle, Opt_keyauth, Opt_blobauth,
-       Opt_pcrinfo, Opt_pcrlock, Opt_migratable
-};
-
-static const match_table_t key_tokens = {
-       {Opt_new, "new"},
-       {Opt_load, "load"},
-       {Opt_update, "update"},
-       {Opt_keyhandle, "keyhandle=%s"},
-       {Opt_keyauth, "keyauth=%s"},
-       {Opt_blobauth, "blobauth=%s"},
-       {Opt_pcrinfo, "pcrinfo=%s"},
-       {Opt_pcrlock, "pcrlock=%s"},
-       {Opt_migratable, "migratable=%s"},
-       {Opt_err, NULL}
-};
-
-/* can have zero or more token= options */
-static int getoptions(char *c, struct trusted_key_payload *pay,
-                     struct trusted_key_options *opt)
-{
-       substring_t args[MAX_OPT_ARGS];
-       char *p = c;
-       int token;
-       int res;
-       unsigned long handle;
-       unsigned long lock;
-
-       while ((p = strsep(&c, " \t"))) {
-               if (*p == '\0' || *p == ' ' || *p == '\t')
-                       continue;
-               token = match_token(p, key_tokens, args);
-
-               switch (token) {
-               case Opt_pcrinfo:
-                       opt->pcrinfo_len = strlen(args[0].from) / 2;
-                       if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
-                               return -EINVAL;
-                       hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len);
-                       break;
-               case Opt_keyhandle:
-                       res = strict_strtoul(args[0].from, 16, &handle);
-                       if (res < 0)
-                               return -EINVAL;
-                       opt->keytype = SEAL_keytype;
-                       opt->keyhandle = handle;
-                       break;
-               case Opt_keyauth:
-                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
-                               return -EINVAL;
-                       hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE);
-                       break;
-               case Opt_blobauth:
-                       if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
-                               return -EINVAL;
-                       hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE);
-                       break;
-               case Opt_migratable:
-                       if (*args[0].from == '0')
-                               pay->migratable = 0;
-                       else
-                               return -EINVAL;
-                       break;
-               case Opt_pcrlock:
-                       res = strict_strtoul(args[0].from, 10, &lock);
-                       if (res < 0)
-                               return -EINVAL;
-                       opt->pcrlock = lock;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-
-/*
- * datablob_parse - parse the keyctl data and fill in the
- *                 payload and options structures
- *
- * On success returns 0, otherwise -EINVAL.
- */
-static int datablob_parse(char *datablob, struct trusted_key_payload *p,
-                         struct trusted_key_options *o)
-{
-       substring_t args[MAX_OPT_ARGS];
-       long keylen;
-       int ret = -EINVAL;
-       int key_cmd;
-       char *c;
-
-       /* main command */
-       c = strsep(&datablob, " \t");
-       if (!c)
-               return -EINVAL;
-       key_cmd = match_token(c, key_tokens, args);
-       switch (key_cmd) {
-       case Opt_new:
-               /* first argument is key size */
-               c = strsep(&datablob, " \t");
-               if (!c)
-                       return -EINVAL;
-               ret = strict_strtol(c, 10, &keylen);
-               if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE)
-                       return -EINVAL;
-               p->key_len = keylen;
-               ret = getoptions(datablob, p, o);
-               if (ret < 0)
-                       return ret;
-               ret = Opt_new;
-               break;
-       case Opt_load:
-               /* first argument is sealed blob */
-               c = strsep(&datablob, " \t");
-               if (!c)
-                       return -EINVAL;
-               p->blob_len = strlen(c) / 2;
-               if (p->blob_len > MAX_BLOB_SIZE)
-                       return -EINVAL;
-               hex2bin(p->blob, c, p->blob_len);
-               ret = getoptions(datablob, p, o);
-               if (ret < 0)
-                       return ret;
-               ret = Opt_load;
-               break;
-       case Opt_update:
-               /* all arguments are options */
-               ret = getoptions(datablob, p, o);
-               if (ret < 0)
-                       return ret;
-               ret = Opt_update;
-               break;
-       case Opt_err:
-               return -EINVAL;
-               break;
-       }
-       return ret;
-}
-
-static struct trusted_key_options *trusted_options_alloc(void)
-{
-       struct trusted_key_options *options;
-
-       options = kzalloc(sizeof *options, GFP_KERNEL);
-       if (options) {
-               /* set any non-zero defaults */
-               options->keytype = SRK_keytype;
-               options->keyhandle = SRKHANDLE;
-       }
-       return options;
-}
-
-static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
-{
-       struct trusted_key_payload *p = NULL;
-       int ret;
-
-       ret = key_payload_reserve(key, sizeof *p);
-       if (ret < 0)
-               return p;
-       p = kzalloc(sizeof *p, GFP_KERNEL);
-       if (p)
-               p->migratable = 1; /* migratable by default */
-       return p;
-}
-
-/*
- * trusted_instantiate - create a new trusted key
- *
- * Unseal an existing trusted blob or, for a new key, get a
- * random key, then seal and create a trusted key-type key,
- * adding it to the specified keyring.
- *
- * On success, return 0. Otherwise return errno.
- */
-static int trusted_instantiate(struct key *key, const void *data,
-                              size_t datalen)
-{
-       struct trusted_key_payload *payload = NULL;
-       struct trusted_key_options *options = NULL;
-       char *datablob;
-       int ret = 0;
-       int key_cmd;
-
-       if (datalen <= 0 || datalen > 32767 || !data)
-               return -EINVAL;
-
-       datablob = kmalloc(datalen + 1, GFP_KERNEL);
-       if (!datablob)
-               return -ENOMEM;
-       memcpy(datablob, data, datalen);
-       datablob[datalen] = '\0';
-
-       options = trusted_options_alloc();
-       if (!options) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       payload = trusted_payload_alloc(key);
-       if (!payload) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       key_cmd = datablob_parse(datablob, payload, options);
-       if (key_cmd < 0) {
-               ret = key_cmd;
-               goto out;
-       }
-
-       dump_payload(payload);
-       dump_options(options);
-
-       switch (key_cmd) {
-       case Opt_load:
-               ret = key_unseal(payload, options);
-               dump_payload(payload);
-               dump_options(options);
-               if (ret < 0)
-                       pr_info("trusted_key: key_unseal failed (%d)\n", ret);
-               break;
-       case Opt_new:
-               ret = my_get_random(payload->key, payload->key_len);
-               if (ret < 0) {
-                       pr_info("trusted_key: key_create failed (%d)\n", ret);
-                       goto out;
-               }
-               ret = key_seal(payload, options);
-               if (ret < 0)
-                       pr_info("trusted_key: key_seal failed (%d)\n", ret);
-               break;
-       default:
-               ret = -EINVAL;
-               goto out;
-       }
-       if (!ret && options->pcrlock)
-               ret = pcrlock(options->pcrlock);
-out:
-       kfree(datablob);
-       kfree(options);
-       if (!ret)
-               rcu_assign_pointer(key->payload.data, payload);
-       else
-               kfree(payload);
-       return ret;
-}
-
-static void trusted_rcu_free(struct rcu_head *rcu)
-{
-       struct trusted_key_payload *p;
-
-       p = container_of(rcu, struct trusted_key_payload, rcu);
-       memset(p->key, 0, p->key_len);
-       kfree(p);
-}
-
-/*
- * trusted_update - reseal an existing key with new PCR values
- */
-static int trusted_update(struct key *key, const void *data, size_t datalen)
-{
-       struct trusted_key_payload *p = key->payload.data;
-       struct trusted_key_payload *new_p;
-       struct trusted_key_options *new_o;
-       char *datablob;
-       int ret = 0;
-
-       if (!p->migratable)
-               return -EPERM;
-       if (datalen <= 0 || datalen > 32767 || !data)
-               return -EINVAL;
-
-       datablob = kmalloc(datalen + 1, GFP_KERNEL);
-       if (!datablob)
-               return -ENOMEM;
-       new_o = trusted_options_alloc();
-       if (!new_o) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       new_p = trusted_payload_alloc(key);
-       if (!new_p) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memcpy(datablob, data, datalen);
-       datablob[datalen] = '\0';
-       ret = datablob_parse(datablob, new_p, new_o);
-       if (ret != Opt_update) {
-               ret = -EINVAL;
-               goto out;
-       }
-       /* copy old key values, and reseal with new pcrs */
-       new_p->migratable = p->migratable;
-       new_p->key_len = p->key_len;
-       memcpy(new_p->key, p->key, p->key_len);
-       dump_payload(p);
-       dump_payload(new_p);
-
-       ret = key_seal(new_p, new_o);
-       if (ret < 0) {
-               pr_info("trusted_key: key_seal failed (%d)\n", ret);
-               kfree(new_p);
-               goto out;
-       }
-       if (new_o->pcrlock) {
-               ret = pcrlock(new_o->pcrlock);
-               if (ret < 0) {
-                       pr_info("trusted_key: pcrlock failed (%d)\n", ret);
-                       kfree(new_p);
-                       goto out;
-               }
-       }
-       rcu_assign_pointer(key->payload.data, new_p);
-       call_rcu(&p->rcu, trusted_rcu_free);
-out:
-       kfree(datablob);
-       kfree(new_o);
-       return ret;
-}
-
-/*
- * trusted_read - copy the sealed blob data to userspace in hex.
- * On success, return to userspace the trusted key datablob size.
- */
-static long trusted_read(const struct key *key, char __user *buffer,
-                        size_t buflen)
-{
-       struct trusted_key_payload *p;
-       char *ascii_buf;
-       char *bufp;
-       int i;
-
-       p = rcu_dereference_protected(key->payload.data,
-                       rwsem_is_locked(&((struct key *)key)->sem));
-       if (!p)
-               return -EINVAL;
-       if (!buffer || buflen <= 0)
-               return 2 * p->blob_len;
-       ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
-       if (!ascii_buf)
-               return -ENOMEM;
-
-       bufp = ascii_buf;
-       for (i = 0; i < p->blob_len; i++)
-               bufp = pack_hex_byte(bufp, p->blob[i]);
-       if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
-               kfree(ascii_buf);
-               return -EFAULT;
-       }
-       kfree(ascii_buf);
-       return 2 * p->blob_len;
-}
-
-/*
- * trusted_destroy - before freeing the key, clear the decrypted data
- */
-static void trusted_destroy(struct key *key)
-{
-       struct trusted_key_payload *p = key->payload.data;
-
-       if (!p)
-               return;
-       memset(p->key, 0, p->key_len);
-       kfree(key->payload.data);
-}
-
-struct key_type key_type_trusted = {
-       .name = "trusted",
-       .instantiate = trusted_instantiate,
-       .update = trusted_update,
-       .match = user_match,
-       .destroy = trusted_destroy,
-       .describe = user_describe,
-       .read = trusted_read,
-};
-
-EXPORT_SYMBOL_GPL(key_type_trusted);
-
-static void trusted_shash_release(void)
-{
-       if (hashalg)
-               crypto_free_shash(hashalg);
-       if (hmacalg)
-               crypto_free_shash(hmacalg);
-}
-
-static int __init trusted_shash_alloc(void)
-{
-       int ret;
-
-       hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hmacalg)) {
-               pr_info("trusted_key: could not allocate crypto %s\n",
-                       hmac_alg);
-               return PTR_ERR(hmacalg);
-       }
-
-       hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hashalg)) {
-               pr_info("trusted_key: could not allocate crypto %s\n",
-                       hash_alg);
-               ret = PTR_ERR(hashalg);
-               goto hashalg_fail;
-       }
-
-       return 0;
-
-hashalg_fail:
-       crypto_free_shash(hmacalg);
-       return ret;
-}
-
-static int __init init_trusted(void)
-{
-       int ret;
-
-       ret = trusted_shash_alloc();
-       if (ret < 0)
-               return ret;
-       ret = register_key_type(&key_type_trusted);
-       if (ret < 0)
-               trusted_shash_release();
-       return ret;
-}
-
-static void __exit cleanup_trusted(void)
-{
-       trusted_shash_release();
-       unregister_key_type(&key_type_trusted);
-}
-
-late_initcall(init_trusted);
-module_exit(cleanup_trusted);
-
-MODULE_LICENSE("GPL");
diff --git a/security/keys/trusted_defined.h b/security/keys/trusted_defined.h
deleted file mode 100644 (file)
index 3249fbd..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef __TRUSTED_KEY_H
-#define __TRUSTED_KEY_H
-
-/* implementation specific TPM constants */
-#define MAX_PCRINFO_SIZE               64
-#define MAX_BUF_SIZE                   512
-#define TPM_GETRANDOM_SIZE             14
-#define TPM_OSAP_SIZE                  36
-#define TPM_OIAP_SIZE                  10
-#define TPM_SEAL_SIZE                  87
-#define TPM_UNSEAL_SIZE                        104
-#define TPM_SIZE_OFFSET                        2
-#define TPM_RETURN_OFFSET              6
-#define TPM_DATA_OFFSET                        10
-
-#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset]))
-#define LOAD32N(buffer, offset)        (*(uint32_t *)&buffer[offset])
-#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset]))
-
-struct tpm_buf {
-       int len;
-       unsigned char data[MAX_BUF_SIZE];
-};
-
-#define INIT_BUF(tb) (tb->len = 0)
-
-struct osapsess {
-       uint32_t handle;
-       unsigned char secret[SHA1_DIGEST_SIZE];
-       unsigned char enonce[TPM_NONCE_SIZE];
-};
-
-/* discrete values, but have to store in uint16_t for TPM use */
-enum {
-       SEAL_keytype = 1,
-       SRK_keytype = 4
-};
-
-struct trusted_key_options {
-       uint16_t keytype;
-       uint32_t keyhandle;
-       unsigned char keyauth[SHA1_DIGEST_SIZE];
-       unsigned char blobauth[SHA1_DIGEST_SIZE];
-       uint32_t pcrinfo_len;
-       unsigned char pcrinfo[MAX_PCRINFO_SIZE];
-       int pcrlock;
-};
-
-#define TPM_DEBUG 0
-
-#if TPM_DEBUG
-static inline void dump_options(struct trusted_key_options *o)
-{
-       pr_info("trusted_key: sealing key type %d\n", o->keytype);
-       pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle);
-       pr_info("trusted_key: pcrlock %d\n", o->pcrlock);
-       pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len);
-       print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
-                      16, 1, o->pcrinfo, o->pcrinfo_len, 0);
-}
-
-static inline void dump_payload(struct trusted_key_payload *p)
-{
-       pr_info("trusted_key: key_len %d\n", p->key_len);
-       print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE,
-                      16, 1, p->key, p->key_len, 0);
-       pr_info("trusted_key: bloblen %d\n", p->blob_len);
-       print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE,
-                      16, 1, p->blob, p->blob_len, 0);
-       pr_info("trusted_key: migratable %d\n", p->migratable);
-}
-
-static inline void dump_sess(struct osapsess *s)
-{
-       print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
-                      16, 1, &s->handle, 4, 0);
-       pr_info("trusted-key: secret:\n");
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
-                      16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
-       pr_info("trusted-key: enonce:\n");
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
-                      16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
-}
-
-static inline void dump_tpm_buf(unsigned char *buf)
-{
-       int len;
-
-       pr_info("\ntrusted-key: tpm buffer\n");
-       len = LOAD32(buf, TPM_SIZE_OFFSET);
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
-}
-#else
-static inline void dump_options(struct trusted_key_options *o)
-{
-}
-
-static inline void dump_payload(struct trusted_key_payload *p)
-{
-}
-
-static inline void dump_sess(struct osapsess *s)
-{
-}
-
-static inline void dump_tpm_buf(unsigned char *buf)
-{
-}
-#endif
-
-static inline void store8(struct tpm_buf *buf, const unsigned char value)
-{
-       buf->data[buf->len++] = value;
-}
-
-static inline void store16(struct tpm_buf *buf, const uint16_t value)
-{
-       *(uint16_t *) & buf->data[buf->len] = htons(value);
-       buf->len += sizeof value;
-}
-
-static inline void store32(struct tpm_buf *buf, const uint32_t value)
-{
-       *(uint32_t *) & buf->data[buf->len] = htonl(value);
-       buf->len += sizeof value;
-}
-
-static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
-                             const int len)
-{
-       memcpy(buf->data + buf->len, in, len);
-       buf->len += len;
-}
-#endif
index e9aa079..02807fb 100644 (file)
@@ -35,7 +35,6 @@ struct key_type key_type_user = {
 
 EXPORT_SYMBOL_GPL(key_type_user);
 
-/*****************************************************************************/
 /*
  * instantiate a user defined key
  */
@@ -65,12 +64,10 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
 
 error:
        return ret;
-
-} /* end user_instantiate() */
+}
 
 EXPORT_SYMBOL_GPL(user_instantiate);
 
-/*****************************************************************************/
 /*
  * dispose of the old data from an updated user defined key
  */
@@ -81,10 +78,8 @@ static void user_update_rcu_disposal(struct rcu_head *rcu)
        upayload = container_of(rcu, struct user_key_payload, rcu);
 
        kfree(upayload);
+}
 
-} /* end user_update_rcu_disposal() */
-
-/*****************************************************************************/
 /*
  * update a user defined key
  * - the key's semaphore is write-locked
@@ -123,24 +118,20 @@ int user_update(struct key *key, const void *data, size_t datalen)
 
 error:
        return ret;
-
-} /* end user_update() */
+}
 
 EXPORT_SYMBOL_GPL(user_update);
 
-/*****************************************************************************/
 /*
  * match users on their name
  */
 int user_match(const struct key *key, const void *description)
 {
        return strcmp(key->description, description) == 0;
-
-} /* end user_match() */
+}
 
 EXPORT_SYMBOL_GPL(user_match);
 
-/*****************************************************************************/
 /*
  * dispose of the links from a revoked keyring
  * - called with the key sem write-locked
@@ -156,12 +147,10 @@ void user_revoke(struct key *key)
                rcu_assign_pointer(key->payload.data, NULL);
                call_rcu(&upayload->rcu, user_update_rcu_disposal);
        }
-
-} /* end user_revoke() */
+}
 
 EXPORT_SYMBOL(user_revoke);
 
-/*****************************************************************************/
 /*
  * dispose of the data dangling from the corpse of a user key
  */
@@ -170,12 +159,10 @@ void user_destroy(struct key *key)
        struct user_key_payload *upayload = key->payload.data;
 
        kfree(upayload);
-
-} /* end user_destroy() */
+}
 
 EXPORT_SYMBOL_GPL(user_destroy);
 
-/*****************************************************************************/
 /*
  * describe the user key
  */
@@ -184,12 +171,10 @@ void user_describe(const struct key *key, struct seq_file *m)
        seq_puts(m, key->description);
 
        seq_printf(m, ": %u", key->datalen);
-
-} /* end user_describe() */
+}
 
 EXPORT_SYMBOL_GPL(user_describe);
 
-/*****************************************************************************/
 /*
  * read the key data
  * - the key's semaphore is read-locked
@@ -213,7 +198,6 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
        }
 
        return ret;
-
-} /* end user_read() */
+}
 
 EXPORT_SYMBOL_GPL(user_read);
index 739e403..7b7308a 100644 (file)
@@ -154,10 +154,9 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(int cap)
+int security_capable(const struct cred *cred, int cap)
 {
-       return security_ops->capable(current, current_cred(), cap,
-                                    SECURITY_CAP_AUDIT);
+       return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT);
 }
 
 int security_real_capable(struct task_struct *tsk, int cap)
index e276eb4..c8d6992 100644 (file)
@@ -3198,7 +3198,11 @@ static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
 
-       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       /*
+        * cred->security == NULL if security_cred_alloc_blank() or
+        * security_prepare_creds() returned an error.
+        */
+       BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
        cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
index c3f845c..a533732 100644 (file)
@@ -178,7 +178,7 @@ int cond_init_bool_indexes(struct policydb *p)
        p->bool_val_to_struct = (struct cond_bool_datum **)
                kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
        if (!p->bool_val_to_struct)
-               return -1;
+               return -ENOMEM;
        return 0;
 }
 
index be9de38..5736356 100644 (file)
@@ -501,8 +501,8 @@ static int policydb_index(struct policydb *p)
        if (rc)
                goto out;
 
-       rc = -ENOMEM;
-       if (cond_init_bool_indexes(p))
+       rc = cond_init_bool_indexes(p);
+       if (rc)
                goto out;
 
        for (i = 0; i < SYM_NUM; i++) {
index 91acc9a..7c1fc64 100644 (file)
@@ -30,6 +30,8 @@
 
 #define DRIVER_NAME    "aaci-pl041"
 
+#define FRAME_PERIOD_US        21
+
 /*
  * PM support is not complete.  Turn it off.
  */
@@ -48,7 +50,11 @@ static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97)
        if (v & SLFR_1RXV)
                readl(aaci->base + AACI_SL1RX);
 
-       writel(maincr, aaci->base + AACI_MAINCR);
+       if (maincr != readl(aaci->base + AACI_MAINCR)) {
+               writel(maincr, aaci->base + AACI_MAINCR);
+               readl(aaci->base + AACI_MAINCR);
+               udelay(1);
+       }
 }
 
 /*
@@ -64,8 +70,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                            unsigned short val)
 {
        struct aaci *aaci = ac97->private_data;
+       int timeout;
        u32 v;
-       int timeout = 5000;
 
        if (ac97->num >= 4)
                return;
@@ -81,14 +87,17 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        writel(val << 4, aaci->base + AACI_SL2TX);
        writel(reg << 12, aaci->base + AACI_SL1TX);
 
-       /*
-        * Wait for the transmission of both slots to complete.
-        */
+       /* Initially, wait one frame period */
+       udelay(FRAME_PERIOD_US);
+
+       /* And then wait an additional eight frame periods for it to be sent */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                v = readl(aaci->base + AACI_SLFR);
        } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
 
-       if (!timeout)
+       if (v & (SLFR_1TXB|SLFR_2TXB))
                dev_err(&aaci->dev->dev,
                        "timeout waiting for write to complete\n");
 
@@ -101,9 +110,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        struct aaci *aaci = ac97->private_data;
+       int timeout, retries = 10;
        u32 v;
-       int timeout = 5000;
-       int retries = 10;
 
        if (ac97->num >= 4)
                return ~0;
@@ -117,35 +125,34 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
         */
        writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
 
-       /*
-        * Wait for the transmission to complete.
-        */
+       /* Initially, wait one frame period */
+       udelay(FRAME_PERIOD_US);
+
+       /* And then wait an additional eight frame periods for it to be sent */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                v = readl(aaci->base + AACI_SLFR);
        } while ((v & SLFR_1TXB) && --timeout);
 
-       if (!timeout) {
+       if (v & SLFR_1TXB) {
                dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
                v = ~0;
                goto out;
        }
 
-       /*
-        * Give the AC'97 codec more than enough time
-        * to respond. (42us = ~2 frames at 48kHz.)
-        */
-       udelay(42);
+       /* Now wait for the response frame */
+       udelay(FRAME_PERIOD_US);
 
-       /*
-        * Wait for slot 2 to indicate data.
-        */
-       timeout = 5000;
+       /* And then wait an additional eight frame periods for data */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                cond_resched();
                v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
        } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
 
-       if (!timeout) {
+       if (v != (SLFR_1RXV|SLFR_2RXV)) {
                dev_err(&aaci->dev->dev, "timeout on RX valid\n");
                v = ~0;
                goto out;
@@ -179,6 +186,7 @@ aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
        int timeout = 5000;
 
        do {
+               udelay(1);
                val = readl(aacirun->base + AACI_SR);
        } while (val & mask && timeout--);
 }
@@ -874,7 +882,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci)
         * Give the AC'97 codec more than enough time
         * to wake up. (42us = ~2 frames at 48kHz.)
         */
-       udelay(42);
+       udelay(FRAME_PERIOD_US * 2);
 
        ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
        if (ret)
@@ -989,6 +997,8 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
         * disabling the channel doesn't clear the FIFO.
         */
        writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
+       readl(aaci->base + AACI_MAINCR);
+       udelay(1);
        writel(aaci->maincr, aaci->base + AACI_MAINCR);
 
        /*
index 2b5387d..7141c42 100644 (file)
@@ -204,13 +204,11 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
 EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
@@ -294,6 +292,13 @@ ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
        CFLAGS := $(CFLAGS) -fstack-protector-all
 endif
 
+ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
+       CFLAGS := $(CFLAGS) -Wstack-protector
+endif
+
+ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
+       CFLAGS := $(CFLAGS) -Wvolatile-register-var
+endif
 
 ### --- END CONFIGURATION SECTION ---
 
index c056cdc..8879463 100644 (file)
@@ -212,7 +212,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename)
                        continue;
 
                offset = start + i;
-               sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
+               sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
                fp = popen(cmd, "r");
                if (!fp)
                        continue;
@@ -270,9 +270,9 @@ static void hist_entry__print_hits(struct hist_entry *self)
 
        for (offset = 0; offset < len; ++offset)
                if (h->ip[offset] != 0)
-                       printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
+                       printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
                               sym->start + offset, h->ip[offset]);
-       printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
+       printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
 }
 
 static int hist_entry__tty_annotate(struct hist_entry *he)
index def7ddc..d97256d 100644 (file)
@@ -371,10 +371,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
                        addr = data->ptr;
 
                if (sym != NULL)
-                       snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
+                       snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
                                 addr - map->unmap_ip(map, sym->start));
                else
-                       snprintf(buf, sizeof(buf), "%#Lx", addr);
+                       snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
                printf(" %-34s |", buf);
 
                printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
index b9c6e54..2b36def 100644 (file)
@@ -782,9 +782,9 @@ static void print_result(void)
                pr_info("%10u ", st->nr_acquired);
                pr_info("%10u ", st->nr_contended);
 
-               pr_info("%15llu ", st->wait_time_total);
-               pr_info("%15llu ", st->wait_time_max);
-               pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ?
+               pr_info("%15" PRIu64 " ", st->wait_time_total);
+               pr_info("%15" PRIu64 " ", st->wait_time_max);
+               pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
                       0 : st->wait_time_min);
                pr_info("\n");
        }
index fcd29e8..60cac6f 100644 (file)
@@ -759,8 +759,8 @@ static int __cmd_record(int argc, const char **argv)
                perf_session__process_machines(session, event__synthesize_guest_os);
 
        if (!system_wide)
-               event__synthesize_thread(target_tid, process_synthesized_event,
-                                        session);
+               event__synthesize_thread_map(threads, process_synthesized_event,
+                                            session);
        else
                event__synthesize_threads(process_synthesized_event, session);
 
@@ -817,7 +817,7 @@ static int __cmd_record(int argc, const char **argv)
         * Approximate RIP event size: 24 bytes.
         */
        fprintf(stderr,
-               "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n",
+               "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
                (double)bytes_written / 1024.0 / 1024.0,
                output_name,
                bytes_written / 24);
index 75183a4..c27e31f 100644 (file)
@@ -197,7 +197,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
                                           event->read.value);
        }
 
-       dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
+       dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
                    attr ? __event_name(attr->type, attr->config) : "FAIL",
                    event->read.value);
 
index 29e7ffd..29acb89 100644 (file)
@@ -193,7 +193,7 @@ static void calibrate_run_measurement_overhead(void)
        }
        run_measurement_overhead = min_delta;
 
-       printf("run measurement overhead: %Ld nsecs\n", min_delta);
+       printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 }
 
 static void calibrate_sleep_measurement_overhead(void)
@@ -211,7 +211,7 @@ static void calibrate_sleep_measurement_overhead(void)
        min_delta -= 10000;
        sleep_measurement_overhead = min_delta;
 
-       printf("sleep measurement overhead: %Ld nsecs\n", min_delta);
+       printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 }
 
 static struct sched_atom *
@@ -617,13 +617,13 @@ static void test_calibrations(void)
        burn_nsecs(1e6);
        T1 = get_nsecs();
 
-       printf("the run test took %Ld nsecs\n", T1-T0);
+       printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
 
        T0 = get_nsecs();
        sleep_nsecs(1e6);
        T1 = get_nsecs();
 
-       printf("the sleep test took %Ld nsecs\n", T1-T0);
+       printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
 }
 
 #define FILL_FIELD(ptr, field, event, data)    \
@@ -816,10 +816,10 @@ replay_switch_event(struct trace_switch_event *switch_event,
                delta = 0;
 
        if (delta < 0)
-               die("hm, delta: %Ld < 0 ?\n", delta);
+               die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 
        if (verbose) {
-               printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
+               printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
                        switch_event->prev_comm, switch_event->prev_pid,
                        switch_event->next_comm, switch_event->next_pid,
                        delta);
@@ -1048,7 +1048,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
                delta = 0;
 
        if (delta < 0)
-               die("hm, delta: %Ld < 0 ?\n", delta);
+               die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 
 
        sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1221,7 +1221,7 @@ static void output_lat_thread(struct work_atoms *work_list)
 
        avg = work_list->total_lat / work_list->nb_atoms;
 
-       printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
+       printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
              (double)work_list->total_runtime / 1e6,
                 work_list->nb_atoms, (double)avg / 1e6,
                 (double)work_list->max_lat / 1e6,
@@ -1423,7 +1423,7 @@ map_switch_event(struct trace_switch_event *switch_event,
                delta = 0;
 
        if (delta < 0)
-               die("hm, delta: %Ld < 0 ?\n", delta);
+               die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 
 
        sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1713,7 +1713,7 @@ static void __cmd_lat(void)
        }
 
        printf(" -----------------------------------------------------------------------------------------\n");
-       printf("  TOTAL:                |%11.3f ms |%9Ld |\n",
+       printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
                (double)all_runtime/1e6, all_count);
 
        printf(" ---------------------------------------------------\n");
index 150a606..b766c2a 100644 (file)
@@ -77,8 +77,8 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
        if (session->sample_type & PERF_SAMPLE_RAW) {
                if (debug_mode) {
                        if (sample->time < last_timestamp) {
-                               pr_err("Samples misordered, previous: %llu "
-                                       "this: %llu\n", last_timestamp,
+                               pr_err("Samples misordered, previous: %" PRIu64
+                                       " this: %" PRIu64 "\n", last_timestamp,
                                        sample->time);
                                nr_unordered++;
                        }
@@ -126,7 +126,7 @@ static int __cmd_script(struct perf_session *session)
        ret = perf_session__process_events(session, &event_ops);
 
        if (debug_mode)
-               pr_err("Misordered timestamps: %llu\n", nr_unordered);
+               pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
 
        return ret;
 }
index 0ff11d9..a482a19 100644 (file)
@@ -206,8 +206,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
                update_stats(&ps->res_stats[i], count[i]);
 
        if (verbose) {
-               fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
-                               count[0], count[1], count[2]);
+               fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+                       event_name(counter), count[0], count[1], count[2]);
        }
 
        /*
index ed56961..5dcdba6 100644 (file)
@@ -146,7 +146,7 @@ next_pair:
                                if (llabs(skew) < page_size)
                                        continue;
 
-                               pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n",
+                               pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
                                         sym->start, sym->name, sym->end, pair->end);
                        } else {
                                struct rb_node *nnd;
@@ -168,11 +168,11 @@ detour:
                                        goto detour;
                                }
 
-                               pr_debug("%#Lx: diff name v: %s k: %s\n",
+                               pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
                                         sym->start, sym->name, pair->name);
                        }
                } else
-                       pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name);
+                       pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
 
                err = -1;
        }
@@ -211,10 +211,10 @@ detour:
 
                if (pair->start == pos->start) {
                        pair->priv = 1;
-                       pr_info(" %Lx-%Lx %Lx %s in kallsyms as",
+                       pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
                                pos->start, pos->end, pos->pgoff, pos->dso->name);
                        if (pos->pgoff != pair->pgoff || pos->end != pair->end)
-                               pr_info(": \n*%Lx-%Lx %Lx",
+                               pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
                                        pair->start, pair->end, pair->pgoff);
                        pr_info(" %s\n", pair->dso->name);
                        pair->priv = 1;
@@ -307,7 +307,7 @@ static int test__open_syscall_event(void)
        }
 
        if (evsel->counts->cpu[0].val != nr_open_calls) {
-               pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld\n",
+               pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
                         nr_open_calls, evsel->counts->cpu[0].val);
                goto out_close_fd;
        }
@@ -332,8 +332,7 @@ static int test__open_syscall_event_on_all_cpus(void)
        struct perf_evsel *evsel;
        struct perf_event_attr attr;
        unsigned int nr_open_calls = 111, i;
-       cpu_set_t *cpu_set;
-       size_t cpu_set_size;
+       cpu_set_t cpu_set;
        int id = trace_event__id("sys_enter_open");
 
        if (id < 0) {
@@ -353,13 +352,8 @@ static int test__open_syscall_event_on_all_cpus(void)
                return -1;
        }
 
-       cpu_set = CPU_ALLOC(cpus->nr);
 
-       if (cpu_set == NULL)
-               goto out_thread_map_delete;
-
-       cpu_set_size = CPU_ALLOC_SIZE(cpus->nr);
-       CPU_ZERO_S(cpu_set_size, cpu_set);
+       CPU_ZERO(&cpu_set);
 
        memset(&attr, 0, sizeof(attr));
        attr.type = PERF_TYPE_TRACEPOINT;
@@ -367,7 +361,7 @@ static int test__open_syscall_event_on_all_cpus(void)
        evsel = perf_evsel__new(&attr, 0);
        if (evsel == NULL) {
                pr_debug("perf_evsel__new\n");
-               goto out_cpu_free;
+               goto out_thread_map_delete;
        }
 
        if (perf_evsel__open(evsel, cpus, threads) < 0) {
@@ -379,14 +373,29 @@ static int test__open_syscall_event_on_all_cpus(void)
 
        for (cpu = 0; cpu < cpus->nr; ++cpu) {
                unsigned int ncalls = nr_open_calls + cpu;
+               /*
+                * XXX eventually lift this restriction in a way that
+                * keeps perf building on older glibc installations
+                * without CPU_ALLOC. 1024 cpus in 2010 still seems
+                * a reasonable upper limit tho :-)
+                */
+               if (cpus->map[cpu] >= CPU_SETSIZE) {
+                       pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
+                       continue;
+               }
 
-               CPU_SET(cpu, cpu_set);
-               sched_setaffinity(0, cpu_set_size, cpu_set);
+               CPU_SET(cpus->map[cpu], &cpu_set);
+               if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
+                       pr_debug("sched_setaffinity() failed on CPU %d: %s ",
+                                cpus->map[cpu],
+                                strerror(errno));
+                       goto out_close_fd;
+               }
                for (i = 0; i < ncalls; ++i) {
                        fd = open("/etc/passwd", O_RDONLY);
                        close(fd);
                }
-               CPU_CLR(cpu, cpu_set);
+               CPU_CLR(cpus->map[cpu], &cpu_set);
        }
 
        /*
@@ -402,6 +411,9 @@ static int test__open_syscall_event_on_all_cpus(void)
        for (cpu = 0; cpu < cpus->nr; ++cpu) {
                unsigned int expected;
 
+               if (cpus->map[cpu] >= CPU_SETSIZE)
+                       continue;
+
                if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
                        pr_debug("perf_evsel__open_read_on_cpu\n");
                        goto out_close_fd;
@@ -409,8 +421,8 @@ static int test__open_syscall_event_on_all_cpus(void)
 
                expected = nr_open_calls + cpu;
                if (evsel->counts->cpu[cpu].val != expected) {
-                       pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n",
-                                expected, cpu, evsel->counts->cpu[cpu].val);
+                       pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
+                                expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
                        goto out_close_fd;
                }
        }
@@ -420,8 +432,6 @@ out_close_fd:
        perf_evsel__close_fd(evsel, 1, threads->nr);
 out_evsel_delete:
        perf_evsel__delete(evsel);
-out_cpu_free:
-       CPU_FREE(cpu_set);
 out_thread_map_delete:
        thread_map__delete(threads);
        return err;
index 746cf03..0ace786 100644 (file)
@@ -264,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
                c->start_time = start;
        if (p->start_time == 0 || p->start_time > start)
                p->start_time = start;
-
-       if (cpu > numcpus)
-               numcpus = cpu;
 }
 
 #define MAX_CPUS 4096
@@ -511,6 +508,9 @@ static int process_sample_event(event_t *event __used,
                if (!event_str)
                        return 0;
 
+               if (sample->cpu > numcpus)
+                       numcpus = sample->cpu;
+
                if (strcmp(event_str, "power:cpu_idle") == 0) {
                        struct power_processor_entry *ppe = (void *)te;
                        if (ppe->state == (u32)PWR_EVENT_EXIT)
index 05344c6..5a29d9c 100644 (file)
@@ -40,6 +40,7 @@
 #include <stdio.h>
 #include <termios.h>
 #include <unistd.h>
+#include <inttypes.h>
 
 #include <errno.h>
 #include <time.h>
@@ -214,7 +215,7 @@ static int parse_source(struct sym_entry *syme)
        len = sym->end - sym->start;
 
        sprintf(command,
-               "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
+               "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s",
                BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
                BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
 
@@ -308,7 +309,7 @@ static void lookup_sym_source(struct sym_entry *syme)
        struct source_line *line;
        char pattern[PATTERN_LEN + 1];
 
-       sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
+       sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4,
                map__rip_2objdump(syme->map, symbol->start));
 
        pthread_mutex_lock(&syme->src->lock);
@@ -537,7 +538,7 @@ static void print_sym_table(void)
        if (nr_counters == 1 || !display_weighted) {
                struct perf_evsel *first;
                first = list_entry(evsel_list.next, struct perf_evsel, node);
-               printf("%Ld", first->attr.sample_period);
+               printf("%" PRIu64, (uint64_t)first->attr.sample_period);
                if (freq)
                        printf("Hz ");
                else
@@ -640,7 +641,7 @@ static void print_sym_table(void)
 
                percent_color_fprintf(stdout, "%4.1f%%", pcnt);
                if (verbose)
-                       printf(" %016llx", sym->start);
+                       printf(" %016" PRIx64, sym->start);
                printf(" %-*.*s", sym_width, sym_width, sym->name);
                printf(" %-*.*s\n", dso_width, dso_width,
                       dso_width >= syme->map->dso->long_name_len ?
@@ -1305,7 +1306,7 @@ static int __cmd_top(void)
                return -ENOMEM;
 
        if (target_tid != -1)
-               event__synthesize_thread(target_tid, event__process, session);
+               event__synthesize_thread_map(threads, event__process, session);
        else
                event__synthesize_threads(event__process, session);
 
index 2302ec0..50d0a93 100644 (file)
@@ -263,11 +263,12 @@ static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event,
                                             process, session);
 }
 
-int event__synthesize_thread(pid_t pid, event__handler_t process,
-                            struct perf_session *session)
+int event__synthesize_thread_map(struct thread_map *threads,
+                                event__handler_t process,
+                                struct perf_session *session)
 {
        event_t *comm_event, *mmap_event;
-       int err = -1;
+       int err = -1, thread;
 
        comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
        if (comm_event == NULL)
@@ -277,8 +278,15 @@ int event__synthesize_thread(pid_t pid, event__handler_t process,
        if (mmap_event == NULL)
                goto out_free_comm;
 
-       err = __event__synthesize_thread(comm_event, mmap_event, pid,
-                                        process, session);
+       err = 0;
+       for (thread = 0; thread < threads->nr; ++thread) {
+               if (__event__synthesize_thread(comm_event, mmap_event,
+                                              threads->map[thread],
+                                              process, session)) {
+                       err = -1;
+                       break;
+               }
+       }
        free(mmap_event);
 out_free_comm:
        free(comm_event);
@@ -459,7 +467,8 @@ int event__process_comm(event_t *self, struct sample_data *sample __used,
 int event__process_lost(event_t *self, struct sample_data *sample __used,
                        struct perf_session *session)
 {
-       dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
+       dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
+                   self->lost.id, self->lost.lost);
        session->hists.stats.total_lost += self->lost.lost;
        return 0;
 }
@@ -575,7 +584,7 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
        u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
        int ret = 0;
 
-       dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
+       dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
                        self->mmap.pid, self->mmap.tid, self->mmap.start,
                        self->mmap.len, self->mmap.pgoff, self->mmap.filename);
 
index 2b7e919..cc7b52f 100644 (file)
@@ -135,14 +135,16 @@ typedef union event_union {
 void event__print_totals(void);
 
 struct perf_session;
+struct thread_map;
 
 typedef int (*event__handler_synth_t)(event_t *event, 
                                      struct perf_session *session);
 typedef int (*event__handler_t)(event_t *event, struct sample_data *sample,
                                struct perf_session *session);
 
-int event__synthesize_thread(pid_t pid, event__handler_t process,
-                            struct perf_session *session);
+int event__synthesize_thread_map(struct thread_map *threads,
+                                event__handler_t process,
+                                struct perf_session *session);
 int event__synthesize_threads(event__handler_t process,
                              struct perf_session *session);
 int event__synthesize_kernel_mmap(event__handler_t process,
index f5cfed6..d8575d3 100644 (file)
@@ -90,7 +90,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
        int cpu, thread;
        struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
-       aggr->val = 0;
+       aggr->val = aggr->ena = aggr->run = 0;
 
        for (cpu = 0; cpu < ncpus; cpu++) {
                for (thread = 0; thread < nthreads; thread++) {
index 989fa2d..f6a929e 100644 (file)
@@ -798,8 +798,8 @@ static int perf_file_section__process(struct perf_file_section *self,
                                      int feat, int fd)
 {
        if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
-               pr_debug("Failed to lseek to %Ld offset for feature %d, "
-                        "continuing...\n", self->offset, feat);
+               pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
+                         "%d, continuing...\n", self->offset, feat);
                return 0;
        }
 
index c749ba6..df51560 100644 (file)
@@ -585,6 +585,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
 {
        struct sort_entry *se;
        u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
+       u64 nr_events;
        const char *sep = symbol_conf.field_sep;
        int ret;
 
@@ -593,6 +594,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
 
        if (pair_hists) {
                period = self->pair ? self->pair->period : 0;
+               nr_events = self->pair ? self->pair->nr_events : 0;
                total = pair_hists->stats.total_period;
                period_sys = self->pair ? self->pair->period_sys : 0;
                period_us = self->pair ? self->pair->period_us : 0;
@@ -600,6 +602,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
                period_guest_us = self->pair ? self->pair->period_guest_us : 0;
        } else {
                period = self->period;
+               nr_events = self->nr_events;
                total = session_total;
                period_sys = self->period_sys;
                period_us = self->period_us;
@@ -636,13 +639,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
                        }
                }
        } else
-               ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
+               ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
 
        if (symbol_conf.show_nr_samples) {
                if (sep)
-                       ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
+                       ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
                else
-                       ret += snprintf(s + ret, size - ret, "%11lld", period);
+                       ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
        }
 
        if (pair_hists) {
@@ -971,7 +974,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
        sym_size = sym->end - sym->start;
        offset = ip - sym->start;
 
-       pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
+       pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
 
        if (offset >= sym_size)
                return 0;
@@ -980,8 +983,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
        h->sum++;
        h->ip[offset]++;
 
-       pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
-                 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
+       pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
+                 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
+                 ip, ip - self->ms.sym->start, h->ip[offset]);
        return 0;
 }
 
@@ -1132,7 +1136,7 @@ fallback:
                goto out_free_filename;
        }
 
-       pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
+       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
                 filename, sym->name, map->unmap_ip(map, sym->start),
                 map->unmap_ip(map, sym->end));
 
@@ -1142,7 +1146,7 @@ fallback:
                 dso, dso->long_name, sym, sym->name);
 
        snprintf(command, sizeof(command),
-                "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
+                "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
                 map__rip_2objdump(map, sym->start),
                 map__rip_2objdump(map, sym->end),
                 symfs_filename, filename);
index 8be0b96..305c848 100644 (file)
@@ -2,6 +2,7 @@
 #define _PERF_LINUX_BITOPS_H_
 
 #include <linux/kernel.h>
+#include <linux/compiler.h>
 #include <asm/hweight.h>
 
 #define BITS_PER_LONG __WORDSIZE
index 3a7eb6e..a16ecab 100644 (file)
@@ -1,5 +1,6 @@
 #include "symbol.h"
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
@@ -195,7 +196,7 @@ int map__overlap(struct map *l, struct map *r)
 
 size_t map__fprintf(struct map *self, FILE *fp)
 {
-       return fprintf(fp, " %Lx-%Lx %Lx %s\n",
+       return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
                       self->start, self->end, self->pgoff, self->dso->name);
 }
 
index bc2732e..135f69b 100644 (file)
@@ -279,7 +279,7 @@ const char *__event_name(int type, u64 config)
        static char buf[32];
 
        if (type == PERF_TYPE_RAW) {
-               sprintf(buf, "raw 0x%llx", config);
+               sprintf(buf, "raw 0x%" PRIx64, config);
                return buf;
        }
 
index b82cafb..458e3ec 100644 (file)
@@ -23,7 +23,7 @@ struct tracepoint_path {
 };
 
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
-extern bool have_tracepoints(struct list_head *evsel_list);
+extern bool have_tracepoints(struct list_head *evlist);
 
 extern int                     nr_counters;
 
index 128aaab..6e29d9c 100644 (file)
@@ -172,7 +172,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
        sym = __find_kernel_function_by_name(tp->symbol, &map);
        if (sym) {
                addr = map->unmap_ip(map, sym->start + tp->offset);
-               pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+               pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
                         tp->offset, addr);
                ret = find_perf_probe_point((unsigned long)addr, pp);
        }
index 313dac2..105f00b 100644 (file)
@@ -652,10 +652,11 @@ static void callchain__printf(struct sample_data *sample)
 {
        unsigned int i;
 
-       printf("... chain: nr:%Lu\n", sample->callchain->nr);
+       printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
 
        for (i = 0; i < sample->callchain->nr; i++)
-               printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]);
+               printf("..... %2d: %016" PRIx64 "\n",
+                      i, sample->callchain->ips[i]);
 }
 
 static void perf_session__print_tstamp(struct perf_session *session,
@@ -672,7 +673,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
                printf("%u ", sample->cpu);
 
        if (session->sample_type & PERF_SAMPLE_TIME)
-               printf("%Lu ", sample->time);
+               printf("%" PRIu64 " ", sample->time);
 }
 
 static void dump_event(struct perf_session *session, event_t *event,
@@ -681,16 +682,16 @@ static void dump_event(struct perf_session *session, event_t *event,
        if (!dump_trace)
                return;
 
-       printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size,
-              event->header.type);
+       printf("\n%#" PRIx64 " [%#x]: event: %d\n",
+              file_offset, event->header.size, event->header.type);
 
        trace_event(event);
 
        if (sample)
                perf_session__print_tstamp(session, event, sample);
 
-       printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size,
-              event__get_event_name(event->header.type));
+       printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
+              event->header.size, event__get_event_name(event->header.type));
 }
 
 static void dump_sample(struct perf_session *session, event_t *event,
@@ -699,8 +700,9 @@ static void dump_sample(struct perf_session *session, event_t *event,
        if (!dump_trace)
                return;
 
-       printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
-              sample->pid, sample->tid, sample->ip, sample->period);
+       printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
+              event->header.misc, sample->pid, sample->tid, sample->ip,
+              sample->period);
 
        if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
                callchain__printf(sample);
@@ -843,8 +845,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
 {
        if (ops->lost == event__process_lost &&
            session->hists.stats.total_lost != 0) {
-               ui__warning("Processed %Lu events and LOST %Lu!\n\n"
-                           "Check IO/CPU overload!\n\n",
+               ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
+                           "!\n\nCheck IO/CPU overload!\n\n",
                            session->hists.stats.total_period,
                            session->hists.stats.total_lost);
        }
@@ -918,7 +920,7 @@ more:
 
        if (size == 0 ||
            (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
-               dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
+               dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
                            head, event.header.size, event.header.type);
                /*
                 * assume we lost track of the stream, check alignment, and
@@ -1023,7 +1025,7 @@ more:
 
        if (size == 0 ||
            perf_session__process_event(session, event, ops, file_pos) < 0) {
-               dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
+               dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
                            file_offset + head, event->header.size,
                            event->header.type);
                /*
index b3637db..96c8660 100644 (file)
@@ -12,6 +12,7 @@
  * of the License.
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -43,11 +44,11 @@ static double cpu2y(int cpu)
        return cpu2slot(cpu) * SLOT_MULT;
 }
 
-static double time2pixels(u64 time)
+static double time2pixels(u64 __time)
 {
        double X;
 
-       X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
+       X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
        return X;
 }
 
@@ -94,7 +95,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
 
        total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
        fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
-       fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
+       fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
 
        fprintf(svgfile, "<defs>\n  <style type=\"text/css\">\n    <![CDATA[\n");
 
@@ -455,9 +456,9 @@ void svg_legenda(void)
                return;
 
        svg_legenda_box(0,      "Running", "sample");
-       svg_legenda_box(100,    "Idle","rect.c1");
-       svg_legenda_box(200,    "Deeper Idle", "rect.c3");
-       svg_legenda_box(350,    "Deepest Idle", "rect.c6");
+       svg_legenda_box(100,    "Idle","c1");
+       svg_legenda_box(200,    "Deeper Idle", "c3");
+       svg_legenda_box(350,    "Deepest Idle", "c6");
        svg_legenda_box(550,    "Sleeping", "process2");
        svg_legenda_box(650,    "Waiting for cpu", "waiting");
        svg_legenda_box(800,    "Blocked on IO", "blocked");
@@ -483,7 +484,7 @@ void svg_time_grid(void)
                        color = 128;
                }
 
-               fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
+               fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
                        time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
 
                i += 10000000;
index 15ccfba..7821d0e 100644 (file)
@@ -11,6 +11,7 @@
 #include <sys/param.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <inttypes.h>
 #include "build-id.h"
 #include "debug.h"
 #include "symbol.h"
@@ -153,7 +154,7 @@ static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
        self->binding = binding;
        self->namelen = namelen - 1;
 
-       pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
+       pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end);
 
        memcpy(self->name, name, namelen);
 
@@ -167,7 +168,7 @@ void symbol__delete(struct symbol *self)
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       return fprintf(fp, " %llx-%llx %c %s\n",
+       return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
                       self->start, self->end,
                       self->binding == STB_GLOBAL ? 'g' :
                       self->binding == STB_LOCAL  ? 'l' : 'w',
@@ -1161,6 +1162,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
 
                section_name = elf_sec__name(&shdr, secstrs);
 
+               /* On ARM, symbols for thumb functions have 1 added to
+                * the symbol address as a flag - remove it */
+               if ((ehdr.e_machine == EM_ARM) &&
+                   (map->type == MAP__FUNCTION) &&
+                   (sym.st_value & 1))
+                       --sym.st_value;
+
                if (self->kernel != DSO_TYPE_USER || kmodule) {
                        char dso_name[PATH_MAX];
 
@@ -1208,8 +1216,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
                }
 
                if (curr_dso->adjust_symbols) {
-                       pr_debug4("%s: adjusting symbol: st_value: %#Lx "
-                                 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
+                       pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
+                                 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
                                  (u64)sym.st_value, (u64)shdr.sh_addr,
                                  (u64)shdr.sh_offset);
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
index 7d6b833..5f3689a 100644 (file)
@@ -1,12 +1,14 @@
 #ifndef __PERF_TYPES_H
 #define __PERF_TYPES_H
 
+#include <stdint.h>
+
 /*
- * We define u64 as unsigned long long for every architecture
- * so that we can print it with %Lx without getting warnings.
+ * We define u64 as uint64_t for every architecture
+ * so that we can print it with "%"PRIx64 without getting warnings.
  */
-typedef unsigned long long u64;
-typedef signed long long   s64;
+typedef uint64_t          u64;
+typedef int64_t                   s64;
 typedef unsigned int      u32;
 typedef signed int        s32;
 typedef unsigned short    u16;
index ebda8c3..60c463c 100644 (file)
@@ -350,7 +350,7 @@ static char *callchain_list__sym_name(struct callchain_list *self,
        if (self->ms.sym)
                return self->ms.sym->name;
 
-       snprintf(bf, bfsize, "%#Lx", self->ip);
+       snprintf(bf, bfsize, "%#" PRIx64, self->ip);
        return bf;
 }
 
index e35437d..e515836 100644 (file)
@@ -1,5 +1,6 @@
 #include "../libslang.h"
 #include <elf.h>
+#include <inttypes.h>
 #include <sys/ttydefaults.h>
 #include <ctype.h>
 #include <string.h>
@@ -57,7 +58,7 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
        int width;
 
        ui_browser__set_percent_color(self, 0, current_entry);
-       slsmg_printf("%*llx %*llx %c ",
+       slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
                     mb->addrlen, sym->start, mb->addrlen, sym->end,
                     sym->binding == STB_GLOBAL ? 'g' :
                     sym->binding == STB_LOCAL  ? 'l' : 'w');
@@ -150,6 +151,6 @@ int map__browse(struct map *self)
                ++mb.b.nr_entries;
        }
 
-       mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
+       mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
        return map_browser__run(&mb);
 }
index cfa55d6..bdd3347 100644 (file)
@@ -150,7 +150,7 @@ static void perf_read_values__display_pretty(FILE *fp,
                if (width > tidwidth)
                        tidwidth = width;
                for (j = 0; j < values->counters; j++) {
-                       width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+                       width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
                        if (width > counterwidth[j])
                                counterwidth[j] = width;
                }
@@ -165,7 +165,7 @@ static void perf_read_values__display_pretty(FILE *fp,
                fprintf(fp, "  %*d  %*d", pidwidth, values->pid[i],
                        tidwidth, values->tid[i]);
                for (j = 0; j < values->counters; j++)
-                       fprintf(fp, "  %*Lu",
+                       fprintf(fp, "  %*" PRIu64,
                                counterwidth[j], values->value[i][j]);
                fprintf(fp, "\n");
        }
@@ -196,13 +196,13 @@ static void perf_read_values__display_raw(FILE *fp,
                width = strlen(values->countername[j]);
                if (width > namewidth)
                        namewidth = width;
-               width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
+               width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
                if (width > rawwidth)
                        rawwidth = width;
        }
        for (i = 0; i < values->threads; i++) {
                for (j = 0; j < values->counters; j++) {
-                       width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+                       width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
                        if (width > countwidth)
                                countwidth = width;
                }
@@ -214,7 +214,7 @@ static void perf_read_values__display_raw(FILE *fp,
                countwidth, "Count");
        for (i = 0; i < values->threads; i++)
                for (j = 0; j < values->counters; j++)
-                       fprintf(fp, "  %*d  %*d  %*s  %*llx  %*Lu\n",
+                       fprintf(fp, "  %*d  %*d  %*s  %*" PRIx64 "  %*" PRIu64,
                                pidwidth, values->pid[i],
                                tidwidth, values->tid[i],
                                namewidth, values->countername[j],
index 4c6983d..362a0cb 100644 (file)
@@ -72,7 +72,7 @@ int need_reinitialize;
 
 int num_cpus;
 
-typedef struct per_cpu_counters {
+struct counters {
        unsigned long long tsc;         /* per thread */
        unsigned long long aperf;       /* per thread */
        unsigned long long mperf;       /* per thread */
@@ -88,13 +88,13 @@ typedef struct per_cpu_counters {
        int pkg;
        int core;
        int cpu;
-       struct per_cpu_counters *next;
-} PCC;
+       struct counters *next;
+};
 
-PCC *pcc_even;
-PCC *pcc_odd;
-PCC *pcc_delta;
-PCC *pcc_average;
+struct counters *cnt_even;
+struct counters *cnt_odd;
+struct counters *cnt_delta;
+struct counters *cnt_average;
 struct timeval tv_even;
 struct timeval tv_odd;
 struct timeval tv_delta;
@@ -125,7 +125,7 @@ unsigned long long get_msr(int cpu, off_t offset)
        return msr;
 }
 
-void print_header()
+void print_header(void)
 {
        if (show_pkg)
                fprintf(stderr, "pkg ");
@@ -160,39 +160,39 @@ void print_header()
        putc('\n', stderr);
 }
 
-void dump_pcc(PCC *pcc)
+void dump_cnt(struct counters *cnt)
 {
-       fprintf(stderr, "package: %d ", pcc->pkg);
-       fprintf(stderr, "core:: %d ", pcc->core);
-       fprintf(stderr, "CPU: %d ", pcc->cpu);
-       fprintf(stderr, "TSC: %016llX\n", pcc->tsc);
-       fprintf(stderr, "c3: %016llX\n", pcc->c3);
-       fprintf(stderr, "c6: %016llX\n", pcc->c6);
-       fprintf(stderr, "c7: %016llX\n", pcc->c7);
-       fprintf(stderr, "aperf: %016llX\n", pcc->aperf);
-       fprintf(stderr, "pc2: %016llX\n", pcc->pc2);
-       fprintf(stderr, "pc3: %016llX\n", pcc->pc3);
-       fprintf(stderr, "pc6: %016llX\n", pcc->pc6);
-       fprintf(stderr, "pc7: %016llX\n", pcc->pc7);
-       fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, pcc->extra_msr);
+       fprintf(stderr, "package: %d ", cnt->pkg);
+       fprintf(stderr, "core:: %d ", cnt->core);
+       fprintf(stderr, "CPU: %d ", cnt->cpu);
+       fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
+       fprintf(stderr, "c3: %016llX\n", cnt->c3);
+       fprintf(stderr, "c6: %016llX\n", cnt->c6);
+       fprintf(stderr, "c7: %016llX\n", cnt->c7);
+       fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
+       fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
+       fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
+       fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
+       fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
+       fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
 }
 
-void dump_list(PCC *pcc)
+void dump_list(struct counters *cnt)
 {
-       printf("dump_list 0x%p\n", pcc);
+       printf("dump_list 0x%p\n", cnt);
 
-       for (; pcc; pcc = pcc->next)
-               dump_pcc(pcc);
+       for (; cnt; cnt = cnt->next)
+               dump_cnt(cnt);
 }
 
-void print_pcc(PCC *p)
+void print_cnt(struct counters *p)
 {
        double interval_float;
 
        interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
 
        /* topology columns, print blanks on 1st (average) line */
-       if (p == pcc_average) {
+       if (p == cnt_average) {
                if (show_pkg)
                        fprintf(stderr, "    ");
                if (show_core)
@@ -262,24 +262,24 @@ void print_pcc(PCC *p)
        putc('\n', stderr);
 }
 
-void print_counters(PCC *cnt)
+void print_counters(struct counters *counters)
 {
-       PCC *pcc;
+       struct counters *cnt;
 
        print_header();
 
        if (num_cpus > 1)
-               print_pcc(pcc_average);
+               print_cnt(cnt_average);
 
-       for (pcc = cnt; pcc != NULL; pcc = pcc->next)
-               print_pcc(pcc);
+       for (cnt = counters; cnt != NULL; cnt = cnt->next)
+               print_cnt(cnt);
 
 }
 
 #define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
 
-
-int compute_delta(PCC *after, PCC *before, PCC *delta)
+int compute_delta(struct counters *after,
+       struct counters *before, struct counters *delta)
 {
        int errors = 0;
        int perf_err = 0;
@@ -391,20 +391,20 @@ int compute_delta(PCC *after, PCC *before, PCC *delta)
                delta->extra_msr = after->extra_msr;
                if (errors) {
                        fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
-                       dump_pcc(before);
+                       dump_cnt(before);
                        fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
-                       dump_pcc(after);
+                       dump_cnt(after);
                        errors = 0;
                }
        }
        return 0;
 }
 
-void compute_average(PCC *delta, PCC *avg)
+void compute_average(struct counters *delta, struct counters *avg)
 {
-       PCC *sum;
+       struct counters *sum;
 
-       sum = calloc(1, sizeof(PCC));
+       sum = calloc(1, sizeof(struct counters));
        if (sum == NULL) {
                perror("calloc sum");
                exit(1);
@@ -438,35 +438,34 @@ void compute_average(PCC *delta, PCC *avg)
        free(sum);
 }
 
-void get_counters(PCC *pcc)
+void get_counters(struct counters *cnt)
 {
-       for ( ; pcc; pcc = pcc->next) {
-               pcc->tsc = get_msr(pcc->cpu, MSR_TSC);
+       for ( ; cnt; cnt = cnt->next) {
+               cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
                if (do_nhm_cstates)
-                       pcc->c3 = get_msr(pcc->cpu, MSR_CORE_C3_RESIDENCY);
+                       cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->c6 = get_msr(pcc->cpu, MSR_CORE_C6_RESIDENCY);
+                       cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
                if (do_snb_cstates)
-                       pcc->c7 = get_msr(pcc->cpu, MSR_CORE_C7_RESIDENCY);
+                       cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
                if (has_aperf)
-                       pcc->aperf = get_msr(pcc->cpu, MSR_APERF);
+                       cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
                if (has_aperf)
-                       pcc->mperf = get_msr(pcc->cpu, MSR_MPERF);
+                       cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
                if (do_snb_cstates)
-                       pcc->pc2 = get_msr(pcc->cpu, MSR_PKG_C2_RESIDENCY);
+                       cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->pc3 = get_msr(pcc->cpu, MSR_PKG_C3_RESIDENCY);
+                       cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->pc6 = get_msr(pcc->cpu, MSR_PKG_C6_RESIDENCY);
+                       cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
                if (do_snb_cstates)
-                       pcc->pc7 = get_msr(pcc->cpu, MSR_PKG_C7_RESIDENCY);
+                       cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
                if (extra_msr_offset)
-                       pcc->extra_msr = get_msr(pcc->cpu, extra_msr_offset);
+                       cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
        }
 }
 
-
-void print_nehalem_info()
+void print_nehalem_info(void)
 {
        unsigned long long msr;
        unsigned int ratio;
@@ -514,38 +513,38 @@ void print_nehalem_info()
 
 }
 
-void free_counter_list(PCC *list)
+void free_counter_list(struct counters *list)
 {
-       PCC *p;
+       struct counters *p;
 
        for (p = list; p; ) {
-               PCC *free_me;
+               struct counters *free_me;
 
                free_me = p;
                p = p->next;
                free(free_me);
        }
-       return;
 }
 
 void free_all_counters(void)
 {
-       free_counter_list(pcc_even);
-       pcc_even = NULL;
+       free_counter_list(cnt_even);
+       cnt_even = NULL;
 
-       free_counter_list(pcc_odd);
-       pcc_odd = NULL;
+       free_counter_list(cnt_odd);
+       cnt_odd = NULL;
 
-       free_counter_list(pcc_delta);
-       pcc_delta = NULL;
+       free_counter_list(cnt_delta);
+       cnt_delta = NULL;
 
-       free_counter_list(pcc_average);
-       pcc_average = NULL;
+       free_counter_list(cnt_average);
+       cnt_average = NULL;
 }
 
-void insert_cpu_counters(PCC **list, PCC *new)
+void insert_counters(struct counters **list,
+       struct counters *new)
 {
-       PCC *prev;
+       struct counters *prev;
 
        /*
         * list was empty
@@ -594,18 +593,16 @@ void insert_cpu_counters(PCC **list, PCC *new)
         */
        new->next = prev->next;
        prev->next = new;
-
-       return;
 }
 
-void alloc_new_cpu_counters(int pkg, int core, int cpu)
+void alloc_new_counters(int pkg, int core, int cpu)
 {
-       PCC *new;
+       struct counters *new;
 
        if (verbose > 1)
                printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -613,9 +610,10 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_odd, new);
+       insert_counters(&cnt_odd, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1,
+               sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -623,9 +621,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_even, new);
+       insert_counters(&cnt_even, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -633,9 +631,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_delta, new);
+       insert_counters(&cnt_delta, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -643,7 +641,7 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       pcc_average = new;
+       cnt_average = new;
 }
 
 int get_physical_package_id(int cpu)
@@ -719,7 +717,7 @@ void re_initialize(void)
 {
        printf("turbostat: topology changed, re-initializing.\n");
        free_all_counters();
-       num_cpus = for_all_cpus(alloc_new_cpu_counters);
+       num_cpus = for_all_cpus(alloc_new_counters);
        need_reinitialize = 0;
        printf("num_cpus is now %d\n", num_cpus);
 }
@@ -728,7 +726,7 @@ void dummy(int pkg, int core, int cpu) { return; }
 /*
  * check to see if a cpu came on-line
  */
-void verify_num_cpus()
+void verify_num_cpus(void)
 {
        int new_num_cpus;
 
@@ -740,14 +738,12 @@ void verify_num_cpus()
                                num_cpus, new_num_cpus);
                need_reinitialize = 1;
        }
-
-       return;
 }
 
 void turbostat_loop()
 {
 restart:
-       get_counters(pcc_even);
+       get_counters(cnt_even);
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        while (1) {
@@ -757,24 +753,24 @@ restart:
                        goto restart;
                }
                sleep(interval_sec);
-               get_counters(pcc_odd);
+               get_counters(cnt_odd);
                gettimeofday(&tv_odd, (struct timezone *)NULL);
 
-               compute_delta(pcc_odd, pcc_even, pcc_delta);
+               compute_delta(cnt_odd, cnt_even, cnt_delta);
                timersub(&tv_odd, &tv_even, &tv_delta);
-               compute_average(pcc_delta, pcc_average);
-               print_counters(pcc_delta);
+               compute_average(cnt_delta, cnt_average);
+               print_counters(cnt_delta);
                if (need_reinitialize) {
                        re_initialize();
                        goto restart;
                }
                sleep(interval_sec);
-               get_counters(pcc_even);
+               get_counters(cnt_even);
                gettimeofday(&tv_even, (struct timezone *)NULL);
-               compute_delta(pcc_even, pcc_odd, pcc_delta);
+               compute_delta(cnt_even, cnt_odd, cnt_delta);
                timersub(&tv_even, &tv_odd, &tv_delta);
-               compute_average(pcc_delta, pcc_average);
-               print_counters(pcc_delta);
+               compute_average(cnt_delta, cnt_average);
+               print_counters(cnt_delta);
        }
 }
 
@@ -892,7 +888,7 @@ void check_cpuid()
         * this check is valid for both Intel and AMD
         */
        asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
-       has_invariant_tsc = edx && (1 << 8);
+       has_invariant_tsc = edx & (1 << 8);
 
        if (!has_invariant_tsc) {
                fprintf(stderr, "No invariant TSC\n");
@@ -905,7 +901,7 @@ void check_cpuid()
         */
 
        asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
-       has_aperf = ecx && (1 << 0);
+       has_aperf = ecx & (1 << 0);
        if (!has_aperf) {
                fprintf(stderr, "No APERF MSR\n");
                exit(1);
@@ -952,7 +948,7 @@ void turbostat_init()
        check_dev_msr();
        check_super_user();
 
-       num_cpus = for_all_cpus(alloc_new_cpu_counters);
+       num_cpus = for_all_cpus(alloc_new_counters);
 
        if (verbose)
                print_nehalem_info();
@@ -962,7 +958,7 @@ int fork_it(char **argv)
 {
        int retval;
        pid_t child_pid;
-       get_counters(pcc_even);
+       get_counters(cnt_even);
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        child_pid = fork();
@@ -985,14 +981,14 @@ int fork_it(char **argv)
                        exit(1);
                }
        }
-       get_counters(pcc_odd);
+       get_counters(cnt_odd);
        gettimeofday(&tv_odd, (struct timezone *)NULL);
-       retval = compute_delta(pcc_odd, pcc_even, pcc_delta);
+       retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
 
        timersub(&tv_odd, &tv_even, &tv_delta);
-       compute_average(pcc_delta, pcc_average);
+       compute_average(cnt_delta, cnt_average);
        if (!retval)
-               print_counters(pcc_delta);
+               print_counters(cnt_delta);
 
        fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);;
 
index 4780dea..65b845b 100644 (file)
@@ -46,7 +46,7 @@ config INITRAMFS_ROOT_GID
          If you are not sure, leave it set to "0".
 
 config RD_GZIP
-       bool "Support initial ramdisks compressed using gzip" if EMBEDDED
+       bool "Support initial ramdisks compressed using gzip" if EXPERT
        default y
        depends on BLK_DEV_INITRD
        select DECOMPRESS_GZIP
@@ -55,8 +55,8 @@ config RD_GZIP
          If unsure, say Y.
 
 config RD_BZIP2
-       bool "Support initial ramdisks compressed using bzip2" if EMBEDDED
-       default !EMBEDDED
+       bool "Support initial ramdisks compressed using bzip2" if EXPERT
+       default !EXPERT
        depends on BLK_DEV_INITRD
        select DECOMPRESS_BZIP2
        help
@@ -64,8 +64,8 @@ config RD_BZIP2
          If unsure, say N.
 
 config RD_LZMA
-       bool "Support initial ramdisks compressed using LZMA" if EMBEDDED
-       default !EMBEDDED
+       bool "Support initial ramdisks compressed using LZMA" if EXPERT
+       default !EXPERT
        depends on BLK_DEV_INITRD
        select DECOMPRESS_LZMA
        help
@@ -73,8 +73,8 @@ config RD_LZMA
          If unsure, say N.
 
 config RD_XZ
-       bool "Support initial ramdisks compressed using XZ" if EMBEDDED
-       default !EMBEDDED
+       bool "Support initial ramdisks compressed using XZ" if EXPERT
+       default !EXPERT
        depends on BLK_DEV_INITRD
        select DECOMPRESS_XZ
        help
@@ -82,8 +82,8 @@ config RD_XZ
          If unsure, say N.
 
 config RD_LZO
-       bool "Support initial ramdisks compressed using LZO" if EMBEDDED
-       default !EMBEDDED
+       bool "Support initial ramdisks compressed using LZO" if EXPERT
+       default !EXPERT
        depends on BLK_DEV_INITRD
        select DECOMPRESS_LZO
        help